diff --git a/README.md b/README.md index 54af306f..e0cbbb7d 100644 --- a/README.md +++ b/README.md @@ -183,7 +183,9 @@ git clone --recursive https://github.com/Coldcard/firmware.git cd firmware # Apply address patch -git apply unix/linux_addr.patch +# if unix/linux_addr.patch exists use below command +# not needed in current revision +# git apply unix/linux_addr.patch # * below is needed for ubuntu 24.04 pushd external/micropython diff --git a/cli/signit.py b/cli/signit.py index ec100c9c..62a2bb43 100755 --- a/cli/signit.py +++ b/cli/signit.py @@ -319,13 +319,14 @@ def doit(keydir, outfn=None, build_dir=None, high_water=False, pubkey_num=pubkey_num, timestamp=timestamp(backdate) ) - assert FW_MIN_LENGTH <= hdr.firmware_length <= FW_MAX_LENGTH_MK4, hdr.firmware_length if hw_compat & MK_3_OK: # actual file length limited by size of SPI flash area reserved to txn data/uploads + assert FW_MIN_LENGTH <= hdr.firmware_length <= FW_MAX_LENGTH, hdr.firmware_length USB_MAX_LEN = (786432-128) else: - # new value for Mk4: limited only by final binary size, not SPI flash + # new value for Mk4 and later: limited only by final binary size, not SPI flash + assert FW_MIN_LENGTH <= hdr.firmware_length <= FW_MAX_LENGTH_MK4, hdr.firmware_length USB_MAX_LEN = 1472 * 1024 assert hdr.firmware_length <= USB_MAX_LEN, \ diff --git a/docs/bip-21-extensions.md b/docs/bip-21-extensions.md new file mode 100644 index 00000000..17a6b73b --- /dev/null +++ b/docs/bip-21-extensions.md @@ -0,0 +1,15 @@ +## Multisig Ownership address check: "wallet" + +If the name of the multisig wallet related to an address is provided, address search +can be greatly accelerated. Just provide `wallet=name` parameter in a standard +[BIP-21](https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki) URL +shown in QR code or NFC record. If omitted, search will continue across +all multisig wallets known by COLDCARD. + +### Examples + +``` +tb1q4d67p7stxml3kdudrgkg5mgaxsrgzcqzjrrj4gg62nxtvnsnvqjsxjkej0?wallet=goldmine + +bitcoin:mtHSVByP9EYZmB26jASDdPVm19gvpecb5R?label=coldcard_purchase&amount=50&wallet=Haystack%20Four +``` diff --git a/docs/generic-wallet-export.md b/docs/generic-wallet-export.md index f9823116..0a503202 100644 --- a/docs/generic-wallet-export.md +++ b/docs/generic-wallet-export.md @@ -57,7 +57,7 @@ to be the first (non-change) receive address for the wallet. segregate funds into sub-wallets. Don't assume it's zero. 3. When making your PSBT files to spend these amounts, remember that the XFP of the master -(`0F056943` in this example) is is the root of the subkey paths found in the file, and +(`0F056943` in this example) is the root of the subkey paths found in the file, and you must include the full derivation path from master. So based on this example, to spend a UTXO on `tb1qc58ys2dphtphg6yuugdf3d0kufmk0tye044g3l`, the input section of your PSBT would need to specify `(m=0F056943)/84'/1'/123'/0/0`. diff --git a/docs/key-teleport.md b/docs/key-teleport.md new file mode 100644 index 00000000..9056e2dd --- /dev/null +++ b/docs/key-teleport.md @@ -0,0 +1,224 @@ + +# Key Teleport + +Purpose: Send a small quantity of very secret data between two COLDCARD Q systems, with +no risk of anything in the middle learning the secret. + +Method: ECDH and AES-256-CTR plus an extra wrapping layer, transmitted over a mixture of +NFC, passive websites, and QR/BBQr codes. + +# Protocol Overview + +## Steps + +- Receiver picks an EC keypair, stores it in settings, and publishes the pubkey via a QR/NFC +- The pubkey is encrypted by a short 8-digit numeric code, which should be + sent by a different channel. +- Sender gets QR and numeric code, picks own keypair, and does ECDH to arrive at a + shared session key +- Sender picks a human-readable secret which is independent of anything else (P key) +- The secret data (perhaps a seed phrase, XPRV, secure note, full backup, etc) is + AES-256-CTR encrypted with P key, then encrypted + MAC added with session key +- Data packet is sent to receiver (via BBQr), who can reconstruct the session key via ECDH +- Prompt user for the P key to finish decoding +- Decoded secret value is saved to Seed Vault or secure notes as appropriate +- Receiver destroys EC keypair used in transfer + +### When used for PSBT Multisig + +- No action required on receiver +- Sender uses the pubkey derived from pre-shared XPUB involved in the multisig wallet. +- Same steps, but drops immediately into signing process when decoded correctly + +## Notes and Limitations + +- max 4k (after encoding) of data is possible due to HTTP limitations +- all transfers are "data typed" and decode only on COLDCARD +- Q model is required due to the use of QR codes to ultimately get data into the COLDCARD + + +# Details + +## Data Type Codes + +The first byte encodes what the package contents (under all the encryption). + +- `s` - 12/18/24 words/raw master/xprv - 17-72 bytes follow, encoded in an internal format +- `x` - XPRV mode, full details - 4 bytes (XPRV) + base58 *decoded* binary-XPRV follows +- `n` - one or many notes export (JSON array) +- `v` - seed vault export (JSON: one secret key but includes name, source of key) +- `p` - binary PSBT to be signed, perhaps multisig but not required. +- `b` - complete system backup file (text lines, internal format) + +## QR details + +BBQr is always used for the QR's involved in this process, even if +they are short enough for a normal QR code. Because the BBQr is +being generated by the COLDCARD embedded firmware, it will not be +compressed and will always be Base32 encoded. + +New type codes for BBQr are defined for the purposes of this application: + +- `R` contains `(pubkey)` ... begins the process from receiver; compressed pubkey is 33 bytes +- `S` contains `(pubkey)(data)` ... data from sender; first 33 bytes are sender's pubkey +- `E` for Multisig PSBT: `(randint)(data)` ... randint (4 byte nonce) indicates which + derived subkey from pre-shared xpub associated with receiver + +All the data is encrypted with the exception randint. Keep in mind +this is a nonce value picked uniquely for each transfer. The +receiver's pubkey is only weakly encrypted by the 8-digit numeric +password, but is also a nonce effectively. + +### PSBT Key Selection + +When sending PSBT data, a nonce is picked at random by the sender +in range: `0..(2^28)` + +This nonce is called `randint`. The receiver's pubkey will be + + .../20250317/(randint) + +where `...` is the derivation used in the multisig wallet for the co-signer who will +receive the package. The sender's keypair has the same sub key path assuming all +co-signers have same derivation path from root (not required). + +Because both the sender and receiver already have each other's XPUB they can derive +the appropriate pubkeys (and privkey for their side) without communicating +more than `randint`. The sending COLDCARD will pick a new random value each time. + +When receiving a multisig PSBT encrypted this way, the receiver does not need +to do any setup (nor numeric password) and can receive a QR code at any time. +This works because the shared multisig wallet is already setup. Receiver will +take the nonce value (randint) and seach all pre-defined multisig wallets for +any pubkey that can decrypt the package successfully (based on checksum inside +first layer of ECDH encryption). + +The next layer of encryption (paranoid password) is unchanged. + +## Encryption Details + +AES-256-CTR is used exclusively. Session key is picked via ECDH with final +key value being the SHA256 over 64 bytes of coordinate X (concat) Y. + +While ECDH is enough to assure privacy from men in the middle, we +add an additional layer of encryption. We call this the "paranoid key" internally +and in the UX it is called "Teleport Password". + +The user sees a random 8-character password, generated as a random 40-bit value, but +shown in Base32 (8 chars) for the human to enter. We apply PBKDF2-SHA512 with +an iteration count of 5000 to stretch that to 512 bits, of which we use half. +The session key is used as the key for the KDF, and the entered value as salt. + +- ECDH arrives at session key +- decrypt (AES-256-CTR) the binary body of message +- verify checksum: + - final 2 bytes should be `== SHA256(decrypted body[0:-2])[-2:]` + - if not, corruption, truncation, or wrong keys +- if that decryption is correct, then prompt user for the paranoid key (8 chars) +- stretch that value using session key and 5000 iterations of PBKDF2-SHA512 +- use upper 256 bits and run AES-256-CTR again +- same checksum of 2 bytes of SHA256 are found inside after decryption + +Encryption adds 4 bytes of overhead because of these MAC values, +but should catch truncation and bitrot. There are no other +protections against truncation as length data is not transmitted. + +# Receiver Password + +When the teleport process is started, the receiver shares his pubkey +as QR. However, we also show an 8-digit numeric password. The +purpose of this is force the receiver to share this separately from +the pubkey QR on another channel. The code is randomly picked, but +only represents about 26 bits of entropy and is stretched with +a single round of SHA256 before being used as a AES-256-CTR key +to decrypt the pubkey. No checksum verifies correct +decryption, so any code is accepted, and will with near-50% odds, +decrypt to a valid pubkey. + +When the sender is given the receiver's pubkey via QR code, it +prompts for the numeric code and uses it to decrypt the pubkey. +Thus a MiTM who injects their pubkey will be detected and blocked. + +The "paranoid key" serves the same role in the other direction but +it is Base32 character set, so it will not look similar or be +confusing as to its purpose. + +# Web Component + +In order to "teleport" the contents of a QR code over NFC, we will +publish a static website directly from an open Github repository. +The single-page website contains javascript code which looks at the +"hash" part of the incoming URL (`window.location.hash`) and if it +meets the requirements, renders a large QR. The QR data must look like +a correctly-encoded BBQr with one of the 3 type-codes above (`R` `S` or `E`). +Otherwise the website could render any QR, which we don't want to +support. + +The page will offer "copy to clipboard" features for the data inside +the QR as a URL (ie. same URL as shown) and as an image and of course, +the COLDCARD Q can scan from the web browser screen itself. + +When the BBQr data is larger than comfortable for a single QR, the +website can split into a multi-frame BBQr. The website can +do this without understanding the contents of the BBQr data (all +of which is encrypted). Download options will be provided for +single-frame QR, animated PNG, and "stacked BBQr" (a single tall +PNG with each QR frame stacked). + +On the COLDCARD side, when NFC is tapped, it will offer a long URL +to this site with the data to be transferred "after the hash". This +is optional since the QR can be shown on the Q itself, and would +pass the same data. + +Since the website is running on Github, Coinkite does not have +access to IP addresses or other access log details. Because the data for +teleport is "after the hash" it is never sent to Github's servers +but remains in the browser only. All JS resources referenced by the +webpage will have content hashes applied to prevent interference, +and the site will be served over SSL. + +Visit [keyteleport.com](https://keyteleport.com/), or an +[example small QR](https://keyteleport.com/#B$2R0100VHT2AGUUH7KUZUUSTOWOIWHJX3XM7GA2N4BHQOXDFHXLVHVA7K6ZO) +and [view source code](https://github.com/coinkite/keyteleport.com). + +# UX Details + +- When the receive process is started by the user, a pubkey is picked + and stored, so that they can come back later (after a power cycle) + and make use of the data encoded by the sender. However once a package + is decoded successfully, that key is deleted. + +- Sender must start by scanning the QR from a receiver. Then can pick what + to send, from secure notes to seeds and so on. + +- For PSBT multisig, user must pick a single co-signer (who hasn't already + signed) and the QR is prepared for that receiver. Because we + cannot do arbitary combining, it's best if the next signer continues + to teleport the updated PSBT to further signers. In other words, + a daisy-chain pattern is prefered to a star pattern. The signer + who completes the Mth (of N) signature will be able to finalize + the transaction, and ideally with PushTx feature, broadcast it. + +# Security Comments + +## Such short passwords? + +We are using 8-character passwords because we want them to be +practical to share over non-digital channels such as a voice phone +call, or hand-written note. + +It is very important to remind users that the passwords should be sent +by a different channel from the QR itself. Best is to call up your +other party and say the letters to them directly. + +## Is it safe to save image of QR to cloud? + +Yes, this seems safe. Of course, if you can control it, perhaps not +a risk to accept... but the QR is encrypted via ECDH using a key +that is forgotten after the transfer, so forward privacy is protected. +Also your cloud service (or photo roll, chat app log, etc) will not +have the 8-character password which is also required unpack the secrets. + +The QR codes themselves are fully random and do not reveal the +identity of your COLDCARD, your on chain funds or anything linked +to you. diff --git a/docs/limitations.md b/docs/limitations.md index 5878b892..7a5bb54a 100644 --- a/docs/limitations.md +++ b/docs/limitations.md @@ -14,11 +14,12 @@ # PIN Codes - 2-2 through 6-6 in size, numeric digits only -- pin code 999999-999999 is reserved (means 'clear pin') +- pin code 999999-999999 was reserved (meaning 'clear pin'), but now available again # Backup Files - we don't know what day it is, so meta data on files will not have correct date/time +- release date of the firmware version that made the file is used instead of true date - encrypted files produced cannot be changed, and we don't support other tools making them # Micro SD @@ -55,14 +56,18 @@ - only one signature will be added per input. However, if needed the partly-signed PSBT can be given again, and the "next" leg will be signed. -- we do not support PSBT combining or finalizing of transactions involving - P2SH signatures (so the combine step must be off-device) +- finalizing of multisig transactions involving P2SH signatures: + * SD/Vdisk signing exports both signed PSBT and finalized txn ready for broadcast (if txn is complete) + * QR/NFC outputs finalized txn ready for broadcast if txn is complete otherwise signed PSBT only + * USB signing requires `--finalize` parameter (as for standard single signature wallets) + - we can sign for P2SH and P2WSH addresses that represent multisig (M of N) but we cannot sign for non-standard scripts because we don't know how to present that to the user for approval. - during USB "show address" for multisig, we limit subkey paths to 16 levels deep (including master fingerprint) -- max of 15 co-signers due to 520 byte script limitation in consensus layer with classic P2SH (same limit applies to segwit even though consensus allows up to 20 co-signers) +- max of 15 co-signers due to 1650 byte `scriptSig` limitation in policy with classic P2SH (same limit applies to segwit even though consensus allows up to 20 co-signers). + note: the consensus layer sets an upper bound of 520 bytes for the length of each stack element - (mk3) we have space for up to 8 M-of-3 wallets, or a single M-of-15 wallet. YMMV - only a single multisig wallet can be involved in a PSBT; can't sign inputs from two different multisig wallets at the same time. @@ -74,6 +79,7 @@ - multisig wallet `name` can only contain printable ASCII characters `range(32, 127)` ### BIP-67 + - importing multisig from PSBT can ONLY create `sortedmulti(...)` multisig according to BIP-67, DO NOT use with `multi(...)` - creating airgapped multisig using COLDCARD as coordinator always produces `sortedmulti(...)` multisig according to BIP-67 - COLDCARD import/export [format](https://coldcard.com/docs/multisig/#configuration-text-file-for-multisig) only supports `sortedmulti(...)` multisig according to BIP-67. To import multisig wallet with `multi(...)` use descriptor import [format](https://github.com/bitcoin/bips/blob/master/bip-0383.mediawiki) @@ -135,6 +141,10 @@ We will summarize transaction outputs as "change" back into same wallet, however - key derivatation paths must be 12 or less in depth (`MAX_PATH_DEPTH`) +# Pay-to-Pubkey + +- although we have some code for "pay to pubkey" (P2PK not P2PKH), it is untested + and unused since this style of payment address is obsolete and largely unused today # NFC Feature @@ -199,3 +209,16 @@ We will summarize transaction outputs as "change" back into same wallet, however - if you have an XFP collision between multiple wallets in SeedVault (ie. two wallets with same descriptors, but different seeds) you will get false negatives +# Spending Policy + +- (Cosign mode) only 12 or 24 word seeds (not XPRV) are accepted for "key C" +- velocity limit: + - based on a max magnitude per txn, and a required minimum block height + gap, based on previous `nLockTime` value in last-signed PSBT. + - if you sign a transaction, but never broadcast it, you will still have to wait out + the velocity policy. + - PSBT creator must put in `nLockTime` block heights (most already do to avoid fee sniping) +- maximum of 25 whitelisted addresses can be stored +- Web2FA: any number of mobile devices can be enrolled, but all will have the same shared secret +- any warning from the PSBT, such as huge fees, will cause the transaction to be rejected + diff --git a/docs/menu-tree.txt b/docs/menu-tree.txt index 724a17c0..8a9dea57 100644 --- a/docs/menu-tree.txt +++ b/docs/menu-tree.txt @@ -16,7 +16,6 @@ Advanced 12 Word Dice Roll 24 Word Dice Roll - Migrate COLDCARD Import Existing 12 Words [SEED WORD ENTRY] @@ -30,6 +29,8 @@ Import XPRV Tapsigner Backup Seed XOR + Migrate Coldcard + Key Teleport (start) Help Advanced/Tools View Identity @@ -57,14 +58,18 @@ List Files Verify Sig File NFC File Share [IF NFC ENABLED] + BBQr File Share [IF QR SCANNER] + QR File Share [IF QR SCANNER] Format SD Card Format RAM Disk [IF VIRTDISK ENABLED] + Key Teleport (start) Paper Wallets Perform Selftest I Am Developer. Serial REPL Warm Reset - Restore Txt Bkup + Restore Bkup + Reflash GPU [IF QWERTY KEYBOARD] Secure Logout Settings Login Settings @@ -106,6 +111,11 @@ NFC Sharing Default Off Enable NFC + NFC Push Tx + coldcard.com + mempool.space + Custom URL... + Disable Display Units BTC mBTC @@ -140,8 +150,9 @@ 50% 60% 70% - 80% (default) + 80% 90% + 95% (default) 100% Delete PSBTs Default Keep @@ -149,17 +160,20 @@ Menu Wrapping Default Off Enable + Home Menu XFP [IF SECRET AND NOT TMP SEED] + Only Tmp + Always Show --- [NORMAL OPERATION] Ready To Sign Passphrase [IF WORD BASED SEED] - Restore Saved [MAYBE] - A*********** - [0C52BAD4] + Restore Saved + c******* + [3A14F788] Restore Delete - Edit Phrase [MAYBE] + Edit Phrase [IF QWERTY] Add Word [IF NOT QWERTY] [SEED WORD MENUS] Add Numbers [IF NOT QWERTY] @@ -183,35 +197,44 @@ Account Number Custom Path CC-2-of-4 - Secure Notes & Passwords [IF ENBALED] - 1: note1 - "note1" + Secure Notes & Passwords [IF ENBALED] [MAYBE] + 1: note0 + "note0" View Note Edit Delete Export - SHORTCUT - SHORTCUT - 2: nostr - "nostr" - ↳ scg - ↳ brb.io + Sign Note Text + 2: secret-PWD + "secret-PWD" + ↳ satoshi + ↳ abc.org View Password Send Password [MAYBE] Export Edit Metadata Delete Change Password - SHORTCUT - SHORTCUT + Sign Note Text New Note New Password Export All + Sort By Title Import Type Passwords [MAYBE] Seed Vault [MAYBE] - 1: [B14E9AE0] - [B14E9AE0] + 1: [7126EB3C] + [7126EB3C] + Use This Seed + Rename + Delete + 2: [CCEE13B9] + [CCEE13B9] + Use This Seed + Rename + Delete + 3: [03EE9989] + [03EE9989] Use This Seed Rename Delete @@ -222,12 +245,18 @@ Restore Backup Clone Coldcard Export Wallet + Sparrow + Cove Bitcoin Core - Sparrow Wallet + Nunchuk + Bull Bitcoin + Zeus Electrum Wallet Wasabi Wallet + Fully Noded Unchained - Lily Wallet + Theya + Bitcoin Safe Samourai Postmix Samourai Premix Descriptor @@ -235,7 +264,7 @@ Export XPUB Segwit (BIP-84) Classic (BIP-44) - P2WPKH/P2SH (49) + P2WPKH/P2SH (BIP-49) Master XPUB Current XFP Dump Summary @@ -247,12 +276,18 @@ Verify Backup Backup System Export Wallet + Sparrow + Cove Bitcoin Core - Sparrow Wallet + Nunchuk + Bull Bitcoin + Zeus Electrum Wallet Wasabi Wallet + Fully Noded Unchained - Lily Wallet + Theya + Bitcoin Safe Samourai Postmix Samourai Premix Descriptor @@ -260,42 +295,44 @@ Export XPUB Segwit (BIP-84) Classic (BIP-44) - P2WPKH/P2SH (49) + P2WPKH/P2SH (BIP-49) Master XPUB Current XFP Dump Summary Sign Text File Batch Sign PSBT + Teleport Multisig PSBT List Files Verify Sig File NFC File Share [IF NFC ENABLED] + BBQr File Share [IF QR SCANNER] + QR File Share [IF QR SCANNER] Clone Coldcard Format SD Card Format RAM Disk [IF VIRTDISK ENABLED] Secure Notes & Passwords [IF QWERTY KEYBOARD] - 1: note1 - "note1" + 1: note0 + "note0" View Note Edit Delete Export - SHORTCUT - SHORTCUT - 2: nostr - "nostr" - ↳ scg - ↳ brb.io + Sign Note Text + 2: secret-PWD + "secret-PWD" + ↳ satoshi + ↳ abc.org View Password Send Password [MAYBE] Export Edit Metadata Delete Change Password - SHORTCUT - SHORTCUT + Sign Note Text New Note New Password Export All + Sort By Title Import Derive Seeds (BIP-85) View Identity @@ -314,18 +351,24 @@ Import XPRV Tapsigner Backup Coldcard Backup + Key Teleport (start) + Spending Policy + Single-Signer [IF SECRET AND NOT TMP SEED] + Co-Sign Multisig (CCC) [IF NOT TMP SEED] + HSM Mode [IF HSM AND SECRET] + Default Off + Enable + User Management [MAYBE] Paper Wallets - Enable HSM [IF HSM AND SECRET] - Default Off - Enable - User Management [IF HSM AND SECRET] NFC Tools [IF NFC ENABLED] + Sign PSBT Show Address Sign Message Verify Sig File Verify Address File Share Import Multisig + Push Transaction [IF PUSHTX ENABLED] Danger Zone Debug Functions Seed Functions @@ -334,13 +377,15 @@ Split Existing [IF WORD BASED SEED] Restore Seed XOR Destroy Seed [IF SECRET AND NOT TMP SEED] - Lock Down Seed + Lock Down Seed [MAYBE] Export SeedQR [IF WORD BASED SEED] I Am Developer. Serial REPL Warm Reset - Restore Txt Bkup - Seed Vault [IF SECRET] + Restore Bkup + BKPW Override + Reflash GPU [IF QWERTY KEYBOARD] + Seed Vault [IF SECRET AND NOT TMP SEED] Default Off Enable Perform Selftest @@ -353,30 +398,43 @@ Warn Testnet Mode Bitcoin - Testnet3 + Testnet4 Regtest - AE Start IDX + AE Start Index Default Off Enable + B85 Idx Values + Default Off + Unlimited Settings Space MCU Key Slots Bless Firmware - Reflash GPU [IF QWERTY KEYBOARD] Wipe LFS Settings Login Settings Change Main PIN Trick PINs [IF SECRET AND NOT TMP SEED] Trick PINs: - ↳123-254 - PIN 123-254 + ↳11-11 + PIN 11-11 + ↳Bricks CC + Hide Trick + Delete Trick + Change PIN + ↳333-3334 + PIN 333-3334 ↳Duress Wallet Activate Wallet Hide Trick Delete Trick Change PIN + ↳WRONG PIN + After 3 wrong: + ↳Wipes seed + ↳Reboots + Hide Trick + Delete Trick Add New Trick - Add If Wrong Delete All Set Nickname Scramble Keys @@ -421,17 +479,27 @@ View Details Delete Coldcard Export + Electrum Wallet Descriptors View Descriptor Export Bitcoin Core - Electrum Wallet Import from File + Import from QR [IF QR SCANNER] Import via NFC [IF NFC ENABLED] Export XPUB Create Airgapped Trust PSBT? Skip Checks? + Full Address View? + Partly Censor + Show Full + Unsorted Multisig? + NFC Push Tx + coldcard.com + mempool.space + Custom URL... + Disable Display Units BTC mBTC @@ -466,8 +534,9 @@ 50% 60% 70% - 80% (default) + 80% 90% + 95% (default) 100% Delete PSBTs Default Keep @@ -475,25 +544,171 @@ Menu Wrapping Default Off Enable + Home Menu XFP [IF SECRET AND NOT TMP SEED] + Only Tmp + Always Show Keyboard EMU Default Off Enable Secure Logout SHORTCUT [IF NFC ENABLED] + Sign PSBT Show Address Sign Message Verify Sig File Verify Address File Share Import Multisig + Push Transaction [IF PUSHTX ENABLED] --- [FACTORY MODE] - Version: 5.x.x Bag Me Now + Version: 5.x.x DFU Upgrade Ship W/O Bag Debug Functions Perform Selftest --- +[SSSP] + Ready To Sign + Passphrase [IF WORD BASED SEED & SSSP RELATED KEYS ENABLED] + Restore Saved + c******* + [3A14F788] + Restore + Delete + Edit Phrase + Scan Any QR Code [IF QR SCANNER] + Address Explorer + Classic P2PKH + ↳ mtHSVByP9EYZ⋯Vm19gvpecb5R + P2SH-Segwit + ↳ 2NCAJ5wD4Gvm⋯NphNU8UYoEJv + Segwit P2WPKH + ↳ tb1qupyd58nd⋯vu9jtdyws9n9 + Applications + Samourai + Post-mix + Pre-mix + Wasabi + Account Number + Custom Path + CC-2-of-4 + Secure Notes & Passwords[IF ENABLED & SSSP ALLOW NOTES] + 1: note0 + "note0" + View Note + Sign Note Text + 2: secret-PWD + "secret-PWD" + ↳ satoshi + ↳ abc.org + View Password + Send Password [MAYBE] + Sign Note Text + Type Passwords [MAYBE] + Seed Vault[IF ENABLED & SSSP RELATED KEYS ENABLED] + 1: [7126EB3C] + [7126EB3C] + Use This Seed + 2: [CCEE13B9] + [CCEE13B9] + Use This Seed + 3: [03EE9989] + [03EE9989] + Use This Seed + Advanced/Tools + File Management + Sign Text File + Batch Sign PSBT + List Files + Export Wallet + Sparrow + Cove + Bitcoin Core + Nunchuk + Bull Bitcoin + Zeus + Electrum Wallet + Wasabi Wallet + Fully Noded + Unchained + Theya + Bitcoin Safe + Samourai Postmix + Samourai Premix + Descriptor + Generic JSON + Export XPUB + Segwit (BIP-84) + Classic (BIP-44) + P2WPKH/P2SH (BIP-49) + Master XPUB + Current XFP + Dump Summary + Verify Sig File + NFC File Share [IF NFC ENABLED] + BBQr File Share [IF QR SCANNER] + QR File Share [IF QR SCANNER] + Format SD Card + Format RAM Disk [IF VIRTDISK ENABLED] + Export Wallet + Sparrow + Cove + Bitcoin Core + Nunchuk + Bull Bitcoin + Zeus + Electrum Wallet + Wasabi Wallet + Fully Noded + Unchained + Theya + Bitcoin Safe + Samourai Postmix + Samourai Premix + Descriptor + Generic JSON + Export XPUB + Segwit (BIP-84) + Classic (BIP-44) + P2WPKH/P2SH (BIP-49) + Master XPUB + Current XFP + Dump Summary + Teleport Multisig PSBT [MAYBE] + View Identity + Temporary Seed [IF SSSP RELATED KEYS ENABLED] + Import from QR Scan [IF QR SCANNER] + Import Words + 12 Words + 18 Words + 24 Words + Import via NFC [IF NFC ENABLED] + Import XPRV + Tapsigner Backup + Coldcard Backup + Paper Wallets + NFC Tools [IF NFC ENABLED] + Sign PSBT + Show Address + Sign Message + Verify Sig File + Verify Address + File Share + Push Transaction [IF PUSHTX ENABLED] + Destroy Seed + Secure Logout + EXIT TEST DRIVE [MAYBE] + SHORTCUT [IF NFC ENABLED] + Sign PSBT + Show Address + Sign Message + Verify Sig File + Verify Address + File Share + Push Transaction [IF PUSHTX ENABLED] +--- + diff --git a/docs/miniscript.md b/docs/miniscript.md index a8a618c9..93c8a316 100644 --- a/docs/miniscript.md +++ b/docs/miniscript.md @@ -22,6 +22,7 @@ item with `` is added to `Address Explorer` menu. ## Limitations * no duplicate keys in miniscript (at least change indexes in subderivation has to be different) * subderivation may be omitted during the import - default `<0;1>/*` is implied -* only keys with key origin info `[xfp/p/a/t/h]xpub` +* both keys with key origin info `[xfp/p/a/t/h]xpub/<0;1>/*` & blinded keys `xpub/<2;3>/*` allowed +* use of blinded keys for co-signers requires PSBT provider to supply path from current key fingerprint * maximum number of keys allowed in segwit v0 miniscript is 20 * check MiniTapscript limitations in `docs/taproot.md` \ No newline at end of file diff --git a/docs/msg-signing.md b/docs/msg-signing.md index 72a48826..a79b6dd7 100644 --- a/docs/msg-signing.md +++ b/docs/msg-signing.md @@ -41,20 +41,26 @@ IFOvGVJrm31S0j+F4dVfQ5kbRKWKcmhmXIn/Lw8iIgaCG5QNZswjrN4X673R7jTZo1kvLmiD4hlIrbuL ### What is signed -1. **Single sig address explorer exports**. Signed by key corresponding to first (0th) address on the exported list. -2. **Specific single sig exports**. Signed by key corresponding to external address at index zero of chosen application specific derivation `m//0/0` +### What Is Signed + +1. **Single sig address explorer exports:** Signed by the key corresponding to the first (0th) address on the exported list. +2. **Specific single sig exports:** Signed by the key corresponding to the external address at index zero of chosen application specific derivation `m/h/'h/h/0/0`. * Bitcoin Core * Electrum Wallet * Wasabi Wallet * Samourai Postmix * Samourai Premix * Descriptor -3. **Generic single sig exports**. Signed by key that corresponds to address at derivation `m/44'/'/0'/0/0` - Lily Wallet - Generic JSON - Dump Summary -4. **BIP85 derived entropy exports**. Signed by path that corresponds to specific BIP85 application. -5. **Paper wallet exports**. Signed by key and address exported as paper wallet itself. +3. **Generic single sig exports:** Signed by key that corresponds to first (0th) external address at derivation `m/44h/h/h/0/0`. + * Lily Wallet + * Generic JSON + * Dump Summary +4. **BIP85 derived entropy exports:** Signed by path that corresponds to specific BIP85 application. +5. **Paper wallet exports:** Signed by key and address exported as paper wallet itself. +6. **Multisig exports:** public keys are encoded as P2PKH address for all multisg signature exports + * Multisig wallet descriptor: signed by the key corresponding to the first external address of own enrolled extended key `my_key/0/0` + * Generic XPUBs export: signed by the key corresponding to the first external address of own standard P2WSH derivation `m/48h/h/h/2h/0/0` + * Multisig address explorer export: Signed by own key at the same derivation as first (0th) row on exported list. `my_key//` ### What is NOT signed diff --git a/docs/seed-xor.md b/docs/seed-xor.md index 719a32cf..b79fb843 100644 --- a/docs/seed-xor.md +++ b/docs/seed-xor.md @@ -157,6 +157,12 @@ with the others on a SEEDPLATE. - right to A, down to B ... take that number, and go to that column - down to C, that is answer: a ⊕ b ⊕ c +## Open Standard +Seed XOR is an open standard. Other software and hardware wallets are encouraged to +implement support. No license or permission is required, including usage of the term +"Seed XOR" when referring to implementations of this feature. Such implementations +should match the process described in this documentation and be fully interoperable. + --- # 24 Words XOR Seed Example Using 3 Parts diff --git a/docs/spending-policy.md b/docs/spending-policy.md new file mode 100644 index 00000000..69381983 --- /dev/null +++ b/docs/spending-policy.md @@ -0,0 +1,209 @@ +# Spending Policy + +This special mode will stop you from signing transactions if they +exceed a spending policy you define beforehand. Once enabled, many +features of the COLDCARD are disabled or inaccessible. + +You might want to use this feature when traveling with your COLDCARD. + +## Spending Policy: Multisig (formerly CCC) + +We also support a mode where the COLDCARD is a multisig co-signer +and only performs its signature when a spending policy is met. The +other multisig signers are free to sign or not sign as appropriate. + +Multisig mode is more advanced and requires use of multisig addresses, +new UTXO, and cooperating multisig on-chain wallets. + +This document will only discuss the "Single signer" version of +Spending Policy. Both modes can be active at the same time, but if +a transaction would be signed by Multisig policy, then we assume +it's also okay to sign your main key as well. + +# Before You Start + +When a Spending Policy is in effect, there are limitations +in effect: + +- Firmware updates are blocked. +- There is no way to backup the COLDCARD. +- Seed vault and Secure Notes are read-only (and can also be hidden). +- Settings menu is inaccessible. +- BIP-39 passphrases may be blocked (optional). + +We recommend getting the COLDCARD fully configured and setup +for typical transactions before enabling the Spending Policy. + +# Setup Spending Policy + +Visit `Advanced / Tools > Spending Policy` menu and choose +"Single-Signer". First some background information is shown, +then you are prompted to define the "Bypass PIN". This PIN code +is only used when you need to disable the spending policy, but is +also the only way to do so once enabled... so don't loose it. + +Once the "Bypass PIN" is confirmed, you will arrive at menu for +related settings. Use "Edit Policy..." to change the spending policy +and define a Max Magnitude (limit number of BTC per transaction), +Velocity (minimum time gaps between signed transactions). You can +define a whitelist of up to 25 destination addresses (leave empty +for any). Finally you can enroll your phone in 2FA (second factor) +so that you must open an Authenticator app on your phone before +transactions are signed. + +## Other Security Settings + +In addition to policy itself, there are a number of on/off +switches which affect operation of the COLDCARD while the Spending +Policy is in effect: + +### Word Check + +If enabled, you will have to enter the first and last seed word +after the Bypass PIN as an additional security check. + +### Allow Notes + +On the Q, secure notes and passwords may be visible or hidden +using this setting. In either case they are strictly readonly. + +### Related Keys + +BIP-39 passphrase entry, Seed Vault usage will be blocked unless this +setting is enabled. Even when enabled, the Seed Vault is always readonly +and cannot be changed. + +# Other Menu Items + +## Last Violation + +If you have recently tried and failed to sign a transaction, the +reason for the transaction being rejected can be viewed and cleared, +using menu item "Last Violation". It is shown only if a Spending +Policy violation (attempt) has occurred since the last valid signing. + +This is meant as a debugging tool, and the information stored is +terse. + +## Remove Policy + +This will remove your spending policy completely and remove +the Bypass PIN. Your COLDCARD will be back to normal. + +## Test Drive + +Experiment with how the COLDCARD will function if the Spending +Policy was enabled. You can try to sign transactions that should +be rejected and view the menus in the new mode without rebooting. + +Choose "EXIT TEST DRIVE" on top menu to return to the Spending +Policy menu. Reboot will also restore normal operation without +any special challenges. + +## ACTIVATE + +This step will enable the Spending Policy and return to the +main menu with it in effect. When you reboot the COLDCARD, +the policy will still be in effect. You must use the +Bypass PIN, followed by the normal main PIN, possibly +followed by entering the first and last words of your seed +phrase, before you can disable and change the policy. + +We recommend test-driving the feature before doing that. + + +# Tips and Tricks + +## Money Manager Mode + +You could setup a Coldcard for another person, perhaps a family member, +and enable web 2FA authentication. There does not need to be any +other spending policy limits (velocity could be unlimited). + +Then enroll your own phone with the required 2FA values, and +keep both that and the spending policy bypass PIN confidential. + +The holder the the Coldcard will need a 2FA code from your phone +when they want to spend. They can call you for the 6-digit code +from the 2FA app on your phone. This is not hard to provide over a +voice call. + +Because a spending policy is in effect, they will not be able to +see the seed words, other private key material, so regardless of +any spoofing or phishing, they cannot move funds without your help. + +You should record the bypass PIN, so it can be revealed somehow, +should you die. You do not need to share the risks associated with +holding a copy of the seed words. + +## Passphrase Considerations + +If you are using the same BIP-39 passphrase for everything, you should +probably do a "Lock Down Seed" (Advanced/Tools > Danger Zone > Seed +Functions) first. This takes your master seed and BIP-39 passphrase +and cooks them together into an XPRV which then is stored as your +master secret. (Replacing the master seed phrase.) This process +cannot be reversed, so other funds you may have on the same seed +words are protected. Once you are operating in XPRV mode, you can +define a spending policy, and know that it is restricted to only +that wallet. + +When operating in XPRV mode, the "Passphrase" menu item is not shown +because BIP-39 passwords cannot be applied to XPRV secrets. + +## Trick PIN Thoughts + +When doing your game theory w.r.t to bypass mode and this feature, +remember that you should assume the attacker already has your main +PIN. That's how they know they cannot spend all your coin, because +they either tried to, or noticed the menus are very limited. They also +have all your UTXO locations and total wallet balance (because they +can export your xpubs to any wallet and load balance from there). + +Therefore, a trick pin that leads to a duress wallet after giving up +the bypass unlock PIN, will not fool them. Best would be to provide +a false bypass PIN that is in fact a brick/wipe PIN. + + +## Lock Out Changes to Policy + +In the Trick Pin menu once Spending Policy has been enabled, you will +find the Bypass PIN listed. You could delete or "hide" it. Hiding +it is pointless since you cannot get to the trick PIN menu while +the policy is in effect. Deleting the PIN however, is useful because +it assures changes to spending policy are impossible. To recover +the COLDCARD when this move is later regretted, under Advanced, +there is "Destroy Seed" option which will clear the seed words and +all settings, including the spending policy. + +### Unlock Policy & Wipe + +We've provided a new trick PIN that pretends to be the unlock +spending policy pin, so the login sequence is correct... but it +will wipe the seed in the process. It will be obvious to your +attackers that you've wiped the seed because the main PIN will lead +to blank wallet now (no seed loaded). + +### Delta Mode and Spending Policy + +If, from the start, you gave your "delta mode PIN" to the attackers, +then when they bypass the policy (after also getting the bypass PIN +from you), they will still be in Delta Mode. + +They could attempt unlimited spending, but transactions signed will +not be valid. If they try to view the seed words or generally export +private key material, they will hit many of the "wipe seed if delta +mode" cases. + +## Forgotten Bypass PIN Code + +If you've enabled a spending policy and still remember the main PIN, +but cannot disable the feature because you've forgotten the Bypass +PIN, your only option is to use `Advanced > Destroy Seed`. After +some confirmations, this erases the master seed, all settings, seed +vault items, secure notes, and trick pins. It's basically a factory +reset except for the main PIN code which is unchanged. Once you've +done that, you can enter your seed words from backup (or restore a +backup file) and continue to use the COLDCARD again. + + diff --git a/docs/taproot.md b/docs/taproot.md index b3ed6f34..df58eba8 100644 --- a/docs/taproot.md +++ b/docs/taproot.md @@ -31,7 +31,8 @@ There are 2 methods to provide provably unspendable internal key, if users wish `tr(xpub/<0:1>/*, sortedmulti_a(2,@0,@1))` which is the same thing as `tr(xpub, sortedmulti_a(2,@0,@1))` because `/<0;1>/*` is implied if not derivation path not provided. -2. **(recommended)** Use `unspend(` [notation](https://gist.github.com/sipa/06c5c844df155d4e5044c2c8cac9c05e#unspendable-keys). Has to be ranged. +### Below option was deprecated in version 6.3.5X & 6.3.5QX +2. Use `unspend(` [notation](https://gist.github.com/sipa/06c5c844df155d4e5044c2c8cac9c05e#unspendable-keys). Has to be ranged. `tr(unspend(77ec0c0fdb9733e6a3c753b1374c4a465cba80dff52fc196972640a26dd08b76)/<0:1>/*, sortedmulti_a(2,@0,@1))` @@ -58,7 +59,7 @@ Options 4. and 5. are problematic to some extent as internal key is static. Use In current version only `TREE` of max depth 4 is allowed (max 8 leaf script allowed). Taproot single leaf multisig has artificial limit of max 32 signers (M=N=32). -Number of keys in taptree is limited to 32. +Number of keys in whole taptree is limited to 32. If Coldcard can sign by both key path and script path - key path has precedence. @@ -68,9 +69,9 @@ PSBT provider MUST provide following Taproot specific input fields in PSBT: 1. `PSBT_IN_TAP_BIP32_DERIVATION` with all the necessary keys with their leaf hashes and derivation (including XFP). Internal key has to be specified here with empty leaf hashes. 2. `PSBT_IN_TAP_INTERNAL_KEY` MUST match internal key provided in `PSBT_IN_TAP_BIP32_DERIVATION` 3. `PSBT_IN_TAP_MERKLE_ROOT` MUST be empty if there is no script path. Otherwise it MUST match what Coldcard can calculate from registered descriptor. -4. `PSBT_IN_TAP_LEAF_SCRIPT` MUST be specified if there is a script path. Currently MUST be of length 1 (only one script allowed) +4. `PSBT_IN_TAP_LEAF_SCRIPT` MUST be specified if there is a script path. PSBT provider MUST provide following Taproot specific output fields in PSBT: 1. `PSBT_OUT_TAP_BIP32_DERIVATION` with all the necessary keys with their leaf hashes and derivation (including XFP). Internal key has to be specified here with empty leaf hashes. 2. `PSBT_OUT_TAP_INTERNAL_KEY` must match internal key provided in `PSBT_OUT_TAP_BIP32_DERIVATION` -3. `PSBT_OUT_TAP_TREE` with depth, leaf version and script defined. Currently only one script is allowed. \ No newline at end of file +3. `PSBT_OUT_TAP_TREE` with depth, leaf version and script defined. \ No newline at end of file diff --git a/docs/web2fa.md b/docs/web2fa.md new file mode 100644 index 00000000..3923b3f3 --- /dev/null +++ b/docs/web2fa.md @@ -0,0 +1,94 @@ +# Web 2FA Authentication + +How to support [RFC 6238](https://www.rfc-editor.org/rfc/rfc6238) +TOTP (Time based One Time Password) 2FA check, on our little embedded +device without a real-time clock? + +Solution: Store the pre-shared secret in the COLDCARD, and send that +securely to a trusted webserver which knows the time and can do a +fancy UX. That webserver accepts the time-based-one-time 2FA numeric +code from the user, and if correct, reveals a secret +that can be used back on the COLDCARD to authorize an action. + +For the Mk4, the secret is 8 digit numeric code to be entered, +for the COLDCARD Q, it is a QR code to be scanned. + +### History / Background + +The HSM feature uses HOTP tokens, which do not require a backend, +but are not as robust as time-based tokens. + +Web2FA is available to be enabled as part of a Spending Policy, +both in Multisig and Single Signer modes. When enabled, you will be +prompted complete 2FA authentication after viewing the details of +the transaction to be signed. You will not be able to sign without +the correct code. + +## How It Works + +- Web backend has a ECC keypair, with pubkey known to CC firmware releases. +- Usual 2fa base32 secret is picked by CC and stored in CC (so that server is stateless) +- CC creates URL encrypted to the pubkey of server, containing args: + - shared secret for TOTP (same value as held in user's phone) + - the response nonce (16 bytes, or 8 digits for Mk4) to be revealed to the user + on successful auth + - flag if Q model, so can provide a QR to be scanned in that case (rather than digits) + - some text label for what's being approved, which is presented to user so they can pick + correct 2fa shared secret. + - above is all encrypted in transit, and only the server can decrypt +- user is sent to that encrypted URL using NFC tap on the COLDCARD +- user arrives at server: + - shown label [which also indicates the server can be trusted, since only it could decrypt it] + - prompt for 6 digits from authenticator app + - does [RFC 6238](https://www.rfc-editor.org/rfc/rfc6238) 2FA check using current time +- checks using current time and the shared secret provided by CC, fails if wrong. + - time based failure: offer retry (they typed too slow / minor clock drift) + - can offer to retry, but also do some rate limiting (only one attempt per 30-sec period) + - server will store very recent responses so attacker cannot get two codes + in any 30sec period (ie. blocks immediate reuse of same URL) + - until a valid code is given, user is stuck here +- when valid token received: + - if Q, show a QR code to be scanned, with the full nonce + - for non-Q system, a 8-digit decimal value is given: user has to enter that into the COLDCARD + - web site shows instructions about what to do next on product. + +## From COLDCARD PoV + +- makes complex encrypted URL, which contains a nonce it wants, waits for that nonce back (or QR) +- it's either the nonce from the URL, or fail +- if the right nonce, then we know the server knows the decryption key, and we + are trusting it actually verify the 2FA token properly. + +## Encryption - Simple ECDH + +- CC picks a secp256k1 keypair, generates compressed pubkey +- multiplies that private key by server's known public key +- apply sha256(resulting coordinate) => the session key +- apply AES-256-CTR over URL contents (ascii text) +- prepend 33 bytes of pubkey, and then base64url encode all of it +- full url is: `https://coldcard.com/2fa?{base64 encoded binary}` + +## Trust Issues + +- 2FA enrol happens on the CC, which picks the shared secret and shows QR for mobile + app setup. Same TRNG process as picking a seed. +- Server knows the shared secret, but only during operation, and we won't store it [sorry, + gotta trust us on that, but no help to us to store it]. +- Only we can run the server, because the private key is company-secret. +- MiTM and network snoopers get nothing because HTTPS is used and only your browser + can see the nonce, and only after you've given the right digits. +- Coinkite server could skip the 2FA checks and just give you the answer + you want to type into the COLDCARD. Again, you have to trust us on that. + +## URL Format + + https://coldcard.com/2fa?ss={shared_secret}&q={is_q}&g={nonce}&nm={label_text} + +- `shared_secret`: 16 chars of Base32-encoded pre-shared secret +- `is_q`: flag indicating use of QR to provide nonce back to user +- `nonce`: text string that is either 8 digits for Mk4, or hex digits for QR +- `nm`: human readable label for the transaction/purpose + +Server will accept plaintext arguments as above, but normally everything +after the question mark is encrypted. + diff --git a/external/ckcc-protocol b/external/ckcc-protocol index 0e686dbd..2afc7d34 160000 --- a/external/ckcc-protocol +++ b/external/ckcc-protocol @@ -1 +1 @@ -Subproject commit 0e686dbda686f76c4d3e8069558b2a31f9d1c2b1 +Subproject commit 2afc7d34d27568f984022c6e006408bf6b50e369 diff --git a/external/libngu b/external/libngu index 1cccb25e..537519a8 160000 --- a/external/libngu +++ b/external/libngu @@ -1 +1 @@ -Subproject commit 1cccb25ef7736efae4a1de83d5dbdc13a2db0e80 +Subproject commit 537519a829259622ea6b0334fbafd6cae852852f diff --git a/graphics/graphics_mk4.py b/graphics/graphics_mk4.py index c2ca930d..4db6a7dd 100644 --- a/graphics/graphics_mk4.py +++ b/graphics/graphics_mk4.py @@ -19,7 +19,7 @@ class Graphics: scroll = (3, 61, 1, 0, b'@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@@\xe0@') - selected = (15, 12, 2, 0, b'\x00\x00\x00\x00\x00\x06\x00\x0c\x00\x18\x0000`\x18\xc0\r\x80\x07\x00\x02\x00\x00\x00') + selected = (9, 12, 2, 0, b'\x00\x00\x00\x00\x00\x80\x01\x80\x01\x00\x03\x00\x82\x00\xc6\x00d\x00<\x00\x18\x00\x00\x00') sm_box = (11, 17, 2, 0, b'\xe4\xe0\x80 \x80 \x80 \x00\x00\x00\x00\x80 \x00\x00\x00\x00\x00\x00\x80 \x00\x00\x00\x00\x80 \x80 \x80 \xe4\xe0') diff --git a/graphics/mono/selected.txt b/graphics/mono/selected.txt index 827efe94..faebfd6b 100644 --- a/graphics/mono/selected.txt +++ b/graphics/mono/selected.txt @@ -1,12 +1,12 @@ - xx - xx - xx - xx - xx xx - xx xx - xx xx - xxx - x + X + XX + X + XX +X X +XX XX + XX X + XXXX + XX diff --git a/releases/ChangeLog.md b/releases/ChangeLog.md index 4f91647b..2e09779d 100644 --- a/releases/ChangeLog.md +++ b/releases/ChangeLog.md @@ -4,64 +4,25 @@ This lists the changes in the most recent firmware, for each hardware platform. # Shared Improvements - Both Mk4 and Q -- New signing features: - - Sign message from note text, or password note - - JSON message signing. Use JSON object to pass data to sign in form - `{"msg":"","subpath":"","addr_fmt": ""}` - - Sign message with key resulting from positive ownership check. Press (0) and - enter or scan message text to be signed. - - Sign message with key selected from Address Explorer Custom Path menu. Press (2) and - enter or scan message text to be signed. -- Enhancement: New address display format improves address verification on screen (groups of 4). -- Deltamode enhancements: - - Hide Secure Notes & Passwords in Deltamode. Wipe seed if notes menu accessed. - - Hide Seed Vault in Deltamode. Wipe seed if Seed Vault menu accessed. - - Catch more DeltaMode cases in XOR submenus. Thanks [@dmonakhov](https://github.com/dmonakhov) -- Enhancement: Add ability to switch between BIP-32 xpub, and obsolete SLIP-132 format - in `Export XPUB` -- Enhancement: Use the fact that master seed cannot be used as ephemeral seed, to show message - about successful master seed verification. -- Enhancement: Allow devs to override backup password. -- Enhancement: Add option to show/export full multisg addresses without censorship. Enable - in `Settings > Multisig Wallets > Full Address View`. -- Enhancement: If derivation path is omitted during message signing, derivation path - default is no longer root (m), instead it is based on requested address format - (`m/44h/0h/0h/0/0` for p2pkh, and `m/84h/0h/0h/0/0` for p2wpkh). Conversely, - if address format is not provided but subpath derivation starts with: - `m/84h/...` or `m/49h/...`, then p2wpkh or p2sh-p2wpkh respectively, is used. -- Bugfix: Sometimes see a struck screen after _Verifying..._ in boot up sequence. - On Q, result is blank screen, on Mk4, result is three-dots screen. -- Bugfix: Do not allow to enable/disable Seed Vault feature when in temporary seed mode. -- Bugfix: Bless Firmware causes hanging progress bar. -- Bugfix: Prevent yikes in ownership search. -- Bugfix: Factory-disabled NFC was not recognized correctly. -- Bugfix: Be more robust about flash filesystem holding the settings. -- Bugfix: Do not include sighash in PSBT input data, if sighash value is `SIGHASH_ALL`. -- Bugfix: Allow import of multisig descriptor with root (m) keys in it. - Thanks [@turkycat](https://github.com/turkycat) -- Change: Do not purge settings of current active tmp seed when deleting it from Seed Vault. -- Change: Rename Testnet3 -> Testnet4 (all parameters unchanged). - +- Enhancement: Address format guessing changed away from using PSBT XPUB's derivation paths. + Now based on witness/redeem script of first PSBT input instead. +- Enhancement: Show master XFP of backup secret and ask user for confirmation before loading backup. +- Enhancement: Show firmware version added to hobbled Advanced/Tools menu. +- Bugfix: Exiting text input of Custom Backup Password caused yikes. +- Bugfix: Temporary seeds in SSSP mode were not able to update block height. # Mk4 Specific Changes -## 5.4.1 - 2024-02-13 +## 5.4.5 - 2025-11-03 -- Enhancement: Export single sig descriptor with simple QR. +- None. # Q Specific Changes -## 1.3.1Q - 2024-02-13 +## 1.3.5Q - 2025-11-03 -- New Feature: Verify Signed RFC messages via BBQr -- New Feature: Sign message from QR scan (format has to be JSON) -- Enhancement: Sign/Verify Address in Sparrow via QR -- Enhancement: Sign scanned Simple Text by pressing (0). Next screen query information - about which key to use. -- Enhancement: Add option to "Sort By Title" in Secure Notes and Passwords. Thanks to - [@MTRitchey](https://x.com/MTRitchey) for suggestion. -- Bugfix: Properly re-draw status bar after Restore Master on COLDCARD without master seed. +- Enhancement: Show backup filename at the top of the screen during backup password entry. diff --git a/releases/EdgeChangeLog.md b/releases/EdgeChangeLog.md index a2fbf21a..56fb5125 100644 --- a/releases/EdgeChangeLog.md +++ b/releases/EdgeChangeLog.md @@ -13,21 +13,47 @@ This lists the changes in the most recent EDGE firmware, for each hardware platf # Shared Improvements - Both Mk4 and Q -Change: Allow origin-less extended keys in multisig & miniscript descriptors -Change: Static internal keys disallowed - all keys need to be ranged extended keys +### WARNING: 6.4.0X is not backwards-compatible with previous firmware versions. +#### Before installing 6.4.0X, create a backup!!! If for some reason migration fails, or you decide to downgrade, only way to get back to previous version(s) is from the backup created on previous version(s). +#### Everything is Miniscript from 6.4.0X. All multisig wallet need to be migrated to Miniscript. Old miniscript backend format is migrated to the new one, that is using BIP-388 wallet policies. After you install 6.4.0X, head directly to Settings->Miniscript to migrate your wallets. + +- New Feature: Key Teleport +- New Feature: Spending Policy for Miniscript Wallets +- New Feature: Internal descriptor cache speeding up sequential operation with miniscript wallets. + To take full advantage of the feature work with miniscript wallets sequentially. First, do all operations + needed with `wallet1` before changing to `wallet2`. +- New Feature: Add ability to import/export [BIP-388](https://github.com/bitcoin/bips/blob/master/bip-0388.mediawiki) Wallet Policies. + BIP-388 policies are now also used as our wallet serialization format, which optimized setting storage. +- New Feature: Sign with specific miniscript wallet. `Settings -> Miniscript -> -> Sign PSBT` +- New Feature: Miniscript wallet name can be specified for `sign` USB command +- New Feature: Rename Miniscript wallet via UX. `Settings -> Miniscript -> -> Rename`. +- Enhancement: Slightly faster HW accelerated tagged hash +- Enhancement: PSBT class optimizations. Ability to sign bigger txn. +- Enhancement: Signing TXN UI shows Miniscript wallet name. +- Change: Everything is miniscript now. To import multisig wallets go to `Settings -> Miniscript` +- Change: Deprecation of legacy mulitsig import format. Ability to import/export in this format was removed. + Old functionality - renaming by reimporting descriptor with different name was removed. + Use descriptors or BIP-388 wallet policies +- Change: Deprecated `p2sh` USB command. Use `miniscript` USB commands to handle multisig wallets. +- Change: Descriptor template was remove from Generic JSON export, and `key_exp` was added + with BIP-380 extended key expression `[xfp/origin_path]xpub`. +- Bugfix: Disjoint derivation in miniscript wallets +- Bugfix: Disallow P2SH legacy miniscript +- Bugfix: Do not allow to import miniscripts with relative lock without consensus meaning. + Only allow to import block-based in range `older(1 - 65535)` & time-based in range `older(4194305 - 4259839)` # Mk4 Specific Changes -## 6.3.5X - 2024-07-04 +## 6.4.0X - 2025-XX-XX -- all updates from `5.4.1` +- synced with master up to `5.4.5` # Q Specific Changes -## 6.3.5QX - 2024-07-04 +## 6.4.0QX - 2025-XX-XX -- all updates from version `1.3.1Q` +- synced with master up to `1.3.5Q` # Release History diff --git a/releases/History-Edge.md b/releases/History-Edge.md index e8e42ff8..4d722384 100644 --- a/releases/History-Edge.md +++ b/releases/History-Edge.md @@ -7,6 +7,19 @@ - for experimental use. DO NOT use for large Bitcoin amounts. ``` +# 6.3.5X & 6.3.5QX Shared Improvements - Both Mk4 and Q + +Change: Allow origin-less extended keys in multisig & miniscript descriptors +Change: Static internal keys disallowed - all keys need to be ranged extended keys + +# Mk4 Specific Changes + +- all updates from `5.4.1` + +# Q Specific Changes + +- all updates from version `1.3.1Q` + # 6.3.4X & 6.3.4QX Shared Improvements - Both Mk4 and Q diff --git a/releases/History-Mk4.md b/releases/History-Mk4.md index dfd7e37c..3a78f39e 100644 --- a/releases/History-Mk4.md +++ b/releases/History-Mk4.md @@ -1,5 +1,126 @@ *See ChangeLog.md for more recent changes, these are historic versions* + +## 5.4.4 - 2025-09-30 + +- Spending policies for "Single Signers" adds new spending policy options: + - limit your Coldcard so it refuses to sign transactions that are "too big" + - require 2FA authentication before signing any transaction (NFC+web) + - velocity limits can restrict how often new transactions can be signed + - see `docs/spending-policy.md` for more details + - "Enable HSM" and "User Management" have moved into `Advanced > Spending Policy`. + - Old "CCC" feature has been renamed and moved into that menu as well: "Co-Sign Multisig" +- Added `Bull Bitcoin` export to `Export Wallet` menu. +- Enhancement: Added warning for zero value outputs if not `OP_RETURN`. +- Enhancement: Show QR codes of output addresses in transaction output explorer. Explorer is + now offered for transactions of all sizes, not just complex ones. +- Enhancement: Added file rename, when listing contents of SD card. +- Enhancement: Added ability to restore Coldcard backup via USB (needs latest of ckcc version) +- Enhancement: Address ownership allows to specify particular multisig wallet in which to search, + if `wallet` query parameter is provided via trivial extension to + [BIP-21](https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki). + Example: `tb1q4d67p7stxml3kdudrgkg5mgaxsrgzcqzjrrj4gg62nxtvnsnvqjsxjkej0?wallet=Haystack` +- Bugfix: If all change outputs have `nValue=0`, they were not shown in UX. +- Bugfix: Disallow negative input/output amounts in PSBT. +- Bugfix: Fix filesystem initialization after Wipe LFS or Destroy Seed. +- Bugfix: Fix MicroSD selftest code. +- Bugfix: NFC loop exporting secrets would not work after first value exported. +- Bugfix: Multisig address format handling. +- Bugfix: Ownership check failing to find addresses near max (~760), needed to be re-run to succeed +- (Mk4 only) Bugfix: Part of extended keys (xpubs) were not always visible. +- (Mk4 only) Change: Mk4 default menu wrap-around lowered from 16 to 10 items. + + +## 5.4.3 - 2025-05-14 + +- Enhancement: Text word-wrap done more carefully so never cuts off any text, and yet + doesn't waste space. +- Bugfix: `Add current tmp` option, which could be shown in `Seed Vault` menu under + specific circumstances, would corrupt master settings if selected. +- Bugfix: PUSHDATA2 in bitcoin script caused yikes. +- Bugfix: Warning for unknown scripts was not shown at the top of the signing story. +- Bugfix: With both NFC & Virtual Disk OFF, user cannot exit `Export Wallet` menu. Gets stuck + in export loop and needs reboot to escape. +- Bugfix: Part of extended keys in stories were not always visible. + + +## 5.4.2 - 2025-04-16 + +- Huge new feature: CCC - ColdCard Cosign + - COLDCARD holds a key in a 2-of-3 multisig, in addition to the normal signing key it has. + - it applies a spending policy like an HSM: + - velocity and magnitude limits + - whitelisted destination addresses + - 2FA authentication using phone app ([RFC 6238](https://www.rfc-editor.org/rfc/rfc6238)) + - but will sign its part of a transaction automatically if those condition are met, + giving you 2 keys of the multisig and control over the funds + - spending policy can be exceeded with help of the other co-signer (3rd key), when needed + - cannot view or change the CCC spending policy once set, policy violations are not explained + - existing multisig wallets can be used by importing the spending-policy-controlled key +- New Feature: Multisig transactions are finalized. Allows use of [PushTX](https://pushtx.org/) + with multisig wallets. Read more [here](https://github.com/Coldcard/firmware/blob/master/docs/limitations.md#p2sh--multisig) +- New Feature: Signing artifacts re-export to various media. Now you have the option of + exporting the signing products (transaction/PSBT) to different media than the original source. + Incoming PSBT over QR can be signed and saved to SD card if desired. +- New Feature: Multisig export files are signed now. Read more [here](https://github.com/Coldcard/firmware/blob/master/docs/msg-signing.md#signed-exports) +- Enhancement: NFC export usability upgrade: NFC keeps exporting until CANCEL/X is pressed +- Enhancement: Add `Bitcoin Safe` option to `Export Wallet` +- Enhancement: 10% performance improvement in USB upload speed for large files +- Bugfix: Do not allow change Main PIN to same value already used as Trick PIN, even if + Trick PIN is hidden. +- Bugfix: Fix stuck progress bar under `Receiving...` after a USB communications failure +- Bugfix: Showing derivation path in Address Explorer for root key (m) showed double slash (//) +- Bugfix: Can restore developer backup with custom password other than 12 words format +- Bugfix: Virtual Disk auto mode ignores already signed PSBTs (with "-signed" in file name) +- Bugfix: Virtual Disk auto mode stuck on "Reading..." screen sometimes +- Bugfix: Finalization of foreign inputs from partial signatures. Thanks Christian Uebber +- Bugfix: Temporary seed from COLDCARD backup failed to load stored multisig wallets +- Change: `Destroy Seed` also removes all Trick PINs from SE2. +- Change: `Lock Down Seed` requires pressing confirm key (4) to execute + +## 5.4.1 - 2025-02-13 + +- New signing features: + - Sign message from note text, or password note + - JSON message signing. Use JSON object to pass data to sign in form + `{"msg":"","subpath":"","addr_fmt": ""}` + - Sign message with key resulting from positive ownership check. Press (0) and + enter or scan message text to be signed. + - Sign message with key selected from Address Explorer Custom Path menu. Press (2) and + enter or scan message text to be signed. +- Enhancement: New address display format improves address verification on screen (groups of 4). +- Deltamode enhancements: + - Hide Secure Notes & Passwords in Deltamode. Wipe seed if notes menu accessed. + - Hide Seed Vault in Deltamode. Wipe seed if Seed Vault menu accessed. + - Catch more DeltaMode cases in XOR submenus. Thanks [@dmonakhov](https://github.com/dmonakhov) +- Enhancement: Add ability to switch between BIP-32 xpub, and obsolete SLIP-132 format + in `Export XPUB` +- Enhancement: Use the fact that master seed cannot be used as ephemeral seed, to show message + about successful master seed verification. +- Enhancement: Allow devs to override backup password. +- Enhancement: Add option to show/export full multisg addresses without censorship. Enable + in `Settings > Multisig Wallets > Full Address View`. +- Enhancement: If derivation path is omitted during message signing, derivation path + default is no longer root (m), instead it is based on requested address format + (`m/44h/0h/0h/0/0` for p2pkh, and `m/84h/0h/0h/0/0` for p2wpkh). Conversely, + if address format is not provided but subpath derivation starts with: + `m/84h/...` or `m/49h/...`, then p2wpkh or p2sh-p2wpkh respectively, is used. +- Bugfix: Sometimes see a struck screen after _Verifying..._ in boot up sequence. + On Q, result is blank screen, on Mk4, result is three-dots screen. +- Bugfix: Do not allow to enable/disable Seed Vault feature when in temporary seed mode. +- Bugfix: Bless Firmware causes hanging progress bar. +- Bugfix: Prevent yikes in ownership search. +- Bugfix: Factory-disabled NFC was not recognized correctly. +- Bugfix: Be more robust about flash filesystem holding the settings. +- Bugfix: Do not include sighash in PSBT input data, if sighash value is `SIGHASH_ALL`. +- Bugfix: Allow import of multisig descriptor with root (m) keys in it. + Thanks [@turkycat](https://github.com/turkycat) +- Change: Do not purge settings of current active tmp seed when deleting it from Seed Vault. +- Change: Rename Testnet3 -> Testnet4 (all parameters unchanged). +- Mk4 Specific Change: + - Enhancement: Export single sig descriptor with simple QR. + + ## 5.4.0 - 2024-09-12 - New Feature: Opt-in support for unsorted multisig, which ignores BIP-67 policy. Use diff --git a/releases/History-Q.md b/releases/History-Q.md index a90cea0b..b0023eb5 100644 --- a/releases/History-Q.md +++ b/releases/History-Q.md @@ -1,5 +1,184 @@ *See ChangeLog.md for more recent changes, these are historic versions* +## 1.3.4Q - 2025-09-30 + +- Spending policies for "Single Signers" adds new spending policy options: + - limit your Coldcard so it refuses to sign transactions that are "too big" + - require 2FA authentication before signing any transaction (NFC+web) + - velocity limits can restrict how often new transactions can be signed + - see `docs/spending-policy.md` for more details + - "Enable HSM" and "User Management" have moved into `Advanced > Spending Policy`. + - Old "CCC" feature has been renamed and moved into that menu as well: "Co-Sign Multisig" +- Added `Bull Bitcoin` export to `Export Wallet` menu. +- Enhancement: Added warning for zero value outputs if not `OP_RETURN`. +- Enhancement: Show QR codes of output addresses in transaction output explorer. Explorer is + now offered for transactions of all sizes, not just complex ones. +- Enhancement: Added file rename, when listing contents of SD card. +- Enhancement: Added ability to restore Coldcard backup via USB (needs latest of ckcc version) +- Enhancement: Address ownership allows to specify particular multisig wallet in which to search, + if `wallet` query parameter is provided via trivial extension to + [BIP-21](https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki). + Example: `tb1q4d67p7stxml3kdudrgkg5mgaxsrgzcqzjrrj4gg62nxtvnsnvqjsxjkej0?wallet=Haystack` +- Bugfix: If all change outputs have `nValue=0`, they were not shown in UX. +- Bugfix: Disallow negative input/output amounts in PSBT. +- Bugfix: Fix filesystem initialization after Wipe LFS or Destroy Seed. +- Bugfix: Fix MicroSD selftest code. +- Bugfix: NFC loop exporting secrets would not work after first value exported. +- Bugfix: Multisig address format handling. +- Bugfix: Ownership check failing to find addresses near max (~760), needed to be re-run to succeed +- (Q only) Enhancement: Enters "forever calculator" mode when Q would otherwise be electronic waste + (ie. after 13 PIN failures). Always enabled, regardless of "login calculator" setting. +- (Q only) Bugfix: Correct line positioning when 24 seed words displayed. + + +## 1.3.3Q - 2025-05-14 + +- Enhancement: Text word-wrap done more carefully so never cuts off any text, and yet + doesn't waste space. +- Bugfix: `Add current tmp` option, which could be shown in `Seed Vault` menu under + specific circumstances, would corrupt master settings if selected. +- Bugfix: PUSHDATA2 in bitcoin script caused yikes. +- Bugfix: Warning for unknown scripts was not shown at the top of the signing story. + +- Bugfix: Do not allow to teleport PSBTs from SD card when CC has no secrets. +- Bugfix: Calculator login mode: added "rand()" command, removed support + for variables/assignments. + + +## 1.3.2Q - 2025-04-16 + +- Feature: Key Teleport -- Easily and securely move seed phrases, secure notes/passwords, + multisig PSBT files, and even full Coldcard backups, between two Q using QR codes + and/or NFC with helper website. See protocol spec in + [docs/key-teleport.md](https://github.com/Coldcard/firmware/blob/master/docs/key-teleport.md) + - can send master seed (words, xprv), anything held in seed vault, secure notes/passwords + (singular, or all) and PSBT involved in a multisig to the other co-signers + - full COLDCARD backup is possible as well, but receiver must be "unseeded" Q for best result + - ECDH to create session key for AES-256-CTR, with another layer of AES-256-CTR using a + short password (stretched by PBKDF2-SHA512) inside + - receiver shows sender a (simple) QR and a numeric code; sender replies with larger BBQr + and 8-char password +- Enhancement: Always choose the biggest possible display size for QR +- Bugfix: Only BBQr is allowed to export Coldcard, Core, and pretty descriptor +- Huge new feature: CCC - ColdCard Cosign + - COLDCARD holds a key in a 2-of-3 multisig, in addition to the normal signing key it has. + - it applies a spending policy like an HSM: + - velocity and magnitude limits + - whitelisted destination addresses + - 2FA authentication using phone app ([RFC 6238](https://www.rfc-editor.org/rfc/rfc6238)) + - but will sign its part of a transaction automatically if those condition are met, + giving you 2 keys of the multisig and control over the funds + - spending policy can be exceeded with help of the other co-signer (3rd key), when needed + - cannot view or change the CCC spending policy once set, policy violations are not explained + - existing multisig wallets can be used by importing the spending-policy-controlled key +- New Feature: Multisig transactions are finalized. Allows use of [PushTX](https://pushtx.org/) + with multisig wallets. Read more [here](https://github.com/Coldcard/firmware/blob/master/docs/limitations.md#p2sh--multisig) +- New Feature: Signing artifacts re-export to various media. Now you have the option of + exporting the signing products (transaction/PSBT) to different media than the original source. + Incoming PSBT over QR can be signed and saved to SD card if desired. +- New Feature: Multisig export files are signed now. Read more [here](https://github.com/Coldcard/firmware/blob/master/docs/msg-signing.md#signed-exports) +- Enhancement: NFC export usability upgrade: NFC keeps exporting until CANCEL/X is pressed +- Enhancement: Add `Bitcoin Safe` option to `Export Wallet` +- Enhancement: 10% performance improvement in USB upload speed for large files +- Bugfix: Do not allow change Main PIN to same value already used as Trick PIN, even if + Trick PIN is hidden. +- Bugfix: Fix stuck progress bar under `Receiving...` after a USB communications failure +- Bugfix: Showing derivation path in Address Explorer for root key (m) showed double slash (//) +- Bugfix: Can restore developer backup with custom password other than 12 words format +- Bugfix: Virtual Disk auto mode ignores already signed PSBTs (with "-signed" in file name) +- Bugfix: Virtual Disk auto mode stuck on "Reading..." screen sometimes +- Bugfix: Finalization of foreign inputs from partial signatures. Thanks Christian Uebber +- Bugfix: Temporary seed from COLDCARD backup failed to load stored multisig wallets +- Change: `Destroy Seed` also removes all Trick PINs from SE2. +- Change: `Lock Down Seed` requires pressing confirm key (4) to execute + +## 1.3.1Q - 2025-02-13 + +- New signing features: + - Sign message from note text, or password note + - JSON message signing. Use JSON object to pass data to sign in form + `{"msg":"","subpath":"","addr_fmt": ""}` + - Sign message with key resulting from positive ownership check. Press (0) and + enter or scan message text to be signed. + - Sign message with key selected from Address Explorer Custom Path menu. Press (2) and + enter or scan message text to be signed. +- Enhancement: New address display format improves address verification on screen (groups of 4). +- Deltamode enhancements: + - Hide Secure Notes & Passwords in Deltamode. Wipe seed if notes menu accessed. + - Hide Seed Vault in Deltamode. Wipe seed if Seed Vault menu accessed. + - Catch more DeltaMode cases in XOR submenus. Thanks [@dmonakhov](https://github.com/dmonakhov) +- Enhancement: Add ability to switch between BIP-32 xpub, and obsolete SLIP-132 format + in `Export XPUB` +- Enhancement: Use the fact that master seed cannot be used as ephemeral seed, to show message + about successful master seed verification. +- Enhancement: Allow devs to override backup password. +- Enhancement: Add option to show/export full multisg addresses without censorship. Enable + in `Settings > Multisig Wallets > Full Address View`. +- Enhancement: If derivation path is omitted during message signing, derivation path + default is no longer root (m), instead it is based on requested address format + (`m/44h/0h/0h/0/0` for p2pkh, and `m/84h/0h/0h/0/0` for p2wpkh). Conversely, + if address format is not provided but subpath derivation starts with: + `m/84h/...` or `m/49h/...`, then p2wpkh or p2sh-p2wpkh respectively, is used. +- Bugfix: Sometimes see a struck screen after _Verifying..._ in boot up sequence. + On Q, result is blank screen, on Mk4, result is three-dots screen. +- Bugfix: Do not allow to enable/disable Seed Vault feature when in temporary seed mode. +- Bugfix: Bless Firmware causes hanging progress bar. +- Bugfix: Prevent yikes in ownership search. +- Bugfix: Factory-disabled NFC was not recognized correctly. +- Bugfix: Be more robust about flash filesystem holding the settings. +- Bugfix: Do not include sighash in PSBT input data, if sighash value is `SIGHASH_ALL`. +- Bugfix: Allow import of multisig descriptor with root (m) keys in it. + Thanks [@turkycat](https://github.com/turkycat) +- Change: Do not purge settings of current active tmp seed when deleting it from Seed Vault. +- Change: Rename Testnet3 -> Testnet4 (all parameters unchanged). + +- New Feature: Verify Signed RFC messages via BBQr +- New Feature: Sign message from QR scan (format has to be JSON) +- Enhancement: Sign/Verify Address in Sparrow via QR +- Enhancement: Sign scanned Simple Text by pressing (0). Next screen query information + about which key to use. +- Enhancement: Add option to "Sort By Title" in Secure Notes and Passwords. Thanks to + [@MTRitchey](https://x.com/MTRitchey) for suggestion. +- Bugfix: Properly re-draw status bar after Restore Master on COLDCARD without master seed. + + +## 1.3.0Q - 2024-09-12 + +- New Feature: Opt-in support for unsorted multisig, which ignores BIP-67 policy. Use + descriptor with `multi(...)`. Disabled by default, Enable in + `Settings > Multisig Wallets > Legacy Multisig`. Recommended for existing multisig + wallets, not new ones. +- New Feature: Named multisig descriptor imports. Wrap descriptor in json: + `{"name:"ms0", "desc":""}` to provide a name for the menu in `name`. + instead of the filename. Most useful for USB and NFC imports which have no filename, + (name is created from descriptor checksum in those cases). +- New Feature: XOR from Seed Vault (select other parts of the XOR from seeds in the vault). +- Enhancement: upgrade to latest + [libsecp256k1: 0.5.0](https://github.com/bitcoin-core/secp256k1/releases/tag/v0.5.0) +- Enhancement: Signature grinding optimizations. Now about 30% faster signing! +- Enhancement: Improve side-channel protection: libsecp256k1 context randomization now happens + before each signing session. +- Enhancement: Allow JSON files in `NFC File Share`. +- Change: Do not require descriptor checksum when importing multisig wallets. +- Bugfix: Do not allow import of multisig wallet when same keys are shuffled. +- Bugfix: Do not read whole PSBT into memory when writing finalized transaction (performance). +- Bugfix: Prevent user from restoring Seed XOR when number of parts is smaller than 2. +- Bugfix: Fix display alignment of Seed Vault menu. +- Bugfix: Properly handle null data in `OP_RETURN`. +- Bugfix: Do not allow lateral scroll in Address Explorer when showing single address + from custom path. +- Change: Remove Lamp Test from Debug Options (covered by selftest). +- New Feature: Seed XOR can be imported by scanning SeedQR parts. +- New Feature: Input backup password from QR scan. +- New Feature: (BB)QR file share of arbitrary files. +- New Feature: `Create Airgapped` now works with BBQRs. +- Change: Default brightness (on battery) adjusted from 80% to 95%. +- Bugfix: Properly clear LCD screen after BBQR is shown. +- Bugfix: Writing to empty slot B caused broken card reader. +- Bugfix: During Seed XOR import, display correct letter B if own seed already added to the mix. +- Bugfix: Stop re-wording UX stories using a regular expression. +- Bugfix: Fixed "easy exit" from quiz after split Seed XOR. + ## 1.3.0Q - 2024-09-12 diff --git a/releases/Next-ChangeLog.md b/releases/Next-ChangeLog.md index b79bd3f0..9b0de56a 100644 --- a/releases/Next-ChangeLog.md +++ b/releases/Next-ChangeLog.md @@ -9,13 +9,15 @@ This lists the new changes that have not yet been published in a normal release. # Mk4 Specific Changes -## 5.4.2 - 2024-03-?? +## 5.4.5 - 2025-12-xx - tbd # Q Specific Changes -## 1.3.2Q - 2024-03-?? +## 1.3.6Q - 2025-12-xx - tbd + + diff --git a/releases/signatures.txt b/releases/signatures.txt index 37ff32c1..2ebea3c2 100644 --- a/releases/signatures.txt +++ b/releases/signatures.txt @@ -2,41 +2,127 @@ Hash: SHA256 95eff9e044cdb6b3d00961ae72d450684d5441c6a3661ab550a3c3aa0882e754 README.md -8f027f7bf0b571f75acac01b6d7bb25ece6873ee2297c9138f40de553613a30e Next-ChangeLog.md -b6015f2f807bc78b6063ed6c12a12a47579a81a68f954cfc2e542e7ac6c02c0e History-Q.md -05228d2c59135c3fe251d877b519bec65f929ecf0aac8b727622359014236568 History-Mk4.md +22595dc8bb7a3d9ccd95a03fbff6f8764f4736c593316f60b561b3ebfd06bac0 Next-ChangeLog.md +3da64b38642e0fa7c6909c563aea648b6ca22b350901662332c3016fa48171c2 History-Q.md +13569699323108af074af0e9ea478f75d1795ac5f5ebcbd0b988d9db63e86a5d History-Mk4.md c8ad43b4e3f9d77777026da6d1210c6fc5cfe435bcfcd241c0f67c9392ad7b82 History-Mk3.md -7fcd753917adbdfeb7f736c2f2269bcc310839d29309eb36543e9826c865cb5d History-Edge.md -0eaa18b39e2c12343584a4dce99b61f29a2305ce3a71ff59dff5ab3e54e5c1c9 EdgeChangeLog.md -45cd0478996bb9da77075846122b8ba732b9b34dbbae0d12cb85ad0d931d40fc ChangeLog.md +76a668643b19d2fb0d13a0d7a69b9ffcb5b7da342abb6172815af06c2cdfeb6b ChangeLog.md +7076ae29c509d3120db0fae434c132e6abd3fb79c1a2a2f1383ab3b2acaba27c 2025-11-03T1527-v5.4.5-mk4-coldcard.dfu +00a337888ff86bf875bcfdab7a734981bce29a49f94f3df9f932924765848ab0 2025-11-03T1527-v5.4.5-mk4-coldcard-factory.dfu +ff6371545943518eb4eb00ba73b6aa3a5ac4e63459621ecec8a300c28c281b3c 2025-11-03T1525-v1.3.5Q-q1-coldcard.dfu +0ce02c8e549cb67b682d621b4a628f3fba2c56350a9ab090b9f08532f49e7afa 2025-11-03T1525-v1.3.5Q-q1-coldcard-factory.dfu +8a8c94e5f64d0bfe4914a236fb8a779f956989fe8de998133b85b23920f46283 2025-09-30T1238-v5.4.4-mk4-coldcard.dfu +0d0aba89027d5127f74b2a2b777a7c592cba12903a3c4c3ce9b0e060c09dddb7 2025-09-30T1238-v5.4.4-mk4-coldcard-factory.dfu +bc9918968b67fefe634342c77513c9c354e7821e9ff002c7e5c8c356d7507892 2025-09-30T1237-v1.3.4Q-q1-coldcard.dfu +00cb1fc2ef360aacf48ba8c9dd2167b3f5c5f1241ba1b2b17d61ea1b7bff0a45 2025-09-30T1237-v1.3.4Q-q1-coldcard-factory.dfu +be166b3bb3ec2259991db998c20c3d44e88eeaa73c2b8114f31cb14cab5e66e6 2025-05-14T1344-v5.4.3-mk4-coldcard.dfu +876932d4ea7634d268145d5bf45577c7198c9d60e8a271b5079faba4d4c91acd 2025-05-14T1344-v5.4.3-mk4-coldcard-factory.dfu +aaed0b90be5de310c8ac9f2d0cb3a7eea58923a53d349eb4b9ac8a902e5cba4e 2025-05-14T1343-v1.3.3Q-q1-coldcard.dfu +9daa2b48abdfa2303a43ee1d0ba3d0d905e7f6286018f44a0dda3c755c46039e 2025-05-14T1343-v1.3.3Q-q1-coldcard-factory.dfu +c1202ba30db68a12b882176997f08844da4ec31087ac2f507ea1d4281d2faa9a 2025-04-16T1907-v5.4.2-mk4-coldcard.dfu +a82fff91f8da35c122b09d54b01b3d3f3b8825fbc7cddee8e686fd8d57a69285 2025-04-16T1907-v5.4.2-mk4-coldcard-factory.dfu +4393c67f8dcbb8890950678f5856d2cca81042b9a447ce149fe624ddfe336a2a 2025-04-16T1906-v1.3.2Q-q1-coldcard.dfu +6f2d77f99d61cad9328cc617754aadb3b828150386def41c946d90db8cfb2277 2025-04-16T1906-v1.3.2Q-q1-coldcard-factory.dfu 495f37ce7ddaba2e9fc3f03dec582f1646f258a3d0cec5e71c04d127357b2fa3 2025-02-19T1941-v6.3.5X-mk4-coldcard.dfu -580701fb2de24362d8de6cf998d5fd42ca9ab003aff75f3c0140d915a06a6803 2025-02-19T1941-v6.3.5X-mk4-coldcard-factory.dfu 605ebb5acde19447e5c1d7c8cfd0302c89de5c5870d85f06b185ecab3437f94e 2025-02-19T1939-v6.3.5QX-q1-coldcard.dfu -245db07574a535a3f068ed9a759bf0088f0d0e1e39704a0e0727f90119833602 2025-02-19T1939-v6.3.5QX-q1-coldcard-factory.dfu eb750a4f095eacc6133b2c8b38fe0738a22b2496a6cdf423ca865acde8c9bc4e 2025-02-13T1415-v5.4.1-mk4-coldcard.dfu 4236453fea241fe044a462a560d8b42df43e560683110306a2714a2ef561eac5 2025-02-13T1415-v5.4.1-mk4-coldcard-factory.dfu 2e1aad0a7a3ceb84db34322b54855a0c5496699e46e53606bfa443fcc992adec 2025-02-13T1413-v1.3.1Q-q1-coldcard.dfu e43932d04bf782f7b9ba218b54f29b9cd361b83ac3aadff9722714bca1ab7ee9 2025-02-13T1413-v1.3.1Q-q1-coldcard-factory.dfu 681874256bcfca71a3908f1dd6c623804517fdba99a51ed04c73b96119650c13 2024-12-18T1413-v6.3.4X-mk4-coldcard.dfu -73f31fbcb064a6b763d50852aafcdff01d7ec72906b5cb0af6cf28328fd80a89 2024-12-18T1413-v6.3.4X-mk4-coldcard-factory.dfu 93ab7615bcedeeff123498c109e5859dae28e58885e29ed86b6f3fd6ba709cce 2024-12-18T1407-v6.3.4QX-q1-coldcard.dfu -7e284bcead1f9c2f468230a588ddf62064014682772a552d05f453d91d55b6ae 2024-12-18T1407-v6.3.4QX-q1-coldcard-factory.dfu +237cfcb3fdf9217550eae1d9ea6fc828c1c8d09470bd60c9f72f9b00a3bb2d11 2024-09-12T1734-v5.4.0-mk4-coldcard.dfu +6d1178f07d543e1777dbbdca41d872b00ca9c40e0c0c1ffb8ef96e19c51daa52 2024-09-12T1734-v5.4.0-mk4-coldcard-factory.dfu +d840fa4e83ebc7b0f961f30f68d795bed61271e2314dda4ab0eb0b8bfe7192f4 2024-09-12T1733-v1.3.0Q-q1-coldcard.dfu +4db89ecffa1376bfc68a37110c2041a29afe52b005d527ecde701131168fc19c 2024-09-12T1733-v1.3.0Q-q1-coldcard-factory.dfu +4d83715772b31643abde3b9a0bb328003f4a31d14e2fe9c1e038077a518acaea 2024-07-05T1348-v5.3.3-mk4-coldcard.dfu +020d6d5c3baa724713b2f906112bb95f7eff43c3f5a4f8f11b77d8c2e96ccc88 2024-07-05T1348-v5.3.3-mk4-coldcard-factory.dfu +54da941c8df84fcb84adcc62fdd3ee97d1fc12e2a9a648551ca614fcbacade3f 2024-07-05T1342-v1.2.3Q-q1-coldcard.dfu +7f704aa37887ed84d6a25f124e9b4a31187430d7cf6b198eb83b86af8ae4e5ea 2024-07-05T1342-v1.2.3Q-q1-coldcard-factory.dfu +ddf5ce1ef1ee2e6ba2922b333213d0cb939a2658b294c0f24c0e489de3fe7c75 2024-07-04T1501-v6.3.3X-mk4-coldcard.dfu +9a2c5ef80a6f8212caa3b455e203da3549a79b08b473113662cf80fff587566a 2024-07-04T1459-v6.3.3QX-q1-coldcard.dfu +a990cc94066486a37071c011cd85a29caed433cb4ca3f1c4dce7f715ef81dc3c 2024-06-26T1741-v5.3.2-mk4-coldcard.dfu +218d17069d05c0ec2829e5629c5216121028d15b145c31b552e2f52daa7bf172 2024-06-26T1741-v5.3.2-mk4-coldcard-factory.dfu +b87505b407b0477e2d15f71cfb20645ac55ac5b7c74493d25a2c9c97e807b2b3 2024-06-26T1739-v1.2.2Q-q1-coldcard.dfu +efff41069f3f82d4e69d08a02a565ae0d2cd55c07dbbbe4c1328e6e3b6d8faa1 2024-06-26T1739-v1.2.2Q-q1-coldcard-factory.dfu +90b1edfbe194b093258f9cda8f4add4aa3317e9ea205ff35914da7d91410fdae 2024-05-09T1529-v1.2.1Q-q1-coldcard.dfu +c7889532323f7b0c08e84589c7cc756e2c46e209b4eea031bdfef4a633a813c1 2024-05-09T1529-v1.2.1Q-q1-coldcard-factory.dfu +ef6526d37bc1a929c94dc8388f3863f6cc1582addf26495f761123f0bfb7aa30 2024-05-09T1527-v5.3.1-mk4-coldcard.dfu +98c675e98a18b2437c52e30a9867c271bbca9969771caa34299556ef3fcb1a43 2024-05-09T1527-v5.3.1-mk4-coldcard-factory.dfu +c7c79a21c206e8b0e816c86ef1b43cd6932cb767ed97291d5fbc2f0e749f95b7 2024-05-06T1812-v1.2.0Q-q1-coldcard.dfu +5c6b69948f0193b3a7bd252195136d6d9f84ab14fbc8c5349150e7d238708c6f 2024-05-06T1812-v1.2.0Q-q1-coldcard-factory.dfu +bab6818787eec45ef28b6c297e2504ffd4fa041ab19da8a3fd27543dffe876b8 2024-05-06T1811-v5.3.0-mk4-coldcard.dfu +3da458c0dabe9a17eaeb92ee959006a64a3e6838eeb31f887a18840f020ef8b9 2024-05-06T1811-v5.3.0-mk4-coldcard-factory.dfu +101f336310b9b460d717d91d2572ea9e9ef7ac3edbdaf132c7c3aa46bb89050a 2024-04-02T1416-v1.1.0Q-q1-coldcard.dfu +5d034bc6b1abec49a067a90766bdb769faf9a1b52b2c9b7e541d32484cf783fc 2024-04-02T1416-v1.1.0Q-q1-coldcard-factory.dfu +6ea843a56e87d7d811d90be6bfa4703794bbc8318d9709e88ada05740e03b12d 2024-03-14T1419-v1.0.1Q-q1-coldcard.dfu +f53c79c64f02dd1e860a8d32f9319edd279485d97f07815b2a1eb180a1305459 2024-03-14T1419-v1.0.1Q-q1-coldcard-factory.dfu +122e6d757eb5a8ce073d98a85851f376adec97856336c5a8f05b953b5c87a533 2024-03-10T1537-v1.0.0Q-q1-coldcard.dfu +ae04aaac47f07e10143c75b5c772b54739830214c8234356d003137897f3f4f4 2024-03-10T1537-v1.0.0Q-q1-coldcard-factory.dfu +6aaa9d5bf1726fe4d4a4834010d9b9b6525e8592bb97945cd08cc728fc884068 2024-03-02T1750-v0.0.8Q-q1-coldcard.dfu +a0cd556693fae5b8b03f2a498c0abb1e6d747f91a92bd8f2559a676f8707d840 2024-03-02T1750-v0.0.8Q-q1-coldcard-factory.dfu +18fe081d84a950e1fddb2151ad50917697dfc218cd68e2e359229b0bdadbff37 2024-02-26T1442-v0.0.7Q-q1-coldcard.dfu +e4f4fe89cf3743d794568fd5b32b14551966139e9199602ea10468f925fab1cf 2024-02-26T1442-v0.0.7Q-q1-coldcard-factory.dfu +2dc7a27f43958f2de9851f221183c94258ac915ae43d997b39b644e7b9daff8f 2024-02-22T1423-v0.0.6Q-q1-coldcard.dfu +1e4f4d4c04835d78fcc4857d3264034a56dccf594e307d7408d7c4cdcdb0a926 2024-02-22T1423-v0.0.6Q-q1-coldcard-factory.dfu +d51573c72d8958ea35357d4e0a36ce6aaa2d05924577efb219e2cc189be63f08 2024-02-16T1635-v0.0.5Q-q1-coldcard.dfu +55f4ef9c3ae116f50db938acfc3a4b09717965f82cf6de8cc7385f68cd66d285 2024-02-16T1635-v0.0.5Q-q1-coldcard-factory.dfu +8fd1ced0d5e0338d845f6d5ec5ab069a5143cceade02d4f17e86b7d182b489eb 2024-02-15T1843-v0.0.4Q-q1-coldcard.dfu +43fac084727b0e69bae7fc040a62854673fd585dc2435d93bf146c80762e41cf 2024-02-15T1843-v0.0.4Q-q1-coldcard-factory.dfu +3064bf7f1a039e7cd5c1a13c6aff8cc4338e52ef2177abbdca4b196955f9e434 2024-02-08T2005-v0.0.3Q-q1-coldcard.dfu +788e7a1b182f920016617411b875fa7095ae007c6a53fc476afb1c93f0eed1c9 2024-02-08T2005-v0.0.3Q-q1-coldcard-factory.dfu a9d0b416c3cb4f122f2826283fce82bbc5fe4464817b601a3a5787b1f8aaba20 2024-01-18T1507-v6.2.2X-mk4-coldcard.dfu -cc93209e800bc05386b5613969e62c27b9acd4388e3a922686525da90a505778 2024-01-18T1507-v6.2.2X-mk4-coldcard-factory.dfu +4651fb81dc04ac07ae53535f4246ef7f32611c50853de9edaefa68f3c64e1fac 2023-12-21T1526-v5.2.2-mk4-coldcard.dfu +a49cd00808732c67b359c9f86814ddeafc63a1040823b6c1d2035a870575c9ed 2023-12-21T1526-v5.2.2-mk4-coldcard-factory.dfu +06d1048bea43c5d7c72c5e5f395a676620ce884aed0cd152627a86d922e2f3ab 2023-12-19T1444-v5.2.1-mk4-coldcard.dfu +3eb9c4b1add88a6fe412d783b8f4b895241a67e423bbacc6a13816a5216a30fe 2023-12-19T1444-v5.2.1-mk4-coldcard-factory.dfu f4457dc44d08cbed9517e6260aa7163ecc254457276d3cdb0c2611af0f49ba9b 2023-10-26T1343-v6.2.1X-mk4-coldcard.dfu -1dcfb450f81883afe8f655239f06e238de7bae51e740cd4aa5ae6a0541772ad8 2023-10-26T1343-v6.2.1X-mk4-coldcard-factory.dfu +7fbed097d2757b21fde920f4b10f5f50d7e1aeca01ff52186dfde4883af5cace 2023-10-10T1735-v5.2.0-mk4-coldcard.dfu +4e3023676be88d6c6480c7f37de302f3a865077f9a2214de9c5a55b24afcba2c 2023-10-10T1735-v5.2.0-mk4-coldcard-factory.dfu +fd707f2f69d006c9db84ceacd2a0dde79c3cb71730750e2676af610942898717 2023-09-08T2009-v5.1.4-mk4-coldcard.dfu +d2a4a8b71b0b102971bf8a6c98968dee776a77e0a5707db862e34be5276fbc78 2023-09-08T2009-v5.1.4-mk4-coldcard-factory.dfu +c03d4e2d1115e9440d1762c95fc82ae5a31122e84ee88d6537a8e75f26f66954 2023-09-07T1501-v5.1.3-mk4-coldcard.dfu +3602f307df06b6658d7731172c2eb3f192a0bc8ee02c606e3cb97c1aa8d49af2 2023-09-07T1501-v5.1.3-mk4-coldcard-factory.dfu +f6fb19d95bd1e38535f137bed60cafbfcd52379a686e3d12f372f881d78e640e 2023-06-26T1241-v4.1.9-coldcard.dfu 489e161f686a0c631fc605054f8e7271208b16191b669174b8a58f5af28b0f4a 2023-06-20T1506-v6.1.0X-mk4-coldcard.dfu -66c83c3f95fd3d0796b1e452d2e8ed8ac6a4abead53faf5ae793eceb6f7bbdb5 2023-06-20T1506-v6.1.0X-mk4-coldcard-factory.dfu +233398cc8f6b9e894072448eb8b8a82a4f546219ce461dd821f0ed0a38b61900 2023-06-19T1627-v4.1.8-coldcard.dfu 2e8ed970f518a476d0b34752ecbad75bab246669aa65de8f43801364c6f5753e 2023-05-12T1316-v6.0.0X-mk4-coldcard.dfu -8dd5ff029bb2b08c857604f0c9b5773931f6683ee331ecbc35d9ab4c460b745f 2023-05-12T1316-v6.0.0X-mk4-coldcard-factory.dfu +7aefd5bcce533f15337e83618ebbd42925d336792c82a5ca19a430b209b30b8a 2023-04-07T1330-v5.1.2-mk4-coldcard.dfu +a6c007992139a847f0f238769023727e8cbc05c54c916b388a4dd8bc7490f0aa 2023-04-07T1330-v5.1.2-mk4-coldcard-factory.dfu +99804b440f41ea47675456b4e20e7bb4e9cb434556c5813ab83c26fcda0f4e80 2023-02-27T2105-v5.1.1-mk4-coldcard.dfu +8b37d0f2bf9ca8990f424e5a79fe62405e1ec3aca515760e509afec8f2dbacbc 2023-02-27T2105-v5.1.1-mk4-coldcard-factory.dfu +bcf4284f7733e9de8d4dba238368552b056a27308e466721be7ca624192e257f 2023-02-27T1509-v5.1.0-mk4-coldcard.dfu +cc946bcb63211e15d85db577e25ab2432d4a74d5dad77d710539e505dce7914a 2022-11-14T1854-v4.1.7-coldcard.dfu +010827a60ebfc25b8a6e2bb94cc69b938419957ac6d4a9b6c0b1357c4c6c8632 2022-10-05T1724-v5.0.7-mk4-coldcard.dfu +bc4d0b2b985aea3a78eb9351cdadf60d1ab00801ed1e7192765b94181cb8933b 2022-10-05T1517-v4.1.6-coldcard.dfu +884f373717c9c605920a1dc29e0f890bf7b3cc6b141666814e396094aeedb3f8 2022-07-29T1816-v5.0.6-mk4-coldcard.dfu +3c680195ef49cd0eb86d8e2426443511e8834bcea2d0a86ab52a35cc9365a801 2022-07-20T1508-v5.0.5-mk4-coldcard.dfu +7bd2b98186370f2d895e1e43949694f6ba61a1c021f72a63f0f86a30f338a0fc 2022-05-27T1500-v5.0.4-mk4-coldcard.dfu +5aa2ccc65e2e5279db78b3068b9f3c60c34dd7cc330c2cc1243160db31a2d0f0 2022-05-04T1258-v4.1.5-coldcard.dfu +6dbf0aca0f98fb7bdc761eeead4786617b804dad4afb42ee02febf23d31b5e9b 2022-05-04T1254-v5.0.3-mk3-coldcard.dfu +d5d9bf50892a4aab6e2ffb106a3d206853a60f879daa94a6f90d68a69bf4fa33 2022-05-04T1252-v5.0.3-mk4-coldcard.dfu +9bb028d3e60239f0fcdb3b1f91075785e2c21795789b38c4c619c1f64c2950ef 2022-04-25T1618-v4.1.4-coldcard.dfu +a363b1f0d1b27b8f21dbaac32844a59dacab8c2fee126815cda84c4df31fd7cd 2022-04-19T1805-v5.0.2-mk4-coldcard.dfu +afb6048397af4093e63567563544098e1cfb45b7ca673536253eb6494d60125c 2022-03-24T1645-v5.0.1-mk3-coldcard.dfu +605807bd448711d54e14057892a100bac299a103f5b5fb6466d73f9a36d0694b 2022-03-24T1643-v5.0.1-mk4-coldcard.dfu +badd10c078996516c6464c9bfa5f696747dd7206c97d1e6a75d6f5ee0436619a 2022-03-14T1907-v5.0.0-mk4-coldcard.dfu +dedfcf8385e35dbdbb26b92f8c0667105404062ad83c8830d809cf9193434d9c 2021-09-02T1752-v4.1.3-coldcard.dfu +d01d81305b209dadcf960b9e9d20affb8d4f11e9f9f916c5a06be29298c80dc2 2021-07-28T1347-v4.1.2-coldcard.dfu +08e1ec1fd073afbbc9014db6da07fd96c6b20a6710fe491eb805afeba865fe3f 2021-04-30T1748-v4.1.1-coldcard.dfu +2c39330bef467af8dcd7e2f393a970e1ca177b1812f830269916657ff79598eb 2021-04-29T1725-v4.1.0-coldcard.dfu +5e0c5f4ba9fa0e5fd7f9846e25c6cd28821a86ff5e1207c56cc3a4f4c3741f15 2021-04-07T1424-v4.0.2-coldcard.dfu +f05bc8dfed047c0c0abe5ed60621d2d14899b10717221c4af0942d96a1754f33 2021-03-29T1927-v4.0.1-coldcard.dfu +3097fa3c173247637aa27376036e384940adeb67ce727c9795471f46deaa5210 2021-01-14T1617-v3.2.2-coldcard.dfu +9e4aeee48d4399a761fec5d4c65cb2495ef5bc0b46995c085d63a65cf67362cb 2021-01-07T1439-v3.2.1-coldcard.dfu +bea27f263b524a66b3ed0a58c16805e98be0d7c3db20c2f7aab3238f2c6a6995 2019-12-19T1623-v3.0.6-coldcard.dfu -----BEGIN PGP SIGNATURE----- -iQEzBAEBCAAdFiEERYl3mt/BTzMnU06oo6MbrVoqWxAFAme2M9sACgkQo6MbrVoq -WxDroQf/eewxSI7773hBITAqWFxy9ISBrtOWmRqTp+uNCB4fz9vKPPrgb9WYFipH -qpsthUZCgL3tF5GuOzXwGrkO6nGzLqEiTHof71CjskVs9f+dwVOAFIFHYBQcZv1s -DeLiFuCENoXrMW36tyywSU9x3kjSmf37+NgVoJrr/dsi/PMfVPgBr8vMvum4COrM -W6opBDWLB3CgWPIAC7QqhJPBZ9KWBR6msFghyMsJm2YMgeg1WnsFKRlxpHUTb0bD -BhUnayt81I/Rmoeb8mpoM9tFohwf/WbPIEMLNYF8BnNQ/iwnvRd29jyDcUkhV8F9 -6s2209+xZLoXC78R9iUkJGM9ksflEg== -=C67v +iQEzBAEBCAAdFiEERYl3mt/BTzMnU06oo6MbrVoqWxAFAmkIydAACgkQo6MbrVoq +WxCpJAgAhTCFZHoB5xqlppWu5RmMe8+ZVGv96omoUyRFwfE920hV/sxdNXKbmMt2 +WzU1xHSHWFBLqV7mlpLslXrQ/DjyZPHh/CYpcRDNqgLAy06CaqyFmYpnR2sMNoKh +9WfMTuhPXJTnK4oeMiWDwERksPmOa+BB8Gq6w2Tcynv63rYGp3HYBVyCnhLNJTzm +pqsc1GLVR15tn+rXZMJ2apn9byWjuamsCOYTKXT+J+KSRUYtirmiJklq7KgU7dvG +/EUkcXmpbpmWfrmaN56Lu6Ay4JJYZBf9qVRhQkJtqdPdpyh9JJfh7gzCksUrc+o2 +DnquXe7O1zZ6iRdG1GXLY8xcp31J6g== +=icSK -----END PGP SIGNATURE----- diff --git a/shared/actions.py b/shared/actions.py index bd0aef81..09845ee0 100644 --- a/shared/actions.py +++ b/shared/actions.py @@ -9,14 +9,14 @@ from uhashlib import sha256 from uasyncio import sleep_ms from ubinascii import hexlify as b2a_hex from utils import imported, problem_file_line, get_filesize, encode_seed_qr -from utils import xfp2str, B2A, txid_from_fname +from utils import xfp2str, B2A, txid_from_fname, wipe_if_deltamode from ux import ux_show_story, the_ux, ux_confirm, ux_dramatic_pause, ux_aborted from ux import ux_enter_bip32_index, ux_input_text, import_export_prompt, OK, X, ux_render_words -from export import make_json_wallet, make_summary_file, make_descriptor_wallet_export +from export import export_contents, make_summary_file, make_descriptor_wallet_export from export import make_bitcoin_core_wallet, generate_wasabi_wallet, generate_generic_export from export import generate_unchained_export, generate_electrum_wallet from files import CardSlot, CardMissingError, needs_microsd -from public_constants import AF_CLASSIC, AF_P2WPKH, AF_P2WPKH_P2SH, AF_P2TR, MAX_TXN_LEN_MK4 +from public_constants import AF_CLASSIC, AF_P2WPKH, AF_P2TR from glob import settings from pincodes import pa from menu import start_chooser, MenuSystem, MenuItem @@ -24,8 +24,6 @@ from version import MAX_TXN_LEN from charcodes import KEY_NFC, KEY_QR, KEY_CANCEL -CLEAR_PIN = '999999-999999' - async def start_selftest(*args): # selftest is harmless, no need to warn anymore, # but this layer saves memory in typical cases @@ -321,7 +319,7 @@ Press (6) to prove you read to the end of this message.''', title='WARNING', esc if ch == '6': break # do the actual picking - pin = await lll.get_new_pin(title) + pin = await lll.get_new_pin() del lll if pin is None: return @@ -525,7 +523,7 @@ async def new_from_dice(menu, label, item): async def any_active_duress_ux(): from trick_pins import tp - tp.reload() + # if TPs are hidden this msg will not be shown if any(tp.get_duress_pins()): await ux_show_story('You have one or more duress wallets defined ' 'under Trick PINs. Please empty them, and clear ' @@ -562,7 +560,7 @@ async def convert_ephemeral_to_master(*a): msg += 'A reboot is part of this process. ' msg += 'PIN code, and %s funds are not affected.' % _type - if not await ux_confirm(msg): + if not await ux_confirm(msg, confirm_key='4'): return await ux_aborted() # settings.save is part of re-building fs @@ -574,24 +572,30 @@ async def clear_seed(*a): # This is super dangerous for the customer's money. import seed - if await any_active_duress_ux(): - return await ux_aborted() + # in hobble mode, they cannot reach duress wallets and/or maybe we don't + # want to reveal them? So don't block them based on that. + if not pa.hobbled_mode: + if await any_active_duress_ux(): + return await ux_aborted() if not await ux_confirm('Wipe seed words and reset wallet. ' 'All funds will be lost. ' 'You better have a backup of the seed words. ' 'All settings like multisig wallets are also wiped. ' - 'Saved temporary seed settings and Seed Vault are lost.'): + 'Saved temporary seed settings and Seed Vault are lost. ' + 'Trick PINs are also completely removed.'): return await ux_aborted() - ch = await ux_show_story('''Are you REALLY sure though???\n\n\ + if not await ux_confirm('''Are you REALLY sure though???\n\n\ This action will certainly cause you to lose all funds associated with this wallet, \ unless you have a backup of the seed words and know how to import them into a \ -new wallet.\n\nPress (4) to prove you read to the end of this message and accept all \ -consequences.''', escape='4') - if ch != '4': +new wallet.''', 'AGAIN...', confirm_key='4'): return await ux_aborted() + # clear all trick PINs from SE2 + from trick_pins import tp + tp.clear_all() + # clear settings, address cache, settings from tmp seeds / seedvault seeds from files import wipe_flash_filesystem wipe_flash_filesystem(False) @@ -616,7 +620,12 @@ def render_master_secrets(mode, raw, node): qr = ' '.join(w[0:4] for w in words) qr_alnum = True - msg = 'Seed words (%d):\n' % len(words) + title = 'Seed words (%d):' % len(words) + msg = "" + if not version.has_qwerty: + msg += title + "\n" + title = None + msg += ux_render_words(words) if stash.bip39_passphrase: @@ -626,28 +635,30 @@ def render_master_secrets(mode, raw, node): elif mode == 'xprv': + title = "Extended Private Key" if version.has_qwerty else None msg = c.serialize_private(node) qr = msg elif mode == 'master': + title = "Master Secret" if version.has_qwerty else None msg = '%d bytes:\n\n' % len(raw) qr = str(b2a_hex(raw), 'ascii') msg += qr else: raise ValueError(mode) - return msg, qr, qr_alnum + return title, msg, qr, qr_alnum async def view_seed_words(*a): - import stash - if not await ux_confirm('The next screen will show the seed words' ' (and if defined, your BIP-39 passphrase).' '\n\nAnyone with knowledge of those words ' 'can control all funds in this wallet.'): return - from glob import dis + import stash + from glob import dis, NFC + dis.fullscreen("Wait...") dis.busy_bar(True) @@ -657,33 +668,35 @@ async def view_seed_words(*a): raw = mode = None if stash.bip39_passphrase: # get main secret - bypass tmp - with stash.SensitiveValues(bypass_tmp=True) as sv: - if not sv.deltamode: - assert sv.mode == "words" - raw = sv.raw[:] - mode = sv.mode + with stash.SensitiveValues(bypass_tmp=True, enforce_delta=True) as sv: + assert sv.mode == "words" + raw = sv.raw[:] + mode = sv.mode stash.SensitiveValues.clear_cache() - with stash.SensitiveValues(bypass_tmp=False) as sv: - if sv.deltamode: - # give up and wipe self rather than show true seed values. - import callgate - callgate.fast_wipe() - + with stash.SensitiveValues(bypass_tmp=False, enforce_delta=True) as sv: dis.busy_bar(False) - msg, qr, qr_alnum = render_master_secrets(mode or sv.mode, - raw or sv.raw, - sv.node) - + title, msg, qr, qr_alnum = render_master_secrets(mode or sv.mode, + raw or sv.raw, + sv.node) + esc = "1" if not version.has_qwerty: - msg += '\n\nPress (1) to view as QR Code.' + msg += '\n\nPress (1) to view as QR Code' + if NFC: + msg += ", (3) to share via NFC" + esc += "3" + msg += "." while 1: - ch = await ux_show_story(msg, sensitive=True, escape='1'+KEY_QR) + ch = await ux_show_story(msg, title=title, sensitive=True, escape=esc, + hint_icons=KEY_QR+(KEY_NFC if NFC else '')) if ch in '1'+KEY_QR: from ux import show_qr_code - await show_qr_code(qr, qr_alnum) + await show_qr_code(qr, qr_alnum, is_secret=True) + continue + elif NFC and (ch in '3'+KEY_NFC): + await NFC.share_text(qr, is_secret=True) continue break @@ -706,12 +719,7 @@ async def export_seedqr(*a): # Note: cannot reach this menu item if no words. If they are tmp, that's cool. - with stash.SensitiveValues(bypass_tmp=False) as sv: - if sv.deltamode: - # give up and wipe self rather than show true seed values. - import callgate - callgate.fast_wipe() - + with stash.SensitiveValues(bypass_tmp=False, enforce_delta=True) as sv: if sv.mode != 'words': raise ValueError(sv.mode) @@ -723,7 +731,7 @@ async def export_seedqr(*a): del words from ux import show_qr_code - await show_qr_code(qr, True, msg="SeedQR") + await show_qr_code(qr, True, msg="SeedQR", is_secret=True) stash.blank_object(qr) @@ -794,26 +802,37 @@ async def start_login_sequence(): # If that didn't work, or no skip defined, force # them to login successfully. - + sp_unlock = False try: + from trick_pins import tp + # Get a PIN and try to use it to login # - does warnings about attempt usage counts await block_until_login() + sp_unlock = tp.was_sp_unlock() + if sp_unlock: + # Trying to unlock spending policy: ask for main PIN next. + await ux_show_story("Spending Policy Unlock: Please provide Main PIN next.") + pa.reset() + await block_until_login() + + # we don't really know if that was the Main PIN (could easily be the bypass + # PIN again) and if it's a duress wallet, that's cool... + # Do we need to do countdown delay? (real or otherwise) - # Q/Mk4 approach: - # - wiping has already occured if that was picked + # - wiping has already occured if that was selected by trick details # - delay is variable, stored in tc_arg - from trick_pins import tp delay = tp.was_countdown_pin() - # Maybe they do know the right PIN, but do a delay anyway, because they wanted that + # Maybe they do know the right PIN, but always do a delay anyway, because they wanted that if not delay: delay = settings.get('lgto', 0) if delay: # kill some time, with countdown, and get "the" PIN again for real login pa.reset() + await ux_login_countdown(delay * (60 if not version.is_devmode else 1)) # keep it simple for Mk4+: just challenge again for any PIN @@ -827,7 +846,7 @@ async def start_login_sequence(): # safe to do so. Remember the bootrom checks PIN on every access to # the secret, so "letting" them past this point is harmless if they don't know # the true pin. - sys.print_exception(exc) + # sys.print_exception(exc) if not pa.is_successful(): raise @@ -841,16 +860,32 @@ async def start_login_sequence(): # handle upgrades/downgrade issues try: await version_migration() - except: - pass + except: pass # Maybe insist on the "right" microSD being already installed? try: from pwsave import MicroSD2FA MicroSD2FA.enforce_policy() - except BaseException as exc: - # robustness: keep going! - sys.print_exception(exc) + except: pass + + # apply the hobbling for the spending policy, if appropriate + try: + from ccc import sssp_spending_policy, sssp_word_challenge + + if sp_unlock and sssp_spending_policy('words'): + # challenge them also for first and last seed word! (will reboot on fail) + await sssp_word_challenge() + dis.fullscreen("Startup...") + + if sp_unlock: + # Disable spending policy going forward; user has to re-enable. + pa.hobbled_mode = False + sssp_spending_policy('en', set_value=False) + else: + # normal entry mode, but might have policy enabled, if so enable it now. + pa.hobbled_mode = sssp_spending_policy('en') + + except: pass # implement idle timeout now that we are logged-in IMPT.start_task('idle', idle_logout()) @@ -946,7 +981,7 @@ async def restore_main_secret(*a): goto_top_menu() def make_top_menu(): - from flow import VirginSystem, NormalSystem, EmptyWallet, FactoryMenu + from flow import VirginSystem, NormalSystem, EmptyWallet, FactoryMenu, HobbledTopMenu from glob import hsm_active, settings from pincodes import pa @@ -962,7 +997,9 @@ def make_top_menu(): assert pa.is_successful(), "nonblank but wrong pin" if pa.has_secrets(): - _cls = NormalSystem[:] + # let them do a few things, but not all the things, when "hobbled" + _cls = HobbledTopMenu[:] if pa.hobbled_mode else NormalSystem[:] + if pa.tmp_value or settings.get("hmx", False): active_xfp = settings.get("xfp", 0) sl, sr = ("[", "]") if pa.tmp_value else ("<", ">") @@ -994,7 +1031,7 @@ SENSITIVE_NOT_SECRET = ''' The file created is sensitive--in terms of privacy--but should not \ compromise your funds directly.''' -PICK_ACCOUNT = '''\n\nPress (1) to enter a non-zero account number.''' +PICK_ACCOUNT = '\n\nPress %s to continue. Press (1) to enter a non-zero account number.' % OK async def dump_summary(*A): @@ -1127,19 +1164,21 @@ def ss_descriptor_export_story(addition="", background="", acct=True): async def ss_descriptor_skeleton(_0, _1, item): # Export of descriptor data (wallet) - int_ext, addition, f_pattern = None, "", "descriptor.txt" + addition, f_pattern = "", "descriptor.txt" + int_ext = direct_way = None allowed_af = chains.SINGLESIG_AF if item.arg: - int_ext, allowed_af, ll, f_pattern = item.arg + int_ext, allowed_af, ll, f_pattern, direct_way = item.arg addition = " for " + ll - ch = await ux_show_story(ss_descriptor_export_story(addition), escape='1') - account_num = 0 - if ch == '1': - account_num = await ux_enter_bip32_index('Account Number:', unlimited=True) or 0 - elif ch != 'y': - return + if not direct_way: + ch = await ux_show_story(ss_descriptor_export_story(addition), escape='1') + + if ch == '1': + account_num = await ux_enter_bip32_index('Account Number:', unlimited=True) or 0 + elif ch != 'y': + return if int_ext is None: ch = await ux_show_story( @@ -1150,13 +1189,12 @@ async def ss_descriptor_skeleton(_0, _1, item): int_ext = False if ch == "1" else True if len(allowed_af) == 1: - await make_descriptor_wallet_export(allowed_af[0], account_num, - int_ext=int_ext, - fname_pattern=f_pattern) + await make_descriptor_wallet_export(allowed_af[0], account_num, int_ext=int_ext, + fname_pattern=f_pattern, direct_way=direct_way) else: rv = [ MenuItem(chains.addr_fmt_label(af), f=descriptor_skeleton_step2, - arg=(af, account_num, int_ext, f_pattern)) + arg=(af, account_num, int_ext, f_pattern, direct_way)) for af in allowed_af ] the_ux.push(MenuSystem(rv)) @@ -1190,9 +1228,9 @@ async def samourai_account_descriptor(name, account_num): async def descriptor_skeleton_step2(_1, _2, item): # pick a semi-random file name, render and save it. - addr_fmt, account_num, int_ext, f_pattern = item.arg + addr_fmt, account_num, int_ext, f_pattern, dw = item.arg await make_descriptor_wallet_export(addr_fmt, account_num, int_ext=int_ext, - fname_pattern=f_pattern) + fname_pattern=f_pattern, direct_way=dw) async def bitcoin_core_skeleton(*A): @@ -1218,9 +1256,9 @@ without ever connecting this Coldcard to a computer.\ async def electrum_skeleton_step2(_1, _2, item): # pick a semi-random file name, render and save it. addr_fmt, account_num = item.arg - await make_json_wallet('Electrum wallet', - lambda: generate_electrum_wallet(addr_fmt, account_num), - "new-electrum.json") + await export_contents('Electrum wallet', + lambda: generate_electrum_wallet(addr_fmt, account_num), + "new-electrum.json", is_json=True) async def _generic_export(prompt, label, f_pattern): # like the Multisig export, make a single JSON file with @@ -1232,7 +1270,8 @@ async def _generic_export(prompt, label, f_pattern): elif ch != 'y': return - await make_json_wallet(label, lambda: generate_generic_export(account_num), f_pattern) + await export_contents(label, lambda: generate_generic_export(account_num), + f_pattern, is_json=True) async def generic_skeleton(*A): # like the Multisig export, make a single JSON file with @@ -1267,7 +1306,8 @@ You can then open that file in Wasabi without ever connecting this Coldcard to a return # no choices to be made, just do it. - await make_json_wallet('Wasabi wallet', lambda: generate_wasabi_wallet(), 'new-wasabi.json') + await export_contents('Wasabi wallet', lambda: generate_wasabi_wallet(), + 'new-wasabi.json', is_json=True) async def unchained_capital_export(*a): # they were using our airgapped export, and the BIP-45 path from that @@ -1284,9 +1324,8 @@ This saves multisig XPUB information required to setup on the Unchained platform xfp = xfp2str(settings.get('xfp', 0)) fname = 'unchained-%s.json' % xfp - await make_json_wallet('Unchained', - lambda: generate_unchained_export(account_num), - fname) + await export_contents('Unchained', lambda: generate_unchained_export(account_num), + fname, is_json=True) async def backup_everything(*A): @@ -1308,17 +1347,13 @@ async def verify_backup(*A): # do a limited CRC-check over encrypted file await backups.verify_backup_file(fn) -async def import_extended_key_as_secret(extended_key, ephemeral, meta=None): +async def import_extended_key_as_secret(extended_key, ephemeral, origin=None): try: import seed if ephemeral: - await seed.set_ephemeral_seed_extended_key(extended_key, meta=meta) + await seed.set_ephemeral_seed_extended_key(extended_key, origin=origin) else: await seed.set_seed_extended_key(extended_key) - except ValueError: - msg = ("Sorry, wasn't able to find a valid extended private key to import. " - "It should be at the start of a line, and probably starts with 'xprv'.") - await ux_show_story(title="FAILED", msg=msg) except Exception as e: await ux_show_story('Failed to import.\n\n%s\n%s' % (e, problem_file_line(e))) @@ -1364,7 +1399,7 @@ async def import_xprv(_1, _2, item): else: # only get here if NFC was not chosen # pick a likely-looking file. - fn = await file_picker(suffix='txt', min_size=50, max_size=2000, taster=contains_xprv, + fn = await file_picker(suffix='.txt', min_size=50, max_size=2000, taster=contains_xprv, none_msg="Must contain " + label + ".", **choice) if not fn: return @@ -1376,50 +1411,29 @@ async def import_xprv(_1, _2, item): extended_key = ln break - await import_extended_key_as_secret(extended_key, ephemeral, meta='Imported XPRV') + await import_extended_key_as_secret(extended_key, ephemeral, origin='Imported XPRV') # not reached; will do reset. -EMPTY_RESTORE_MSG = '''\ +async def need_clear_seed(*a): + await ux_show_story('''\ You must clear the wallet seed before restoring a backup because it replaces \ the seed value and the old seed would be lost.\n\n\ -Visit the advanced menu and choose 'Destroy Seed'.''' - -async def restore_temporary(*A): +Visit the advanced menu and choose 'Destroy Seed'.''') +async def restore_backup(a, b, item): + # normal word based imports (tmp or master depending on item.arg) fn = await file_picker(suffix=".7z") - if fn: import backups - await backups.restore_complete(fn, temporary=True) - -async def restore_everything(*A): - - if not pa.is_secret_blank(): - await ux_show_story(EMPTY_RESTORE_MSG) - return - - # restore everything, using a password, from single encrypted 7z file - fn = await file_picker(suffix='.7z') + await backups.restore_complete(fn, item.arg, True) +async def restore_backup_dev(*a): + # used ONLY for Restore Bkup in I Am Developer + fn = await file_picker(suffix=[".7z", ".txt"]) if fn: + words = False if fn[-3:] == ".7z" else None import backups - await backups.restore_complete(fn) - -async def restore_everything_cleartext(*A): - # Asssume no password on backup file; devs and crazy people only - - if not pa.is_secret_blank(): - await ux_show_story(EMPTY_RESTORE_MSG) - return - - # restore everything, using NO password, from single text file, like would be wrapped in 7z - fn = await file_picker(suffix='.txt') - - if fn: - import backups - prob = await backups.restore_complete_doit(fn, []) - if prob: - await ux_show_story(prob, title='FAILED') + await backups.restore_complete(fn, not pa.is_secret_blank(), words) async def bkpw_override(*A): # allows user to: @@ -1433,9 +1447,7 @@ async def bkpw_override(*A): if pa.is_secret_blank(): return - if pa.is_deltamode(): - import callgate - callgate.fast_wipe() + wipe_if_deltamode() while True: pwd = settings.get("bkpw", None) @@ -1483,7 +1495,7 @@ async def wipe_filesystem(*A): Erase internal filesystem and rebuild it. Resets contents of internal flash area \ used for settings, address search cache, and HSM config file. Does not affect funds, \ or seed words but will reset settings used with other temporary seeds & BIP-39 passphrases. \ -Does not affect MicroSD card, if any.'''): +Does not affect MicroSD card, if any.''', confirm_key="4"): return from files import wipe_flash_filesystem @@ -1518,47 +1530,52 @@ async def qr_share_file(_1, _2, item): return f.endswith('.psbt') or f.endswith('.txn') \ or f.endswith('.txt') or f.endswith(".json") or fname.endswith(".sig") - while 1: - txid = None - fn = await file_picker(min_size=10, max_size=MAX_TXN_LEN_MK4, taster=is_suitable) - if not fn: return + try: + while 1: + txid = None + fn = await file_picker(min_size=10, max_size=MAX_TXN_LEN, taster=is_suitable) + if not fn: return - basename = fn.split('/')[-1] - ext = fn.split('.')[-1].lower() + basename = fn.split('/')[-1] + ext = fn.split('.')[-1].lower() - try: - with CardSlot() as card: - with open(fn, 'rb') as fp: - data = fp.read() + try: + with CardSlot() as card: + with open(fn, 'rb') as fp: + data = fp.read() - except CardMissingError: - await needs_microsd() - return + except CardMissingError: + await needs_microsd() + return - if ext == "txn": - tc = "T" - txid = txid_from_fname(basename) - if data[2:8] == b'000000': - # it's a txn, and we wrote as hex + if ext == "txn": + tc = "T" + txid = txid_from_fname(basename) + if data[2:8] == b'000000': + # it's a txn, and we wrote as hex + data = data.decode() + else: + assert data[2:8] == bytes(6) + data = b2a_hex(data).decode() + elif data[0:5] == b'psbt\xff': + tc = "P" + elif data[0:6] in (b'cHNidP', b'707362'): + tc = "U" + data = data.decode().strip() + elif ext in ('txt', 'json', 'sig'): + tc = "U" + if ext == "json": + tc = "J" data = data.decode() else: - assert data[2:8] == bytes(6) - data = b2a_hex(data).decode() - elif data[0:5] == b'psbt\xff': - tc = "P" - elif data[0:6] in (b'cHNidP', b'707362'): - tc = "U" - data = data.decode().strip() - elif ext in ('txt', 'json', 'sig'): - tc = "U" - if ext == "json": - tc = "J" - data = data.decode() - else: - raise ValueError(ext) - - await export_by_qr(data, txid, tc, force_bbqr=force_bbqr) + raise ValueError(ext) + await export_by_qr(data, txid, tc, force_bbqr=force_bbqr) + except Exception as e: + await ux_show_story( + title="ERROR", + msg="Failed to share file via QR.\n\n%s\n%s" % (e, problem_file_line(e)) + ) async def nfc_share_file(*A): # Share txt, txn and PSBT files over NFC. @@ -1668,41 +1685,58 @@ async def list_files(*A): from pincodes import pa digest = chk.digest() - basename = fn.rsplit('/', 1)[-1] - msg_base = 'SHA256(%s)\n\n%s\n\nPress ' % (basename, B2A(digest)) - escape = "6" + path, basename = fn.rsplit('/', 1) + msg_base = 'SHA256(%s)\n\n' + B2A(digest) + '\n\nPress (1) to rename file, ' + escape = "61" if pa.has_secrets(): - msg_sign = '(4) to sign file digest and export detached signature, ' + msg_base += '(4) to sign file digest and export detached signature, ' escape += "4" - else: - msg_sign = "" - msg_delete = '(6) to delete.' - msg = msg_base + msg_sign + msg_delete + msg_base += '(6) to delete.' + while True: - ch = await ux_show_story(msg, escape=escape) + ch = await ux_show_story(msg_base % basename, escape=escape) if ch == "x": break - if ch in '46': + if ch in '461': with CardSlot() as card: if ch == '6': card.securely_blank_file(fn) break + elif ch == '1': + new_basename = await ux_input_text(basename, max_len=32, min_len=3) + if new_basename: + try: + # prohibit both slashes and space in filenames + for s in "\/ ": + assert s not in new_basename, "illegal char" + uos.rename(path + "/" + basename, path + "/" + new_basename) + basename = new_basename + except Exception as e: + await ux_show_story("Failed to rename the file. " + str(e), + title="Failure") else: - from auth import write_sig_file + from msgsign import write_sig_file sig_nice = write_sig_file([(digest, fn)]) await ux_show_story("Signature file %s written." % sig_nice) - msg = msg_base + msg_delete return async def file_picker(suffix=None, min_size=1, max_size=1000000, taster=None, choices=None, none_msg=None, force_vdisk=False, slot_b=None, - allow_batch_sign=False, ux=True): + allow_batch=False, ux=True): # present a menu w/ a list of files... to be read # - optionally, enforce a max size, and provide a "tasting" function - # - if msg==None, don't prompt, just do the search and return list + # - if (not ux), don't prompt, just do the search and return list # - if choices is provided; skip search process # - escape: allow these chars to skip picking process # - slot_b: None=>pick slot w/ card in it, or A if both. + # - allow_batch: adds an "all of the above" choice: ("menu label", menu_handler) + # - suffix argument MUST contain the dot (.txt), if list of suffixes, all MUST + + if suffix: + # actually make it a list of "suffixes" + if not isinstance(suffix, list): + suffix = [suffix] + assert all(s[0] == '.' for s in suffix) if choices is None: choices = [] @@ -1716,13 +1750,13 @@ async def file_picker(suffix=None, min_size=1, max_size=1000000, taster=None, # ignore subdirs continue - if suffix: - if not isinstance(suffix, list): - suffix = [suffix] - if not any([fn.lower().endswith(s) for s in suffix]): - continue + if fn[0] == '.': + # unix-style hidden files + continue - if fn[0] == '.': continue + if suffix and not any(fn.lower().endswith(s) for s in suffix): + # wrong suffix, skip + continue full_fname = path + '/' + fn @@ -1746,7 +1780,7 @@ async def file_picker(suffix=None, min_size=1, max_size=1000000, taster=None, label = fn while label in sofar: # just the file name isn't unique enough sometimes? - # - shouldn't happen anymore now that we dno't support internal FS + # - shouldn't happen anymore now that we don't support internal FS # - unless we do muliple paths label += path.split('/')[-1] + '/' + fn @@ -1768,7 +1802,7 @@ async def file_picker(suffix=None, min_size=1, max_size=1000000, taster=None, if none_msg: msg += none_msg if suffix: - msg += '\n\nThe filename must end in "%s". ' % suffix + msg += '\n\nThe filename must end in: ' + ' OR '.join(suffix) msg += '\n\nMaybe insert (another) SD card and try again?' @@ -1783,10 +1817,10 @@ async def file_picker(suffix=None, min_size=1, max_size=1000000, taster=None, choices.sort() items = [MenuItem(label, f=clicked, arg=(path, fn)) for label, path, fn in choices] - if allow_batch_sign and len(choices) > 1: - # we know that each choices member is psbt as allow_batch_sign is only True - # in Ready To Sign - items.insert(0, MenuItem("[Sign All]", f=batch_sign, arg=choices)) + if allow_batch and len(choices) > 1: + # Allow an "all" selection + label, funct = allow_batch + items.insert(0, MenuItem(label, f=funct, arg=choices)) menu = MenuSystem(items) the_ux.push(menu) @@ -1848,7 +1882,7 @@ async def _batch_sign(choices=None): return assert isinstance(picked, dict) - choices = await file_picker(suffix='psbt', min_size=50, ux=False, + choices = await file_picker(suffix='.psbt', min_size=50, ux=False, max_size=MAX_TXN_LEN, taster=is_psbt, **picked) if not choices: @@ -1874,20 +1908,22 @@ async def batch_sign(_1, _2, item): import sys await ux_show_story("FAILURE: batch sign failed\n\n" + problem_file_line(e)) - -async def ready2sign(*a): - # Top menu choice of top menu! Signing! - # - check if any signable in SD card, if so do it +async def _ready2sign(intro="", probe=True, miniscript_wallet=None): + # - if probe=True -> check if any signable in SD card (A slot on Q), if so do it + # - if probe=False -> offer all enabled import options via UX # - if no card, check virtual disk for PSBT - # - if still nothing, then talk about USB connection from pincodes import pa from glob import NFC opt = {} + choices = [] + sb_only = False - # just check if we have candidates, no UI - choices = await file_picker(suffix='psbt', min_size=50, ux=False, - max_size=MAX_TXN_LEN, taster=is_psbt) + if probe: + # just check if we have candidates, no UI + sb_only = True + choices = await file_picker(suffix='.psbt', min_size=50, ux=False, + max_size=MAX_TXN_LEN, taster=is_psbt) if pa.tmp_value: title = '[%s]' % xfp2str(settings.get('xfp')) @@ -1895,25 +1931,17 @@ async def ready2sign(*a): title = None if not choices: - msg = '''Coldcard is ready to sign spending transactions! - -Put the proposed transaction onto MicroSD card \ -in PSBT format (Partially Signed Bitcoin Transaction) \ -or upload a transaction to be signed \ -from your desktop wallet software or command line tools.\n\n''' - - footnotes = ("\n\nYou will always be prompted to confirm the details " - "before any signature is performed.") - # if we have only one SD card inserted, at this point, we know no PSBTs on them # as above file_picker already checked # if we have both inserted, A was already checked - so only care about B - picked = await import_export_prompt("PSBT", is_import=True, intro=msg, - footnotes=footnotes, slot_b_only=True, + footnotes = ("You will always be prompted to confirm the details " + "before any signature is performed.") + picked = await import_export_prompt("PSBT", is_import=True, intro=intro, + footnotes=footnotes, slot_b_only=sb_only, title=title) if isinstance(picked, dict): opt = picked # reset options to what was chosen by user - choices = await file_picker(suffix='psbt', min_size=50, ux=False, + choices = await file_picker(suffix='.psbt', min_size=50, ux=False, max_size=MAX_TXN_LEN, taster=is_psbt, **opt) if not choices: @@ -1922,9 +1950,9 @@ from your desktop wallet software or command line tools.\n\n''' return else: if NFC and picked == KEY_NFC: - await NFC.start_psbt_rx() + await NFC.start_psbt_rx(miniscript_wallet) if picked == KEY_QR: - await _scan_any_qr() + await _scan_any_qr(miniscript_wallet=miniscript_wallet) return @@ -1934,16 +1962,29 @@ from your desktop wallet software or command line tools.\n\n''' input_psbt = path + '/' + fn else: # multiples - ask which, and offer batch to sign them all - input_psbt = await file_picker(choices=choices, allow_batch_sign=True) + input_psbt = await file_picker(choices=choices, allow_batch=("[Sign All]", batch_sign)) if not input_psbt: return # start the process from auth import sign_psbt_file - + opt["miniscript_wallet"] = miniscript_wallet await sign_psbt_file(input_psbt, **opt) +async def ready2sign(*a): + # Top menu choice of top menu! Signing! + # - check if any signable in SD card, if so do it + # - if no card, check virtual disk for PSBT + + await _ready2sign('''Coldcard is ready to sign spending transactions! + +Put the proposed transaction onto MicroSD card \ +in PSBT format (Partially Signed Bitcoin Transaction) \ +or upload a transaction to be signed \ +from your desktop wallet software or command line tools.''') + + async def sign_message_on_sd(*a): # Menu item: choose a file to be signed (as a short text message) # @@ -1955,7 +1996,7 @@ async def sign_message_on_sd(*a): # min 1 line max 3 lines return 1 <= len(lines) <= 3 - fn = await file_picker(suffix=['txt', "json"], min_size=2, max_size=500, taster=is_signable, + fn = await file_picker(suffix=['.txt', ".json"], min_size=2, max_size=500, taster=is_signable, none_msg=('Must be txt file with one msg line, optionally ' 'followed by a subkey derivation path on a second line ' 'and/or address format on third line. JSON msg signing ' @@ -1984,7 +2025,7 @@ async def verify_sig_file(*a): return # start the process - from auth import verify_txt_sig_file + from msgsign import verify_txt_sig_file await verify_txt_sig_file(fn) @@ -2031,7 +2072,7 @@ Write it down.''' while 1: lll.reset() lll.subtitle = "New " + title - pin = await lll.get_new_pin(title, allow_clear=False) + pin = await lll.get_new_pin() if pin is None: return await ux_aborted() @@ -2324,10 +2365,11 @@ async def scan_any_qr(menu, label, item): expect_secret, tmp = item.arg await _scan_any_qr(expect_secret, tmp) -async def _scan_any_qr(expect_secret=False, tmp=False): +async def _scan_any_qr(expect_secret=False, tmp=False, miniscript_wallet=None): from ux_q1 import QRScannerInteraction x = QRScannerInteraction() - await x.scan_anything(expect_secret=expect_secret, tmp=tmp) + await x.scan_anything(expect_secret=expect_secret, tmp=tmp, + miniscript_wallet=miniscript_wallet) PUSHTX_SUPPLIERS = [ @@ -2337,6 +2379,21 @@ PUSHTX_SUPPLIERS = [ ('mempool.space', 'https://mempool.space/pushtx#'), ] +async def feature_requires_nfc(): + # prompt them that it's need (iff not already enabled) + # - return F if they decline + if settings.get('nfc'): + return True + + # force on NFC, so it works... but they can still turn it off later, etc. + if not await ux_confirm("This feature requires NFC to be enabled. %s to enable." % OK): + return False + + settings.set("nfc", 1) + await change_nfc_enable(1) + + return True + async def pushtx_setup_menu(*a): # let them pick a URL from menu to enable "pushtx" feature, and provide # some background, and even let them enter a custom URL. @@ -2355,12 +2412,9 @@ async def pushtx_setup_menu(*a): if ch != "y": return - if not settings.get('nfc'): - # force on NFC, so it works... but they can still turn it off later, etc. - if not await ux_confirm("This feature requires NFC to be enabled. %s to enable." % OK): - return - settings.set("nfc", 1) - await change_nfc_enable(1) + if not await feature_requires_nfc(): + # they don't want to proceed + return async def doit(menu, picked, xx_self): # using stock values, or Disable diff --git a/shared/address_explorer.py b/shared/address_explorer.py index 2739a375..e0404705 100644 --- a/shared/address_explorer.py +++ b/shared/address_explorer.py @@ -7,28 +7,17 @@ import chains, stash, version from ux import ux_show_story, the_ux, ux_enter_bip32_index from ux import export_prompt_builder, import_export_prompt_decode -from menu import MenuSystem, MenuItem -from public_constants import AFC_BECH32, AFC_BECH32M, AF_P2WPKH, AF_P2TR -from multisig import MultisigWallet -from miniscript import MiniScriptWallet +from menu import MenuSystem, MenuItem, ToggleMenuItem +from public_constants import AFC_BECH32, AFC_BECH32M, AF_P2WPKH, AF_P2TR, AF_CLASSIC +from wallet import MiniScriptWallet from uasyncio import sleep_ms from uhashlib import sha256 from glob import settings -from auth import write_sig_file +from msgsign import write_sig_file from charcodes import KEY_QR, KEY_NFC, KEY_PAGE_UP, KEY_PAGE_DOWN, KEY_HOME, KEY_LEFT, KEY_RIGHT from charcodes import KEY_CANCEL -from utils import show_single_address, problem_file_line +from utils import show_single_address, problem_file_line, truncate_address -def truncate_address(addr): - # Truncates address to width of screen, replacing middle chars - if not version.has_qwerty: - # - 16 chars screen width - # - but 2 lost at left (menu arrow, corner arrow) - # - want to show not truncated on right side - return addr[0:6] + '⋯' + addr[-6:] - else: - # tons of space on Q1 - return addr[0:12] + '⋯' + addr[-12:] class KeypathMenu(MenuSystem): def __init__(self, path=None, nl=0): @@ -209,14 +198,15 @@ class AddressListMenu(MenuSystem): items.append(MenuItem("Account Number", f=self.change_account)) items.append(MenuItem("Custom Path", menu=self.make_custom)) - # if they have MS wallets, add those next - for ms in MultisigWallet.iter_wallets(): - if not ms.addr_fmt: continue - items.append(MenuItem(ms.name, f=self.pick_miniscript, arg=ms)) - # if they have miniscript wallets, add those next - for msc in MiniScriptWallet.iter_wallets(): - items.append(MenuItem(msc.name, f=self.pick_miniscript, arg=msc)) + if MiniScriptWallet.exists(): + items.append(ToggleMenuItem('MS Scripts/Derivs', 'aemscsv', + ['Default Off', 'Enable'], story=( + "Enable this option to add script(s) and derivations to the CSV export" + " of Miniscript wallets. Default is to only export addresses."))) + + for msc in MiniScriptWallet.iter_wallets(): + items.append(MenuItem(msc.name, f=self.pick_miniscript, arg=msc)) else: items.append(MenuItem("Account: %d" % self.account_num, f=self.change_account)) @@ -277,7 +267,7 @@ Press (3) if you really understand and accept these risks. async def show_n_addresses(self, path, addr_fmt, ms_wallet, start=0, n=10, allow_change=True): # Displays n addresses by replacing {idx} in path format. # - also for other {account} numbers - # - or multisig case + # - or miniscript case from glob import dis, NFC from wallet import MAX_BIP32_IDX @@ -312,8 +302,10 @@ Press (3) if you really understand and accept these risks. # export options k0 = 'to show change addresses' if allow_change and change == 0 else None - export_msg, escape = export_prompt_builder('address summary file', - key0=k0, force_prompt=True) + export_msg, escape = export_prompt_builder( + 'address summary file', + key0=k0, force_prompt=True + ) if version.has_qwerty: escape += KEY_LEFT+KEY_RIGHT+KEY_HOME+KEY_PAGE_UP+KEY_PAGE_DOWN+KEY_QR else: @@ -359,6 +351,7 @@ Press (3) if you really understand and accept these risks. addr_fmt = addr_fmt or ms_wallet.addr_fmt is_alnum = bool(addr_fmt & (AFC_BECH32 | AFC_BECH32M)) await show_qr_codes(addrs, is_alnum, start, is_addrs=True) + continue elif NFC and (choice == KEY_NFC): @@ -376,7 +369,7 @@ Press (3) if you really understand and accept these risks. else: # only custom path sets allow_change to False # msg sign - from auth import sign_with_own_address + from msgsign import sign_with_own_address await sign_with_own_address(path, addr_fmt) elif n is None: @@ -409,16 +402,14 @@ def generate_address_csv(path, addr_fmt, ms_wallet, account_num, n, start=0, cha from ownership import OWNERSHIP if ms_wallet: - if (start == 0) and (n > 100) and change in (0, 1): - saver = OWNERSHIP.saver(ms_wallet, change, start) - else: - saver = None + # saver will be None if we don't think it worth saving these addresses + saver = OWNERSHIP.saver(ms_wallet, change, start, n) - for line in ms_wallet.generate_address_csv(start, n, change): + for line in ms_wallet.generate_address_csv(start, n, change, saver=saver): yield line if saver: - saver(None) # close file + saver(None, 0) # close cache file return @@ -426,26 +417,24 @@ def generate_address_csv(path, addr_fmt, ms_wallet, account_num, n, start=0, cha from wallet import MasterSingleSigWallet main = MasterSingleSigWallet(addr_fmt, path, account_num) - if n and (start == 0) and (n > 100) and change in (0, 1): - saver = OWNERSHIP.saver(main, change, start) - else: - saver = None + # saver will be None if we don't think it worth saving these addresses + saver = OWNERSHIP.saver(main, change, start, n) yield '"Index","Payment Address","Derivation"\n' - for (idx, addr, deriv) in main.yield_addresses(start, n, change_idx=change): + for (idx, addr, deriv) in main.yield_addresses(start, n, change): if saver: - saver(addr) + saver(addr, idx) yield '%d,"%s","%s"\n' % (idx, addr, deriv) if saver: - saver(None) # close + saver(None, 0) # close cache file async def make_address_summary_file(path, addr_fmt, ms_wallet, account_num, start=0, count=250, change=0, **save_opts): # write addresses into a text file on the MicroSD/VirtDisk - from glob import dis + from glob import dis, settings from files import CardSlot, CardMissingError, needs_microsd # simple: always set number of addresses. @@ -457,7 +446,6 @@ async def make_address_summary_file(path, addr_fmt, ms_wallet, account_num, # generator function body = generate_address_csv(path, addr_fmt, ms_wallet, account_num, count, start=start, change=change) - # pick filename and write try: with CardSlot(**save_opts) as card: @@ -468,27 +456,32 @@ async def make_address_summary_file(path, addr_fmt, ms_wallet, account_num, for idx, part in enumerate(body): ep = part.encode() fd.write(ep) - if not ms_wallet: - h.update(ep) - + h.update(ep) dis.progress_sofar(idx, count or 1) sig_nice = None - if not ms_wallet and addr_fmt != AF_P2TR: + if ms_wallet: + # sign with my key at the same path as first address of export + addr_fmt = AF_CLASSIC + derive = ms_wallet.get_my_deriv() + derive += "/%d/%d" % (change, start) + else: + addr_fmt = AF_CLASSIC if addr_fmt == AF_P2TR else addr_fmt derive = path.format(account=account_num, change=change, idx=start) # first addr - sig_nice = write_sig_file([(h.digest(), fname)], derive, addr_fmt) + + sig_nice = write_sig_file([(h.digest(), fname)], derive, addr_fmt) + + + msg = '''Address summary file written:\n\n%s''' % nice + if sig_nice: + msg += "\n\nAddress signature file written:\n\n%s" % sig_nice + await ux_show_story(msg) except CardMissingError: await needs_microsd() - return except Exception as e: - await ux_show_story('Failed to write!\n\n\n%s\n%s' % (e, problem_file_line(e))) - return + await ux_show_story('Failed to write!\n\n%s\n%s' % (e, problem_file_line(e))) - msg = '''Address summary file written:\n\n%s''' % nice - if sig_nice: - msg += "\n\nAddress signature file written:\n\n%s" % sig_nice - await ux_show_story(msg) async def address_explore(*a): # explore addresses based on derivation path chosen diff --git a/shared/auth.py b/shared/auth.py index 39d2f8dd..de9520f2 100644 --- a/shared/auth.py +++ b/shared/auth.py @@ -3,25 +3,24 @@ # Operations that require user authorization, like our core features: signing messages # and signing bitcoin transactions. # -import stash, ure, ux, chains, sys, gc, uio, version, ngu, ujson +import stash, ure, chains, sys, gc, uio, version, ngu, ujson from ubinascii import b2a_base64, a2b_base64 from ubinascii import hexlify as b2a_hex from ubinascii import unhexlify as a2b_hex from uhashlib import sha256 -from public_constants import MSG_SIGNING_MAX_LENGTH, SUPPORTED_ADDR_FORMATS, AF_P2TR -from public_constants import AFC_SCRIPT, AF_CLASSIC, AFC_BECH32, AF_P2WPKH, AF_P2WPKH_P2SH -from public_constants import STXN_FLAGS_MASK, STXN_FINALIZE, STXN_VISUALIZE, STXN_SIGNED +from public_constants import AFC_SCRIPT, AF_CLASSIC, AFC_BECH32, SUPPORTED_ADDR_FORMATS, AF_P2TR +from public_constants import STXN_FINALIZE, STXN_VISUALIZE, STXN_SIGNED from sffile import SFFile -from ux import ux_aborted, ux_show_story, abort_and_goto, ux_dramatic_pause, ux_clear_keys -from ux import show_qr_code, OK, X, ux_input_text, ux_enter_bip32_index +from ux import ux_show_story, abort_and_goto, ux_dramatic_pause, ux_clear_keys, ux_confirm +from ux import show_qr_code, OK, X, abort_and_push, AbortInteraction from usb import CCBusyError -from utils import HexWriter, xfp2str, problem_file_line, cleanup_deriv_path -from utils import B2A, to_ascii_printable, show_single_address +from utils import HexWriter, xfp2str, problem_file_line, cleanup_deriv_path, B2A, show_single_address from psbt import psbtObject, FatalPSBTIssue, FraudulentChangeOutput -from files import CardSlot, CardMissingError, needs_microsd -from exceptions import HSMDenied +from files import CardSlot, CardMissingError +from exceptions import HSMDenied, QRTooBigError from version import MAX_TXN_LEN from charcodes import KEY_QR, KEY_NFC, KEY_ENTER, KEY_CANCEL, KEY_LEFT, KEY_RIGHT +from msgsign import sign_message_digest # Where in SPI flash/PSRAM the two PSBT files are (in and out) TXN_INPUT_OFFSET = 0 @@ -73,13 +72,12 @@ class UserAuthorizedAction: if allowed_cls and isinstance(cls.active_request, allowed_cls): return - # check if UX actally was cleared, and we're not really doing that anymore; recover + # check if UX actually was cleared, and we're not really doing that anymore; recover # - happens if USB caller never comes back for their final results from ux import the_ux top_ux = the_ux.top_of_stack() if not isinstance(top_ux, cls) and cls.active_request.ux_done: # do cleaup - print('recovery cleanup') cls.cleanup() return @@ -91,8 +89,8 @@ class UserAuthorizedAction: # show line number and/or simple text about error if exc: - print("%s:" % msg) - sys.print_exception(exc) + #print("%s:" % msg) + #sys.print_exception(exc) msg += '\n\n' em = str(exc) @@ -128,245 +126,14 @@ Using the key associated with address: Press %s to continue, otherwise %s to cancel.''' % (OK, X) -# RFC2440 style signatures, popular -# since the genesis block, but not really part of any BIP as far as I know. -# -def rfc_signature_template_gen(msg, addr, sig): - template = [ - "-----BEGIN BITCOIN SIGNED MESSAGE-----\n", - "%s\n" % msg, - "-----BEGIN BITCOIN SIGNATURE-----\n", - "%s\n" % addr, - "%s\n" % sig, - "-----END BITCOIN SIGNATURE-----\n" - ] - for part in template: - yield part - -def parse_armored_signature_file(contents): - sep = "-----" - assert contents.count(sep) == 6, "Armor text MUST be surrounded by exactly five (5) dashes." - temp = contents.split(sep) - msg = temp[2].strip() - addr_sig = temp[4].strip() - addr, sig_str = addr_sig.split() - return msg, addr, sig_str - -def sign_message_digest(digest, subpath, prompt, addr_fmt=AF_CLASSIC, pk=None): - # do the signature itself! - from glob import dis - - ch = chains.current_chain() - - if prompt: - dis.fullscreen(prompt, percent=.25) - - if pk is None: - with stash.SensitiveValues() as sv: - # if private key is provided, derivation subpath is ignored - # and provided private key is used for signing - node = sv.derive_path(subpath) - dis.progress_bar_show(.50) - pk = node.privkey() - addr = ch.address(node, addr_fmt) - else: - node = ngu.hdnode.HDNode().from_chaincode_privkey(bytes(32), pk) - dis.progress_bar_show(.50) - addr = ch.address(node, addr_fmt) - - dis.progress_bar_show(.75) - rv = ngu.secp256k1.sign(pk, digest, 0).to_bytes() - # AF_CLASSIC header byte base 31 is returned by default from ngu - NOOP - if addr_fmt != AF_CLASSIC: - header_byte, rs = rv[0], rv[1:] - # ngu only produces header base for compressed p2pkh, anyways get only rec_id - rec_id = (header_byte - 27) & 0x03 - new_header_byte = rec_id + ch.sig_hdr_base(addr_fmt=addr_fmt) - rv = bytes([new_header_byte]) + rs - - dis.progress_bar_show(1) - - return rv, addr - -def make_signature_file_msg(content_list): - # list of tuples consisting of (hash, file_name) - return b"\n".join([ - b2a_hex(h) + b" " + fname.encode() - for h, fname in content_list - ]) - -def parse_signature_file_msg(msg): - # only succeed for our format digest + 2 spaces + fname - try: - res = [] - lines = msg.split('\n') - for ln in lines: - d, fn = ln.split(' ') - # should not need to strip if our file format, so dont - # is hex? is 32 bytes long? - assert len(a2b_hex(d)) == 32 - res.append((d, fn)) - - return res - except: - return - -def sign_export_contents(content_list, deriv, addr_fmt, pk=None): - msg2sign = make_signature_file_msg(content_list) - bitcoin_digest = chains.current_chain().hash_message(msg2sign) - sig_bytes, addr = sign_message_digest(bitcoin_digest, deriv, "Signing...", addr_fmt, pk=pk) - sig = b2a_base64(sig_bytes).decode().strip() - gen = rfc_signature_template_gen(addr=addr, msg=msg2sign.decode(), sig=sig) - return gen - -def verify_signed_file_digest(msg): - from files import CardSlot - - parsed_msg = parse_signature_file_msg(msg) - if not parsed_msg: - # not our format - return - - try: - err, warn = [], [] - with CardSlot() as card: - for digest, fname in parsed_msg: - path = card.abs_path(fname) - if not card.exists(path): - warn.append((fname, None)) - continue - path = card.abs_path(fname) - - md = sha256() - with open(path, "rb") as f: - while True: - chunk = f.read(1024) - if not chunk: - break - md.update(chunk) - - h = b2a_hex(md.digest()).decode().strip() - if h != digest: - err.append((fname, h, digest)) - except: - # fail silently if issues with reading files or SD issues - # no digest checking - return - - return err, warn - -def write_sig_file(content_list, derive=None, addr_fmt=AF_CLASSIC, pk=None, sig_name=None): - from glob import dis - - if derive is None: - ct = chains.current_chain().b44_cointype - derive = "m/44'/%d'/0'/0/0" % ct - - fpath = content_list[0][1] - if len(content_list) > 1: - # we're signing contents of more files - need generic name for sig file - assert sig_name - sig_nice = sig_name + ".sig" - sig_fpath = fpath.rsplit("/", 1)[0] + "/" + sig_nice - else: - sig_fpath = fpath.rsplit(".", 1)[0] + ".sig" - sig_nice = sig_fpath.split("/")[-1] - - sig_gen = sign_export_contents([(h, f.split("/")[-1]) for h, f in content_list], - derive, addr_fmt, pk=pk) - - with open(sig_fpath, 'wt') as fd: - for i, part in enumerate(sig_gen): - fd.write(part) - # rfc template generator has length of 6 - dis.progress_bar_show(i / 6) - return sig_nice - -def validate_text_for_signing(text, only_printable=True): - # Check for some UX/UI traps in the message itself. - # - messages must be short and ascii only. Our charset is limited - # - too many spaces, leading/trailing can be an issue - # MSG_MAX_SPACES = 4 # impt. compared to -=- positioning - - result = to_ascii_printable(text, only_printable=only_printable) - - length = len(result) - assert length >= 2, "msg too short (min. 2)" - assert length <= MSG_SIGNING_MAX_LENGTH, "msg too long (max. %d)" % MSG_SIGNING_MAX_LENGTH - assert " " not in result, 'too many spaces together in msg(max. 3)' - # other confusion w/ whitepace - assert result[0] != ' ', 'leading space(s) in msg' - assert result[-1] != ' ', 'trailing space(s) in msg' - - # looks ok - return result - -def addr_fmt_from_subpath(subpath): - if not subpath: - af = "p2pkh" - elif subpath[:4] == "m/84": - af = "p2wpkh" - elif subpath[:4] == "m/49": - af = "p2sh-p2wpkh" - else: - af = "p2pkh" - return af - -def parse_msg_sign_request(data): - subpath = "" - addr_fmt = None - is_json = False - - # sparrow compat - if "signmessage" in data: - try: - mark, subpath, *msg_line = data.split(" ", 2) - assert mark == "signmessage" - # subpath will be verified & cleaned later - assert msg_line[0][:6] == "ascii:" - text = msg_line[0][6:] - return text, subpath, addr_fmt_from_subpath(subpath), is_json - except:pass - # === - - try: - data_dict = ujson.loads(data.strip()) - text = data_dict.get("msg", None) - if text is None: - raise AssertionError("MSG required") - subpath = data_dict.get("subpath", subpath) - addr_fmt = data_dict.get("addr_fmt", addr_fmt) - is_json = True - except ValueError: - lines = data.split("\n") - assert len(lines) >= 1, "min 1 line" - assert len(lines) <= 3, "max 3 lines" - - if len(lines) == 1: - text = lines[0] - elif len(lines) == 2: - text, subpath = lines - else: - text, subpath, addr_fmt = lines - - if not addr_fmt: - addr_fmt = addr_fmt_from_subpath(subpath) - - if not subpath: - subpath = chains.STD_DERIVATIONS[addr_fmt] - subpath = subpath.format( - coin_type=chains.current_chain().b44_cointype, - account=0, change=0, idx=0 - ) - - return text, subpath, addr_fmt, is_json - - class ApproveMessageSign(UserAuthorizedAction): def __init__(self, text, subpath, addr_fmt, approved_cb=None, msg_sign_request=None, only_printable=True): super().__init__() is_json = False + + from msgsign import validate_text_for_signing, parse_msg_sign_request + if msg_sign_request: text, subpath, addr_fmt, is_json = parse_msg_sign_request(msg_sign_request) @@ -392,7 +159,7 @@ class ApproveMessageSign(UserAuthorizedAction): async def interact(self): # Prompt user w/ details and get approval - from glob import dis, hsm_active + from glob import hsm_active if hsm_active: ch = await hsm_active.approve_msg_sign(self.text, self.address, self.subpath) @@ -407,7 +174,7 @@ class ApproveMessageSign(UserAuthorizedAction): else: # perform signing (progress bar shown) digest = chains.current_chain().hash_message(self.text.encode()) - self.result = sign_message_digest(digest, self.subpath, "Signing...", self.addr_fmt)[0] + self.result, _ = sign_message_digest(digest, self.subpath, "Signing...", self.addr_fmt) if self.approved_cb: # for micro sd case @@ -422,48 +189,18 @@ class ApproveMessageSign(UserAuthorizedAction): def sign_msg(text, subpath, addr_fmt): + # Start the approval process for message signing. UserAuthorizedAction.check_busy() UserAuthorizedAction.active_request = ApproveMessageSign(text, subpath, addr_fmt) + # kill any menu stack, and put our thing at the top abort_and_goto(UserAuthorizedAction.active_request) - -async def msg_sign_ux_get_subpath(addr_fmt): - purpose = chains.af_to_bip44_purpose(addr_fmt) - chain_n = chains.current_chain().b44_cointype - acct = await ux_enter_bip32_index('Account Number:') or 0 - ch = await ux_show_story(title="Change?", - msg="Press (0) to use internal/change address," - " %s to use external/receive address." % OK, escape="0") - change = 1 if ch == '0' else 0 - idx = await ux_enter_bip32_index('Index Number:') or 0 - return "m/%dh/%dh/%dh/%d/%d" % (purpose, chain_n, acct, change, idx) - - -async def ux_sign_msg(txt, approved_cb=None, kill_menu=True): - from menu import MenuSystem, MenuItem - from ux import the_ux - - async def done(_1, _2, item): - from auth import approve_msg_sign, msg_sign_ux_get_subpath - - text, af = item.arg - subpath = await msg_sign_ux_get_subpath(af) - - await approve_msg_sign(text, subpath, af, approved_cb=approved_cb, - kill_menu=kill_menu, only_printable=False) - - # pick address format - rv = [ - MenuItem(chains.addr_fmt_label(af), f=done, arg=(txt, af)) - for af in (AF_P2WPKH, AF_CLASSIC, AF_P2WPKH_P2SH) # cannot use SINGLE_AF here as it contains taproot - ] - the_ux.push(MenuSystem(rv)) - - async def approve_msg_sign(text, subpath, addr_fmt, approved_cb=None, msg_sign_request=None, kill_menu=False, only_printable=True): + + # Ask user if they want to sign some short text message. UserAuthorizedAction.cleanup() UserAuthorizedAction.check_busy(ApproveMessageSign) try: @@ -473,114 +210,22 @@ async def approve_msg_sign(text, subpath, addr_fmt, approved_cb=None, msg_sign_request=msg_sign_request, only_printable=only_printable, ) + if kill_menu: abort_and_goto(UserAuthorizedAction.active_request) else: - # do not kill the menu stack! just append + # do not kill the menu stack! just push from ux import the_ux the_ux.push(UserAuthorizedAction.active_request) + except (AssertionError, ValueError) as exc: await ux_show_story("Problem: %s\n\nMessage to be signed must be a single line of ASCII text." % exc) - return - - -async def msg_signing_done(signature, address, text): - from ux import import_export_prompt - - ch = await import_export_prompt("Signed Msg", is_import=False, - no_qr=not version.has_qwerty) - if ch == KEY_CANCEL: - return - - if isinstance(ch, dict): - await sd_sign_msg_done(signature, address, text, "msg_sign", **ch) - elif version.has_qr and ch == KEY_QR: - from ux_q1 import qr_msg_sign_done - await qr_msg_sign_done(signature, address, text) - elif ch in KEY_NFC+"3": - from glob import NFC - if NFC: - await NFC.msg_sign_done(signature, address, text) - - -async def sign_with_own_address(subpath, addr_fmt): - # used for cases where we already have the key picked, but need the message: - # * address_explorer custom path - # * positive ownership test - from glob import dis - - to_sign = await ux_input_text("", scan_ok=True, prompt="Enter MSG") # max len is 100 only here - if not to_sign: return - - await approve_msg_sign(to_sign, subpath, addr_fmt, approved_cb=msg_signing_done, kill_menu=True) - - -async def sd_sign_msg_done(signature, address, text, base=None, orig_path=None, - slot_b=None, force_vdisk=False): - from glob import dis - dis.fullscreen('Generating...') - - out_fn = None - sig = b2a_base64(signature).decode('ascii').strip() - - while 1: - # try to put back into same spot - # add -signed to end. - target_fname = base + '-signed.txt' - lst = [orig_path] - if orig_path: - lst.append(None) - - for path in lst: - try: - with CardSlot(readonly=True, slot_b=slot_b, force_vdisk=force_vdisk) as card: - out_full, out_fn = card.pick_filename(target_fname, path) - out_path = path - if out_full: break - except CardMissingError: - prob = 'Missing card.\n\n' - out_fn = None - - if not out_fn: - # need them to insert a card - prob = '' - else: - # attempt write-out - try: - dis.fullscreen("Saving...") - with CardSlot(slot_b=slot_b, force_vdisk=force_vdisk) as card: - with card.open(out_full, 'wt') as fd: - # save in full RFC style - # gen length is 6 - gen = rfc_signature_template_gen(addr=address, msg=text, sig=sig) - for i, part in enumerate(gen): - fd.write(part) - dis.progress_bar_show(i / 6) - - # success and done! - break - - except OSError as exc: - prob = 'Failed to write!\n\n%s\n\n' % exc - sys.print_exception(exc) - # fall through to try again - - # prompt them to input another card? - ch = await ux_show_story(prob + "Please insert an SDCard to receive signed message, " - "and press %s." % OK, title="Need Card") - if ch == 'x': - await ux_aborted() - return - - # done. - msg = "Created new file:\n\n%s" % out_fn - await ux_show_story(msg, title='File Signed') - async def sign_txt_file(filename): # sign a one-line text file found on a MicroSD card # - not yet clear how to do address types other than 'classic' from ux import the_ux + from msgsign import sd_sign_msg_done async def done(signature, address, text): # complete. write out result @@ -603,139 +248,10 @@ async def sign_txt_file(filename): await approve_msg_sign(None, None, None, approved_cb=done, msg_sign_request=res) -def verify_signature(msg, addr, sig_str): - warnings = "" - script = None - hash160 = None - invalid_addr_fmt_msg = "Invalid address format - must be one of p2pkh, p2sh-p2wpkh, or p2wpkh." - invalid_addr = "Invalid signature for message." - - if addr[0] in "1mn": - addr_fmt = AF_CLASSIC - decoded_addr = ngu.codecs.b58_decode(addr) - hash160 = decoded_addr[1:] # remove prefix - elif addr.startswith("bc1q") or addr.startswith("tb1q") or addr.startswith("bcrt1q"): - if len(addr) > 44: # testnet/mainnet max singlesig len 42, regtest 44 - # p2wsh - raise ValueError(invalid_addr_fmt_msg) - addr_fmt = AF_P2WPKH - _, _, hash160 = ngu.codecs.segwit_decode(addr) - elif addr[0] in "32": - addr_fmt = AF_P2WPKH_P2SH - decoded_addr = ngu.codecs.b58_decode(addr) - script = decoded_addr[1:] # remove prefix - else: - raise ValueError(invalid_addr_fmt_msg) - - try: - sig_bytes = a2b_base64(sig_str) - if not sig_bytes or len(sig_bytes) != 65: - # can return b'' in case of wrong, can also raise - raise ValueError("invalid encoding") - - header_byte = sig_bytes[0] - header_base = chains.current_chain().sig_hdr_base(addr_fmt) - if (header_byte - header_base) not in (0, 1, 2, 3): - # wrong header value only - this can still verify OK - warnings += "Specified address format does not match signature header byte format." - - # least two significant bits - rec_id = (header_byte - 27) & 0x03 - # need to normalize it to 31 base for ngu - new_header_byte = 31 + rec_id - sig = ngu.secp256k1.signature(bytes([new_header_byte]) + sig_bytes[1:]) - except ValueError as e: - raise ValueError("Parsing signature failed - %s." % str(e)) - - digest = chains.current_chain().hash_message(msg.encode('ascii')) - try: - rec_pubkey = sig.verify_recover(digest) - except ValueError as e: - raise ValueError("Invalid signature for msg - %s." % str(e)) - - rec_pubkey_bytes = rec_pubkey.to_bytes() - rec_hash160 = ngu.hash.hash160(rec_pubkey_bytes) - - if script: - target = bytes([0, 20]) + rec_hash160 - target = ngu.hash.hash160(target) - if target != script: - raise ValueError(invalid_addr) - else: - if rec_hash160 != hash160: - raise ValueError(invalid_addr) - - return warnings - -async def verify_armored_signed_msg(contents, digest_check=True): - # digest_check=False for NFC cases, where we do not have filesystem - from glob import dis - - dis.fullscreen("Verifying...") - - try: - msg, addr, sig_str = parse_armored_signature_file(contents) - except Exception as e: - e_line = problem_file_line(e) - await ux_show_story("Malformed signature file. %s %s" % (str(e), e_line), title="FAILURE") - return - - try: - sig_warn = verify_signature(msg, addr, sig_str) - except Exception as e: - await ux_show_story(str(e), title="ERROR") - return - - title = "CORRECT" - warn_msg = "" - err_msg = "" - story = "Good signature by address:\n%s" % show_single_address(addr) - - if digest_check: - digest_prob = verify_signed_file_digest(msg) - if digest_prob: - err, digest_warn = digest_prob - if digest_warn: - title = "WARNING" - wmsg_base = "not present. Contents verification not possible." - if len(digest_warn) == 1: - fname = digest_warn[0][0] - warn_msg += "'%s' is %s" % (fname, wmsg_base) - else: - warn_msg += "Files:\n" + "\n".join("> %s" % fname for fname, _ in digest_warn) - warn_msg += "\nare %s" % wmsg_base - - if err: - title = "ERROR" - for fname, calc, got in err: - err_msg += ("Referenced file '%s' has wrong contents.\n" - "Got:\n%s\n\nExpected:\n%s" % (fname, got, calc)) - - if sig_warn: - # we know not ours only because wrong recid header used & not BIP-137 compliant - story = "Correctly signed, but not by this Coldcard. %s" % sig_warn - - await ux_show_story('\n\n'.join(m for m in [err_msg, story, warn_msg] if m), title=title) - -async def verify_txt_sig_file(filename): - # copy message into memory - try: - with CardSlot() as card: - with card.open(filename, 'rt') as fd: - text = fd.read() - except CardMissingError: - await needs_microsd() - return - except Exception as e: - await ux_show_story('Error: ' + str(e)) - return - - await verify_armored_signed_msg(text) - - async def try_push_tx(data, txid, txn_sha=None): - from glob import settings, PSRAM, NFC # if NFC PushTx is enabled, do that w/o questions. + from glob import settings, PSRAM, NFC + url = settings.get('ptxurl', False) if NFC and url: try: @@ -746,55 +262,87 @@ async def try_push_tx(data, txid, txn_sha=None): await NFC.share_push_tx(url, txid, data, txn_sha) return True except: pass # continue normally if it fails, perhaps too big? + return False - class ApproveTransaction(UserAuthorizedAction): - def __init__(self, psbt_len, flags=0x0, approved_cb=None, psbt_sha=None, is_sd=None): + def __init__(self, psbt_len, flags=None, psbt_sha=None, input_method=None, + output_encoder=None, filename=None, miniscript_wallet=None): super().__init__() self.psbt_len = psbt_len - self.do_finalize = bool(flags & STXN_FINALIZE) - self.do_visualize = bool(flags & STXN_VISUALIZE) + + # do finalize is None if not USB, None = decide based on is_complete + if flags is None: + self.do_finalize = self.do_visualize = None + else: + self.do_finalize = bool(flags & STXN_FINALIZE) + self.do_visualize = bool(flags & STXN_VISUALIZE) + self.stxn_flags = flags self.psbt = None self.psbt_sha = psbt_sha - self.approved_cb = approved_cb + self.input_method = input_method + self.output_encoder = output_encoder + self.filename = filename self.result = None # will be (len, sha256) of the resulting PSBT - self.is_sd = is_sd self.chain = chains.current_chain() + self.miniscript_wallet = miniscript_wallet def render_output(self, o): # Pretty-print a transactions output. # - expects CTxOut object # - gives user-visible string + # returns: tuple(ux_output_rendition, address_or_script_str_for_qr_display) # val = ' '.join(self.chain.render_value(o.nValue)) try: dest = self.chain.render_address(o.scriptPubKey) - - return '%s\n - to address -\n%s\n' % (val, show_single_address(dest)) + # known script types are short enough that we can display QR on both hw versions + return '%s\n - to address -\n%s\n' % (val, show_single_address(dest)), dest except ValueError: pass - # check for OP_RETURN - data = self.chain.op_return(o.scriptPubKey) - if data: - data_hex, data_ascii = data - to_ret = '%s\n - OP_RETURN -\n%s' % (val, data_hex) - if data_ascii: - return to_ret + " (ascii: %s)\n" % data_ascii - return to_ret + "\n" - # Handle future things better: allow them to happen at least. - self.psbt.warnings.append( - ('Output?', 'Sending to a script that is not well understood.')) + # sending to some unknown script, possibly very long + # but full-show required for verification + # OP_RETURN dest contains also OP_RETURN itself (for PSBT qr explorer) dest = B2A(o.scriptPubKey) - return '%s\n - to script -\n%s\n' % (val, dest) + # check for OP_RETURN + data = self.chain.op_return(o.scriptPubKey) + # In UX story only data are shown as OP_RETURN is part of base msg + if data is None: + rv = '%s\n - to script -\n%s\n' % (val, dest) + else: + base = '%s\n - OP_RETURN -\n%s' + if not data: + dest = "" + rv = base % (val, "null-data\n") + else: + data_ascii = None + if len(data) > 160: + # completely arbitrary limit, prevents huge stories + # anchor data are not relevant for verification - can be hidden + ss = b2a_hex(data[:80]).decode() + "\n ⋯\n" + b2a_hex(data[-80:]).decode() + # but we show empty QR in txn explorer for these big, modified data + else: + ss = b2a_hex(data).decode() + if (min(data) >= 32) and (max(data) < 127): # printable & not huge + try: + data_ascii = data.decode("ascii") + except: pass + + rv = base % (val, ss) + if data_ascii: + rv += " (ascii: %s)" % data_ascii + rv += "\n" + + return rv, dest async def interact(self): # Prompt user w/ details and get approval from glob import dis, hsm_active + from ccc import CCCFeature, SSSPFeature # step 1: parse PSBT from PSRAM into in-memory objects. @@ -803,6 +351,7 @@ class ApproveTransaction(UserAuthorizedAction): # NOTE: psbtObject captures the file descriptor and uses it later self.psbt = psbtObject.read_psbt(fd) except BaseException as exc: + # sys.print_exception(exc) if isinstance(exc, MemoryError): msg = "Transaction is too complex" exc = None @@ -812,28 +361,29 @@ class ApproveTransaction(UserAuthorizedAction): return await self.failure(msg, exc) dis.fullscreen("Validating...") + self.psbt.active_miniscript = self.miniscript_wallet # Do some analysis/ validation try: - await self.psbt.validate() # might do UX: accept multisig import - dis.progress_bar_show(0.10) - self.psbt.consider_inputs() + await self.psbt.validate() # might do UX: accept multisig import - dis.progress_bar_show(0.33) - self.psbt.consider_keys() - - dis.progress_bar_show(0.66) - self.psbt.consider_outputs() + ccc_c_xfp = CCCFeature.get_xfp() # can be None + args = self.psbt.consider_inputs(cosign_xfp=ccc_c_xfp) + self.psbt.consider_outputs(*args, cosign_xfp=ccc_c_xfp) + del args # not needed anymore + # we can properly assess sighash only after we know + # which outputs are change self.psbt.consider_dangerous_sighash() - dis.progress_bar_show(0.85) except FraudulentChangeOutput as exc: - print('FraudulentChangeOutput: ' + exc.args[0]) + # sys.print_exception(exc) + #print('FraudulentChangeOutput: ' + exc.args[0]) return await self.failure(exc.args[0], title='Change Fraud') except FatalPSBTIssue as exc: - print('FatalPSBTIssue: ' + exc.args[0]) + #print('FatalPSBTIssue: ' + exc.args[0]) return await self.failure(exc.args[0]) except BaseException as exc: + # sys.print_exception(exc) del self.psbt gc.collect() @@ -845,6 +395,16 @@ class ApproveTransaction(UserAuthorizedAction): return await self.failure(msg, exc) + # early test for spending policy; not an error if violates policy + # - might add warnings + could_ccc_sign, ccc_needs_2fa = CCCFeature.could_cosign(self.psbt) + + # test for allowing any signature when in single-signer mode + # - but CCC will override it. + should_block, ss_needs_2fa = SSSPFeature.can_allow(self.psbt) + if should_block and not could_ccc_sign: + return await self.failure('Spending Policy violation.') + # step 2: figure out what we are approving, so we can get sign-off # - outputs, amounts # - fee @@ -866,6 +426,10 @@ class ApproveTransaction(UserAuthorizedAction): elif wl >= 2: msg.write('(%d warnings below)\n\n' % wl) + if self.psbt.active_miniscript: + # show name of the multisig/miniscript wallet that we signed with + msg.write("Wallet: " + self.psbt.active_miniscript.name + "\n\n") + if self.psbt.consolidation_tx: # consolidating txn that doesn't change balance of account. msg.write("Consolidating %s %s\nwithin wallet.\n\n" % @@ -886,7 +450,7 @@ class ApproveTransaction(UserAuthorizedAction): )) # outputs + change story created here - needs_txn_explorer = self.output_summary_text(msg) + self.output_summary_text(msg) gc.collect() if self.psbt.ux_notes: @@ -895,7 +459,6 @@ class ApproveTransaction(UserAuthorizedAction): for label, m in self.psbt.ux_notes: msg.write('- %s: %s\n' % (label, m)) - msg.write("\n") if self.psbt.warnings: msg.write('---WARNING---\n\n') @@ -912,16 +475,19 @@ class ApproveTransaction(UserAuthorizedAction): ux_clear_keys(True) dis.progress_bar_show(1) # finish the Validating... + if not hsm_active: - msg.write("\nPress %s to approve and sign transaction." % OK) - if needs_txn_explorer: - msg.write(" Press (2) to explore txn.") - if self.is_sd and CardSlot.both_inserted(): + esc = "2" + msg.write("Press %s to approve and sign transaction." + " Press (2) to explore txn outputs." % OK) + if (self.input_method == "sd") and CardSlot.both_inserted(): + esc += "b" msg.write(" (B) to write to lower SD slot.") - msg.write(" X to abort.") + msg.write(" %s to abort." % X) + while True: - ch = await ux_show_story(msg, title="OK TO SEND?", escape="2b") - if ch == "2" and needs_txn_explorer: + ch = await ux_show_story(msg, title="OK TO SEND?", escape=esc) + if ch == "2": await self.txn_explorer() continue else: @@ -929,8 +495,8 @@ class ApproveTransaction(UserAuthorizedAction): del msg break else: + # get approval (maybe) from the HSM ch = await hsm_active.approve_transaction(self.psbt, self.psbt_sha, msg.getvalue()) - dis.progress_bar_show(1) # finish the Validating... except MemoryError: # recovery? maybe. @@ -944,7 +510,7 @@ class ApproveTransaction(UserAuthorizedAction): return await self.failure(msg) if ch not in 'yb': - # they don't want to! + # they don't want to sign! self.refused = True await ux_dramatic_pause("Refused.", 1) @@ -954,73 +520,59 @@ class ApproveTransaction(UserAuthorizedAction): self.done() return + if ccc_needs_2fa and could_ccc_sign: + # They still need to pass web2fa challenge (but it meets other specs ok) + try: + await CCCFeature.web2fa_challenge() + except: + could_ccc_sign = False + ch2 = await ux_show_story("Will not add CCC signature. Proceed anyway?") + if ch2 != 'y': + return await self.failure("2FA Failed") + + elif ss_needs_2fa: + # Need 2FA for single-sig case .. refuse to sign if it fails. + try: + await SSSPFeature.web2fa_challenge() + except: + return await self.failure("2FA Failed") + # do the actual signing. try: dis.fullscreen('Wait...') gc.collect() # visible delay caused by this but also sign_it() below self.psbt.sign_it() + + if could_ccc_sign: + # this is where the CCC co-signing happens. + dis.fullscreen('Co-Signing...') + gc.collect() + CCCFeature.sign_psbt(self.psbt) + else: + # maybe capture new min-height for velocity limit + SSSPFeature.update_last_signed(self.psbt) + except FraudulentChangeOutput as exc: return await self.failure(exc.args[0], title='Change Fraud') except MemoryError: msg = "Transaction is too complex" return await self.failure(msg) except BaseException as exc: + # sys.print_exception(exc) return await self.failure("Signing failed late", exc) - if self.approved_cb: - # for NFC, micro SD cases - kws = dict(psbt=self.psbt) - if self.is_sd and (ch == "b"): - kws["slot_b"] = True - await self.approved_cb(**kws) - self.done() - return - - txid = None try: - # re-serialize the PSBT back out - with SFFile(TXN_OUTPUT_OFFSET, max_size=MAX_TXN_LEN, message="Saving...") as fd: - if self.do_finalize: - txid = self.psbt.finalize(fd) - else: - self.psbt.serialize(fd) - - self.result = (fd.tell(), fd.checksum.digest()) - - self.done(redraw=(not txid)) - + await done_signing(self.psbt, self, self.input_method, + self.filename, self.output_encoder, + slot_b=(ch == "b"), finalize=self.do_finalize) + self.done() + except AbortInteraction: + # user might have sent new sign cmd, while we still at export prompt + pass except BaseException as exc: + # sys.print_exception(exc) return await self.failure("PSBT output failed", exc) - from glob import NFC - - if self.do_finalize and txid and not hsm_active: - - if await try_push_tx(self.result[0], txid, self.result[1]): - return # success, exit - - kq, kn = "(1)", "(3)" - if version.has_qwerty: - kq, kn = KEY_QR, KEY_NFC - while 1: - # Show txid when we can; advisory - # - maybe even as QR, hex-encoded in alnum mode - tmsg = txid + '\n\nPress %s for QR Code of TXID. ' % kq - - if NFC: - tmsg += 'Press %s to share signed txn via NFC.' % kn - - ch = await ux_show_story(tmsg, "Final TXID", escape='13'+KEY_NFC+KEY_QR) - - if ch in '1'+KEY_QR: - await show_qr_code(txid, True) - continue - - if ch in KEY_NFC+"3" and NFC: - await NFC.share_signed_txn(txid, TXN_OUTPUT_OFFSET, - self.result[0], self.result[1]) - continue - break async def txn_explorer(self): # Page through unlimited-sized transaction details @@ -1031,11 +583,16 @@ class ApproveTransaction(UserAuthorizedAction): dis.fullscreen('Wait...') rv = "" end = min(offset + count, self.psbt.num_outputs) - - for idx, out in self.psbt.output_iter(offset, end): + addrs = [] + change = [] + for i, (idx, out) in enumerate(self.psbt.output_iter(offset, end)): outp = self.psbt.outputs[idx] item = "Output %d%s:\n\n" % (idx, " (change)" if outp.is_change else "") - item += self.render_output(out) + msg, addr_or_script = self.render_output(out) + item += msg + addrs.append(addr_or_script) + if outp.is_change: + change.append(i) item += "\n" rv += item dis.progress_sofar(idx-offset+1, count) @@ -1043,18 +600,31 @@ class ApproveTransaction(UserAuthorizedAction): rv += 'Press RIGHT to see next group' if offset: rv += ', LEFT to go back' - rv += '. X to quit.' - return rv + if not version.has_qwerty: + # Q has hint key + rv += ", (4) to show QR code" + rv += ('. %s to quit.' % X) + + return rv, addrs, change, end start = 0 n = 10 - msg = make_msg(start, n) + msg, addrs, change, end = make_msg(start, n) while True: - ch = await ux_show_story(msg, escape='79'+KEY_RIGHT+KEY_LEFT) + ch = await ux_show_story(msg, title="%d-%d" % (start, end-1), + escape='479'+KEY_RIGHT+KEY_LEFT+KEY_QR, + hint_icons=KEY_QR) if ch == 'x': del msg return + elif ch in "4"+KEY_QR: + from ux import show_qr_codes + # showing addresses from PSBT, no idea what is in there + # handle QR code failures gracefully + await show_qr_codes(addrs, False, start, is_addrs=True, + change_idxs=change, can_raise=False) + continue elif (ch in KEY_LEFT+"7"): if (start - n) < 0: continue @@ -1071,7 +641,7 @@ class ApproveTransaction(UserAuthorizedAction): # nothing changed - do not recalc msg continue - msg = make_msg(start, n) + msg, addrs, change, end = make_msg(start, n) async def save_visualization(self, msg, sign_text=False): # write story text out, maybe signing it as we go @@ -1095,7 +665,7 @@ class ApproveTransaction(UserAuthorizedAction): if chk: # append the signature digest = ngu.hash.sha256s(chk.digest()) - sig = sign_message_digest(digest, 'm', None, AF_CLASSIC)[0] + sig, _ = sign_message_digest(digest, 'm', None, AF_CLASSIC) fd.write(b2a_base64(sig).decode('ascii').strip()) fd.write('\n') @@ -1113,14 +683,15 @@ class ApproveTransaction(UserAuthorizedAction): MAX_VISIBLE_OUTPUTS = const(10) MAX_VISIBLE_CHANGE = const(20) - needs_txn_explorer = False largest_outs = [] largest_change = [] total_change = 0 + has_change = False for idx, tx_out in self.psbt.output_iter(): outp = self.psbt.outputs[idx] if outp.is_change: + has_change = True total_change += tx_out.nValue if len(largest_change) < MAX_VISIBLE_CHANGE: largest_change.append((tx_out.nValue, self.chain.render_address(tx_out.scriptPubKey))) @@ -1130,7 +701,8 @@ class ApproveTransaction(UserAuthorizedAction): else: if len(largest_outs) < MAX_VISIBLE_OUTPUTS: - largest_outs.append((tx_out.nValue, self.render_output(tx_out))) + rendered, _ = self.render_output(tx_out) + largest_outs.append((tx_out.nValue, rendered)) if len(largest_outs) == MAX_VISIBLE_OUTPUTS: # descending sort from the biggest value to lowest (sort on out.nValue) largest_outs = sorted(largest_outs, key=lambda x: x[0], reverse=True) @@ -1150,7 +722,8 @@ class ApproveTransaction(UserAuthorizedAction): if outp.is_change: ret = (here, self.chain.render_address(tx_out.scriptPubKey)) else: - ret = (here, self.render_output(tx_out)) + rendered, _ = self.render_output(tx_out) + ret = (here, rendered) largest.insert(keep, ret) # foreign outputs (soon to be other people's coins) @@ -1162,7 +735,6 @@ class ApproveTransaction(UserAuthorizedAction): left = self.psbt.num_outputs - len(largest_outs) - self.psbt.num_change_outputs if left > 0: - needs_txn_explorer = True msg.write('.. plus %d smaller output(s), not shown here, which total: ' % left) # calculate left over value @@ -1172,12 +744,12 @@ class ApproveTransaction(UserAuthorizedAction): msg.write("\n") # change outputs - verified to be coming back to our wallet - if total_change > 0: + if has_change: msg.write("Change back:\n%s %s\n" % self.chain.render_value(total_change)) visible_change_sum = 0 if len(largest_change) == 1: visible_change_sum += largest_change[0][0] - msg.write(' - to address -\n%s\n' % show_single_address(largest_change[0][1])) + msg.write(' - to address -\n%s\n\n' % show_single_address(largest_change[0][1])) else: msg.write(' - to addresses -\n') for val, addr in largest_change: @@ -1187,21 +759,18 @@ class ApproveTransaction(UserAuthorizedAction): left_c = self.psbt.num_change_outputs - len(largest_change) if left_c: - needs_txn_explorer = True msg.write('.. plus %d smaller change output(s), not shown here, which total: ' % left_c) - msg.write('%s %s\n' % self.chain.render_value(total_change - visible_change_sum)) - - msg.write("\n") - - # if we didn't already show all outputs, then give user a chance to - # view them individually - return needs_txn_explorer + msg.write('%s %s\n\n' % self.chain.render_value(total_change - visible_change_sum)) -def sign_transaction(psbt_len, flags=0x0, psbt_sha=None): +def sign_transaction(psbt_len, flags=0x0, psbt_sha=None, miniscript_wallet=None): # transaction (binary) loaded into PSRAM already, checksum checked + # optional miniscript_wallet arg, choose particular enrolled wallet by name to sign UserAuthorizedAction.check_busy(ApproveTransaction) - UserAuthorizedAction.active_request = ApproveTransaction(psbt_len, flags, psbt_sha=psbt_sha) + UserAuthorizedAction.active_request = ApproveTransaction( + psbt_len, flags, psbt_sha=psbt_sha, input_method="usb", + miniscript_wallet=miniscript_wallet, + ) # kill any menu stack, and put our thing at the top abort_and_goto(UserAuthorizedAction.active_request) @@ -1226,21 +795,295 @@ def psbt_encoding_taster(taste, psbt_len): raise ValueError("not psbt") return decoder, output_encoder, psbt_len - -async def sign_psbt_file(filename, force_vdisk=False, slot_b=None): + + +async def done_signing(psbt, tx_req, input_method=None, filename=None, + output_encoder=None, slot_b=False, finalize=None): + # User authorized PSBT for signing, and we added signatures. + # - allow PushTX if enabled (first thing) + # - can save final TXN out to SD card/VirtDisk, share by NFC, QR. + + from glob import PSRAM, hsm_active + from sffile import SFFile + from ux import show_qr_code, import_export_prompt + + first_time = True + msg = None + title = None + + is_complete = psbt.is_complete() + if finalize is not None: + # USB case - user can choose whether to attempt finalization + is_complete = finalize + + with SFFile(TXN_OUTPUT_OFFSET, max_size=MAX_TXN_LEN, message="Saving...") as psram: + if is_complete: + txid = psbt.finalize(psram) + noun = "Finalized TX ready for broadcast" + else: + psbt.serialize(psram) + noun = "Partly Signed PSBT" + txid = None + + data_len = psram.tell() + data_sha2 = psram.checksum.digest() + + # BBQR is at TMP_OUTPUT_OFFSET + 1MB - allowing it in this case would overwrite txn + # allow_qr = data_len < (1024*1024) + # actual more reasonable limit - as BBQR has some overhead and only 1Mbit of space + allow_qr = data_len < (671*1024) + + if input_method == "usb": + # return result over USB before going to all options + tx_req.result = data_len, data_sha2 + if hsm_active: + # it is enough to just return back via USB, other options + # are pointless + return + + first_time = False + msg = noun + " shared via USB." + title = "PSBT Signed" + + if txid and await try_push_tx(data_len, txid, data_sha2): + # go directly to reexport menu after pushTX + first_time = False + title = "TX Pushed" + + # for specific cases, key teleport is an option + offer_kt = False + if not is_complete and version.has_qwerty and psbt.active_miniscript: + offer_kt = 'use Key Teleport to send PSBT to other co-signers' + + while True: + ch = None + if first_time: + # first time, assume they want to send out same way it came in -- don't prompt + if input_method == "qr": + if allow_qr: + ch = KEY_QR + elif input_method == "nfc": + ch = KEY_NFC + elif input_method == "kt": + ch = 't' + else: + # SD/VDisk + ch = {"force_vdisk": input_method == "vdisk", "slot_b": slot_b} + + if not ch: + # show all possible export options (based on hardware enabled, features) + intro = [] + if msg: + intro.append(msg) + if txid: + intro.append('TXID:\n' + txid) + + # "force_prompt" is needed after first iteration as we can be Mk4, with NFC,Vdisk off, + # no QR support & not finalizing (no option to show txid provided). + # In that case this would just return dict and keep producing signed + # files on SD infinitely (would never actually prompt). + ch = await import_export_prompt(noun, intro="\n\n".join(intro), offer_kt=offer_kt, + txid=txid, title=title, force_prompt=not first_time, + no_qr=not version.has_qwerty or not allow_qr) + if ch == KEY_CANCEL: + UserAuthorizedAction.cleanup() + break + + elif txid and (ch == '6'): + await show_qr_code(txid, is_alnum=True, force_msg=True) + continue + + elif ch == KEY_QR: + here = PSRAM.read_at(TXN_OUTPUT_OFFSET, data_len) + msg = txid or 'Partly Signed PSBT' + try: + if len(here) > 920: + # too big for simple QR - use BBQr instead + raise QRTooBigError + hex_here = b2a_hex(here).upper().decode() + await show_qr_code(hex_here, is_alnum=True, msg=msg) + except QRTooBigError: + from ux_q1 import show_bbqr_codes + await show_bbqr_codes('T' if txid else 'P', here, msg) + + msg = noun + " shared via QR." + del here + + elif ch == KEY_NFC: + from glob import NFC + if is_complete: + await NFC.share_signed_txn(txid, TXN_OUTPUT_OFFSET, data_len, data_sha2) + else: + await NFC.share_psbt(TXN_OUTPUT_OFFSET, data_len, data_sha2) + + msg = noun + " shared via NFC." + + elif (ch == 't') and not is_complete: + # they might want to teleport it, but only if we have PSBT + # there is no need to teleport PSBT if txn is already complete & ready to be broadcast + from teleport import kt_send_psbt + ok = await kt_send_psbt(psbt, data_len) + if ok: + title = "Sent by Teleport" + else: + title = "Failed to Teleport" + + continue + + else: + # typical case: save to SD card, show filenames we used + assert isinstance(ch, dict) + msg = await _save_to_disk(psbt, txid, ch, is_complete, data_len, + output_encoder, filename) + + input_method = None + first_time = False + title = "PSBT Signed" + +async def _save_to_disk(psbt, txid, save_options, is_complete, data_len, output_encoder, filename=None): + # Saving a PSBT from PSRAM to something disk-like. + # - handle save-to-SD/VirtDisk cases. With re-attempt when no card, etc. + assert isinstance(save_options, dict) # from import_export_prompt + + from glob import dis, settings, PSRAM + import os + + dis.fullscreen("Wait...") + + if filename: + _, basename = filename.rsplit('/', 1) + base = basename.rsplit('.', 1)[0] + else: + base = 'recent-txn' + + # default encoding is binary + output_encoder = output_encoder or (lambda x:x) + + out2_fn = None + out_fn = None + + del_after = settings.get('del', 0) + + def _chunk_write(file_d, ofs, chunk=2048): + written = 0 + while written < data_len: + if (written + chunk) > data_len: + chunk = data_len - written + + file_d.write(PSRAM.read_at(ofs, chunk)) + written += chunk + ofs += chunk + + while 1: + # try to put back into same spot, but also do top-of-card + if not is_complete: + # keep the filename under control during multiple passes + target_fname = base.replace('-part', '') + '-part.psbt' + else: + # add -signed to end. We won't offer to sign again. + target_fname = base + '-signed.psbt' + + # attempt write-out + try: + with CardSlot(**save_options) as card: + out_full, out_fn = card.pick_filename(target_fname) + out_path = out_full.rsplit("/", 1)[0] + "/" + + if is_complete and del_after: + # don't write signed PSBT if we'd just delete it anyway + out_fn = None + else: + with output_encoder(card.open(out_full, 'wb')) as fd: + # save as updated PSBT + if not is_complete: + _chunk_write(fd, TXN_OUTPUT_OFFSET) + else: + psbt.serialize(fd) + + if is_complete: + # write out as hex too, if it's final + out2_full, out2_fn = card.pick_filename( + base + '-final.txn' if not del_after else 'tmp.txn', + out_path) + + if out2_full: + with HexWriter(card.open(out2_full, 'w+t')) as fd: + # save transaction, in hex + if is_complete: + _chunk_write(fd, TXN_OUTPUT_OFFSET) + else: + txid = psbt.finalize(fd) + + if del_after: + # rename it now that we know the txid + after_full, out2_fn = card.pick_filename( + txid + '.txn', out_path, overwrite=True) + os.rename(out2_full, after_full) + + if del_after and filename: + # this can do nothing if they swapped SDCard between steps, which is ok, + # but if the original file is still there, this blows it away. + # - if not yet final, the foo-part.psbt file stays + try: + card.securely_blank_file(filename) + except: pass + + # success and done! + break + + except CardMissingError: + prob = 'Need a card!\n\n' + + except OSError as exc: + prob = 'Failed to write!\n\n%s\n\n' % exc + # sys.print_exception(exc) + # fall through to try again + + # If this point reached, some problem, we could not write. + + if save_options.get('force_vdisk'): + await ux_show_story(prob, title='Error') + # they can't fix here, so give up + return + + # prompt them to input another card? + ch = await ux_show_story( + prob + "Please insert a card to receive signed transaction, " + "and press OK.", title="Need Card") + if ch == 'x': + return + + # Done, show the filenames we used. + if out_fn: + msg = "Updated PSBT is:\n\n%s" % out_fn + if out2_fn: + msg += '\n\n' + else: + # del_after is probably set + msg = '' + + if out2_fn: + msg += 'Finalized transaction (ready for broadcast):\n\n%s' % out2_fn + + return msg + + +async def sign_psbt_file(filename, force_vdisk=False, slot_b=None, just_read=False, ux_abort=False, + miniscript_wallet=None): # sign a PSBT file found on a MicroSD card # - or from VirtualDisk (mk4) + # - to re-use reading/decoding logic, pass just_read from glob import dis from ux import the_ux - tmp_buf = bytearray(1024) + tmp_buf = bytearray(4096) # copy file into PSRAM # - can't work in-place on the card because we want to support writing out to different card - # - accepts hex or base64 encoding, but binary prefered + # - accepts hex or base64 encoding, but binary preferred with CardSlot(force_vdisk, readonly=True, slot_b=slot_b) as card: with card.open(filename, 'rb') as fd: - dis.fullscreen('Reading...') + dis.fullscreen('Reading...', 0) # see how long it is psbt_len = fd.seek(0, 2) @@ -1271,138 +1114,26 @@ async def sign_psbt_file(filename, force_vdisk=False, slot_b=None): out.write(here) total += len(here) - dis.progress_bar_show(total / psbt_len) + dis.progress_sofar(total, psbt_len) # might have been whitespace inflating initial estimate of PSBT size assert total <= psbt_len psbt_len = total - async def done(psbt, slot_b=None): - dis.fullscreen("Wait...") - orig_path, basename = filename.rsplit('/', 1) - orig_path += '/' - base = basename.rsplit('.', 1)[0] - out2_fn = None - out_fn = None - txid = None - - from glob import settings - import os - del_after = settings.get('del', 0) - - while 1: - # try to put back into same spot, but also do top-of-card - is_comp = psbt.is_complete() - if not is_comp: - # keep the filename under control during multiple passes - target_fname = base.replace('-part', '')+'-part.psbt' - else: - # add -signed to end. We won't offer to sign again. - target_fname = base+'-signed.psbt' - - for path in [orig_path, None]: - try: - with CardSlot(force_vdisk, readonly=True, slot_b=slot_b) as card: - out_full, out_fn = card.pick_filename(target_fname, path) - out_path = path - if out_full: break - except CardMissingError: - prob = 'Missing card.\n\n' - out_fn = None - - if not out_fn: - # need them to insert a card - prob = '' - else: - # attempt write-out - try: - with CardSlot(force_vdisk, slot_b=slot_b) as card: - if is_comp and del_after: - # don't write signed PSBT if we'd just delete it anyway - out_fn = None - else: - with output_encoder(card.open(out_full, 'wb')) as fd: - # save as updated PSBT - psbt.serialize(fd) - - if is_comp: - # write out as hex too, if it's final - out2_full, out2_fn = card.pick_filename( - base+'-final.txn' if not del_after else 'tmp.txn', out_path) - - with SFFile(TXN_OUTPUT_OFFSET, max_size=MAX_TXN_LEN, message="Saving...") as fd0: - txid = psbt.finalize(fd0) - fd0.flush_out() # need to flush here as we are probably not gona call .read( again - tx_len, tx_sha = fd0.tell(), fd0.checksum.digest() - if txid and await try_push_tx(tx_len, txid, tx_sha): - return # success, exit - - if out2_full: - fd0.seek(0) - - with HexWriter(card.open(out2_full, 'w+t')) as fd: - # save transaction, in hex - tmp_buf = bytearray(4096) - while True: - rv = fd0.readinto(tmp_buf) - if not rv: break - fd.write(memoryview(tmp_buf)[:rv]) - - if del_after: - # rename it now that we know the txid - after_full, out2_fn = card.pick_filename( - txid+'.txn', out_path, overwrite=True) - os.rename(out2_full, after_full) - - if del_after: - # this can do nothing if they swapped SDCard between steps, which is ok, - # but if the original file is still there, this blows it away. - # - if not yet final, the foo-part.psbt file stays - try: - card.securely_blank_file(filename) - except: pass - - # success and done! - break - - except OSError as exc: - prob = 'Failed to write!\n\n%s\n\n' % exc - sys.print_exception(exc) - # fall thru to try again - - if force_vdisk: - await ux_show_story(prob, title='Error') - return - - # prompt them to input another card? - ch = await ux_show_story(prob+"Please insert an SDCard to receive signed transaction, " - "and press %s." % OK, title="Need Card") - if ch == 'x': - await ux_aborted() - return - - # done. - if out_fn: - msg = "Updated PSBT is:\n\n%s" % out_fn - if out2_fn: - msg += '\n\n' - else: - # del_after is probably set - msg = '' - - if out2_fn: - msg += 'Finalized transaction (ready for broadcast):\n\n%s' % out2_fn - if txid and not del_after: - msg += '\n\nFinal TXID:\n'+txid - - await ux_show_story(msg, title='PSBT Signed') - - UserAuthorizedAction.cleanup() + if just_read: + return psbt_len UserAuthorizedAction.cleanup() - UserAuthorizedAction.active_request = ApproveTransaction(psbt_len, approved_cb=done, - is_sd=not force_vdisk) - the_ux.push(UserAuthorizedAction.active_request) + UserAuthorizedAction.active_request = ApproveTransaction( + psbt_len, input_method="vdisk" if force_vdisk else "sd", + filename=filename, output_encoder=output_encoder, + miniscript_wallet=miniscript_wallet, + ) + if ux_abort: + # needed for auto vdisk mode + abort_and_push(UserAuthorizedAction.active_request) + else: + the_ux.push(UserAuthorizedAction.active_request) class RemoteBackup(UserAuthorizedAction): def __init__(self): @@ -1424,8 +1155,53 @@ class RemoteBackup(UserAuthorizedAction): except BaseException as exc: self.failed = "Error during backup process." - print("Backup failure: ") - sys.print_exception(exc) + #print("Backup failure: ") + #sys.print_exception(exc) + finally: + self.done() + + +class RemoteRestoreBackup(UserAuthorizedAction): + def __init__(self, file_len, bitflag): + super().__init__() + self.file_len = file_len + self.custom_pwd = bitflag & 1 + self.plaintext = bitflag & 2 + self.force_tmp = bitflag & 4 + + def to_words(self): + # conversion to "words" argument of "restore_complete" function + if self.plaintext: + return None + elif self.custom_pwd: + return False + return True + + def to_tmp(self): + # conversion to "temporary" argument of "restore_complete" function + from pincodes import pa + if pa.is_secret_blank() and not self.force_tmp: + # no master secret & not forcing tmp + # will load backup as master seed + return False, "master" + + # has master secret --> load backup as tmp + # secret is blank but user forcing tmp + return True, "temporary" + + async def interact(self): + try: + # requires confirm from user + tmp, noun = self.to_tmp() + if await ux_confirm("Restore uploaded backup as a %s seed?" % noun): + from backups import restore_complete + await restore_complete(self.file_len, tmp, self.to_words(), usb=True) + else: + self.refused = True + + except BaseException as exc: + self.failed = "Error during backup restore." + # sys.print_exception(exc) finally: self.done() @@ -1440,6 +1216,12 @@ def start_remote_backup(): # kill any menu stack, and put our thing at the top abort_and_goto(UserAuthorizedAction.active_request) +def start_remote_restore_backup(file_len, bitflag): + UserAuthorizedAction.cleanup() + UserAuthorizedAction.active_request = RemoteRestoreBackup(file_len, bitflag) + # kill any menu stack, and put our thing at the top + abort_and_goto(UserAuthorizedAction.active_request) + class NewPassphrase(UserAuthorizedAction): def __init__(self, pw): @@ -1486,7 +1268,7 @@ class NewPassphrase(UserAuthorizedAction): except BaseException as exc: self.failed = "Exception" - sys.print_exception(exc) + # sys.print_exception(exc) finally: self.done() @@ -1528,14 +1310,16 @@ class ShowAddressBase(UserAuthorizedAction): msg = self.get_msg() msg += '\n\nCompare this payment address to the one shown on your other, less-trusted, software.' + esc = "4" if not version.has_qwerty: if NFC: - msg += ' Press %s to share via NFC.' % (KEY_NFC if version.has_qwerty else "(3)") + msg += ' Press (3) to share via NFC.' + esc += "3" msg += ' Press (4) to view QR Code.' while 1: - ch = await ux_show_story(msg, title=self.title, escape='34', - hint_icons=KEY_QR+(KEY_NFC if NFC else '')) + ch = await ux_show_story(msg, title=self.title, escape=esc, + hint_icons=KEY_QR+(KEY_NFC if NFC else '')) if ch in '4'+KEY_QR: await show_qr_code(self.address, (self.addr_fmt & AFC_BECH32), is_addrs=True) @@ -1574,34 +1358,6 @@ class ShowPKHAddress(ShowAddressBase): sp=self.subpath) -class ShowP2SHAddress(ShowAddressBase): - - def setup(self, ms, addr_fmt, xfp_paths, witdeem_script): - - self.witdeem_script = witdeem_script - self.addr_fmt = addr_fmt - self.ms = ms - - # calculate all the pubkeys involved. - self.subpath_help = ms.validate_script(witdeem_script, xfp_paths=xfp_paths) - - self.address = chains.current_chain().p2sh_address(addr_fmt, witdeem_script) - - def get_msg(self): - return '''\ -{addr} - -Wallet: - - {name} - {M} of {N} - -Paths: - -{sp}'''.format(addr=show_single_address(self.address), name=self.ms.name, - M=self.ms.M, N=self.ms.N, sp='\n\n'.join(self.subpath_help)) - - class ShowMiniscriptAddress(ShowAddressBase): def setup(self, msc, change, idx): @@ -1609,8 +1365,8 @@ class ShowMiniscriptAddress(ShowAddressBase): self.change = change self.idx = idx - d = self.msc.desc.derive(None, change=change).derive(idx) - self.address = chains.current_chain().render_address(d.script_pubkey()) + d = self.msc.to_descriptor().derive(None, change=change).derive(idx) + self.address = self.msc.chain.render_address(d.script_pubkey()) self.addr_fmt = self.msc.addr_fmt def get_msg(self): @@ -1638,36 +1394,6 @@ def start_show_miniscript_address(msc, change, index): # provide the value back to attached desktop return UserAuthorizedAction.active_request.address -def start_show_p2sh_address(M, N, addr_format, xfp_paths, witdeem_script): - # Show P2SH address to user, also returns it. - # - first need to find appropriate multisig wallet associated - # - they must provide full redeem script, and we will re-verify it and check pubkeys inside it - - from multisig import MultisigWallet - - try: - assert addr_format in SUPPORTED_ADDR_FORMATS - assert addr_format & AFC_SCRIPT - except: - raise AssertionError('Unknown/unsupported addr format') - - # Search for matching multisig wallet that we must already know about - xs = list(xfp_paths) - xs.sort() - - ms = MultisigWallet.find_match(M, N, xs) - assert ms, 'Multisig wallet with those fingerprints not found' - assert ms.M == M - assert ms.N == N - - UserAuthorizedAction.check_busy(ShowAddressBase) - UserAuthorizedAction.active_request = ShowP2SHAddress(ms, addr_format, xfp_paths, witdeem_script) - - # kill any menu stack, and put our thing at the top - abort_and_goto(UserAuthorizedAction.active_request) - - # provide the value back to attached desktop - return UserAuthorizedAction.active_request.address def show_address(addr_format, subpath, restore_menu=False): try: @@ -1702,7 +1428,7 @@ class MiniscriptDeleteRequest(UserAuthorizedAction): self.wallet = msc async def interact(self): - from miniscript import miniscript_delete + from wallet import miniscript_delete await miniscript_delete(self.wallet) self.done() @@ -1740,17 +1466,17 @@ class NewMiniscriptEnrollRequest(UserAuthorizedAction): return await self.failure('No space left') except BaseException as exc: self.failed = "Exception" - sys.print_exception(exc) + # sys.print_exception(exc) finally: UserAuthorizedAction.cleanup() # because no results to store if self.bsms_index is not None: # bsms special case, get him back to multisig menu from ux import the_ux, restore_menu - from multisig import MultisigMenu + from wallet import MiniscriptMenu while 1: top = the_ux.top_of_stack() if not top: break - if not isinstance(top, MultisigMenu): + if not isinstance(top, MiniscriptMenu): the_ux.pop() continue break @@ -1759,46 +1485,47 @@ class NewMiniscriptEnrollRequest(UserAuthorizedAction): self.pop_menu() -def maybe_enroll_xpub(sf_len=None, config=None, name=None, ux_reset=False, bsms_index=None, miniscript=False): +def maybe_enroll_xpub(sf_len=None, config=None, name=None, ux_reset=False, + bsms_index=None, desc_obj=None): # Offer to import (enroll) a new multisig/miniscript wallet. Allow reject by user. from glob import dis - from multisig import MultisigWallet - from miniscript import MiniScriptWallet + from wallet import MiniScriptWallet UserAuthorizedAction.cleanup() dis.fullscreen('Wait...') dis.busy_bar(True) + bip388 = False try: - if sf_len: - with SFFile(TXN_INPUT_OFFSET, length=sf_len) as fd: - config = fd.read(sf_len).decode() - - try: - j_conf = ujson.loads(config) - assert "desc" in j_conf, "'desc' key required" - config = j_conf["desc"] - assert config, "'desc' empty" - - if "name" in j_conf: - # name from json has preference over filenames and desc checksum - name = j_conf["name"] - assert 2 <= len(name) <= 40, "'name' length" - except ValueError: pass - - # this call will raise on parsing errors, so let them rise up - # and be shown on screen/over usb - if miniscript is None: - # autodetect - try: - msc = MiniScriptWallet.from_file(config, name=name) - except AssertionError: - msc = MultisigWallet.from_file(config, name=name) - - elif miniscript: - msc = MiniScriptWallet.from_file(config, name=name) + if desc_obj: + # caller is sending us already validated descriptor object + assert name + msc = MiniScriptWallet.from_descriptor_obj(name, desc_obj) else: - msc = MultisigWallet.from_file(config, name=name) + if sf_len: + with SFFile(TXN_INPUT_OFFSET, length=sf_len) as fd: + config = fd.read(sf_len).decode() + + try: + j_conf = ujson.loads(config) + if "desc_template" in j_conf and "keys_info" in j_conf: + assert "name" in j_conf + config = j_conf + bip388 = True + else: + assert "desc" in j_conf, "'desc' key required" + config = j_conf["desc"] + assert config, "'desc' empty" + + if "name" in j_conf: + # name from json has preference over filenames and desc checksum + name = j_conf["name"] + assert 2 <= len(name) <= 40, "'name' length" + except ValueError: pass + + # this call will raise on parsing errors, so let them rise up + # and be shown on screen/over usb + msc = MiniScriptWallet.from_file(config, name=name, bip388=bip388) UserAuthorizedAction.active_request = NewMiniscriptEnrollRequest(msc, bsms_index=bsms_index) @@ -1874,7 +1601,7 @@ Binary checksum and signature will be further verified before any changes are ma except BaseException as exc: self.failed = "Exception" - sys.print_exception(exc) + # sys.print_exception(exc) finally: UserAuthorizedAction.cleanup() # because no results to store self.pop_menu() diff --git a/shared/backups.py b/shared/backups.py index 329ceb16..5bc44123 100644 --- a/shared/backups.py +++ b/shared/backups.py @@ -5,10 +5,11 @@ import compat7z, stash, ckcc, chains, gc, sys, bip39, uos, ngu from ubinascii import hexlify as b2a_hex from ubinascii import unhexlify as a2b_hex -from utils import pad_raw_secret -from ux import ux_show_story, ux_confirm, ux_dramatic_pause, OK, X +from utils import deserialize_secret, swab32, xfp2str +from sffile import SFFile +from ux import ux_show_story, ux_confirm, ux_dramatic_pause, OK, X, ux_input_text import version, ujson -from uio import StringIO +from uio import StringIO, BytesIO import seed from glob import settings from pincodes import pa @@ -44,12 +45,7 @@ def render_backup_contents(bypass_tmp=False): COMMENT('Private key details: ' + chain.name) - with stash.SensitiveValues(bypass_tmp=bypass_tmp) as sv: - if sv.deltamode: - # die rather than give up our secrets - import callgate - callgate.fast_wipe() - + with stash.SensitiveValues(bypass_tmp=bypass_tmp, enforce_delta=True) as sv: if sv.mode == 'words': ADD('mnemonic', bip39.b2a_words(sv.raw)) @@ -104,6 +100,9 @@ def render_backup_contents(bypass_tmp=False): if k == 'bkpw': continue # confusing/circular if k == 'sd2fa': continue # do NOT backup SD 2FA (card can be lost or damaged) if k == 'words': continue # words length is recalculated from secret + if k == 'ccc': continue # not supported, security issue + if k == 'ktrx': continue # not useful after the fact + if k == 'lfr': continue # temporary error msg value if k == 'seedvault' and not v: continue if k == 'seeds' and not v: continue ADD('setting.' + k, v) @@ -124,14 +123,14 @@ def render_backup_contents(bypass_tmp=False): return rv.getvalue() -def extract_raw_secret(chain, vals): +def extract_raw_secret(vals): # step1: the private key # - prefer raw_secret over other values # - TODO: fail back to other values assert 'raw_secret' in vals rs = vals.pop('raw_secret') - raw = pad_raw_secret(rs) + raw = deserialize_secret(rs) # check we can decode this right (might be different firmare) opmode, bits, node = stash.SecretStash.decode(raw) @@ -139,22 +138,23 @@ def extract_raw_secret(chain, vals): # verify against xprv value (if we have it) if 'xprv' in vals: - check_xprv = chain.serialize_private(node) + check_xprv = chains.get_chain(vals.get('chain', 'BTC')).serialize_private(node) assert check_xprv == vals['xprv'], 'xprv mismatch' - return raw + return raw, node def extract_long_secret(vals): ls = None if ('long_secret' in vals) and version.has_608: try: ls = a2b_hex(vals.pop('long_secret')) - except Exception as exc: - sys.print_exception(exc) + except: + # sys.print_exception(exc) # but keep going. + pass return ls -def restore_from_dict_ll(vals): +def restore_from_dict_ll(vals, raw): # Restore from a dict of values. Already JSON decoded. # Need a Reboot on success, return string on failure # - low-level version, factored out for better testing @@ -165,12 +165,6 @@ def restore_from_dict_ll(vals): #print("Restoring from: %r" % vals) chain = chains.get_chain(vals.get('chain', 'BTC')) - try: - raw = extract_raw_secret(chain, vals) - except Exception as e: - return ('Unable to decode raw_secret and ' - 'restore the seed value!\n\n\n'+str(e)), None - dis.fullscreen("Saving...") dis.progress_bar_show(.1) @@ -189,9 +183,7 @@ def restore_from_dict_ll(vals): if ls is not None: try: pa.ls_change(ls) - except Exception as exc: - sys.print_exception(exc) - # but keep going + except: pass # but keep going pb = .70 dis.progress_bar_show(pb) @@ -215,13 +207,17 @@ def restore_from_dict_ll(vals): # old backups need this to function properly continue + if k == 'ccc': + # CCC feature cannot be backed-up nor restored for security reasons + # (would allow replay attacks) + continue + if k == 'tp': # restore trick pins, which may involve many ops from trick_pins import tp try: tp.restore_backup(vals[key]) - except Exception as exc: - sys.print_exception(exc) + except: pass # continue as `tp.restore_backup` handles # saving into settings @@ -262,36 +258,50 @@ def restore_from_dict_ll(vals): return None, need_ftux -async def restore_tmp_from_dict_ll(vals): +def text_bk_parser(contents): + # given a (binary encoded) text file, decode into a dict of values + # - use json rules to decode the "value" sides + vals = {} + for line in contents.decode().split('\n'): + if not line: continue + if line[0] == '#': continue + + try: + k,v = line.split(' = ', 1) + #print("%s = %s" % (k, v)) + + vals[k] = ujson.loads(v) + except: + print("unable to decode line: %r" % line) + # but keep going! + + return vals + +async def restore_tmp_from_dict_ll(vals, raw): from glob import dis chain = chains.get_chain(vals.get('chain', 'BTC')) - try: - raw = extract_raw_secret(chain, vals) - except Exception as e: - return ('Unable to decode raw_secret and ' - 'restore the seed value!\n\n\n' + str(e)) dis.fullscreen("Applying...") from seed import set_ephemeral_seed from actions import goto_top_menu - await set_ephemeral_seed(raw, chain, meta="Coldcard Backup") + await set_ephemeral_seed(raw, chain, origin="Coldcard Backup") for k, v in vals.items(): if not k[:8] == "setting.": continue key = k[8:] - if key in ["multisig", "miniscript"]: + if key == "miniscript": # whitelist - settings.set(k, v) + settings.set(key, v) goto_top_menu() -async def restore_from_dict(vals): +async def restore_from_dict(vals, raw): # Restore from a dict of values. Already JSON decoded (ie. dict object). # Need a Reboot on success, return string on failure - prob, need_ftux = restore_from_dict_ll(vals) + prob, need_ftux = restore_from_dict_ll(vals, raw) if prob: return prob if need_ftux: @@ -362,15 +372,17 @@ async def make_complete_backup(fname_pattern='backup.7z', write_sflash=False): ckcc.rng_bytes(b) pwd = bip39.b2a_words(b).rsplit(' ', num_pw_words)[0] - ch = await seed.show_words(prompt="Record this (%d word) backup file password:\n", - words=pwd.split(" "), escape='6') + ch = await seed.show_words( + prompt="Record this (%d word) backup file password:\n" % num_pw_words, + words=pwd.split(" "), escape='6' + ) - if ch == '6' and not write_sflash: + if (ch == '6') and not write_sflash: # Secret feature: plaintext mode # - only safe for people living in faraday cages inside locked vaults. if await ux_confirm("The file will **NOT** be encrypted and " "anyone who finds the file will get all of your money for free!"): - words = [] + pwd = [] fname_pattern = 'backup.txt' break continue @@ -435,8 +447,6 @@ async def write_complete_backup(pwd, fname_pattern, write_sflash=False, if write_sflash: # for use over USB and unit testing: commit file into PSRAM - from sffile import SFFile - with SFFile(0, max_size=MAX_BACKUP_FILE_SIZE, message='Saving...') as fd: if zz: fd.write(hdr) @@ -465,11 +475,9 @@ async def write_complete_backup(pwd, fname_pattern, write_sflash=False, except Exception as e: # includes CardMissingError - import sys - sys.print_exception(e) # catch any error ch = await ux_show_story('Failed to write! Please insert formated MicroSD card, ' - 'and press %s to try again.\n\nX to cancel.\n\n\n' % OK +str(e)) + 'and press %s to try again.\n\n%s to cancel.\n\n\n%s' % (OK, X, e)) if ch == 'x': break continue @@ -535,103 +543,157 @@ async def verify_backup_file(fname): await ux_show_story("Backup file CRC checks out okay.\n\nPlease note this is only a check against accidental truncation and similar. Targeted modifications can still pass this test.") -async def restore_complete(fname_or_fd, temporary=False): +async def restore_complete(fname_or_fd, temporary=False, words=True, usb=False): from ux import the_ux async def done(words): # remove all pw-picking from menu stack - seed.WordNestMenu.pop_all() + if not version.has_qwerty and words: + seed.WordNestMenu.pop_all() prob = await restore_complete_doit(fname_or_fd, words, temporary=temporary) - if prob: await ux_show_story(prob, title='FAILED') - if version.has_qwerty: - from ux_q1 import seed_word_entry - return await seed_word_entry('Enter Password:', num_pw_words, - done_cb=done, has_checksum=False) - # give them a menu to pick from, and start picking - m = seed.WordNestMenu(num_words=num_pw_words, has_checksum=False, done_cb=done) + if words: + if version.has_qwerty: + from ux_q1 import seed_word_entry, CHARS_W - the_ux.push(m) + basename = None + if isinstance(fname_or_fd, str): + basename = fname_or_fd.split('/')[-1] + if len(basename) > CHARS_W: + basename = basename[:16] + "⋯" + basename[-16:] -async def restore_complete_doit(fname_or_fd, words, file_cleanup=None, temporary=False): + return await seed_word_entry("Enter Password%s:" % (" for" if basename else ""), + num_pw_words, done_cb=done, has_checksum=False, + line2=basename) + + # give them a menu to pick from, and start picking + if usb: + # we're not originating from a menu + words = await seed.WordNestMenu.get_n_words(12) + await done(words) + else: + m = seed.WordNestMenu(num_words=num_pw_words, has_checksum=False, done_cb=done) + the_ux.push(m) + + else: + pwd = [] # cleartext if words=None + if words is False: + ipw = await ux_input_text("", prompt="Your Backup Password", + min_len=bkpw_min_len, max_len=128) + if not ipw: return + pwd.append(ipw) + + await done(pwd) + + +def check_and_decrypt(fd, password): + try: + compat7z.check_file_headers(fd) + except Exception as e: + raise RuntimeError('Unable to read backup file.' + ' Has it been touched?\n\nError: '+str(e)) + + from glob import dis + dis.fullscreen("Decrypting...") + try: + zz = compat7z.Builder() + fname, contents = zz.read_file(fd, password, MAX_BACKUP_FILE_SIZE, + progress_fcn=dis.progress_bar_show) + + # simple quick sanity checks + assert fname.endswith('.txt') # was == 'ckcc-backup.txt' + assert contents[0:1] == b'#' and contents[-1:] == b'\n' + return contents + + except Exception as e: + # assume everything here is "password wrong" errors + raise RuntimeError('Unable to decrypt backup file. Incorrect password?' + '\n\nTried:\n\n' + password) + + +async def restore_complete_doit(fname_or_fd, words, file_cleanup=None, temporary=False, + ux_confirm=True): # Open file, read it, maybe decrypt it; return string if any error # - some errors will be shown, None return in that case # - no return if successful (due to reboot) - from glob import dis from files import CardSlot, CardMissingError, needs_microsd # build password password = ' '.join(words) - prob = None - try: - with CardSlot(readonly=True) as card: - # filename already picked, taste it and maybe consider using its data. - try: - fd = open(fname_or_fd, 'rb') if isinstance(fname_or_fd, str) else fname_or_fd - except: - return 'Unable to open backup file.\n\n' + str(fname_or_fd) + if isinstance(fname_or_fd, int): + # USB restore - backup is already in PSRAM, fname of fd is length + # TXN_INPUT_OFFSET = 0 + with SFFile(0, length=fname_or_fd) as fd: + if not words: + contents = fd.read(fname_or_fd) + else: + # read full size, then decrypt + fd = BytesIO(fd.read(fname_or_fd)) + try: + contents = check_and_decrypt(fd, password) + except RuntimeError as e: + return str(e) + else: + try: + with CardSlot(readonly=True) as card: + # filename already picked, taste it and maybe consider using its data. + try: + fd = open(fname_or_fd, 'rb') + except: + return 'Unable to open backup file.\n\n' + str(fname_or_fd) - try: - if not words: - contents = fd.read() - else: - try: - compat7z.check_file_headers(fd) - except Exception as e: - return 'Unable to read backup file. Has it been touched?\n\nError: ' \ - + str(e) + try: + if words: + contents = check_and_decrypt(fd, password) + else: + contents = fd.read() - dis.fullscreen("Decrypting...") - try: - zz = compat7z.Builder() - fname, contents = zz.read_file(fd, password, MAX_BACKUP_FILE_SIZE, - progress_fcn=dis.progress_bar_show) - - # simple quick sanity checks - assert fname.endswith('.txt') # was == 'ckcc-backup.txt' - assert contents[0:1] == b'#' and contents[-1:] == b'\n' - - except Exception as e: - # assume everything here is "password wrong" errors - #print("pw wrong? %s" % e) - - return ('Unable to decrypt backup file. Incorrect password?' - '\n\nTried:\n\n' + password) - finally: - fd.close() + except RuntimeError as e: + return str(e) + finally: + fd.close() if file_cleanup: file_cleanup(fname_or_fd) - except CardMissingError: - await needs_microsd() - return + except CardMissingError: + await needs_microsd() + return - vals = {} - for line in contents.decode().split('\n'): - if not line: continue - if line[0] == '#': continue + try: + vals = text_bk_parser(contents) + except: + return "Invalid backup file." - try: - k,v = line.split(' = ', 1) - #print("%s = %s" % (k, v)) + try: + raw, node = extract_raw_secret(vals) + except Exception as e: + return ('Unable to decode raw_secret and ' + 'restore the seed value!\n\n\n'+str(e)) - vals[k] = ujson.loads(v) - except: - print("unable to decode line: %r" % line) - # but keep going! + if ux_confirm: + # check master fingerprint from raw secret that is actually being loaded + # master extended public keys can be wrong & is unverified + xfp_str = xfp2str(swab32(node.my_fp())) + ch = await ux_show_story("Above is the master fingerprint of the seed stored in the backup." + " Press %s to continue, and load backup as %s seed. Press %s" + " to abort." % (OK, "temporary" if temporary else "master", X), + title="["+xfp_str+"]") + if ch != "y": + await ux_dramatic_pause('Aborted.', 2) + return # this leads to reboot if it works, else errors shown, etc. if temporary: - return await restore_tmp_from_dict_ll(vals) + return await restore_tmp_from_dict_ll(vals, raw) else: - return await restore_from_dict(vals) + return await restore_from_dict(vals, raw) async def clone_start(*a): # Begins cloning process, on target device. @@ -714,8 +776,9 @@ back and press %s to complete clone process.''' % OK) uos.remove(fname) # ccbk-start.json # this will reset in successful case, no return (but delme is called) - prob = await restore_complete_doit(incoming, words, file_cleanup=delme) - + # no need to ask for UX confirmation during clone - as user can see what is loaded on source CC + prob = await restore_complete_doit(incoming, words, file_cleanup=delme, + ux_confirm=False) if prob: await ux_show_story(prob, title='FAILED') diff --git a/shared/bbqr.py b/shared/bbqr.py index 61a90fb9..c684e0b8 100644 --- a/shared/bbqr.py +++ b/shared/bbqr.py @@ -6,12 +6,14 @@ import utime, uzlib, ngu from utils import problem_file_line from exceptions import QRDecodeExplained from ubinascii import unhexlify as a2b_hex +from version import MAX_TXN_LEN b32encode = ngu.codecs.b32_encode b32decode = ngu.codecs.b32_decode TYPE_LABELS = dict(P='PSBT File', T='Transaction', J='JSON', C='CBOR', U='Unicode Text', - X='Executable', B='Binary') + X='Executable', B='Binary', + R='KT Rx', S='KT Tx', E='KT PSBT') def int2base36(n): # convert an integer to two digits of base 36 string. 00 thu ZZ as bytes @@ -212,7 +214,7 @@ class BBQrState: # can happen if QR got corrupted between scanner and us (overlap) # or back BBQr implementation #print("corrupt QR: %s" % scan) - import sys; sys.print_exception(exc) + # import sys; sys.print_exception(exc) dis.draw_bbqr_progress(hdr, self.parts, corrupt=True) return True @@ -241,7 +243,7 @@ class BBQrState: # provide UX -- even if we didn't use it dis.draw_bbqr_progress(hdr, self.parts) - # do we need more still? + # return T if we need more parts still return (len(self.parts) < hdr.num_parts) or self.runt class BBQrStorage: @@ -328,14 +330,12 @@ class BBQrPsramStorage(BBQrStorage): def alloc_buf(self, upper_bound): # using first part of PSRAM - from public_constants import MAX_TXN_LEN_MK4 - - if upper_bound >= MAX_TXN_LEN_MK4: + if upper_bound >= MAX_TXN_LEN: raise QRDecodeExplained("Too big") # If data is compressed, write tmp (compressed) copy into top half of PSRAM # and we'll put final, decompressed copy at zero offset (later) - self.psr_offset = MAX_TXN_LEN_MK4 if self.hdr.encoding == 'Z' else 0 + self.psr_offset = MAX_TXN_LEN if self.hdr.encoding == 'Z' else 0 self.buf = True @@ -394,7 +394,6 @@ class BBQrPsramStorage(BBQrStorage): from glob import PSRAM, dis from uzlib import DecompIO from io import BytesIO - from public_constants import MAX_TXN_LEN_MK4 dis.fullscreen('Decompressing...') @@ -414,7 +413,7 @@ class BBQrPsramStorage(BBQrStorage): buf += here ln = len(buf) & ~3 - if off+ln > MAX_TXN_LEN_MK4: + if off+ln > MAX_TXN_LEN: # test with: `yes | dd bs=1000 count=2700 | bbqr make - | pbcopy` raise QRDecodeExplained("Too big") diff --git a/shared/bsms.py b/shared/bsms.py index 298520ef..2e788fc4 100644 --- a/shared/bsms.py +++ b/shared/bsms.py @@ -15,7 +15,7 @@ from public_constants import AF_P2WSH, AF_P2WSH_P2SH, AF_CLASSIC, MAX_SIGNERS from utils import xfp2str, problem_file_line from menu import MenuSystem, MenuItem from files import CardSlot, CardMissingError, needs_microsd -from ux import ux_show_story, ux_enter_number, restore_menu, ux_input_numbers, ux_input_text +from ux import ux_show_story, ux_enter_number, restore_menu, ux_input_text from ux import the_ux, _import_prompt_builder, export_prompt_builder from descriptor import Descriptor, Key, append_checksum from miniscript import Sortedmulti, Number @@ -499,7 +499,6 @@ async def bsms_coordinator_round2(menu, label, item): import version as version_mod from glob import NFC, dis from actions import file_picker - from multisig import make_redeem_script bsms_settings_index = item.arg chain = chains.current_chain() @@ -699,24 +698,23 @@ async def bsms_coordinator_round2(menu, label, item): dis.progress_bar_show(i_div_N / 1) dis.fullscreen("Generating...") - miniscript = Sortedmulti(Number(M), *keys) - desc_obj = Descriptor(miniscript=miniscript) - desc_obj.set_from_addr_fmt(addr_fmt) - desc = desc_obj.to_string(checksum=False) - desc = desc.replace("<0;1>/*", "**") - if not is_encrypted: - # append checksum for unencrypted BSMS - desc = append_checksum(desc) - for i, ko in enumerate(keys): - ko.node.derive(0, False) # external is always first our coordinating "0/*,1/*" - dis.progress_bar_show(i / N) + try: + dis.busy_bar(True) + miniscript = Sortedmulti(Number(M), *keys) + desc_obj = Descriptor(miniscript=miniscript, addr_fmt=addr_fmt) + desc = desc_obj.to_string(checksum=False) + desc = desc.replace("<0;1>/*", "**") + if not is_encrypted: + # append checksum for unencrypted BSMS + desc = append_checksum(desc) + # external address at index 0 -> 0/0 + derived_desc = desc_obj.derive(0).derive(0) + addr = chain.render_address(derived_desc.script_pubkey()) + # == + r2_data = coordinator_data_round2(desc, addr) - # TODO this can be done with .script_pubkey - script = make_redeem_script(M, [k.node for k in keys], 0) # first address - addr = chain.p2sh_address(addr_fmt, script) - # == - r2_data = coordinator_data_round2(desc, addr) - dis.progress_bar_show(1) + finally: + dis.busy_bar(False) force_vdisk = False title = "BSMS descriptor template file(s)" @@ -820,7 +818,8 @@ async def bsms_signer_round1(*a): if version.has_qwerty: token_int = await ux_input_text("", scan_ok=True, prompt="Decimal Token") else: - token_int = await ux_input_numbers("", lambda: True) + from ux_mk4 import ux_input_digits + token_int = await ux_input_digits("", prompt="Decimal Token") token_hex = hex(int(token_int)) else: return @@ -965,12 +964,8 @@ async def bsms_signer_round2(menu, label, item): from glob import NFC, dis, settings from actions import file_picker from auth import maybe_enroll_xpub - from multisig import make_redeem_script chain = chains.current_chain() - - # or xpub or tpub as we use descriptors (no SLIP132 allowed) - ext_key_prefix = "%spub" % chain.slip132[AF_CLASSIC].hint force_vdisk = False # choose correct values based on label (index in signer bsms settings) @@ -1018,75 +1013,50 @@ async def bsms_signer_round2(menu, label, item): assert desc_template_data, decrypt_fail_msg dis.fullscreen("Validating...") - assert desc_template_data.startswith(BSMS_VERSION), \ - "Incompatible BSMS version. Need %s got %s" % (BSMS_VERSION, desc_template_data[:9]) - - dis.progress_bar_show(0.05) - version, desc_template, pth_restrictions, addr = desc_template_data.split("\n") - assert pth_restrictions == ALLOWED_PATH_RESTRICTIONS, \ - "Only '%s' allowed as path restrictions. Got %s" % ( - ALLOWED_PATH_RESTRICTIONS, pth_restrictions) - - # if checksum is provided we better verify it - # remove checksum as we need to replace /** - desc_template, csum = Descriptor.checksum_check(desc_template) - desc = desc_template.replace("/**", "/0/*") - - dis.progress_bar_show(0.1) - desc = append_checksum(desc) - - ms_name = "bsms_" + desc[-4:] - - desc_obj = Descriptor.from_string(desc) - assert desc_obj.is_sortedmulti, "sortedmulti required" - - dis.progress_bar_show(0.2) - - my_xfp = settings.get('xfp') - my_keys = [] - nodes = [] - progress_counter = 0.2 # last displayed progress - # (desired value after loop - last displayed progress) / N - progress_chunk = (0.5 - progress_counter) / len(desc_obj.miniscript.keys) - for key in desc_obj.keys: - if key.origin.cc_fp == my_xfp: - my_keys.append(key) - nodes.append(key.node) - progress_counter += progress_chunk - dis.progress_bar_show(progress_counter) - - num_my_keys = len(my_keys) - assert num_my_keys <= 1, "Multiple %s keys in descriptor (%d)" % (xfp2str(my_xfp), num_my_keys) - assert num_my_keys == 1, "My key %s missing in descriptor." % xfp2str(my_xfp) - - with stash.SensitiveValues() as sv: - node = sv.derive_path(my_keys[0].origin.str_derivation()) - ext_key = chain.serialize_public(node) - assert ext_key == my_keys[0].extended_public_key(), "My key %s missing in descriptor." % ext_key - - dis.progress_bar_show(0.55) - - # check address is correct - progress_counter = 0.55 # last displayed progress - # (desired value after loop - last displayed progress) / N - M, N = desc_obj.miniscript.m_n() - progress_chunk = (0.9 - progress_counter) / N - for node in nodes: - node.derive(0, False) # external is always first in our allowed path restrictions - progress_counter += progress_chunk - dis.progress_bar_show(progress_counter) - - script = make_redeem_script(M, nodes, 0) # first address - dis.progress_bar_show(0.95) - calc_addr = chain.p2sh_address(desc_obj.addr_fmt, script) - - assert calc_addr == addr, "Address mismatch! Calculated %s, got %s" % (calc_addr, addr) - - dis.progress_bar_show(1) try: - maybe_enroll_xpub(config=desc, name=ms_name, bsms_index=bsms_settings_index) - # bsms_settings_signer_delete(bsms_settings_index) --> moved to auth.py to only be done if actually approved - except Exception as e: - await ux_show_story('Failed to import.\n\n%s\n%s' % (e, problem_file_line(e))) + dis.busy_bar(True) + assert desc_template_data.startswith(BSMS_VERSION), \ + "Incompatible BSMS version. Need %s got %s" % (BSMS_VERSION, desc_template_data[:9]) + + version, desc_template, pth_restrictions, addr = desc_template_data.split("\n") + assert pth_restrictions == ALLOWED_PATH_RESTRICTIONS, \ + "Only '%s' allowed as path restrictions. Got %s" % ( + ALLOWED_PATH_RESTRICTIONS, pth_restrictions) + + # if checksum is provided we better verify it before descriptor modification /** + # remove checksum as we need to replace /** + desc_template, csum = Descriptor.checksum_check(desc_template) + desc = desc_template.replace("/**", "/<0;1>/*") + + desc_obj = Descriptor.from_string(desc) + desc_obj.validate() + assert desc_obj.is_sortedmulti, "sortedmulti required" + + my_xfp = settings.get('xfp') + my_keys = 0 + + for key in desc_obj.keys: + if key.origin.cc_fp == my_xfp: + my_keys += 1 + + assert my_keys <= 1, "Multiple %s keys in descriptor (%d)" % (xfp2str(my_xfp), my_keys) + + # check address is correct + calc_addr = chain.render_address(desc_obj.derive(0).derive(0).script_pubkey()) + assert calc_addr == addr, "Address mismatch! Calculated %s, got %s" % (calc_addr, addr) + + # name consists last 4 characters of the address at /0/0 + ms_name = "bsms_" + addr[-4:] + + try: + # at this point we have properly validated descriptor + maybe_enroll_xpub(desc_obj=desc_obj, name=ms_name, bsms_index=bsms_settings_index) + # bsms_settings_signer_delete(bsms_settings_index) + # moved to auth.py to only be done if actually approved + except Exception as e: + await ux_show_story('Failed to import.\n\n%s\n%s' % (e, problem_file_line(e))) + + finally: + dis.busy_bar(False) # EOF \ No newline at end of file diff --git a/shared/calc.py b/shared/calc.py index f746e4a8..3649634e 100644 --- a/shared/calc.py +++ b/shared/calc.py @@ -1,6 +1,6 @@ # (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. # -# calc.py - Simple python REPL before login +# calc.py - Simple TOY calculator, before login. Not meant to be useful, just fun! # # Test with: ./simulator.py --q1 --eff -g --set calc=1 # @@ -9,7 +9,7 @@ from utils import B2A, word_wrap from ux_q1 import ux_input_text async def login_repl(): - from glob import dis, settings + from glob import dis from pincodes import pa NUM_LINES = 7 # 10 - title - 2 for prompt @@ -19,22 +19,25 @@ async def login_repl(): re_pin = re.compile(r'^(\d\d+)[-_ ](\d\d+)$') # in decreasing order of hazard... - blacklist = ['import', '__', 'exec', 'locals', 'globals', 'eval', 'input'] + # - find these with: import builtins; help(builtins) + blacklist = ['import', '__', 'exec', 'locals', 'globals', 'eval', 'input', + 'getattr', 'setattr', 'delattr', 'open', 'execfile', 'compile' ] lines = '''\ Example Commands: >> 23 + 55 / 22 ->> a = 4; b = 3; ->> a*b ->> sha256('123456123456') ->> cls() # clear screen\ +>> 1.020 * 45.88 +>> sha256('some message') +>> cls # clear screen +>> help\ '''.split('\n') state = dict() state['sha256'] = lambda x: B2A(ngu.hash.sha256s(x)) state['sha512'] = lambda x: B2A(ngu.hash.sha512(x).digest()) state['ripemd'] = lambda x: B2A(ngu.hash.ripemd160(x)) + state['rand'] = lambda x=32: B2A(ngu.random.bytes(x)) state['cls'] = lambda: lines.clear() state['help'] = lambda: 'Commands: ' + (', '.join(state)) @@ -56,17 +59,17 @@ Example Commands: try: dis.busy_bar(1) - if ln == None : + if ln is None : # Cancel key - do nothing ans = None - elif ln in state and callable(state[ln]): - # no needs for () in my world + elif ln in ('help', 'cls', 'rand'): + # no need for () for these commands ans = state[ln]() - elif re_pin.match(ln) and len(ln) <= 13: + elif pa.attempts_left and re_pin.match(ln) and (len(ln) <= 13): # try login m = re_pin.match(ln) ln = m.group(1)+ '-' + m.group(2) - print(ln) + try: pa.setup(ln) ok = pa.login() @@ -80,16 +83,14 @@ Example Commands: else: ans = 'Error: ' + repr(exc.args) - elif re_prefix.match(ln) and len(ln) <= 7: + elif re_prefix.match(ln) and (len(ln) <= 7): # show words ans = pa.prefix_words(ln[:-1].encode()) else: if any((b in ln) for b in blacklist): ans = None - elif '=' in ln: - ans = exec(ln, state) else: - ans = eval(ln, state) + ans = eval(ln, state.copy()) except Exception as exc: lines.extend(word_wrap(str(exc), 34)) diff --git a/shared/ccc.py b/shared/ccc.py new file mode 100644 index 00000000..644edaff --- /dev/null +++ b/shared/ccc.py @@ -0,0 +1,1285 @@ +# (c) Copyright 2024 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# +# ccc.py - ColdCard Co-sign feature. Be a leg in a 2-of-3 that is signed based on a policy. +# +# Rebranding/single-signer additions: +# +# - "CCC" (was "ColdCard Cosigning") will now be branded as "Spending Policy: Multisig" +# - single singer policies will be called "Spending Policy: Single Sig" +# - internally: CCC is the multisig stuff, vs SSSP: Single Signer Spending Policy +# - "hobbled" refers to less-than full control over Coldcard, even though you have main PIN +# +import gc, chains, version, ngu, web2fa, bip39, re +from chains import NLOCK_IS_TIME +from utils import swab32, xfp2str, truncate_address, deserialize_secret, show_single_address +from glob import settings, dis +from ux import ux_confirm, ux_show_story, the_ux, OK, ux_dramatic_pause, ux_enter_number, ux_aborted +from menu import MenuSystem, MenuItem, start_chooser +from seed import seed_words_to_encoded_secret +from stash import SecretStash +from charcodes import KEY_QR, KEY_CANCEL, KEY_NFC +from exceptions import SpendPolicyViolation + + +# limit to number of addresses in list +MAX_WHITELIST = const(25) + +class LastFailReason: + # We don't show the user the reason for policy fail (by design, so attacker + # cannot maximize their take against the policy), but during setup/experiments + # we offer to show the reason in the menu. Includes both SS and MS cases. + # - now holding this in a setting so they can power-cycle and bypass to view + + @classmethod + def record(cls, msg): + settings.put('lfr', msg) + + @classmethod + def get(cls): + return settings.get('lfr', None) + + @classmethod + def clear(cls): + settings.remove_key('lfr') + +class SpendingPolicy(dict): + # Details of what is allowed or not. Same for single vs. multisig signing. + # - a dict() but with write-thru to setting value + + def __init__(self, nvkey, pol_dict=None): + # deserialize and construct + #assert nvkey in { 'ccc', 'sssp' } + self.nvkey = nvkey + super().__init__() + + if pol_dict is not None: + self.clear() + self.update(pol_dict.items()) + else: + v = dict(settings.master_get(self.nvkey, {})).get('pol', None) + if v is not None: + self.update(v.items()) # mpy bugfix, when called with SpendingPolicy + + + def _save_policy(self): + # serialize the spending policy, save it + v = dict(settings.master_get(self.nvkey, {})) + v['pol'] = self.copy() + settings.master_set(self.nvkey, v, master_only=True) + + def update_policy_key(self, _quiet=False, **kws): + # Update a few elements of the spending policy + # - all changes are saved immediately (which is a little slow/visible) + if not _quiet: + dis.fullscreen("Saving...") + self.update(kws) + self._save_policy() + + def meets_policy(self, psbt): + # Does policy allow signing this? Else raise why. Return T if web2fa required. + pol = self + + # not safe to sign any txn w/ warnings: might be complaining about + # massive miner fees, or weird OP_RETURN stuff + if psbt.warnings: + raise SpendPolicyViolation("has warnings") + + # Magnitude: size limits for output side (non change) + magnitude = pol.get("mag", None) + if magnitude is not None: + if magnitude < 1000: + # it is a BTC, convert to sats + magnitude = magnitude * 100000000 + + outgoing = psbt.total_value_out - psbt.total_change_value + if outgoing > magnitude: + raise SpendPolicyViolation("magnitude") + + # Velocity: if zero => no velocity checks + velocity = pol.get("vel", None) + if velocity: + if not psbt.lock_time: + raise SpendPolicyViolation("no nLockTime") + + if psbt.lock_time >= NLOCK_IS_TIME: + # this is unix timestamp - not allowed - fail + raise SpendPolicyViolation("nLockTime not height") + + block_h = pol.get("block_h", chains.current_chain().ccc_min_block) + if psbt.lock_time <= block_h: + raise SpendPolicyViolation("rewound (%d)" % psbt.lock_time) + + # we won't sign txn unless old height + velocity >= new height + if psbt.lock_time < (block_h + velocity): + raise SpendPolicyViolation("velocity (%d)" % psbt.lock_time) + + # Whitelist of outputs addresses + wl = pol.get("addrs", None) + if wl: + c = chains.current_chain() + wl = set(wl) + for idx, txo in psbt.output_iter(): + out = psbt.outputs[idx] + if not out.is_change: # ignore change + addr = c.render_address(txo.scriptPubKey) + if addr not in wl: + raise SpendPolicyViolation("whitelist: " + addr) + + # Web 2FA + # - slow, requires UX, and they might not achieve it... + # - wait until about to do signature + if pol.get('web2fa', False): + psbt.warnings.append((pol.nvkey.upper(), 'Web 2FA required.')) + return True + + async def web2fa_challenge(self, msg): + # they are trying to sign something, so make them get out their phone + # - at this point they have already ok'ed the details of the txn + # - and we have approved other elements of the spending policy. + # - could show MS wallet name, or txn details but will not because that is + # an info leak to Coinkite... and we just don't want to know. + assert self.get('web2fa') + + ok = await web2fa.perform_web2fa(msg, self.get('web2fa')) + if not ok: + LastFailReason.record('2FA Fail') + raise SpendPolicyViolation + + def update_last_signed(self, psbt): + # Call after successfully signing a PSBT ... notes the height involved. + # - might add other things besides height here someday + LastFailReason.clear() + + old_h = self.get('block_h', 1) + + if old_h < psbt.lock_time < NLOCK_IS_TIME: + # always update last block height, even if velocity isn't enabled yet + # - attacker might have changed to testnet, but there is no + # reason to ever lower block height. strictly ascending + self.update_policy_key(_quiet=True, block_h=psbt.lock_time) + +class SSSPFeature: + # Using setting value "sssp" + + @classmethod + def is_enabled(cls): + # can be test drive, or is feature enabled? + from pincodes import pa + return (pa.hobbled_mode == 2) or sssp_spending_policy('en') + + @classmethod + def update_last_signed(cls, psbt): + # new PSBT has been completely signed successfully. + if not cls.is_enabled(): + return + pol = cls.get_policy() + pol.update_last_signed(psbt) + + @classmethod + def default_policy(cls): + # a very basic and permissive policy, but non-zero too. + # - 1BTC per day + chain = chains.current_chain() + return SpendingPolicy('sssp', dict(mag=1, vel=144, + block_h=chain.ccc_min_block, web2fa='', addrs=[])) + + @classmethod + def get_policy(cls): + # de-serialize just the spending policy + return SpendingPolicy('sssp') + + @classmethod + def can_allow(cls, psbt): + # We are looking at a PSBT: should we let user sign it, or block? + # - return (block_signing, needs_2fa_step) + if not cls.is_enabled(): + exists = bool(settings.master_get('sssp', False)) + if exists: + # this will not block CCC co-signing, because that test is already + # done before this call. + psbt.warnings.append(('SP', "Spending Policy defined but disabled.")) + return False, False + + try: + # check policy + pol = cls.get_policy() + needs_2fa = pol.meets_policy(psbt) + except SpendPolicyViolation as e: + LastFailReason.record(str(e)) + # caller will show msg + return True, False + + return False, needs_2fa + + @classmethod + async def web2fa_challenge(cls): + # they are trying to sign something, so make them get out their phone + # - at this point they have already ok'ed the details of the txn + # - and we have approved other elements of the spending policy. + # - could show MS wallet name, or txn details but will not because that is + # an info leak to Coinkite... and we just don't want to know. + await cls.get_policy().web2fa_challenge('Approve Transaction') + + +class CCCFeature: + # Using setting value "ccc" + + @classmethod + def is_enabled(cls): + # Is the feature enabled right now? + return bool(settings.get('ccc', False)) + + @classmethod + def words_check(cls, words): + # Test if words provided are right + enc = seed_words_to_encoded_secret(words) + exp = cls.get_encoded_secret() + return enc == exp + + @classmethod + def get_num_words(cls): + # return 12 or 24 + return SecretStash.is_words(cls.get_encoded_secret()) + + @classmethod + def get_encoded_secret(cls): + # Gets the key C as encoded binary secret, compatible w/ + # encodings used in stash. + return deserialize_secret(settings.get('ccc')['secret']) + + @classmethod + def get_xfp(cls): + # Just the XFP value for our key C + ccc = settings.get('ccc') + return ccc['c_xfp'] if ccc else None + + @classmethod + def get_master_xpub(cls): + ccc = settings.get('ccc') + return ccc['c_xpub'] if ccc else None + + @classmethod + def init_setup(cls, words): + # Encode 12 or 24 words into the secret to held as key C. + # - also capture XFP and XPUB for key C + # TODO: move to "storage locker"? + assert len(words) in (12, 24) + enc = seed_words_to_encoded_secret(words) + _,_,node = SecretStash.decode(enc) + + chain = chains.current_chain() + xfp = swab32(node.my_fp()) + xpub = chain.serialize_public(node) # fully useless value tho + + # NOTE: b_xfp and b_xpub still needed, but that's another step, not yet. + + v = dict(secret=SecretStash.storage_serialize(enc), + c_xfp=xfp, c_xpub=xpub, + pol=CCCFeature.default_policy()) + + settings.put('ccc', v) + settings.save() + + @classmethod + def default_policy(cls): + # a very basic and permissive policy, but non-zero too. + # - 1BTC per day + chain = chains.current_chain() + return SpendingPolicy('ccc', dict(mag=1, vel=144, + block_h=chain.ccc_min_block, web2fa='', addrs=[])) + + @classmethod + def get_policy(cls): + # de-serialize just the spending policy + return SpendingPolicy('ccc') + + @classmethod + def remove_ccc(cls): + # delete our settings complete; lose key C .. already confirmed + # - leave MS in place + settings.remove_key('ccc') + settings.save() + + @classmethod + def could_cosign(cls, psbt): + # We are looking at a PSBT: can we sign it, and would we? + # - if we **could** but will not, due to policy, add warning msg + # - return (we could sign, needs 2fa step) + if not cls.is_enabled(): + return False, False + + ms = psbt.active_miniscript + if not ms: + # not multisig, so ignore/permit + return False, False + + # TODO: if key B has already signed the PSBT, and so we don't need key C, + # don't try to sign; maybe show warning? + + xfp = cls.get_xfp() + if xfp not in [i[0] for i in ms.to_descriptor().xfp_paths()]: + # does not involve us + return False, False + + try: + # check policy + pol = cls.get_policy() + needs_2fa = pol.meets_policy(psbt) + except SpendPolicyViolation as e: + LastFailReason.record(str(e)) + psbt.warnings.append(('CCC', "Violates spending policy. Won't sign.")) + return False, False + + return True, needs_2fa + + @classmethod + def sign_psbt(cls, psbt): + # do the math + psbt.sign_it(cls.get_encoded_secret(), cls.get_xfp()) + LastFailReason.clear() + + pol = cls.get_policy() + pol.update_last_signed(psbt) + + @classmethod + async def web2fa_challenge(cls): + # do UX for web2fa; user is given option to proceed even if it fails + # (without the co-signing) + await cls.get_policy().web2fa_challenge('Approve Transaction: Co-Sign') + + +def render_mag_value(mag): + # handle integer bitcoins, and satoshis in same value + if mag < 1000: + return '%d BTC' % mag + else: + return '%d SATS' % mag + + +class CCCConfigMenu(MenuSystem): + def __init__(self): + items = self.construct() + super().__init__(items) + + def update_contents(self): + tmp = self.construct() + self.replace_items(tmp) + + def construct(self): + from wallet import MiniScriptWallet, make_miniscript_wallet_menu + + my_xfp = CCCFeature.get_xfp() + items = [ + MenuItem(('[%s] Co-Signing' if version.has_qwerty else '[%s]') + % xfp2str(my_xfp), f=self.show_ident), + MenuItem('Spending Policy', + menu=lambda *a: SpendingPolicyMenu.be_a_submenu(CCCFeature.get_policy())), + MenuItem('Export CCC XPUBs', f=self.export_xpub_c), + MenuItem('Multisig Wallets'), + ] + + # look for wallets that are defined related to CCC feature, shortcut to them + count = 0 + for i, ms in enumerate(MiniScriptWallet.iter_wallets()): + if not ms.m_n: # basic multisig check + continue + if my_xfp in [i[0] for i in ms.xfp_paths()]: + M, N = ms.m_n + items.append(MenuItem('↳ %d/%d: %s' % (M, N, ms.name), + menu=make_miniscript_wallet_menu, arg=(i,ms))) + count += 1 + + items.append(MenuItem('↳ Build 2-of-N', f=self.build_2ofN, arg=count)) + + if LastFailReason.get(): + # xxxxxxxxxxxxxxxx + items.insert(1, MenuItem('Last Violation', f=self.debug_last_fail)) + + items.append(MenuItem('Load Key C', f=self.enter_temp_mode)) + items.append(MenuItem('Remove CCC', f=self.remove_ccc)) + + return items + + async def debug_last_fail(self, *a): + # debug for customers: why did we reject that last txn? + pol = CCCFeature.get_policy() + bh = pol.get('block_h', None) + msg = '' + if bh: + msg += "CCC height:\n\n%s\n\n" % bh + + lfr = LastFailReason.get() + msg += 'The most recent policy check failed because of:\n\n%s\n\nPress (4) to clear.' \ + % lfr + ch = await ux_show_story(msg, escape='4') + + if ch == '4': + LastFailReason.clear() + self.update_contents() + + async def remove_ccc(self, *a): + # disable and remove feature + if not await ux_confirm('Key C will be lost, and policy settings forgotten.' + ' This unit will only be able to partly sign transactions.' + ' To completely remove this wallet, proceed to the multisig' + ' menu and remove related wallet entries.'): + return + + if not await ux_confirm("Funds in related wallet/s may be impacted.", confirm_key='4'): + return await ux_aborted() + + CCCFeature.remove_ccc() + the_ux.pop() + + async def on_cancel(self): + # trying to exit from CCCConfigMenu + from seed import in_seed_vault + + enc = CCCFeature.get_encoded_secret() + + if in_seed_vault(enc): + # remind them to clear the seed-vault copy of Key C because it defeats feature + await ux_show_story("Key C is in your Seed Vault. If you are done with setup, " + "you MUST delete it from the Vault!", title='REMINDER') + + the_ux.pop() + + async def export_xpub_c(self, *a): + # do standard Coldcard export for multisig setups + xfp = CCCFeature.get_xfp() + enc = CCCFeature.get_encoded_secret() + + from wallet import export_miniscript_xpubs + await export_miniscript_xpubs(xfp=xfp, alt_secret=enc, skip_prompt=True) + + async def build_2ofN(self, m, l, i): + count = i.arg + # ask for a key B, assume A and C are defined => export MS config and import into self. + # - like the airgap setup, but assume A and C are this Coldcard + m = '''Builds simple 2-of-N multisig wallet, with this Coldcard's main secret (key A), \ +the CCC policy-controlled key C, and at least one other device, as key B. \ +\nYou will need to export the XPUB from another Coldcard and place it on an SD Card, or \ +be ready to show it as a QR, before proceeding.''' + if await ux_show_story(m) != 'y': + return + + from multisig import create_ms_step1 + + # picks addr fmt, QR or not, gets at least one file, then... + await create_ms_step1(for_ccc=(CCCFeature.get_encoded_secret(), count)) + + # prompt for file, prompt for our acct number, unless already exported to this card? + + async def show_ident(self, *a): + # give some background? or just KISS for now? + xfp = xfp2str(CCCFeature.get_xfp()) + xpub = CCCFeature.get_master_xpub() + await ux_show_story( + "Key C:\n\n" + "XFP (Master Fingerprint):\n\n %s\n\n" + "Master Extended Public Key:\n\n %s " % (xfp, xpub)) + + async def enter_temp_mode(self, *a): + # apply key C as temp seed, so you can do anything with it + # - just a shortcut, since they have the words, and could enter them + # - one-way trip because the CCC feature won't be enabled inside the temp seed settings + if await ux_show_story( + 'Loads the CCC controlled seed (key C) as a Temporary Seed and allows ' + 'easy use of all Coldcard features on that key.\n\nIf you save into Seed Vault, ' + 'access to CCC Config menu is quick and easy.') != 'y': + return + + from seed import set_ephemeral_seed + from actions import goto_top_menu + + enc = CCCFeature.get_encoded_secret() + await set_ephemeral_seed(enc, origin='Key C from CCC') + + goto_top_menu() + + +class SPAddrWhitelist(MenuSystem): + # simulator arg: --seq tcENTERENTERsENTERwENTER + def __init__(self, pol): + self.policy = pol + items = self.construct() + super().__init__(items) + + def update_contents(self): + tmp = self.construct() + self.replace_items(tmp) + + @classmethod + async def be_a_submenu(cls, pol, *a): + return cls(pol) + + def construct(self): + # list of addresses + addrs = self.policy.get('addrs', []) + maxxed = (len(addrs) >= MAX_WHITELIST) + + items = [] + # better to show usability options at the top, as we can have up to 25 addresses in the menu + if version.has_qr: + items.append(MenuItem('Scan QR', f=(self.maxed_out if maxxed else self.scan_qr), + shortcut=KEY_QR)) + + items.append(MenuItem('Import from File', + f=(self.maxed_out if maxxed else self.import_file))) + + # show most recent added addresses at the top of the menu list + a_items = [MenuItem(truncate_address(a), f=self.edit_addr, arg=a) for a in addrs[::-1]] + + if a_items: + items += a_items + if len(a_items) > 1: + items.append(MenuItem("Clear Whitelist", f=self.clear_all)) + else: + items.append(MenuItem("(none yet)")) + + return items + + async def edit_addr(self, menu, idx, item): + # show detail and offer delete + addr = item.arg + msg = ('Spends to this address will be permitted:\n\n%s' + '\n\nPress (4) to delete.' % show_single_address(addr)) + ch = await ux_show_story(msg, escape='4') + if ch == '4': + self.delete_addr(addr) + + def delete_addr(self, addr): + # no confirm, stakes are low + addrs = self.policy.get('addrs', []) + addrs.remove(addr) + self.policy.update_policy_key(addrs=addrs) + self.update_contents() + + async def clear_all(self, *a): + if await ux_confirm("Remove all addresses from the whitelist?", confirm_key='4'): + self.policy.update_policy_key(addrs=[]) + self.update_contents() + + async def import_file(self, *a): + # Import from a file, or NFC. + # - simulator: --seq tcENTERENTERsENTERwENTERiENTER1 + # - very forgiving, does not care about file format + # - but also silent on all errors + from ux import import_export_prompt + from glob import NFC + from actions import file_picker + from files import CardSlot + from utils import cleanup_payment_address + + choice = await import_export_prompt("List of addresses", is_import=True, no_qr=True) + + if choice == KEY_CANCEL: + return + elif choice == KEY_NFC: + addr = await NFC.read_address() + if not addr: + # error already displayed in nfc.py + return + + await self.add_addresses([addr]) + return + + # loose RE to match any group of chars that could be addresses + # - really just removing whitespace and punctuation + # - lacking re.findall(), so using re.split() on negatives + pat = re.compile(r'[^A-Za-z0-9]') + + # pick a likely-looking file: just looking at size and extension + fn = await file_picker(suffix=['.csv', '.txt'], + min_size=20, max_size=20000, + none_msg="Must contain payment addresses", **choice) + + if not fn: return + + results = [] + with CardSlot(readonly=True, **choice) as card: + with open(fn, 'rt') as fd: + for ln in fd.readlines(): + if len(results) >= MAX_WHITELIST: + # no need to clog memory and parse more, we're done + break + for here in pat.split(ln): + if len(here) >= 4: + try: + addr = cleanup_payment_address(here) + results.append(addr) + except: pass + + if not results: + await ux_show_story("Unable to find any payment addresses in that file.") + else: + # silently limit to first 25 results; lets them use addresses.csv easily + await self.add_addresses(results[:MAX_WHITELIST]) + + + async def scan_qr(self, *a): + # Scan and return a text string. For things like BIP-39 passphrase + # and perhaps they are re-using a QR from something else. Don't act on contents. + from ux_q1 import QRScannerInteraction + q = QRScannerInteraction() + + got = [] + ln = '' + while 1: + here = await q.scan_for_addresses("Bitcoin Address(es) to Whitelist", line2=ln) + if not here: break + for addr in here: + if addr not in got: + got.append(addr) + ln = 'Got %d so far. ENTER to apply.' % len(got) + + if got: + # import them + await self.add_addresses(got) + + async def maxed_out(self, *a): + await ux_show_story("Max %d items in whitelist. Please make room first." % MAX_WHITELIST) + + async def add_addresses(self, more_addrs): + # add new entries, if unique; preserve ordering + addrs = self.policy.get('addrs', []) + new = [] + for a in more_addrs: + if a not in addrs: + addrs.append(a) + new.append(a) + + if not new: + await ux_show_story("Already in whitelist:\n\n" + + '\n\n'.join(show_single_address(a) for a in more_addrs)) + return + + if len(addrs) > MAX_WHITELIST: + return await self.maxed_out() + + self.policy.update_policy_key(addrs=addrs) + self.update_contents() + + if len(new) > 1: + await ux_show_story("Added %d new addresses to whitelist:\n\n%s" % + (len(new), '\n\n'.join(show_single_address(a) for a in new))) + else: + await ux_show_story("Added new address to whitelist:\n\n%s" % + show_single_address(new[0])) + +class SPCheckedMenuItem(MenuItem): + # Show a checkmark if **policy** setting is defined and not the default + # - only works inside SpendingPolicyMenu + def __init__(self, label, polkey, **kws): + super().__init__(label, **kws) + self.polkey = polkey + + def is_chosen(self): + # should we show a check in parent menu? check the policy + m = the_ux.top_of_stack() + #assert isinstance(m, SpendingPolicyMenu) + return bool(m.policy.get(self.polkey, False)) + +class SpendingPolicyMenu(MenuSystem): + # Build menu stack that allows edit of all features of the spending + # policy. + # - supports both CCC and SSSP modes w/ same policies + # - Key C is set already at this point. + # - and delete/cancel CCC (clears setting?) + # - be a sticky menu that's hard to exit (ie. SAVE choice and no cancel out) + + def __init__(self, pol): + self.policy = pol + items = self.construct() + super().__init__(items) + + def update_contents(self): + tmp = self.construct() + self.replace_items(tmp) + + @classmethod + async def be_a_submenu(cls, pol, *a): + return cls(pol) + + def construct(self): + items = [ + # xxxxxxxxxxxxxxxx + SPCheckedMenuItem('Max Magnitude', 'mag', f=self.set_magnitude), + SPCheckedMenuItem('Limit Velocity', 'vel', f=self.set_velocity), + SPCheckedMenuItem('Whitelist' + (' Addresses' if version.has_qr else ''), + 'addrs', + menu=lambda *a: SPAddrWhitelist.be_a_submenu(self.policy)), + SPCheckedMenuItem('Web 2FA', 'web2fa', f=self.toggle_2fa), + ] + + if self.policy.get('web2fa'): + items.extend([ + MenuItem('↳ Test 2FA', f=self.test_2fa), + MenuItem('↳ Enroll More', f=self.enroll_more_2fa), + ]) + + return items + + async def test_2fa(self, *a): + ss = self.policy.get('web2fa') + assert ss + ok = await web2fa.perform_web2fa('Testing Only', ss) + + await ux_show_story('Correct code was given.' if ok else 'Failed or aborted.') + + async def enroll_more_2fa(self, *a): + # let more phones in on the party, but they get same shared secret + ss = self.policy.get('web2fa') + assert ss + await web2fa.web2fa_enroll(ss) + + async def set_magnitude(self, *a): + # Looks decent on both Q and Mk4... + was = self.policy.get('mag', 0) + val = await ux_enter_number('Transaction Max:', max_value=int(1e8), + can_cancel=True, value=(was or '')) + + args = dict(mag=val) + if (val is None) or (val == was): + msg = "Did not change" + val = was + else: + msg = "You have set the" + unchanged = False + + if not val: + msg = "No check for maximum transaction size will be done. " + if self.policy.get('vel', 0): + msg += 'Velocity check also disabled. ' + args['vel'] = 0 + else: + msg += " maximum per-transaction: \n\n %s" % render_mag_value(val) + + self.policy.update_policy_key(**args) + + await ux_show_story(msg, title="TX Magnitude") + + async def set_velocity(self, *a): + mag = self.policy.get('mag', 0) or 0 + + if not mag: + msg = 'Velocity limit requires a per-transaction magnitude to be set.'\ + ' This has been set to 1BTC as a starting value.' + self.policy.update_policy_key(mag=1) + + await ux_show_story(msg) + + start_chooser(self.velocity_chooser) + + + def velocity_chooser(self): + # offer some useful values from a menu + vel = self.policy.get('vel', 0) # in blocks + + # xxxxxxxxxxxxxxxx + ch = [ 'Unlimited', + '6 blocks (hour)', + '24 blocks (4h)', + '48 blocks (8h)', + '72 blocks (12h)', + '144 blocks (day)', + '288 blocks (2d)', + '432 blocks (3d)', + '720 blocks (5d)', + '1008 blocks (1w)', + '2016 blocks (2w)', + '3024 blocks (3w)', + '4032 blocks (4w)', + ] + va = [0] + [int(x.split()[0]) for x in ch[1:]] + + try: + which = va.index(vel) + except ValueError: + which = 0 + + def set(idx, text): + self.policy.update_policy_key(vel=va[idx]) + + return which, ch, set + + async def toggle_2fa(self, *a): + if self.policy.get('web2fa'): + # enabled already + + if not await ux_confirm("Disable web 2FA check? Effect is immediate."): + return + + self.policy.update_policy_key(web2fa='') + self.update_contents() + + await ux_show_story("Web 2FA has been disabled. If you re-enable it, a new " + "secret will be generated, so it is safe to remove it from your " + "phone at this point.") + + return + + ch = await ux_show_story('''When enabled, any spend (signing) requires \ +use of mobile 2FA application (TOTP RFC-6238). Shared-secret is picked now, \ +and loaded on your phone via QR code. + +WARNING: You will not be able to sign transactions if you do not have an NFC-enabled \ +phone with Internet access and 2FA app holding correct shared-secret.''', + title="Web 2FA") + if ch != 'y': + return + + # challenge them, and don't set unless it works + ss = await web2fa.web2fa_enroll() + if not ss: + return + + # update state + self.policy.update_policy_key(web2fa=ss) + self.update_contents() + +async def gen_or_import(): + # returns 12 words, or None to abort + from seed import WordNestMenu, generate_seed, approve_word_list, SeedVaultChooserMenu + + msg = "Press %s to generate a new 12-word seed phrase to be used "\ + "as the Coldcard Co-Signing Secret (key C).\n\nOr press (1) to import existing "\ + "12-words or (2) for 24-words import." % OK + + if settings.master_get("seedvault", False): + msg += ' Press (6) to import from Seed Vault.' + + ch = await ux_show_story(msg, escape='126', title="CCC Key C") + + if ch in '12': + nwords = 24 if ch == '2' else 12 + + async def done_key_C_import(words): + if not version.has_qwerty: + WordNestMenu.pop_all() + await enable_step1(words) + + if version.has_qwerty: + from ux_q1 import seed_word_entry + await seed_word_entry('Key C Seed Words', nwords, done_cb=done_key_C_import) + else: + nxt = WordNestMenu(nwords, done_cb=done_key_C_import) + the_ux.push(nxt) + + return None # will call parent again + + elif ch == '6': + # pick existing from Seed Vault + picked = await SeedVaultChooserMenu.pick(words_only=True) + if picked: + words = SecretStash.decode_words(deserialize_secret(picked.encoded)) + await enable_step1(words) + + return None + + elif ch == 'y': + # normal path: pick 12 words, quiz them + await ux_dramatic_pause('Generating...', 3) + seed = generate_seed() + words = await approve_word_list(seed, 12) + else: + return None + + return words + + +async def toggle_ccc_feature(*a): + # The only menu item show to user! + if settings.get('ccc'): + return await modify_ccc_settings() + + # enable the feature -- not simple! + # - create C key (maybe import?) + # - collect a policy setup, maybe 2FA enrol too + # - lock that down + # - TODO copy + ch = await ux_show_story('''\ +Adds an additional seed to your Coldcard, and enforces a "spending policy" whenever \ +it signs with that key. Spending policies can restrict: magnitude (BTC out), \ +velocity (blocks between txn), address whitelisting, and/or require confirmation by 2FA phone app. + +Assuming the use of a 2-of-3 multisig wallet, keys are as follows:\n +A=Coldcard (master seed), B=Backup Key (offline/recovery), C=Spending Policy Key. + +Spending policy cannot be viewed or changed without knowledge of key C.\ +''', + title="Coldcard Co-Signing" if version.has_qwerty else 'CC Co-Sign') + + if ch != 'y': + # just a tourist + return + + await enable_step1(None) + +async def enable_step1(words): + if not words: + words = await gen_or_import() + if not words: return + + dis.fullscreen("Wait...") + dis.busy_bar(True) + try: + # do BIP-32 basics: capture XFP and XPUB and encoded version of the secret + CCCFeature.init_setup(words) + finally: + dis.busy_bar(False) + + # continue into config menu + m = CCCConfigMenu() + + the_ux.push(m) + +async def modify_ccc_settings(): + # Generally not expecting changes to policy on the fly because + # that's the whole point. Use the B key to override individual spends + # but if you can prove you have C key, then it's harmless to allow changes + # since you could just spend as needed. + + enc = CCCFeature.get_encoded_secret() + bypass = False + + from seed import in_seed_vault + if in_seed_vault(enc): + # If seed vault enabled and they have the key C in there already, just go + # directly into menu (super helpful for debug/setup/testing time). We do warn tho. + await ux_show_story('''You have a copy of the CCC key C in the Seed Vault, so \ +you may proceed to change settings now.\n\nYou must delete that key from the vault once \ +setup and debug is finished, or all benefit of this feature is lost!''', title='REMINDER') + + bypass = True + + else: + ch = await ux_show_story( + "Spending policy cannot be viewed, changed nor disabled, " + "unless you have the seed words for key C.", + title="CCC Enabled") + + if ch != 'y': return + + if bypass: + # doing full decode cycle here for better testing + chk, raw, _ = SecretStash.decode(enc) + assert chk == 'words' + words = bip39.b2a_words(raw).split(' ') + await key_c_challenge(words) + return + + # small info-leak here: exposing 12 vs 24 words, but we expect most to be 12 anyway + nwords = CCCFeature.get_num_words() + + import seed + if version.has_qwerty: + from ux_q1 import seed_word_entry + await seed_word_entry('Enter Seed Words', nwords, done_cb=key_c_challenge) + else: + return seed.WordNestMenu(nwords, done_cb=key_c_challenge) + +NUM_CHALLENGE_FAILS = 0 + +async def key_c_challenge(words): + # They entered some words, if they match our key C then allow edit of policy + + if not version.has_qwerty: + from seed import WordNestMenu + WordNestMenu.pop_all() + + dis.fullscreen('Verifying...') + + if not CCCFeature.words_check(words): + # keep an in-memory counter, and after 3 fails, reboot + global NUM_CHALLENGE_FAILS + NUM_CHALLENGE_FAILS += 1 + if NUM_CHALLENGE_FAILS >= 3: + from utils import clean_shutdown + clean_shutdown() + + await ux_show_story("Sorry, those words are incorrect.") + return + + # success. they are in. + + # got to config menu + m = CCCConfigMenu() + the_ux.push(m) + +def sssp_spending_policy(key, default=False, set_value=None): + # This function can be used to check if feature(s) are enabled in + # the single-signer policy settings. Might be used while hobbled. + # keys: + # 'en' = feature enabled; hobble on next boot + # 'notes' = allow access to knows + # 'words' = add first/last seed words to challenge to unlock + # 'okeys' = allow BIP-39 and/or seed vault + + v = settings.master_get('sssp', dict()) + + if key in { 'en', 'notes', 'words', 'okeys' }: + # booleans: present or removed from dict + if set_value is not None: + if set_value: + v[key] = True + else: + v.pop(key, None) + + settings.master_set('sssp', v, master_only=True) + + return (key in v) or default + + raise KeyError(key) + + +async def sssp_feature_menu(*a): + # Show the top menu for SSSP feature, or enable access first time. + from pincodes import pa + from actions import goto_top_menu + + if pa.hobbled_mode == 2: + # allow exit from test-drive mode, directly into editing settings + pa.hobbled_mode = False + goto_top_menu() + elif settings.master_get('sssp'): + # normal entry into menu system, after the first time + assert not pa.hobbled_mode + else: + # tell them a story, and maybe enable feature + en = await sssp_enable() + if not en: return + + m = SSSPConfigMenu() + the_ux.push(m) + +async def sssp_enable(): + # enabling the feature + # - collect and setup a new trick pin + # - set sssp settings w/ something non-empty but still disabled. + # - return T if they completed enabling process + + from login import LoginUX + from trick_pins import tp + from pincodes import pa + + # enable the feature -- not simple! + # - pick new (trick pin) that lets you back here. + # - collect a policy setup, maybe 2FA enrol too + # - lock that down + ch = await ux_show_story('''\ +You can define a "spending policy" which stops you from signing \ +transactions unless conditions are met. +Spending policies can restrict: magnitude (BTC out), \ +velocity (blocks between txn), address whitelisting, \ +and/or require confirmation by 2FA phone app. + +When active, your COLDCARD \ +is locked into a special mode that restricts seed access, backups, settings and other features. + +First step is to define a new PIN code that is used when you want to bypass or \ +disable this feature. +''', + title="Spending Policy") + + if ch != 'y': + # just a tourist + return + + # re-use existing PIN if there for some reason + new_pin = tp.has_sp_unlock() + + if not new_pin: + have = tp.all_tricks() + main_pin = pa.pin.decode() + while 1: + lll = LoginUX() + lll.is_setting = True + lll.subtitle = "Spending Policy" + (" Unlock" if version.has_qwerty else '') + + new_pin = await lll.get_new_pin() + if new_pin is None: + return + + dis.fullscreen("Saving...") + + # quick checks - does not spot hidden trick pins + if (new_pin != main_pin) and (new_pin not in have): + # verify uniqueness within SE2 + b, slot = tp.get_by_pin(new_pin) + if slot is None: + tp.define_unlock_pin(new_pin) + break + + await tp.err_unique_pin(new_pin) + + # all features disabled to start + settings.master_set('sssp', dict(en=False, pol={}), master_only=True) + + # continue into config menu + return True + +async def sssp_word_challenge(*a): + # Ask for first/last seed word and verify. Return if correct answers given. + # Reboots on failure. + from stash import SensitiveValues + + with SensitiveValues() as sv: + if sv.mode != 'words': + # they are using XPRV or something, skip test entirely + return + + words = bip39.b2a_words(sv.raw).split(' ') + want_words = words[:1] + words[-1:] + assert len(want_words) == 2 + + for retry in range(2): + if version.has_qwerty: + # see special rendering code for this case in ux_q1.py:ux_draw_words(num_words=2) + from ux_q1 import seed_word_entry + got_words = await seed_word_entry('First and Last Seed Words', 2, has_checksum=False) + else: + from seed import WordNestMenu + got_words = await WordNestMenu.get_n_words(2) + + if got_words == want_words: + # success - done + return + + await ux_show_story("Sorry, those words are incorrect.") + + # they failed; log them out ... they can just try login again + from actions import login_now + await login_now() + + # NOT-REACHED + +class SSSPCheckedMenuItem(MenuItem): + # Show a checkmark if **top level** security setting is defined and not the default + # - only works inside SSSPPolicyMenu? + # - similar to menu.py:ToggleMenuItem + + def __init__(self, label, polkey, story, **kws): + super().__init__(label, **kws) + self.polkey = polkey + self.story = story + + def is_chosen(self): + # should we show a check in menu? check the current SSSP settings + return sssp_spending_policy(self.polkey) + + async def activate(self, menu, idx): + # do simple toggle on request + was = sssp_spending_policy(self.polkey) + + msg = self.story + "\n\n%s?" % ('Disable' if was else 'Enable') + + ch = await ux_show_story(msg) + if ch == 'x': return + + # this can be slow, so show something + dis.fullscreen("Saving...") + sssp_spending_policy(self.polkey, set_value=(not was)) + + +class SSSPConfigMenu(MenuSystem): + def __init__(self): + items = self.construct() + super().__init__(items) + + def update_contents(self): + tmp = self.construct() + self.replace_items(tmp) + + def construct(self): + items = [ + # xxxxxxxxxxxxxxxx + MenuItem('Edit Policy...', + menu=lambda *a: SpendingPolicyMenu.be_a_submenu(SSSPFeature.get_policy())), + SSSPCheckedMenuItem('Word Check', 'words', 'To change Spending Policy, in addition to special PIN, you must provide the first and last seed words.'), + SSSPCheckedMenuItem('Allow Notes', 'notes', 'Allow (read-only) access to secure notes and passwords? Otherwise, they are inaccessible.', predicate=version.has_qwerty), + SSSPCheckedMenuItem('Related Keys', 'okeys', 'Allow access to BIP-39 passphrase wallets based on master seed, and Seed Vault (read-only). Single Spending Policy applies to all.'), + #MenuItem('Test Word Challenge', f=sssp_word_challenge), # XXX test only? + ] + + if LastFailReason.get(): + # xxxxxxxxxxxxxxxx + items.insert(1, MenuItem('Last Violation', f=self.debug_last_fail)) + + items.append(MenuItem('Remove Policy', f=self.remove_sssp)) + items.append(MenuItem('Test Drive', f=self.test_drive)) + items.append(MenuItem('ACTIVATE', f=self.activate_feature)) + + return items + + async def activate_feature(self, *a): + # Policy is being set in stone now; confirm and switch to hobble mode, etc. + from trick_pins import tp + + bypass_pin = tp.has_sp_unlock() + + if not bypass_pin: + msg = "You have no Spending Policy bypass PIN defined, so changes to this COLDCARD cannot be made past this point. Only option will be to destroy seed and reload everything." + else: + msg = "To return to normal unlimited spending mode, you will need to enter the special pin (%s), then the Main PIN" % bypass_pin + if sssp_spending_policy('words'): + msg += ', followed by the first and last seed words' + msg += '.' + + if not await ux_confirm(msg, 'CONTINUE?'): + return + + # set it for next login + dis.fullscreen("Saving...") + sssp_spending_policy('en', set_value=True) + + # make it real ... could reboot here instead, but no need. + from pincodes import pa + from actions import goto_top_menu + + pa.hobbled_mode = True + goto_top_menu() + + async def test_drive(self, *a): + # allow test drive of feature + if not await ux_confirm("See what COLDCARD operation will look like with Spending Policy enabled.", 'CONTINUE?'): + return + + from pincodes import pa + from actions import goto_top_menu + + pa.hobbled_mode = 2 # Truthy value to indicate they can escape easily + goto_top_menu() + + async def debug_last_fail(self, *a): + # debug for customers: why did we reject that last txn? + pol = SSSPFeature.get_policy() + bh = pol.get('block_h', None) + msg = '' + if bh: + msg += "Last height:\n\n%s\n\n" % bh + + lfr = LastFailReason.get() + msg += 'The most recent policy check failed because of:\n\n%s\n\nPress (4) to clear.' \ + % lfr + ch = await ux_show_story(msg, escape='4') + + if ch == '4': + LastFailReason.clear() + self.update_contents() + + async def remove_sssp(self, *a): + # disable and remove feature + if not await ux_confirm('Bypass PIN will be removed, and all spending policy settings forgotten.'): + return + + settings.remove_key('sssp') + settings.save() + + from trick_pins import tp + tp.delete_sp_unlock_pins() + + the_ux.pop() + + +# EOF diff --git a/shared/chains.py b/shared/chains.py index 514481d2..10d65d02 100644 --- a/shared/chains.py +++ b/shared/chains.py @@ -5,13 +5,14 @@ import ngu from uhashlib import sha256 from ubinascii import hexlify as b2a_hex -from public_constants import AF_CLASSIC, AF_P2WPKH, AF_P2TR +from public_constants import AF_CLASSIC, AF_P2WPKH, AF_P2TR, AF_BARE_PK from public_constants import AF_P2SH, AF_P2WSH, AF_P2WPKH_P2SH, AF_P2WSH_P2SH -from public_constants import AFC_PUBKEY, AFC_SEGWIT, AFC_BECH32, AFC_SCRIPT +from public_constants import AFC_PUBKEY, AFC_BECH32, AFC_SCRIPT from public_constants import TAPROOT_LEAF_TAPSCRIPT, TAPROOT_LEAF_MASK from serializations import hash160, ser_compact_size, disassemble, ser_string from ucollections import namedtuple from opcodes import OP_RETURN, OP_1, OP_16 +from precomp_tag_hash import TAP_TWEAK_H, TAP_LEAF_H SINGLESIG_AF = (AF_P2WPKH, AF_CLASSIC, AF_P2TR, AF_P2WPKH_P2SH) @@ -23,20 +24,22 @@ Slip132Version = namedtuple('Slip132Version', ('pub', 'priv', 'hint')) # See also: # - # - defines ypub/zpub/Xprc variants -# - -# - nice bech32 encoded scheme for going forward # - # - mailing list post proposed ypub, etc. # - from # - also electrum source: electrum/lib/constants.py +# nLockTime in transaction equal or above this value is a unix timestamp (time_t) not block height. +NLOCK_IS_TIME = const(500000000) + + def taptweak(internal_key, tweak=None): # BIP 341 states: "If the spending conditions do not require a script path, # the output key should commit to an unspendable script path instead of having no script path. # This can be achieved by computing the output key point as: # Q = P + int(hashTapTweak(bytes(P)))G." actual_tweak = internal_key if tweak is None else internal_key + tweak - tweak = ngu.secp256k1.tagged_sha256(b"TapTweak", actual_tweak) + tweak = ngu.hash.sha256t(TAP_TWEAK_H, actual_tweak, True) xo_pubkey = ngu.secp256k1.xonly_pubkey(internal_key) xo_pubkey_tweaked = xo_pubkey.tweak_add(tweak) return xo_pubkey_tweaked.to_bytes() @@ -47,13 +50,14 @@ def tapscript_serialize(script, leaf_version=TAPROOT_LEAF_TAPSCRIPT): return bytes([lv]) + ser_string(script) def tapleaf_hash(script, leaf_version=TAPROOT_LEAF_TAPSCRIPT): - return ngu.secp256k1.tagged_sha256(b"TapLeaf", - tapscript_serialize(script, leaf_version)) + return ngu.hash.sha256t(TAP_LEAF_H, tapscript_serialize(script, leaf_version), True) class ChainsBase: curve = 'secp256k1' + menu_name = None # use 'name' if this isn't defined + ccc_min_block = 0 # b44_cointype comes from # @@ -88,68 +92,50 @@ class ChainsBase: return node.serialize(cls.slip132[addr_fmt].pub, False) @classmethod - def deserialize_node(cls, text, addr_fmt): - # xpub/xprv to object - addr_fmt = AF_CLASSIC if addr_fmt == AF_P2SH else addr_fmt - node = ngu.hdnode.HDNode() - version = node.deserialize(text) - assert (version == cls.slip132[addr_fmt].pub) \ - or (version == cls.slip132[addr_fmt].priv) - return node + def script_pubkey(cls, addr_fmt, pubkey=None, script=None): + digest = None + if addr_fmt & AFC_SCRIPT: + assert script, "need witness/redeem script" - @classmethod - def p2sh_address(cls, addr_fmt, witdeem_script): - # Multisig and general P2SH support - # - witdeem => witness script for segwit, or redeem script otherwise - # - redeem script can be generated from witness script if needed. - # - this function needs a witdeem script to be provided, not simple to make - # - more verification needed to prove it's change/included address (NOT HERE) - # - reference: - # - returns: str(address) + if addr_fmt in [AF_P2WSH, AF_P2WSH_P2SH]: + digest = ngu.hash.sha256s(script) + # bech32 encoded segwit p2sh + spk = b'\x00\x20' + digest + if addr_fmt == AF_P2WSH_P2SH: + # segwit p2wsh encoded as classic P2SH + digest = hash160(spk) + spk = b'\xA9\x14' + digest + b'\x87' - assert addr_fmt & AFC_SCRIPT, 'for p2sh only' - assert witdeem_script, "need witness/redeem script" + else: + assert addr_fmt == AF_P2SH + digest = hash160(script) + spk = b'\xA9\x14' + digest + b'\x87' - if addr_fmt & AFC_SEGWIT: - digest = ngu.hash.sha256s(witdeem_script) else: - digest = hash160(witdeem_script) + assert pubkey + keyhash = ngu.hash.hash160(pubkey) + if addr_fmt == AF_P2TR: + assert len(pubkey) == 32 # internal + spk = b'\x51\x20' + taptweak(pubkey) + elif addr_fmt == AF_CLASSIC: + spk = b'\x76\xA9\x14' + keyhash + b'\x88\xAC' + elif addr_fmt == AF_P2WPKH_P2SH: + redeem_script = b'\x00\x14' + keyhash + spk = b'\xA9\x14' + ngu.hash.hash160(redeem_script) + b'\x87' + elif addr_fmt == AF_P2WPKH: + spk = b'\x00\x14' + keyhash + else: + raise ValueError('bad address template: %s' % addr_fmt) - if addr_fmt & AFC_BECH32: - # bech32 encoded segwit p2sh - addr = ngu.codecs.segwit_encode(cls.bech32_hrp, 0, digest) - elif addr_fmt == AF_P2WSH_P2SH: - # segwit p2wsh encoded as classic P2SH - addr = ngu.codecs.b58_encode(cls.b58_script + hash160(b'\x00\x20' + digest)) - else: - # P2SH classic - addr = ngu.codecs.b58_encode(cls.b58_script + digest) - - return addr + return spk, digest @classmethod def pubkey_to_address(cls, pubkey, addr_fmt): # - renders a pubkey to an address # - works only with single-key addresses assert not addr_fmt & AFC_SCRIPT - - if addr_fmt == AF_P2TR: - assert len(pubkey) == 32 # internal - script = b'\x51\x20' + taptweak(pubkey) - else: - keyhash = ngu.hash.hash160(pubkey) - if addr_fmt == AF_CLASSIC: - script = b'\x76\xA9\x14' + keyhash + b'\x88\xAC' - elif addr_fmt == AF_P2WPKH_P2SH: - redeem_script = b'\x00\x14' + keyhash - scripthash = ngu.hash.hash160(redeem_script) - script = b'\xA9\x14' + scripthash + b'\x87' - elif addr_fmt == AF_P2WPKH: - script = b'\x00\x14' + keyhash - else: - raise ValueError('bad address template: %s' % addr_fmt) - - return cls.render_address(script) + spk, _ = cls.script_pubkey(addr_fmt, pubkey=pubkey) + return cls.render_address(spk) @classmethod def address(cls, node, addr_fmt): @@ -164,7 +150,7 @@ class ChainsBase: return node.addr_help(cls.b58_addr[0]) if addr_fmt & AFC_SCRIPT: - # use p2sh_address() instead. + # use chain.render_address raise ValueError(hex(addr_fmt)) # so must be P2PKH, fetch it. @@ -191,7 +177,7 @@ class ChainsBase: @classmethod def hash_message(cls, msg=None, msg_len=0): # Perform sha256 for message-signing purposes (only) - # - or get setup for that, if msg == None + # - or get setup for that, if msg is None s = sha256() s.update(cls.msg_signing_prefix()) @@ -272,37 +258,37 @@ class ChainsBase: @classmethod def op_return(cls, script): - """Returns decoded string op return data if script is op return otherwise None""" + # returns decoded string op return data if script is op return otherwise None gen = disassemble(script) script_type = next(gen) - if OP_RETURN in script_type: - try: - data = next(gen)[0] - if data is None: raise RuntimeError - except (RuntimeError, StopIteration): - return "null-data", "" - data_hex = b2a_hex(data).decode() - data_ascii = None - if min(data) >= 32 and max(data) < 127: # printable - try: - data_ascii = data.decode("ascii") - except: - pass - return data_hex, data_ascii - return None + if OP_RETURN not in script_type: + return + + try: + data = next(gen)[0] + if data: + return data + except StopIteration: + pass + + return b"" @classmethod def possible_address_fmt(cls, addr): # Given a text (serialized) address, return what # address format applies to the address, but # for AF_P2SH case, could be: AF_P2SH, AF_P2WPKH_P2SH, AF_P2WSH_P2SH. .. we don't know - if addr.startswith(cls.bech32_hrp): - if addr.startswith(cls.bech32_hrp+'1p'): - # really any ver=1 script or address, but for now... + hrp = cls.bech32_hrp + "1" + if addr.startswith(hrp): + if addr.startswith(hrp+'p'): + # segwit v1 (any ver=1 script or address, but for now just taproot...) return AF_P2TR - else: + elif addr.startswith(hrp+'q'): + # segwit v0 return AF_P2WPKH if len(addr) < 55 else AF_P2WSH + return 0 + try: raw = ngu.codecs.b58_decode(addr) except ValueError: @@ -321,6 +307,7 @@ class BitcoinMain(ChainsBase): # see ctype = 'BTC' name = 'Bitcoin Mainnet' + ccc_min_block = 922061 # Nov 3/2025 slip132 = { AF_CLASSIC: Slip132Version(0x0488B21E, 0x0488ADE4, 'x'), @@ -339,7 +326,7 @@ class BitcoinMain(ChainsBase): b44_cointype = 0 -class BitcoinTestnet(BitcoinMain): +class BitcoinTestnet(ChainsBase): # testnet4 (was testnet3 up until 2025 but all parameters are the same) ctype = 'XTN' name = 'Bitcoin Testnet 4' @@ -362,7 +349,7 @@ class BitcoinTestnet(BitcoinMain): b44_cointype = 1 -class BitcoinRegtest(BitcoinMain): +class BitcoinRegtest(ChainsBase): ctype = 'XRT' name = 'Bitcoin Regtest' @@ -417,7 +404,7 @@ def current_key_chain(): # Overbuilt: will only be testnet and mainchain. AllChains = [BitcoinMain, BitcoinTestnet, BitcoinRegtest] -def slip32_deserialize(xp): +def slip132_deserialize(xp): # .. and classify chain and addr-type, as implied by prefix node = ngu.hdnode.HDNode() version = node.deserialize(xp) @@ -450,15 +437,38 @@ STD_DERIVATIONS = { "p2sh-p2wpkh": CommonDerivations[1][1], "p2wpkh-p2sh": CommonDerivations[1][1], "p2wpkh": CommonDerivations[2][1], + "p2tr": CommonDerivations[3][1], +} + +MS_STD_DERIVATIONS = { + ("p2sh", "m/45h", AF_P2SH), + ("p2sh_p2wsh", "m/48h/{coin}h/{acct_num}h/1h", AF_P2WSH_P2SH), + ("p2wsh", "m/48h/{coin}h/{acct_num}h/2h", AF_P2WSH), + ('p2tr', "m/48h/{coin}h/{acct_num}h/3h", AF_P2TR), +} + +AF_TO_STR_AF = { + AF_BARE_PK: "p2pk", + AF_CLASSIC: "p2pkh", + AF_P2TR: "p2tr", + AF_P2WPKH: "p2wpkh", + AF_P2WPKH_P2SH: "p2sh-p2wpkh", + AF_P2SH: "p2sh", + AF_P2WSH: "p2wsh", + AF_P2WSH_P2SH: "p2sh-p2wsh", } def parse_addr_fmt_str(addr_fmt): # accepts strings and also integers if already parsed + # integers are coming from USB try: if isinstance(addr_fmt, int): if addr_fmt in [AF_P2WPKH_P2SH, AF_P2WPKH, AF_CLASSIC]: return addr_fmt else: + try: + addr_fmt = AF_TO_STR_AF[addr_fmt] # just for error msg + except: pass raise ValueError addr_fmt = addr_fmt.lower() @@ -477,7 +487,8 @@ def parse_addr_fmt_str(addr_fmt): def af_to_bip44_purpose(addr_fmt): - # single signature only + # Address format to BIP-44 "purpose" number + # - single signature only return {AF_CLASSIC: 44, AF_P2WPKH_P2SH: 49, AF_P2WPKH: 84, @@ -490,7 +501,8 @@ def addr_fmt_label(addr_fmt): AF_P2WPKH: "Segwit P2WPKH", AF_P2TR: "Taproot P2TR", AF_P2WSH: "Segwit P2WSH", - AF_P2WSH_P2SH: "P2SH-P2WSH" + AF_P2WSH_P2SH: "P2SH-P2WSH", + AF_P2SH: "Legacy P2SH", }[addr_fmt] def verify_recover_pubkey(sig, digest): diff --git a/shared/charcodes.py b/shared/charcodes.py index a7947475..f1242afd 100644 --- a/shared/charcodes.py +++ b/shared/charcodes.py @@ -109,7 +109,9 @@ if has_qwerty: # These affect how 'ux stories' are rendered; they are control # characters on the output side of things, not input. -OUT_CTRL_TITLE = '\x01' # must be first char in line: be a title line -OUT_CTRL_ADDRESS = '\x02' # must be first char in line: it's a payment address +# - must be first char in line +OUT_CTRL_TITLE = '\x01' # be a title line +OUT_CTRL_ADDRESS = '\x02' # it's a payment address +OUT_CTRL_NOWRAP = '\x03' # do not word wrap this line # EOF diff --git a/shared/compat7z.py b/shared/compat7z.py index e475c4f6..3034d1ce 100644 --- a/shared/compat7z.py +++ b/shared/compat7z.py @@ -198,7 +198,7 @@ class SectionHeader(namedtuple('SectionHeader', ['offset', 'size', 'crc' ])): # read only next one; ftell has to be on first byte already rv = cls.read(f) - if expect_crc != None: + if expect_crc is not None: assert rv # read past end assert masked_crc(rv.bits) == expect_crc @@ -315,7 +315,7 @@ class Builder(object): padded_len = (here + 15) & ~15 if padded_len != here: - if self.padding != None: + if self.padding is not None: raise ValueError() # "can't do less than a block except at end" self.padding = (padded_len - here) raw += bytes(self.padding) diff --git a/shared/decoders.py b/shared/decoders.py index 13f8b212..a71483fb 100644 --- a/shared/decoders.py +++ b/shared/decoders.py @@ -101,7 +101,7 @@ def decode_qr_result(got, expect_secret=False, expect_text=False, expect_bbqr=Fa try: ty, final_size, got = got.storage.finalize() except BaseException as exc: - import sys; sys.print_exception(exc) + #import sys; sys.print_exception(exc) raise QRDecodeExplained("BBQr decode failed: " + str(exc)) if expect_bbqr: @@ -136,6 +136,18 @@ def decode_qr_result(got, expect_secret=False, expect_text=False, expect_bbqr=Fa what = "smsg" return what, (got,) + + elif ty in 'RSE': + # key-teleport related + + from pincodes import pa + if pa.hobbled_mode and ty != 'E': + raise QRDecodeExplained("KT Blocked") + + if ty == 'R' and len(got) != 33: + raise QRDecodeExplained("Truncated KT RX") + + return 'teleport', (ty, got) else: msg = TYPE_LABELS.get(ty, 'Unknown FileType') raise QRDecodeExplained("Sorry, %s not useful." % msg) @@ -211,21 +223,6 @@ def decode_short_text(got): # was something else. pass - if ("\n" in got) and ('pub' in got): - # legacy multisig import/export format - # [0-9a-fA-F]{8}\s*:\s*[xtyYzZuUvV]pub[1-9A-HJ-NP-Za-km-z]{107} - # above is more precise BUT counted repetitions not supported in mpy - cc_ms_pat = r"[0-9a-fA-F]+\s*:\s*[xtyYzZuUvV]pub[1-9A-HJ-NP-Za-km-z]+" - rgx = ure.compile(cc_ms_pat) - # go line by line and match above, once 2 matches observed - considered multisig - # important to not use ure.search for big strings (can run out of stack) - c = 0 # match count - for l in got.split("\n"): - if rgx.search(l): - c += 1 - if c > 1: - return 'multi', (got,) - from descriptor import Descriptor if Descriptor.is_descriptor(got): return 'minisc', (got,) diff --git a/shared/desc_utils.py b/shared/desc_utils.py index 28aaaa4e..50232ead 100644 --- a/shared/desc_utils.py +++ b/shared/desc_utils.py @@ -2,9 +2,9 @@ # # Copyright (c) 2020 Stepan Snigirev MIT License embit/arguments.py # -import ngu, chains, ustruct +import ngu, chains, ustruct, stash from io import BytesIO -from public_constants import AF_P2SH, AF_P2WSH_P2SH, AF_P2WSH, AF_CLASSIC, AF_P2TR +from public_constants import MAX_PATH_DEPTH from binascii import unhexlify as a2b_hex from binascii import hexlify as b2a_hex from utils import keypath_to_str, str_to_keypath, swab32, xfp2str @@ -80,30 +80,8 @@ def parse_desc_str(string): return res -def multisig_descriptor_template(xpub, path, xfp, addr_fmt): - key_exp = "[%s%s]%s/0/*" % (xfp.lower(), path.replace("m", ''), xpub) - if addr_fmt == AF_P2WSH_P2SH: - descriptor_template = "sh(wsh(sortedmulti(M,%s,...)))" - elif addr_fmt == AF_P2WSH: - descriptor_template = "wsh(sortedmulti(M,%s,...))" - elif addr_fmt == AF_P2SH: - descriptor_template = "sh(sortedmulti(M,%s,...))" - elif addr_fmt == AF_P2TR: - # provably unspendable BIP-0341 - descriptor_template = "tr(" + b2a_hex(PROVABLY_UNSPENDABLE[1:]).decode() + ",sortedmulti_a(M,%s,...))" - else: - return None - descriptor_template = descriptor_template % key_exp - return descriptor_template - - def read_until(s, chars=b",)(#"): - # TODO potential infinite loop - # what is the longest possible element? (proly some raw( but that is unsupported) - # res = b"" - chunk = b"" - char = None while True: chunk = s.read(1) if len(chunk) == 0: @@ -111,14 +89,13 @@ def read_until(s, chars=b",)(#"): if chunk in chars: return res, chunk res += chunk - return res, None class KeyOriginInfo: - def __init__(self, fingerprint: bytes, derivation: list): + def __init__(self, fingerprint: bytes, derivation: list, cc_fp=None): self.fingerprint = fingerprint self.derivation = derivation - self.cc_fp = swab32(int(b2a_hex(self.fingerprint).decode(), 16)) + self._cc_fp = cc_fp def __eq__(self, other): return self.psbt_derivation() == other.psbt_derivation() @@ -126,6 +103,12 @@ class KeyOriginInfo: def __hash__(self): return hash(tuple(self.psbt_derivation())) + @property + def cc_fp(self): + if self._cc_fp is None: + self._cc_fp = ustruct.unpack('") - assert end_i - inner = s[start_i+1:end_i] - assert ";" in inner - inner_split = inner.split(";") - assert len(inner_split) == 2, "wrong multipath" - res.append([int(i) for i in inner_split]) - mp += 1 - mpi = idx + def parse(cls, s): + err = "Malformed key derivation" + multi_i = None + idxs = [] + while True: + got, char = read_until(s, b"<,)/") + if char == b"<": + assert multi_i is None, "too many multipaths" + ext_num, char = read_until(s, b";") + assert char, err + cls.not_hardened(ext_num) + int_num, char = read_until(s, b">") + assert char, err + assert b";" not in int_num, "Solved cardinality > 2" + cls.not_hardened(int_num) + + assert int_num != ext_num # cannot be the same + multi_i = len(idxs) + idxs.append((int(ext_num.decode()), int(int_num.decode()))) + else: - if i == WILDCARD: - res.append(WILDCARD) - else: - assert "'" not in i, fail_msg - assert "h" not in i, fail_msg - res.append(int(i)) + # char in "/)," + if got == b"*": + # every derivation has to end with wildcard (only ranged keys allowed) + idxs.append(WILDCARD) + break + elif got: + cls.not_hardened(got) + idxs.append(int(got.decode())) - # only one allowed in subderivation - assert mp <= 1, "too many multipaths (%d)" % mp + # comma and parenthesis not allowed in subderivation, marker of the end + if char in b",)": break - if res == [0, WILDCARD]: + assert idxs[-1] == WILDCARD, "All keys must be ranged" + if idxs == [0, WILDCARD]: + # normalize and instead save as <0;1> as change derivation was not provided obj = cls() else: - assert len(res) == 2, "Key derivation too long" - assert res[-1] == WILDCARD, "All keys must be ranged" - obj = cls(res) - obj.multi_path_index = mpi + + assert multi_i is not None, "need multipath" + assert len(idxs[multi_i]) == 2, "wrong multipath" + + obj = cls(tuple(idxs)) + obj.multi_path_index = multi_i + return obj def to_string(self, external=True, internal=True): res = [] for i in self.indexes: - if isinstance(i, list): + if isinstance(i, tuple): if internal is True and external is False: i = str(i[1]) elif internal is False and external is True: @@ -239,25 +219,21 @@ class KeyDerivationInfo: res.append(i) return "/".join(res) - def to_int_list(self, branch_idx, idx): - assert branch_idx in self.indexes[0] - return [branch_idx, idx] - class Key: def __init__(self, node, origin, derivation=None, taproot=False, chain_type=None): self.origin = origin self.node = node - self.derivation = derivation + self.derivation = derivation or KeyDerivationInfo() self.taproot = taproot self.chain_type = chain_type def __eq__(self, other): - return self.origin == other.origin \ - and self.derivation.indexes == other.derivation.indexes + return hash(self) == hash(other) def __hash__(self): - return hash(self.to_string()) + # return hash(self.to_string()) + return hash(self.node.pubkey()) + hash(self.derivation) def __len__(self): return 34 - int(self.taproot) # <33:sec> or <32:xonly> @@ -277,9 +253,6 @@ class Key: def parse(cls, s): first = s.read(1) origin = None - if first == b"u": - s.seek(-1, 1) - return Unspend.parse(s) if first == b"[": prefix, char = read_until(s, b"]") @@ -288,43 +261,86 @@ class Key: origin = KeyOriginInfo.from_string(prefix.decode()) else: s.seek(-1, 1) + k, char = read_until(s, b",)/") - der = b"" + der = None if char == b"/": - der, char = read_until(s, b"<,)") - if char == b"<": - der += b"<" - branch, char = read_until(s, b">") - if char is None: - raise ValueError("Failed reading the key, missing >") - der += branch + b">" - rest, char = read_until(s, b",)") - der += rest + der = KeyDerivationInfo.parse(s) if char is not None: s.seek(-1, 1) + # parse key node, chain_type = cls.parse_key(k) - der = KeyDerivationInfo.from_string(der.decode()) if origin is None: - origin = KeyOriginInfo(ustruct.pack('") - if char is None: - raise ValueError("Failed reading the key, missing >") - der += branch + b">" - rest, char = read_until(s, b",)") - der += rest - if char is not None: - s.seek(-1, 1) - - node = ngu.hdnode.HDNode().from_chaincode_pubkey(chain_code, - PROVABLY_UNSPENDABLE) - der = KeyDerivationInfo.from_string(der.decode()) - return cls(node, None, der, chain_type=None) - - def to_string(self, external=True, internal=True, subderiv=True): - res = "unspend(%s)" % b2a_hex(self.node.chain_code()).decode() - if self.derivation and subderiv: - res += "/" + self.derivation.to_string(external, internal) - - return res - - @property - def is_provably_unspendable(self): - return True - - -def fill_policy(policy, keys, external=True, internal=True): - orig_keys = [] - for k in keys: - if not isinstance(k, str): - k_orig = k.to_string(external, internal, subderiv=False) - else: - _idx = k.find("]") # end of key origin info - no more / expected besides subderivation - if _idx != -1: - ek = k[_idx+1:].split("/")[0] - k_orig = k[:_idx+1] + ek - else: - # no origin info - k_orig = k.split("/")[0] - - if k_orig not in orig_keys: - orig_keys.append(k_orig) - - for i in range(len(orig_keys) - 1, -1, -1): - k = orig_keys[i] +def bip388_wallet_policy_to_descriptor(desc_tmplt, keys_info): + for i in range(len(keys_info) - 1, -1, -1): + k_str = keys_info[i] ph = "@%d" % i - ph_len = len(ph) - while True: - ix = policy.find(ph) - if ix == -1: - break - - assert policy[ix+ph_len] == "/" - # subderivation is part of the policy - x = ix + ph_len - substr = policy[x:x+26] # 26 is the longest possible subderivation allowed "/<2147483647;2147483646>/*" - mp_start = substr.find("<") - assert mp_start != -1 - mp_end = substr.find(">") - mp = substr[mp_start:mp_end + 1] - _ext, _int = mp[1:-1].split(";") - if external and not internal: - sub = _ext - elif internal and not external: - sub = _int - else: - sub = None - if sub is not None: - policy = policy[:x + mp_start] + sub + policy[x + mp_end + 1:] - - x = policy[ix:ix + ph_len] - assert x == ph - policy = policy[:ix] + k + policy[ix + ph_len:] - - return policy + desc_tmplt = desc_tmplt.replace(ph, k_str) + return desc_tmplt.replace("/**", "/<0;1>/*") -def taproot_tree_helper(scripts): - from miniscript import Miniscript +def bip388_validate_policy(desc_tmplt, keys_info): + from uio import BytesIO - if isinstance(scripts, Miniscript): - script = scripts.compile() - assert isinstance(script, bytes) - h = ngu.secp256k1.tagged_sha256(b"TapLeaf", chains.tapscript_serialize(script)) - return [(chains.TAPROOT_LEAF_TAPSCRIPT, script, bytes())], h - if len(scripts) == 1: - return taproot_tree_helper(scripts[0]) + s = BytesIO(desc_tmplt) + r = [] + while True: + got, char = read_until(s, b"@") + if not char: + # no more - done + break - split_pos = len(scripts) // 2 - left, left_h = taproot_tree_helper(scripts[0:split_pos]) - right, right_h = taproot_tree_helper(scripts[split_pos:]) - left = [(version, script, control + right_h) for version, script, control in left] - right = [(version, script, control + left_h) for version, script, control in right] - if right_h < left_h: - right_h, left_h = left_h, right_h - h = ngu.secp256k1.tagged_sha256(b"TapBranch", left_h + right_h) - return left + right, h \ No newline at end of file + # key derivation info required for policy + got, char = read_until(s, b"/") + assert char, "key derivation missing" + num = int(got.decode()) + if num not in r: + r.append(num) + + assert s.read(1) in b"<*", "need multipath" + + + assert len(r) == len(keys_info), "Invalid policy" + assert r == list(range(len(r))), "Out of order" diff --git a/shared/descriptor.py b/shared/descriptor.py index aa996e09..ed08bbbf 100644 --- a/shared/descriptor.py +++ b/shared/descriptor.py @@ -6,308 +6,215 @@ import ngu, chains from io import BytesIO from collections import OrderedDict from binascii import hexlify as b2a_hex -from utils import cleanup_deriv_path, check_xpub, xfp2str, swab32 +from utils import xfp2str from public_constants import AF_CLASSIC, AF_P2WPKH, AF_P2WPKH_P2SH, AF_P2TR -from public_constants import AF_P2WSH, AF_P2WSH_P2SH, AF_P2SH, MAX_SIGNERS, MAX_TR_SIGNERS +from public_constants import AF_P2WSH, AF_P2WSH_P2SH, AF_P2SH, MAX_TR_SIGNERS from desc_utils import parse_desc_str, append_checksum, descriptor_checksum, Key -from desc_utils import taproot_tree_helper, fill_policy, Unspend from miniscript import Miniscript - - -class DescriptorException(ValueError): - pass - - -class WrongCheckSumError(Exception): - pass +from precomp_tag_hash import TAP_BRANCH_H class Tapscript: - def __init__(self, tree=None, keys=None, policy=None): - self.tree = tree - self.keys = keys - self.policy = policy + def __init__(self, tree): + self.tree = tree # miniscript or (tapscript, tapscript) self._merkle_root = None + self._processed_tree = None - @staticmethod - def iter_leaves(tree): - if isinstance(tree, Miniscript): - yield tree + def iter_leaves(self): + if isinstance(self.tree, Miniscript): + yield self.tree else: - assert isinstance(tree, list) - for lv in tree: - yield from Tapscript.iter_leaves(lv) + for ts in self.tree: + yield from ts.iter_leaves() @property def merkle_root(self): if not self._merkle_root: - self.process_tree() + self._processed_tree, self._merkle_root = self.process_tree() return self._merkle_root - @staticmethod - def _derive(tree, idx, key_map, change=False): - if isinstance(tree, Miniscript): - return tree.derive(idx, key_map, change=change) + def derive(self, idx, key_map, change=False): + if isinstance(self.tree, Miniscript): + tree = self.tree.derive(idx, key_map, change=change) else: - if len(tree) == 1 and isinstance(tree[0], Miniscript): - return tree[0].derive(idx, key_map, change=change) - l, r = tree - return [Tapscript._derive(l, idx, key_map, change=change), - Tapscript._derive(r, idx, key_map, change=change)] + l, r = self.tree + tree = [l.derive(idx, key_map, change=change), + r.derive(idx, key_map, change=change)] - def derive(self, idx=None, change=False): - derived_keys = OrderedDict() - for k in self.keys: - derived_keys[k] = k.derive(idx, change=change) - tree = Tapscript._derive(self.tree, idx, derived_keys, change=change) - return type(self)(tree, policy=self.policy, keys=list(derived_keys.values())) + return type(self)(tree) def process_tree(self): - info, mr = taproot_tree_helper(self.tree) - self._merkle_root = mr - return info, mr + if isinstance(self.tree, Miniscript): + script = self.tree.compile() + h = chains.tapleaf_hash(script) + return [(chains.TAPROOT_LEAF_TAPSCRIPT, script, bytes())], h + + l, r = self.tree + left, left_h = l.process_tree() + right, right_h = r.process_tree() + left = [(version, script, control + right_h) for version, script, control in left] + right = [(version, script, control + left_h) for version, script, control in right] + if right_h < left_h: + right_h, left_h = left_h, right_h + + h = ngu.hash.sha256t(TAP_BRANCH_H, left_h + right_h, True) + return left + right, h + + # UNUSED - using above proces tree cached result to dump scripts to CSV + # def script_tree(self): + # if isinstance(self.tree, Miniscript): + # return b2a_hex(chains.tapscript_serialize(self.tree.compile())).decode() + # + # l, r = self.tree + # return "{" + l.script_tree() + "," +r.script_tree() + "}" @classmethod def read_from(cls, s): - num_leafs = 0 - depth = 0 - tapscript = [] - p0 = s.read(1) - if p0 != b"{": - # depth zero - s.seek(-1, 1) - alone = Miniscript.read_from(s, taproot=True) - alone.is_sane(taproot=True) - alone.verify() - tapscript.append(alone) - num_leafs += 1 - else: - assert p0 == b"{" - depth += 1 - itmp = None - itmp_p = None - while True: - p1 = s.read(1) - if p1 == b'': - break - elif p1 == b")": - s.seek(-1, 1) - break - elif p1 == b",": - continue - elif p1 == b"{": - if itmp is None: - itmp = [] - else: - if itmp_p: - itmp[itmp_p].append([]) - else: - itmp.append(([])) - itmp_p = -1 + c = s.read(1) + assert len(c) + if c == b"{": # more than one miniscript + left = cls.read_from(s) + c = s.read(1) + if c == b"}": + return left + if c != b",": + raise ValueError("Invalid tapscript: expected ','") - depth += 1 - continue - elif p1 == b"}": - depth -= 1 - if depth == 1: - tapscript.append(itmp) - itmp = None + right = cls.read_from(s) + if s.read(1) != b"}": + raise ValueError("Invalid tapscript: expected '}'") - if depth <= 2: - itmp_p = None - continue + return cls((left, right)) - s.seek(-1, 1) - item = Miniscript.read_from(s, taproot=True) - item.is_sane(taproot=True) - item.verify() - num_leafs += 1 - if itmp is None: - tapscript.append(item) - else: - if itmp_p and depth == 4: - itmp[itmp_p][itmp_p].append(item) - elif itmp_p: - itmp[itmp_p].append(item) - else: - itmp.append(item) - - assert num_leafs <= 8, "num_leafs > 8" - ts = cls(tapscript) - ts.parse_policy() - return ts - - def parse_policy(self): - self.policy, self.keys = self._parse_policy(self.tree, []) - orig_keys = OrderedDict() - for k in self.keys: - if k.origin not in orig_keys: - orig_keys[k.origin] = [] - orig_keys[k.origin].append(k) - for i, k_lst in enumerate(orig_keys.values()): - # always keep subderivation in policy string - self.policy = self.policy.replace(k_lst[0].to_string(subderiv=False), chr(64) + str(i)) - - @staticmethod - def _parse_policy(tree, all_keys): - if isinstance(tree, Miniscript): - keys, leaf_str = tree.keys, tree.to_string() - for k in keys: - if k not in all_keys: - all_keys.append(k) - - return leaf_str, all_keys - else: - assert isinstance(tree, list) - if len(tree) == 1 and isinstance(tree[0], Miniscript): - keys, leaf_str = tree[0].keys, tree[0].to_string() - for k in keys: - if k not in all_keys: - all_keys.append(k) - - return leaf_str, all_keys - else: - l, r = tree - ll, all_keys = Tapscript._parse_policy(l, all_keys) - rr, all_keys = Tapscript._parse_policy(r, all_keys) - return "{" + ll + "," + rr + "}", all_keys - - @staticmethod - def script_tree(tree): - if isinstance(tree, Miniscript): - return b2a_hex(chains.tapscript_serialize(tree.compile())).decode() - else: - assert isinstance(tree, list) - if len(tree) == 1 and isinstance(tree[0], Miniscript): - return b2a_hex(chains.tapscript_serialize(tree[0].compile())).decode() - else: - l, r = tree - ll = Tapscript.script_tree(l) - rr = Tapscript.script_tree(r) - return "{" + ll + "," + rr + "}" + s.seek(-1, 1) + ms = Miniscript.read_from(s, taproot=True) + return cls(ms) def to_string(self, external=True, internal=True): - return fill_policy(self.policy, self.keys, external, internal) + if isinstance(self.tree, Miniscript): + return self.tree.to_string(external, internal) + + l, r = self.tree + return ("{" + l.to_string(external,internal) + "," + + r.to_string(external, internal) + "}") class Descriptor: - def __init__(self, miniscript=None, sh=False, wsh=True, key=None, wpkh=True, - taproot=False, tapscript=None): - if key is None and miniscript is None: - raise DescriptorException("Provide either miniscript or a key") + def __init__(self, key=None, miniscript=None, tapscript=None, addr_fmt=None, keys=None): + if addr_fmt in [AF_P2SH, AF_P2WSH, AF_P2WSH_P2SH]: + assert miniscript + assert not key + else: + # single-sig + taproot/tapscript + assert miniscript is None + assert key - self.sh = sh - self.wsh = wsh self.key = key self.miniscript = miniscript - self.wpkh = wpkh - self.taproot = taproot self.tapscript = tapscript + self.addr_fmt = addr_fmt + # cached keys + self._keys = keys - if taproot: - if self.key: - self.key.taproot = True - for k in self.keys: - k.taproot = taproot - - def validate(self): + def validate(self, disable_checks=False): + # should only be run once while importing wallet from glob import settings - if self.miniscript: - if self.is_basic_multisig: - assert len(self.keys) <= MAX_SIGNERS - else: - assert len(self.keys) <= 20 - self.miniscript.verify() - if self.miniscript.type != "B": - raise DescriptorException("Top level miniscript should be 'B'") + c = 0 has_mine = 0 - my_xfp = settings.get('xfp') - to_check = self.keys.copy() + err_top_B = "Top level miniscript should be 'B'" + max_signers = 20 + if self.tapscript: - assert len(self.keys) <= MAX_TR_SIGNERS assert self.key # internal key (would fail during parse) - if not self.key.is_provably_unspendable: - to_check += [self.key] - else: - assert self.key is None and self.miniscript, "not miniscript" + max_signers = MAX_TR_SIGNERS + for l in self.tapscript.iter_leaves(): + assert l.type == "B", err_top_B + l.verify() + l.is_sane(taproot=True) + # cannot have same keys in single miniscript + # provably unspendable taproot internal key is not covered here + assert len(l.keys) == len(set(l.keys)), "Insane" - c = chains.current_key_chain().ctype - for k in to_check: - assert k.chain_type == c, "wrong chain" - xfp = k.origin.cc_fp - deriv = k.origin.str_derivation() - xpub = k.extended_public_key() - deriv = cleanup_deriv_path(deriv) - is_mine, _ = check_xpub(xfp, xpub, deriv, c, my_xfp, False) - if is_mine: - has_mine += 1 + elif self.miniscript: + assert self.key is None + assert self.miniscript.type == "B", err_top_B + self.miniscript.verify() + self.miniscript.is_sane(taproot=False) + # cannot have same keys in single miniscript + assert len(self.miniscript.keys) == len(set(self.miniscript.keys)), "Insane" - assert has_mine != 0, 'My key %s missing in descriptor.' % xfp2str(my_xfp).upper() - - def storage_policy(self): - if self.tapscript: - return self.tapscript.policy - - s = self.miniscript.to_string() - orig_keys = OrderedDict() + my_xfp = settings.get('xfp', 0) + ext_nums = set() + int_nums = set() for k in self.keys: - if k.origin not in orig_keys: - orig_keys[k.origin] = [] - orig_keys[k.origin].append(k) - for i, k_lst in enumerate(orig_keys.values()): - s = s.replace(k_lst[0].to_string(subderiv=False), chr(64) + str(i)) - return s + has_mine += k.validate(my_xfp, disable_checks) + ext, int = k.derivation.get_ext_int() + ext_nums.add(ext) + int_nums.add(int) + c += 1 - def ux_policy(self): - if self.tapscript: - return "Taproot tree keys:\n\n" + self.tapscript.policy + if not self.tapscript and not self.is_basic_multisig: + # this is non-taproot Miniscript + # Miniscript expressions can only be used in wsh or tr. + assert self.addr_fmt != AF_P2SH, "Miniscript in legacy P2SH not allowed" - return self.storage_policy() + assert ext_nums.isdisjoint(int_nums), "Non-disjoint multipath" + assert c <= max_signers, "max signers" + + assert has_mine > 0, 'My key %s missing in descriptor.' % xfp2str(my_xfp).upper() + + def bip388_wallet_policy(self): + # only same origin keys + keys_info = OrderedDict() + for k in self.keys: + pk = k.node.pubkey() + if pk not in keys_info: + keys_info[pk] = k.to_string(external=False, internal=False) + + desc_tmplt = self.to_string(checksum=False).replace("/<0;1>/*", "/**") + + keys_info = list(keys_info.values()) + for i, k_str in enumerate(keys_info): + desc_tmplt = desc_tmplt.replace(k_str, chr(64) + str(i)) + + return desc_tmplt, keys_info @property def script_len(self): - if self.taproot: + if self.is_taproot: return 34 # OP_1 <32:xonly> if self.miniscript: return len(self.miniscript) - if self.wpkh: + if self.addr_fmt == AF_P2WPKH: return 22 # 00 <20:pkh> return 25 # OP_DUP OP_HASH160 <20:pkh> OP_EQUALVERIFY OP_CHECKSIG - def xfp_paths(self): + def xfp_paths(self, skip_unspend_ik=False): res = [] - if self.taproot: - if self.key.origin: - # spendable internal key - res.append(self.key.origin.psbt_derivation()) - elif self.key.is_provably_unspendable: - res.append([swab32(self.key.node.my_fp())]) - for k in self.keys: - if k.origin: - res.append(k.origin.psbt_derivation()) + if self.is_taproot and k.is_provably_unspendable and skip_unspend_ik: + continue + + res.append(k.origin.psbt_derivation()) + return res @property - def is_wrapped(self): - return self.sh and self.is_segwit - - @property - def is_legacy(self): - return not (self.is_segwit or self.is_taproot) + def is_segwit_v0(self): + return self.addr_fmt in [AF_P2WPKH, AF_P2WPKH_P2SH, AF_P2WSH, AF_P2WSH_P2SH] @property def is_segwit(self): - return (self.wsh and self.miniscript) or (self.wpkh and self.key) or self.taproot - - @property - def is_pkh(self): - return self.key is not None and not self.taproot + return self.is_taproot or self.is_segwit_v0 @property def is_taproot(self): - return self.taproot + return self.addr_fmt == AF_P2TR + + @property + def is_legacy_sh(self): + return self.addr_fmt in [AF_P2SH, AF_P2WSH_P2SH, AF_P2WPKH_P2SH] @property def is_basic_multisig(self): @@ -319,142 +226,96 @@ class Descriptor: @property def keys(self): + if self._keys: + return self._keys + if self.tapscript: - return self.tapscript.keys - elif self.key: - return [self.key] - return self.miniscript.keys + # internal is always first + # use ordered dict as order preserving set + keys = OrderedDict() + # add internal key + keys[self.key] = None + # taptree keys + for lv in self.tapscript.iter_leaves(): + for k in lv.keys: + keys[k] = None - @property - def addr_fmt(self): - if self.sh and not self.wsh: - af = AF_P2SH - elif self.wsh and not self.sh: - af = AF_P2WSH - elif self.sh and self.wsh: - af = AF_P2WSH_P2SH - elif self.taproot: - af = AF_P2TR - elif self.sh and self.wpkh: - af = AF_P2WPKH_P2SH - elif self.wpkh and not self.sh: - af = AF_P2WPKH - else: - af = AF_CLASSIC - return af + self._keys = list(keys) - def set_from_addr_fmt(self, addr_fmt): - self.taproot = False - self.wsh = False - self.wpkh = False - self.sh = False - if addr_fmt == AF_P2TR: - self.taproot = True - assert self.key - elif addr_fmt == AF_P2WPKH: - self.wpkh = True - self.miniscript = None - assert self.key - elif addr_fmt == AF_P2WPKH_P2SH: - self.wpkh = True - self.sh = True - self.miniscript = None - assert self.key - elif addr_fmt == AF_P2SH: - self.sh = True - assert self.miniscript - assert not self.key - elif addr_fmt == AF_P2WSH: - self.wsh = True - assert self.miniscript - assert not self.key - elif addr_fmt == AF_P2WSH_P2SH: - self.wsh = True - self.sh = True - assert self.miniscript - assert not self.key - else: - # AF_CLASSIC - assert self.key - assert not self.miniscript + elif self.miniscript: + self._keys = self.miniscript.keys - def scriptpubkey_type(self): - if self.is_taproot: - return "p2tr" - if self.sh: - return "p2sh" - if self.is_pkh: - if self.is_legacy: - return "p2pkh" - if self.is_segwit: - return "p2wpkh" else: - return "p2wsh" + # single-sig + self._keys = [self.key] + + return self._keys def derive(self, idx=None, change=False): - if self.taproot: + if self.is_taproot: + # derive keys first + # duplicate keys can be may be found in different leaves + # use map to derive each key just once + derived_keys = OrderedDict() + ikd = None + for i, k in enumerate(self.keys): + dk = k.derive(idx, change=change) + dk.taproot = self.is_taproot + derived_keys[k] = dk + if not i: + # internal key is always at index 0 in self.keys + ikd = dk + return type(self)( - None, - self.sh, - self.wsh, - self.key.derive(idx, change=change), - self.wpkh, - self.taproot, - tapscript=self.tapscript.derive(idx, change=change), + ikd, + tapscript=self.tapscript.derive(idx, derived_keys, change=change), + addr_fmt=self.addr_fmt, + keys=list(derived_keys.values()), ) if self.miniscript: return type(self)( + None, self.miniscript.derive(idx, change=change), - self.sh, - self.wsh, - None, - self.wpkh, - self.taproot, - tapscript=None, - ) - else: - return type(self)( - None, self.sh, self.wsh, - self.key.derive(idx, change=change), - self.wpkh, self.taproot, tapscript=None + addr_fmt=self.addr_fmt, ) - def witness_script(self): - if self.wsh and self.miniscript is not None: - return self.miniscript.compile() + # single-sig + return type(self)(self.key.derive(idx, change=change)) - def redeem_script(self): - if not self.sh: - return None - if self.miniscript: - if self.wsh: - return b"\x00\x20" + ngu.hash.sha256s(self.miniscript.compile()) - else: - return self.miniscript.compile() - - else: - return b"\x00\x14" + ngu.hash.hash160(self.key.node.pubkey()) - - def script_pubkey(self): - if self.taproot: + def script_pubkey(self, compiled_scr=None): + if self.is_taproot: tweak = None if self.tapscript: tweak = self.tapscript.merkle_root output_pubkey = chains.taptweak(self.key.serialize(), tweak) return b"\x51\x20" + output_pubkey - if self.sh: - return b"\xa9\x14" + ngu.hash.hash160(self.redeem_script()) + b"\x87" - if self.wsh: - return b"\x00\x20" + ngu.hash.sha256s(self.witness_script()) - if self.miniscript: - return self.miniscript.compile() - if self.wpkh: + + if self.is_legacy_sh: + if self.miniscript: + # caller may have already built a script + scr = compiled_scr or self.miniscript.compile() + redeem_scr = scr + if self.addr_fmt == AF_P2WSH_P2SH: + redeem_scr = b"\x00\x20" + ngu.hash.sha256s(scr) + else: + redeem_scr = b"\x00\x14" + ngu.hash.hash160(self.key.node.pubkey()) + + return b"\xa9\x14" + ngu.hash.hash160(redeem_scr) + b"\x87" + + if self.addr_fmt == AF_P2WSH: + # witness script p2wsh only + return b"\x00\x20" + ngu.hash.sha256s(compiled_scr or self.miniscript.compile()) + + if self.addr_fmt == AF_P2WPKH: return b"\x00\x14" + ngu.hash.hash160(self.key.serialize()) + + # p2pkh + assert self.addr_fmt == AF_CLASSIC return b"\x76\xa9\x14" + ngu.hash.hash160(self.key.serialize()) + b"\x88\xac" @classmethod def is_descriptor(cls, desc_str): - """Quick method to guess whether this is a descriptor""" + # Quick method to guess whether this is a descriptor try: temp = parse_desc_str(desc_str) except: @@ -481,7 +342,7 @@ class Descriptor: return desc_w_checksum, None calc_checksum = descriptor_checksum(desc) if calc_checksum != checksum: - raise WrongCheckSumError("Wrong checksum %s, expected %s" % (checksum, calc_checksum)) + raise ValueError("Wrong checksum %s, expected %s" % (checksum, calc_checksum)) return desc, checksum @classmethod @@ -500,19 +361,15 @@ class Descriptor: return res @classmethod - def read_from(cls, s, taproot=False): + def read_from(cls, s): start = s.read(8) - sh = False - wsh = False - wpkh = False - is_miniscript = True + af = AF_CLASSIC internal_key = None tapscript = None if start.startswith(b"tr("): - is_miniscript = False # miniscript vs. tapscript (that can contain miniscripts in tree) - taproot = True + af = AF_P2TR s.seek(-5, 1) - internal_key = Key.parse(s) # internal key is a must - also handles unspend( + internal_key = Key.parse(s) internal_key.taproot = True sep = s.read(1) if sep == b")": @@ -520,76 +377,68 @@ class Descriptor: else: assert sep == b"," tapscript = Tapscript.read_from(s) + elif start.startswith(b"sh(wsh("): - sh = True - wsh = True + af = AF_P2WSH_P2SH s.seek(-1, 1) elif start.startswith(b"wsh("): - sh = False - wsh = True + af = AF_P2WSH s.seek(-4, 1) elif start.startswith(b"sh(wpkh("): - is_miniscript = False - sh = True - wpkh = True + af = AF_P2WPKH_P2SH elif start.startswith(b"wpkh("): - is_miniscript = False - wpkh = True + af = AF_P2WPKH s.seek(-3, 1) elif start.startswith(b"pkh("): - is_miniscript = False s.seek(-4, 1) elif start.startswith(b"sh("): - sh = True - wsh = False + af = AF_P2SH s.seek(-5, 1) else: raise ValueError("Invalid descriptor") - if is_miniscript: - miniscript = Miniscript.read_from(s) - miniscript.is_sane(taproot=False) - key = internal_key - nbrackets = int(sh) + int(wsh) - elif taproot: - miniscript = None + miniscript = None + if af == AF_P2TR: key = internal_key nbrackets = 1 + elif af in [AF_P2SH, AF_P2WSH_P2SH, AF_P2WSH]: + miniscript = Miniscript.read_from(s) + key = internal_key + nbrackets = 1 + int(af == AF_P2WSH_P2SH) else: - miniscript = None key = Key.parse(s) - nbrackets = 1 + int(sh) + nbrackets = 1 + int(af == AF_P2WPKH_P2SH) end = s.read(nbrackets) if end != b")" * nbrackets: raise ValueError("Invalid descriptor") - o = cls(miniscript, sh=sh, wsh=wsh, key=key, wpkh=wpkh, - taproot=taproot, tapscript=tapscript) - o.validate() - return o + + desc = cls(key, miniscript, tapscript, af) + return desc def to_string(self, external=True, internal=True, checksum=True): - if self.taproot: + if self.is_taproot: desc = "tr(%s" % self.key.to_string(external, internal) if self.tapscript: desc += "," tree = self.tapscript.to_string(external, internal) desc += tree - desc = desc + ")" - return append_checksum(desc) + res = desc + ")" - if self.miniscript is not None: - res = self.miniscript.to_string(external, internal) - if self.wsh: - res = "wsh(%s)" % res else: - if self.wpkh: - res = "wpkh(%s)" % self.key.to_string(external, internal) + if self.miniscript is not None: + res = self.miniscript.to_string(external, internal) + if self.addr_fmt in [AF_P2WSH, AF_P2WSH_P2SH]: + res = "wsh(%s)" % res else: - res = "pkh(%s)" % self.key.to_string(external, internal) - if self.sh: - res = "sh(%s)" % res + if self.addr_fmt in [AF_P2WPKH, AF_P2WPKH_P2SH]: + res = "wpkh(%s)" % self.key.to_string(external, internal) + else: + res = "pkh(%s)" % self.key.to_string(external, internal) + + if self.is_legacy_sh: + res = "sh(%s)" % res if checksum: res = append_checksum(res) diff --git a/shared/display.py b/shared/display.py index a3d42346..787e117d 100644 --- a/shared/display.py +++ b/shared/display.py @@ -76,7 +76,7 @@ class Display: if x is None or x < 0: # center/rjust w = self.width(msg, font) - if x == None: + if x is None: x = max(0, (self.WIDTH - w) // 2) else: # measure from right edge (right justify) @@ -156,11 +156,14 @@ class Display: def fullscreen(self, msg, percent=None, line2=None): # show a simple message "fullscreen". - # - 'line2' not supported on smaller screen sizes, ignore self.clear() y = 14 self.text(None, y, msg, font=FontLarge) + if line2: + # 21 + 6 ie. FontLarge.height of above text + FontTiny.height as space between + self.text(None, y + 27, line2, font=FontSmall) + if percent is not None: self.progress_bar(percent) self.show() @@ -272,17 +275,18 @@ class Display: if is_sel: self.dis.fill_rect(0, y, Display.WIDTH, h-1, 1) self.icon(2, y, 'wedge', invert=1) - self.text(x, y, msg, invert=1) + nx = self.text(x, y, msg, invert=1) else: - self.text(x, y, msg) + nx = self.text(x, y, msg) # LATER: removed because caused confusion w/ underscore #if msg[0] == ' ' and space_indicators: # see also graphics/mono/space.txt #self.icon(x-2, y+9, 'space', invert=is_sel) - if is_checked: - self.icon(108, y, 'selected', invert=is_sel) + if is_checked and nx <= 113: + # omit checkmark if it doesn't fit + self.icon(113, y, 'selected', invert=is_sel) def menu_show(self, *a): self.show() @@ -334,14 +338,25 @@ class Display: # no status bar on Mk4 return - def draw_qr_display(self, qr_data, msg, is_alnum, sidebar, idx_hint, invert, is_addr=False): + def draw_qr_error(self, idx_hint, msg): + self.clear() + lm = 4 + bw = 54 + y = (self.HEIGHT - bw) // 2 + # empty rectangle + self.dis.fill_rect(lm, y, bw, bw, 1) + self.dis.fill_rect(lm+1, y+1, bw-2, bw-2, 0) + # error in rectangle - handpicked position + self.text(lm+5,y+10, "QR too") + self.text(lm+16,y+24, "big") + self._draw_qr_display(bw, lm, msg, False, None, idx_hint, False) + + def draw_qr_display(self, qr_data, msg, is_alnum, sidebar, idx_hint, invert, + is_addr=False, force_msg=False, is_change=False): # 'sidebar' is a pre-formated obj to show to right of QR -- oled life # - 'msg' will appear to right if very short, else under in tiny # - ignores "is_addr" because exactly zero space to do anything special - from utils import word_wrap - self.clear() - w = qr_data.width() if w <= 29: # version 1,2,3 => we can double-up the pixels @@ -381,13 +396,23 @@ class Display: gly = framebuf.FrameBuffer(bytearray(packed), w, w, framebuf.MONO_HLSB) self.dis.blit(gly, XO, YO, 1) + self._draw_qr_display(bw, lm, msg, is_alnum, sidebar, idx_hint, invert, is_addr, is_change) + + def _draw_qr_display(self, bw, lm, msg, is_alnum, sidebar, idx_hint, invert, + is_addr=False, is_change=False): + # does not draw actual QR, but all other things in the screen + from utils import word_wrap + if not sidebar and not msg: pass - elif not sidebar and len(msg) > (5*7): + elif not sidebar and ((len(msg) > (5*7)) or is_change): # use FontTiny and word wrap (will just split if no spaces) + # native segwit addresses and taproot + # if is_change=True also p2pkh and p2sh fall into this category as space is needed for "CHANGE" x = bw + lm + 4 ww = ((128 - x)//4) - 1 # char width avail y = 1 + parts = list(word_wrap(msg, ww)) if len(parts) > 8: parts = parts[:8] @@ -398,9 +423,13 @@ class Display: for line in parts: self.text(x, y, line, FontTiny) y += 8 + + if is_addr and is_change: + self.text(x+4, y+8, "CHANGE BACK", FontTiny) else: # hand-positioned for known cases # - sidebar = (text, #of char per line) + # p2pkh and p2sh addresses (if is_change=False) x, y = 73, (0 if is_alnum else 2) dy = 10 if is_alnum else 12 sidebar, ll = sidebar if sidebar else (msg, 7) diff --git a/shared/drv_entro.py b/shared/drv_entro.py index 91ce4cef..8f52d94e 100644 --- a/shared/drv_entro.py +++ b/shared/drv_entro.py @@ -11,8 +11,8 @@ from ux import ux_show_story, ux_enter_bip32_index, the_ux, ux_confirm, ux_drama from menu import MenuItem, MenuSystem from ubinascii import hexlify as b2a_hex from ubinascii import b2a_base64 -from auth import write_sig_file -from utils import chunk_writer, xfp2str, swab32 +from msgsign import write_sig_file +from utils import xfp2str, swab32 from charcodes import KEY_QR, KEY_NFC, KEY_CANCEL BIP85_PWD_LEN = 21 @@ -161,7 +161,7 @@ async def drv_entro_step2(_1, picked, _2, just_pick=False): qr_alnum = True msg = 'Seed words (%d):\n' % len(words) - msg += ux_render_words(words) + msg += ux_render_words(words, leading_blanks=1) encoded = stash.SecretStash.encode(seed_phrase=new_secret) @@ -226,12 +226,13 @@ async def drv_entro_step2(_1, picked, _2, just_pick=False): choice = import_export_prompt_decode(ch) if isinstance(choice, dict): # write to SD card or Virtual Disk: simple text file + dis.fullscreen("Saving...") try: with CardSlot(**choice) as card: fname, out_fn = card.pick_filename('drv-%s-idx%d.txt' % (s_mode, index)) body = msg + "\n" with open(fname, 'wt') as fp: - chunk_writer(fp, body) + fp.write(body) h = ngu.hash.sha256s(body.encode()) sig_nice = write_sig_file([(h, fname)], derive=path) @@ -240,7 +241,7 @@ async def drv_entro_step2(_1, picked, _2, just_pick=False): await needs_microsd() continue except Exception as e: - await ux_show_story('Failed to write!\n\n\n'+str(e)) + await ux_show_story('Failed to write!\n\n'+str(e)) continue story = "Filename is:\n\n%s" % out_fn @@ -250,7 +251,7 @@ async def drv_entro_step2(_1, picked, _2, just_pick=False): break elif choice == KEY_QR: from ux import show_qr_code - await show_qr_code(qr, qr_alnum) + await show_qr_code(qr, qr_alnum, is_secret=True) elif choice == '0': if s_mode == 'pw': # gets confirmation then types it @@ -263,14 +264,14 @@ async def drv_entro_step2(_1, picked, _2, just_pick=False): xfp_str = xfp2str(settings.get("xfp", 0)) await seed.set_ephemeral_seed( encoded, - meta='BIP85 Derived from [%s], index=%d' % (xfp_str, index) + origin='BIP85 Derived from [%s], index=%d' % (xfp_str, index) ) goto_top_menu() break elif NFC and choice == KEY_NFC: # Share any of these over NFC - await NFC.share_text(qr) + await NFC.share_text(qr, is_secret=True) stash.blank_object(msg) stash.blank_object(new_secret) diff --git a/shared/exceptions.py b/shared/exceptions.py index 2d92d136..6f84242d 100644 --- a/shared/exceptions.py +++ b/shared/exceptions.py @@ -19,10 +19,10 @@ class CCBusyError(RuntimeError): # HSM is blocking your action class HSMDenied(RuntimeError): pass - class HSMCMDDisabled(RuntimeError): pass + # PSBT / transaction related class FatalPSBTIssue(RuntimeError): pass @@ -51,4 +51,12 @@ class QRDecodeExplained(ValueError): class UnknownAddressExplained(ValueError): pass +# We're not going to (co-)sign using spending policy features +class SpendPolicyViolation(RuntimeError): + pass + +# data too big for simple QR +class QRTooBigError(ValueError): + pass + # EOF diff --git a/shared/export.py b/shared/export.py index f387243f..7686fb33 100644 --- a/shared/export.py +++ b/shared/export.py @@ -5,26 +5,25 @@ import stash, chains, version, ujson, ngu from uio import StringIO from ucollections import OrderedDict -from utils import xfp2str, swab32, chunk_writer -from ux import ux_show_story +from utils import xfp2str, swab32, problem_file_line +from ux import ux_show_story, import_export_prompt from glob import settings -from auth import write_sig_file +from msgsign import write_sig_file from public_constants import AF_CLASSIC, AF_P2WPKH, AF_P2WPKH_P2SH, AF_P2WSH, AF_P2WSH_P2SH, AF_P2SH, AF_P2TR from charcodes import KEY_NFC, KEY_CANCEL, KEY_QR from ownership import OWNERSHIP +from exceptions import QRTooBigError async def export_by_qr(body, label, type_code, force_bbqr=False): # render as QR and show on-screen from ux import show_qr_code try: - # ignore label/title - provides no useful info - # makes qr smaller and harder to read - if force_bbqr: - raise ValueError + if force_bbqr or len(body) > 2000: + raise QRTooBigError await show_qr_code(body) - except (ValueError, RuntimeError, TypeError): + except QRTooBigError: if version.has_qwerty: # do BBQr on Q from ux_q1 import show_bbqr_codes @@ -34,6 +33,81 @@ async def export_by_qr(body, label, type_code, force_bbqr=False): return + +async def export_contents(title, contents, fname_pattern, derive=None, addr_fmt=None, + is_json=False, force_bbqr=False, force_prompt=False, direct_way=None): + # export text and json files while offering NFC, QR & Vdisk + # produces signed export in case of SD/Vdisk (signed with key at deriv and addr_fmt) + # checks if suitable to offer QR export on Mk4 + # argument contents can support function that generates content + # argument direct way can be KEY_{NFC,QR}, any other truth value is SD/Vdisk, + # if None ask for way via UX story + from glob import dis, NFC, VD + from files import CardSlot, CardMissingError, needs_microsd + from qrs import MAX_V11_CHAR_LIMIT + + if callable(contents): + dis.fullscreen('Generating...') + contents, derive, addr_fmt = contents() + + # figure out if offering QR code export make sense given HW + # len() is O(1) + no_qr = not version.has_qwerty and (len(contents) >= MAX_V11_CHAR_LIMIT) + + if addr_fmt == AF_P2TR: + sig = None + else: + sig = not (derive is None and addr_fmt is None) + + ch = direct_way # set it to direct way only once, outside the loop + while True: + if direct_way is None: + ch = await import_export_prompt("%s file" % title, + force_prompt=force_prompt, no_qr=no_qr) + if ch == KEY_CANCEL: + break + elif ch == KEY_QR: + await export_by_qr(contents, title, "J" if is_json else "U", force_bbqr=force_bbqr) + elif ch == KEY_NFC: + if is_json: + await NFC.share_json(contents) + else: + await NFC.share_text(contents) + else: + # SD/VDisk + # choose a filename + try: + dis.fullscreen("Saving...") + with CardSlot(**ch) as card: + fname, nice = card.pick_filename(fname_pattern) + + # do actual write + with open(fname, 'wt' if is_json else 'wb') as fd: + fd.write(contents) + + if sig: + h = ngu.hash.sha256s(contents.encode()) + sig_nice = write_sig_file([(h, fname)], derive, addr_fmt) + + msg = '%s file written:\n\n%s' % (title, nice) + if sig: + msg += "\n\n%s signature file written:\n\n%s" % (title, sig_nice) + + await ux_show_story(msg) + + except CardMissingError: + await needs_microsd() + except Exception as e: + await ux_show_story('Failed to write!\n\n%s\n%s' % (e, problem_file_line(e))) + + # both exceptions & success gets here + if no_qr and (NFC is None) and (VD is None) and not force_prompt: + # user has no other ways enabled, we already exported to SD - done + return + + if direct_way: + return + def generate_public_contents(): # Generate public details about wallet. # @@ -116,64 +190,13 @@ be needed for different systems. yield ('\n\n') - from multisig import MultisigWallet - exists, exists_other_chain = MultisigWallet.exists() - if exists: - yield '\n# Your Multisig Wallets\n\n' + from wallet import MiniScriptWallet + if MiniScriptWallet.exists(): + yield '\n# Your Miniscript Wallets\n\n' - for ms in MultisigWallet.get_all(): - fp = StringIO() + for msc in MiniScriptWallet.iter_wallets(): + yield msc.to_string() + "\n---\n" - ms.render_export(fp) - print("\n---\n", file=fp) - - yield fp.getvalue() - del fp - -async def write_text_file(fname_pattern, body, title, derive, addr_fmt, - force_prompt=False): - # Export data as a text file. - from glob import dis, NFC - from files import CardSlot, CardMissingError, needs_microsd - from ux import import_export_prompt - - choice = await import_export_prompt("%s file" % title, is_import=False, - force_prompt=force_prompt) # QR offered also on Mk4 - if choice == KEY_CANCEL: - return - elif choice == KEY_QR: - await export_by_qr(body, title, "U") - return - elif choice == KEY_NFC: - await NFC.share_text(body) - return - - # choose a filename - try: - dis.fullscreen("Saving...") - with CardSlot(**choice) as card: - fname, nice = card.pick_filename(fname_pattern) - - # do actual write - with open(fname, 'wb') as fd: - chunk_writer(fd, body) - - sig_nice = None - if addr_fmt != AF_P2TR: - h = ngu.hash.sha256s(body.encode()) - sig_nice = write_sig_file([(h, fname)], derive, addr_fmt) - - except CardMissingError: - await needs_microsd() - return - except Exception as e: - await ux_show_story('Failed to write!\n\n\n'+str(e)) - return - - msg = '%s file written:\n\n%s' % (title, nice) - if sig_nice: - msg += '\n\n%s signature file written:\n\n%s' % (title, sig_nice) - await ux_show_story(msg) async def make_summary_file(fname_pattern='public.txt'): from glob import dis @@ -184,7 +207,7 @@ async def make_summary_file(fname_pattern='public.txt'): # generator function: body = "".join(list(generate_public_contents())) ch = chains.current_chain() - await write_text_file(fname_pattern, body, 'Summary', + await export_contents('Summary', body, fname_pattern, "m/44h/%dh/0h/0/0" % ch.b44_cointype, AF_CLASSIC) @@ -246,7 +269,7 @@ importmulti '{imp_multi}' ch = chains.current_chain() derive = "84h/{coin_type}h/{account}h".format(account=account_num, coin_type=ch.b44_cointype) - await write_text_file(fname_pattern, body, 'Bitcoin Core', derive + "/0/0", AF_P2WPKH) + await export_contents('Bitcoin Core', body, fname_pattern, derive + "/0/0", AF_P2WPKH) def generate_bitcoin_core_wallet(account_num, example_addrs): # Generate the data for an RPC command to import keys into Bitcoin Core @@ -283,12 +306,10 @@ def generate_bitcoin_core_wallet(account_num, example_addrs): xfp = settings.get('xfp') key0 = Key.from_cc_data(xfp, derive_v0, xpub_v0) - desc_v0 = Descriptor(key=key0) - desc_v0.set_from_addr_fmt(AF_P2WPKH) + desc_v0 = Descriptor(key=key0, addr_fmt=AF_P2WPKH) key1 = Key.from_cc_data(xfp, derive_v1, xpub_v1) - desc_v1 = Descriptor(key=key1) - desc_v1.set_from_addr_fmt(AF_P2TR) + desc_v1 = Descriptor(key=key1, addr_fmt=AF_P2TR) OWNERSHIP.note_wallet_used(AF_P2WPKH, account_num) OWNERSHIP.note_wallet_used(AF_P2TR, account_num) @@ -347,20 +368,16 @@ def generate_unchained_export(account_num=0): # - no account numbers (at this level) chain = chains.current_chain() - todo = [ - ( "m/48h/{coin}h/{acct_num}h/2h", 'p2wsh', AF_P2WSH ), - ( "m/48h/{coin}h/{acct_num}h/1h", 'p2sh_p2wsh', AF_P2WSH_P2SH), - ( "m/45h", 'p2sh', AF_P2SH), # if acct_num == 0 - ] - xfp = xfp2str(settings.get('xfp', 0)) rv = OrderedDict(xfp=xfp, account=account_num) - + sign_der = None with stash.SensitiveValues() as sv: - for deriv, name, fmt in todo: + for name, deriv, fmt in chains.MS_STD_DERIVATIONS: if fmt == AF_P2SH and account_num: continue dd = deriv.format(coin=chain.b44_cointype, acct_num=account_num) + if fmt == AF_P2WSH: + sign_der = dd + "/0/0" node = sv.derive_path(dd) xp = chain.serialize_public(node, fmt) @@ -369,14 +386,11 @@ def generate_unchained_export(account_num=0): rv['%s_deriv' % name] = dd rv[name] = xp - # sig_deriv = "m/44'/{ct}'/{acc}'".format(ct=chain.b44_cointype, acc=account_num) + "/0/0" - # return ujson.dumps(rv), sig_deriv, AF_CLASSIC - return ujson.dumps(rv), False, False + return ujson.dumps(rv), sign_der, AF_CLASSIC def generate_generic_export(account_num=0): # Generate data that other programers will use to import Coldcard (single-signer) from descriptor import Descriptor, Key - from desc_utils import multisig_descriptor_template chain = chains.current_chain() master_xfp = settings.get("xfp") @@ -407,26 +421,24 @@ def generate_generic_export(account_num=0): xfp = xfp2str(swab32(node.my_fp())) xp = chain.serialize_public(node, AF_CLASSIC) zp = chain.serialize_public(node, fmt) if fmt not in (AF_CLASSIC, AF_P2TR) else None - if is_ms: - desc = multisig_descriptor_template(xp, dd, master_xfp_str, fmt) - else: - key = Key.from_cc_data(master_xfp, dd, xp) - desc_obj = Descriptor(key=key) - desc_obj.set_from_addr_fmt(fmt) - desc = desc_obj.to_string() - - OWNERSHIP.note_wallet_used(fmt, account_num) + key = Key.from_cc_data(master_xfp, dd, xp) + key_exp = key.to_string(external=False, internal=False) rv[name] = OrderedDict(name=atype, xfp=xfp, deriv=dd, xpub=xp, - desc=desc) + key_exp=key_exp) if zp and zp != xp: rv[name]['_pub'] = zp if not is_ms: + desc_obj = Descriptor(key=key, addr_fmt=fmt) + rv[name]['desc'] = desc_obj.to_string() + + OWNERSHIP.note_wallet_used(fmt, account_num) + # bonus/check: first non-change address: 0/0 node.derive(0, False).derive(0, False) rv[name]['first'] = chain.address(node, fmt) @@ -437,14 +449,14 @@ def generate_generic_export(account_num=0): def generate_electrum_wallet(addr_type, account_num): # Generate line-by-line JSON details about wallet. # - # Much reverse enginerring of Electrum here. It's a complex + # Much reverse engineering of Electrum here. It's a complex # legacy file format. chain = chains.current_chain() xfp = settings.get('xfp') - # Must get the derivation path, and the SLIP32 version bytes right! + # Must get the derivation path, and the SLIP132 version bytes right! mode = chains.af_to_bip44_purpose(addr_type) OWNERSHIP.note_wallet_used(addr_type, account_num) @@ -475,63 +487,9 @@ def generate_electrum_wallet(addr_type, account_num): return ujson.dumps(rv), derive + "/0/0", addr_type -async def make_json_wallet(label, func, fname_pattern='new-wallet.json'): - # Record **public** values and helpful data into a JSON file - # - OWNERSHIP.note_wallet_used(..) should be called already by our caller or func - - from glob import dis, NFC - from files import CardSlot, CardMissingError, needs_microsd - from ux import import_export_prompt - from qrs import MAX_V11_CHAR_LIMIT - - dis.fullscreen('Generating...') - json_str, derive, addr_fmt = func() - skip_sig = derive is False and addr_fmt is False - - choice = await import_export_prompt("%s file" % label, is_import=False, - no_qr=(not version.has_qwerty and len(json_str) >= MAX_V11_CHAR_LIMIT)) - - if choice == KEY_CANCEL: - return - elif choice == KEY_NFC: - await NFC.share_json(json_str) - return - elif choice == KEY_QR: - # render as QR and show on-screen - # - on mk4, this isn't offered if more than about 300 bytes because we can't - # show that as a single QR - await export_by_qr(json_str, label, "J") - return - - # choose a filename and save - try: - with CardSlot(**choice) as card: - fname, nice = card.pick_filename(fname_pattern) - - # do actual write - with open(fname, 'wt') as fd: - chunk_writer(fd, json_str) - - if not skip_sig: - h = ngu.hash.sha256s(json_str.encode()) - sig_nice = write_sig_file([(h, fname)], derive, addr_fmt) - - except CardMissingError: - await needs_microsd() - return - except Exception as e: - await ux_show_story('Failed to write!\n\n\n'+str(e)) - return - - msg = '%s file written:\n\n%s' % (label, nice) - if not skip_sig: - msg += '\n\n%s signature file written:\n\n%s' % (label, sig_nice) - - await ux_show_story(msg) - async def make_descriptor_wallet_export(addr_type, account_num=0, mode=None, int_ext=True, - fname_pattern="descriptor.txt"): + fname_pattern="descriptor.txt", direct_way=None): from descriptor import Descriptor, Key from glob import dis @@ -556,8 +514,7 @@ async def make_descriptor_wallet_export(addr_type, account_num=0, mode=None, int dis.progress_bar_show(0.7) key = Key.from_cc_data(xfp, derive, xpub) - desc = Descriptor(key=key) - desc.set_from_addr_fmt(addr_type) + desc = Descriptor(key=key, addr_fmt=addr_type) dis.progress_bar_show(0.8) if int_ext: # with <0;1> notation @@ -571,8 +528,8 @@ async def make_descriptor_wallet_export(addr_type, account_num=0, mode=None, int ) dis.progress_bar_show(1) - await write_text_file(fname_pattern, body, "Descriptor", derive + "/0/0", - addr_type, force_prompt=True) + await export_contents("Descriptor", body, fname_pattern, derive + "/0/0", + addr_type, force_prompt=True, direct_way=direct_way) # EOF diff --git a/shared/files.py b/shared/files.py index 321a2aaa..5b0f3e20 100644 --- a/shared/files.py +++ b/shared/files.py @@ -264,7 +264,7 @@ class CardSlot: self.active_led = self.active_led2 if use_b_slot else self.active_led1 def __enter__(self): - # Mk4: maybe use our virtual disk in preference to SD Card + # maybe use our virtual disk in preference to SD Card if glob.VD and (self.force_vdisk or not self.is_inserted()): self.mountpt = glob.VD.mount(self.readonly) return self diff --git a/shared/flow.py b/shared/flow.py index 5ab306a9..6864bd4e 100644 --- a/shared/flow.py +++ b/shared/flow.py @@ -9,8 +9,7 @@ from glob import settings from actions import * from choosers import * from mk4 import dev_enable_repl -from multisig import make_multisig_menu, import_multisig_nfc -from miniscript import make_miniscript_menu +from wallet import make_miniscript_menu, import_miniscript_nfc from seed import make_ephemeral_seed_menu, make_seed_vault_menu, start_b39_pw from address_explorer import address_explore from drv_entro import drv_entro_start, password_entry @@ -20,9 +19,11 @@ from countdowns import countdown_chooser from paper import make_paper_wallet from trick_pins import TrickPinMenu from tapsigner import import_tapsigner_backup_file +from ccc import toggle_ccc_feature, sssp_spending_policy, sssp_feature_menu # useful shortcut keys from charcodes import KEY_QR, KEY_NFC +from public_constants import AF_P2WPKH_P2SH, AF_P2WPKH # Optional feature: HSM, depends on hardware @@ -39,12 +40,14 @@ if version.has_battery: from battery import battery_idle_timeout_chooser, brightness_chooser from q1 import scan_and_bag from notes import make_notes_menu + from teleport import kt_start_rx, kt_send_file_psbt else: battery_idle_timeout_chooser = None brightness_chooser = None scan_and_bag = None make_notes_menu = None - + kt_start_rx = None + kt_send_file_psbt = None # # NOTE: "Always In Title Case" @@ -70,6 +73,8 @@ def has_secrets(): from pincodes import pa return pa.has_secrets() +qr_and_has_secrets = has_secrets if version.has_qr else False + def nfc_enabled(): from glob import NFC return bool(NFC) @@ -96,6 +101,33 @@ def hsm_available(): # contains hsm feature + can it be used (needs se2 secret and no tmp active) return version.supports_hsm and has_real_secret() +def qr_and_ms(): + # has QR scanner, and at least one MS wallet + if not version.has_qr: return False + return bool(settings.get('miniscript', False)) + +def has_pushtx_url(): + # they want to use PushTX feature + return bool(settings.get("ptxurl", False)) + +# Spending Policy (Hobbled mode) predicates. +# +def is_hobble_testdrive(): + from pincodes import pa + return (pa.hobbled_mode == 2) + +def sssp_related_keys(): + return sssp_spending_policy('okeys') + +def sssp_allow_passphrase(): + return word_based_seed() and sssp_related_keys() + +def sssp_allow_notes(): + return settings.get("secnap", False) and sssp_spending_policy('notes') + +def sssp_allow_vault(): + return settings.master_get('seedvault') and sssp_related_keys() + async def goto_home(*a): goto_top_menu() @@ -137,10 +169,8 @@ SettingsMenu = [ # xxxxxxxxxxxxxxxx MenuItem('Login Settings', menu=LoginPrefsMenu), MenuItem('Hardware On/Off', menu=HWTogglesMenu), - NonDefaultMenuItem('Multisig Wallets', 'multisig', - menu=make_multisig_menu, predicate=has_secrets), NonDefaultMenuItem('Miniscript', 'miniscript', - menu=make_miniscript_menu, predicate=has_secrets), + menu=make_miniscript_menu, predicate=has_secrets, shortcut="m"), NonDefaultMenuItem('NFC Push Tx', 'ptxurl', menu=pushtx_setup_menu), MenuItem('Display Units', chooser=value_resolution_chooser), MenuItem('Max Network Fee', chooser=max_fee_chooser), @@ -157,9 +187,9 @@ The signed transaction will be named .txn, so the file name does not leak MS-DOS tools should not be able to find the PSBT data (ie. undelete), but forensic tools \ which take apart the flash chips of the SDCard may still be able to find the \ data or filenames.'''), - ToggleMenuItem('Menu Wrapping', 'wa', ['Default Off', 'Enable'], + ToggleMenuItem('Menu Wrapping', 'wa', ['Default', 'Always Wrap'], story='''When enabled, allows scrolling past menu top/bottom \ -(wrap around). By default, this only happens in very large menus.'''), +(wrap around). By default, this only happens in menus whose length is greater than 10.'''), ToggleMenuItem('Home Menu XFP', 'hmx', ['Only Tmp', 'Always Show'], story=('Forces display of XFP (seed fingerprint) ' 'at top of main menu. Normally, XFP is shown only when ' @@ -187,17 +217,20 @@ XpubExportMenu = [ WalletExportMenu = [ # xxxxxxxxxxxxxxxx + MenuItem("Sparrow", f=named_generic_skeleton, arg="Sparrow"), + MenuItem("Cove", f=named_generic_skeleton, arg="Cove"), MenuItem("Bitcoin Core", f=bitcoin_core_skeleton), - MenuItem("Fully Noded", f=named_generic_skeleton, arg="Fully Noded"), - MenuItem("Sparrow Wallet", f=named_generic_skeleton, arg="Sparrow"), MenuItem("Nunchuk", f=named_generic_skeleton, arg="Nunchuk"), + MenuItem("Bull Bitcoin", f=ss_descriptor_skeleton, + arg=(True, [AF_P2WPKH], "", "bull-bitcoin.txt", KEY_QR)), MenuItem("Zeus", f=ss_descriptor_skeleton, - arg=(True, [AF_P2WPKH, AF_P2WPKH_P2SH], "Zeus Wallet", "zeus-export.txt")), + arg=(True, [AF_P2WPKH, AF_P2WPKH_P2SH], "Zeus Wallet", "zeus-export.txt", None)), MenuItem("Electrum Wallet", f=electrum_skeleton), - MenuItem("Theya", f=named_generic_skeleton, arg="Theya"), MenuItem("Wasabi Wallet", f=wasabi_skeleton), + MenuItem("Fully Noded", f=named_generic_skeleton, arg="Fully Noded"), MenuItem("Unchained", f=unchained_capital_export), - MenuItem("Lily Wallet", f=named_generic_skeleton, arg="Lily"), + MenuItem("Theya", f=named_generic_skeleton, arg="Theya"), + MenuItem("Bitcoin Safe", f=named_generic_skeleton, arg="Bitcoin Safe"), MenuItem("Samourai Postmix", f=samourai_post_mix_descriptor_export), MenuItem("Samourai Premix", f=samourai_pre_mix_descriptor_export), # MenuItem("Samourai BadBank", f=samourai_bad_bank_descriptor_export), # not released yet @@ -215,6 +248,7 @@ FileMgmtMenu = [ MenuItem('Export Wallet', predicate=has_secrets, menu=WalletExportMenu), #dup elsewhere MenuItem('Sign Text File', predicate=has_secrets, f=sign_message_on_sd), MenuItem('Batch Sign PSBT', predicate=has_secrets, f=batch_sign), + MenuItem('Teleport Miniscript PSBT', predicate=qr_and_has_secrets, f=kt_send_file_psbt), MenuItem('List Files', f=list_files), MenuItem('Verify Sig File', f=verify_sig_file), MenuItem('NFC File Share', predicate=nfc_enabled, f=nfc_share_file, shortcut=KEY_NFC), @@ -236,8 +270,9 @@ DevelopersMenu = [ # xxxxxxxxxxxxxxxx MenuItem("Serial REPL", f=dev_enable_repl), MenuItem('Warm Reset', f=reset_self), - MenuItem("Restore Txt Bkup", f=restore_everything_cleartext), - MenuItem("BKPW Override", menu=bkpw_override), + MenuItem("Restore Bkup", f=restore_backup_dev), + MenuItem("BKPW Override", menu=bkpw_override, predicate=has_secrets), + MenuItem('Reflash GPU', f=reflash_gpu, predicate=version.has_qwerty), ] AdvancedVirginMenu = [ # No PIN, no secrets yet (factory fresh) @@ -254,6 +289,7 @@ AdvancedPinnedVirginMenu = [ # Has PIN but no secrets yet MenuItem("Temporary Seed", menu=make_ephemeral_seed_menu), MenuItem("Upgrade Firmware", menu=UpgradeMenu, predicate=is_not_tmp), MenuItem("File Management", menu=FileMgmtMenu), + MenuItem("Key Teleport (start)", f=kt_start_rx, predicate=version.has_qr), MenuItem('Paper Wallets', f=make_paper_wallet), MenuItem('Perform Selftest', f=start_selftest), MenuItem("I Am Developer.", menu=maybe_dev_menu), @@ -329,7 +365,6 @@ correctly- crafted transactions signed on Testnet could be broadcast on Mainnet. MenuItem('Settings Space', f=show_settings_space), MenuItem('MCU Key Slots', f=show_mcu_keys_left), MenuItem('Bless Firmware', f=bless_flash), # no need for this anymore? - MenuItem('Reflash GPU', f=reflash_gpu, predicate=version.has_qwerty), MenuItem("Wipe LFS", f=wipe_filesystem), # kills other-seed settings, HSM stuff, addr cache ] @@ -337,7 +372,7 @@ BackupStuffMenu = [ # xxxxxxxxxxxxxxxx MenuItem("Backup System", f=backup_everything), MenuItem("Verify Backup", f=verify_backup), - MenuItem("Restore Backup", f=restore_everything), # just a redirect really + MenuItem("Restore Backup", f=need_clear_seed), # just a UX msg really MenuItem('Clone Coldcard', predicate=has_secrets, f=clone_write_data), ] @@ -348,8 +383,21 @@ NFCToolsMenu = [ MenuItem('Verify Sig File', f=nfc_sign_verify), MenuItem('Verify Address', f=nfc_address_verify), MenuItem('File Share', f=nfc_share_file), - MenuItem('Import Multisig', f=import_multisig_nfc), - MenuItem('Push Transaction', f=nfc_pushtx_file, predicate=lambda: settings.get("ptxurl", False)), + MenuItem('Import Miniscript', f=import_miniscript_nfc), + MenuItem('Push Transaction', f=nfc_pushtx_file, predicate=has_pushtx_url), +] + + +SpendingPolicySubMenu = [ + NonDefaultMenuItem('Single-Signer', 'sssp', f=sssp_feature_menu, predicate=has_real_secret), + NonDefaultMenuItem('Co-Sign Multi.' if not version.has_qwerty else 'Co-Sign Multisig (CCC)', + 'ccc', f=toggle_ccc_feature, predicate=is_not_tmp), + ToggleMenuItem('HSM Mode', 'hsmcmd', ['Default Off', 'Enable'], + story=("Enable HSM? Enables all user management commands, and other HSM-only USB commands. " + "By default these commands are disabled."), + predicate=hsm_available), + MenuItem('User Management', menu=make_users_menu, + predicate=lambda: hsm_available() and settings.get('hsmcmd', False)), ] AdvancedNormalMenu = [ @@ -364,13 +412,9 @@ AdvancedNormalMenu = [ f=drv_entro_start), MenuItem("View Identity", f=view_ident), MenuItem("Temporary Seed", menu=make_ephemeral_seed_menu), + MenuItem("Key Teleport (start)", f=kt_start_rx, predicate=version.has_qr), + MenuItem("Spending Policy", menu=SpendingPolicySubMenu,shortcut='s',predicate=has_real_secret), MenuItem('Paper Wallets', f=make_paper_wallet), - ToggleMenuItem('Enable HSM', 'hsmcmd', ['Default Off', 'Enable'], - story=("Enable HSM? Enables all user management commands, and other HSM-only USB commands. " - "By default these commands are disabled."), - predicate=hsm_available), - MenuItem('User Management', menu=make_users_menu, - predicate=hsm_available), MenuItem('NFC Tools', predicate=nfc_enabled, menu=NFCToolsMenu, shortcut=KEY_NFC), MenuItem("Danger Zone", menu=DangerZoneMenu, shortcut='z'), ] @@ -379,7 +423,7 @@ AdvancedNormalMenu = [ VirginSystem = [ # xxxxxxxxxxxxxxxx MenuItem('Choose PIN Code', f=initial_pin_setup), - MenuItem('Advanced/Tools', menu=AdvancedVirginMenu), + MenuItem('Advanced/Tools', menu=AdvancedVirginMenu, shortcut='t'), MenuItem('Bag Number', f=show_bag_number), MenuItem('Help', f=virgin_help, predicate=not version.has_qwerty), ] @@ -390,7 +434,7 @@ ImportWallet = [ MenuItem("24 Words", menu=start_seed_import, arg=24), MenuItem('Scan QR Code', predicate=version.has_qr, shortcut=KEY_QR, f=scan_any_qr, arg=(True, False)), - MenuItem("Restore Backup", f=restore_everything), + MenuItem("Restore Backup", f=restore_backup, arg=False), # tmp=False MenuItem("Clone Coldcard", menu=clone_start), MenuItem("Import XPRV", f=import_xprv, arg=False), # ephemeral=False MenuItem("Tapsigner Backup", f=import_tapsigner_backup_file, arg=False), @@ -414,9 +458,11 @@ EmptyWallet = [ MenuItem('New Seed Words', menu=NewSeedMenu), MenuItem('Import Existing', menu=ImportWallet), MenuItem("Migrate Coldcard", menu=clone_start), + MenuItem("Key Teleport (start)", f=kt_start_rx, predicate=version.has_qr), MenuItem('Help', f=virgin_help, predicate=not version.has_qwerty), - MenuItem('Advanced/Tools', menu=AdvancedPinnedVirginMenu), + MenuItem('Advanced/Tools', menu=AdvancedPinnedVirginMenu, shortcut='t'), MenuItem('Settings', menu=SettingsMenu), + ShortcutItem(KEY_QR, predicate=version.has_qr, f=scan_any_qr, arg=(True, False)), ] # In operation, normal system, after a good PIN received. @@ -443,10 +489,78 @@ NormalSystem = [ # Shown until unit is put into a numbered bag FactoryMenu = [ - MenuItem('Version: ' + version.get_mpy_version()[1], f=show_version), MenuItem('Bag Me Now', f=scan_and_bag), + MenuItem('Version: ' + version.get_mpy_version()[1], f=show_version), MenuItem('DFU Upgrade', f=start_dfu, shortcut='u'), MenuItem('Ship W/O Bag', f=ship_wo_bag), MenuItem("Debug Functions", menu=DebugFunctionsMenu, shortcut='f'), MenuItem("Perform Selftest", f=start_selftest, shortcut='s'), ] + +# Special menus for hobbled mode where we have a (single signer) spending policy in effect. +# - no access to secrets, backups, firmware up/downgrades. +# - secure notes, but readonly; can be disabled completely. +# - key teleport, but only for PSBT & multisig purposes. +# - can only be enabled after we have secrets, so no need for has_secrets tests here +# + +# Slightly limited file menu when hobbled. +# - no backup/restore +HobbledFileMgmtMenu = [ + # xxxxxxxxxxxxxxxx + MenuItem('Sign Text File', f=sign_message_on_sd), + MenuItem('Batch Sign PSBT', f=batch_sign), + MenuItem('List Files', f=list_files), + MenuItem('Export Wallet', menu=WalletExportMenu), # dup under Adv/Tools + MenuItem('Verify Sig File', f=verify_sig_file), + MenuItem('NFC File Share', predicate=nfc_enabled, f=nfc_share_file, shortcut=KEY_NFC), + MenuItem('BBQr File Share', predicate=version.has_qr, f=qr_share_file, arg=True), + MenuItem('QR File Share', predicate=version.has_qr, f=qr_share_file, shortcut=KEY_QR), + MenuItem('Format SD Card', f=wipe_sd_card), + MenuItem('Format RAM Disk', predicate=vdisk_enabled, f=wipe_vdisk), +] + +# NFC tools when hobbled: not much different. +HobbledNFCToolsMenu = [ + MenuItem('Sign PSBT', f=nfc_sign_psbt), + MenuItem('Show Address', f=nfc_show_address), + MenuItem('Sign Message', f=nfc_sign_msg), + MenuItem('Verify Sig File', f=nfc_sign_verify), + MenuItem('Verify Address', f=nfc_address_verify), + MenuItem('File Share', f=nfc_share_file), + MenuItem('Push Transaction', f=nfc_pushtx_file, predicate=has_pushtx_url), +] + +# Very limited advanced menu when hobbled. +HobbledAdvancedMenu = [ + # xxxxxxxxxxxxxxxx + MenuItem("File Management", menu=HobbledFileMgmtMenu), + MenuItem('Export Wallet', menu=WalletExportMenu, shortcut='x'), # also inside FileMgmt + MenuItem('Teleport Miniscript PSBT', predicate=qr_and_ms, f=kt_send_file_psbt), + MenuItem("View Identity", f=view_ident), + MenuItem("Temporary Seed", menu=make_ephemeral_seed_menu, predicate=sssp_related_keys), + MenuItem('Paper Wallets', f=make_paper_wallet), + MenuItem('NFC Tools', predicate=nfc_enabled, menu=HobbledNFCToolsMenu, shortcut=KEY_NFC), + MenuItem('Show %s Version' % ("Firmware" if version.has_qwerty else "FW"), f=show_version), + MenuItem("Destroy Seed", f=clear_seed, predicate=has_real_secret), +] + +# Main menu when a spending policy (hobbled) is in effect. +HobbledTopMenu = [ + # xxxxxxxxxxxxxxxx + MenuItem('Ready To Sign', f=ready2sign, shortcut='r'), + MenuItem('Passphrase', menu=start_b39_pw, predicate=sssp_allow_passphrase, shortcut='p'), + MenuItem('Scan Any QR Code', predicate=version.has_qr, f=scan_any_qr, arg=(False, True), + shortcut=KEY_QR), + MenuItem("Address Explorer", menu=address_explore, shortcut='x'), + MenuItem('Secure Notes & Passwords', menu=make_notes_menu, predicate=sssp_allow_notes, + shortcut='n'), + MenuItem('Type Passwords', f=password_entry, shortcut='t', + predicate=lambda: settings.get("emu", False) and sssp_related_keys()), + MenuItem('Seed Vault', menu=make_seed_vault_menu, predicate=sssp_allow_vault, + shortcut='v'), + MenuItem('Advanced/Tools', menu=HobbledAdvancedMenu, shortcut='t'), + MenuItem('Secure Logout', f=logout_now, predicate=not version.has_battery), + MenuItem('EXIT TEST DRIVE', f=sssp_feature_menu, predicate=is_hobble_testdrive), + ShortcutItem(KEY_NFC, predicate=nfc_enabled, menu=HobbledNFCToolsMenu), +] diff --git a/shared/glob.py b/shared/glob.py index 0c30e97d..101f9865 100644 --- a/shared/glob.py +++ b/shared/glob.py @@ -29,4 +29,9 @@ NFC = None # QR scanner (Q1 only) SCAN = None +# Miniscript descriptor cache +# mapping from unique miniscript wallet name to Descriptor object +# cache size = 1 +DESC_CACHE = {} + # EOF diff --git a/shared/gpu.py b/shared/gpu.py index 4e092468..35da5b1c 100644 --- a/shared/gpu.py +++ b/shared/gpu.py @@ -8,7 +8,6 @@ # import utime, struct import uasyncio as asyncio -from utils import B2A from machine import Pin from ustruct import pack diff --git a/shared/history.py b/shared/history.py index bccccde4..479d2580 100644 --- a/shared/history.py +++ b/shared/history.py @@ -18,7 +18,7 @@ from glob import settings # - 8 bytes exact satoshi value => base64 (pad trimmed) => 11 chars # - stored satoshi value is XOR'ed with LSB from prevout txn hash, which isn't stored # - result is a 31 character string for each history entry, plus 4 overhead => 35 each -# - if we store 30 of those it's about 25% of total setting space +# - if we store 30 of those it's about 25% of total setting space (Mk3) # HISTORY_SAVED = const(30) HISTORY_MAX_MEM = const(128) @@ -132,7 +132,7 @@ class OutptValueCache: # save new addition assert len(key) == ENCKEY_LEN - assert amount > 0 + # assert amount > 0 entry = key + cls.encode_value(prevout, amount) cls.runtime_cache.append(entry) diff --git a/shared/hsm.py b/shared/hsm.py index 7b999207..4f153f5b 100644 --- a/shared/hsm.py +++ b/shared/hsm.py @@ -6,12 +6,12 @@ # import ustruct, chains, sys, gc, uio, ujson, uos, utime, ckcc, ngu from utils import problem_file_line, cleanup_deriv_path, match_deriv_path +from utils import cleanup_payment_address from pincodes import AE_LONG_SECRET_LEN from stash import blank_object from users import Users, MAX_NUMBER_USERS, calc_local_pincode from public_constants import MAX_USERNAME_LEN -from multisig import MultisigWallet -from miniscript import MiniScriptWallet +from wallet import MiniScriptWallet from ubinascii import hexlify as b2a_hex from uhashlib import sha256 from ucollections import OrderedDict @@ -69,9 +69,9 @@ def restore_backup(s): with open(POLICY_FNAME, 'wt') as f: f.write(s) - except BaseException as exc: + except: # keep going, we don't want to brick - sys.print_exception(exc) + # sys.print_exception(exc) pass def pop_list(j, fld_name, cleanup_fcn=None): @@ -148,22 +148,6 @@ def assert_empty_dict(j): if extra: raise ValueError("Unknown item: " + ', '.join(extra)) -def cleanup_whitelist_value(s): - # one element in a list of addresses or paths or descriptors? - # - later matching is string-based, so just doing basic syntax check here - # - must be checksumed-base58 or bech32 - try: - ngu.codecs.b58_decode(s) - return s - except: pass - - try: - ngu.codecs.segwit_decode(s) - return s - except: pass - - raise ValueError('bad whitelist value: ' + s) - class WhitelistOpts: # contains various options related to whitelisting @@ -194,7 +178,7 @@ class ApprovalRule: # - users: list of authorized users # - min_users: how many of those are needed to approve # - local_conf: local user must also confirm w/ code - # - wallet: which multisig/miniscript wallet to restrict to, or '1' for single signer only + # - wallet: which miniscript wallet to restrict to, or '1' for single signer only # - min_pct_self_transfer: minimum percentage of own input value that must go back to self # - patterns: list of transaction patterns to check for. Valid values: # * EQ_NUM_INS_OUTS: the number of inputs and outputs must be equal @@ -211,11 +195,10 @@ class ApprovalRule: return u self.index = idx+1 - self.ms_type = "multisig" self.per_period = pop_int(j, 'per_period', 0, MAX_SATS) self.max_amount = pop_int(j, 'max_amount', 0, MAX_SATS) self.users = pop_list(j, 'users', check_user) - self.whitelist = pop_list(j, 'whitelist', cleanup_whitelist_value) + self.whitelist = pop_list(j, 'whitelist', cleanup_payment_address) self.whitelist_opts = pop_dict(j, 'whitelist_opts', False, WhitelistOpts) self.min_users = pop_int(j, 'min_users', 1, len(self.users)) self.local_conf = pop_bool(j, 'local_conf') @@ -236,13 +219,10 @@ class ApprovalRule: # redundant w/ code in pop_int() above assert 1 <= self.min_users <= len(self.users), "range" - # if specified, 'wallet' must be an existing multisig wallet's name + # if specified, 'wallet' must be an existing miniscript wallet's name if self.wallet and self.wallet != '1': - ms_names = [ms.name for ms in MultisigWallet.get_all()] - msc_names = [msc.name for msc in MiniScriptWallet.get_all()] - assert self.wallet in (ms_names+msc_names), "unknown wallet: "+self.wallet - if self.wallet in msc_names: - self.ms_type = "miniscript" + msc_names = [msc.name for msc in MiniScriptWallet.iter_wallets()] + assert self.wallet in msc_names, "unknown wallet: " + self.wallet # patterns must be valid for p in self.patterns: @@ -288,7 +268,7 @@ class ApprovalRule: if self.wallet == '1': rv += ' (singlesig only)' elif self.wallet: - rv += ' from %s wallet "%s"' % (self.ms_type, self.wallet) + rv += ' from miniscript wallet "%s"' % self.wallet if self.users: rv += ' may be authorized by ' @@ -329,13 +309,10 @@ class ApprovalRule: # Does this rule apply to this PSBT file? if self.wallet: # rule limited to one wallet - if psbt.active_multisig: - # if multisig signing, might need to match specific wallet name - assert self.wallet == psbt.active_multisig.name, 'wrong multisig wallet' - elif psbt.active_miniscript: + if psbt.active_miniscript: assert self.wallet == psbt.active_miniscript.name, 'wrong miniscript wallet' else: - # non multisig, but does this rule apply to all wallets or single-singers + # not miniscript, but does this rule apply to all wallets or single-singers assert self.wallet == '1', 'singlesig only' if self.max_amount is not None: @@ -372,7 +349,7 @@ class ApprovalRule: # we are verifying the whole consensus-encoded txout txo_bytes = CTxOut(txo.nValue, txo.scriptPubKey).serialize() digest = chain.hash_message(txo_bytes) - addr_fmt, pubkey = chains.verify_recover_pubkey(o.attestation, digest) + addr_fmt, pubkey = chains.verify_recover_pubkey(psbt.get(o.attestation), digest) # we have extracted a valid pubkey from the sig, but is it # a whitelisted pubkey or something else? ver_addr = chain.pubkey_to_address(pubkey, addr_fmt) @@ -395,11 +372,11 @@ class ApprovalRule: # check the self-transfer percentage if self.min_pct_self_transfer: - own_in_value = sum([i.amount for i in psbt.inputs if i.num_our_keys]) + own_in_value = sum([i.amount for i in psbt.inputs if i.sp_idxs]) own_out_value = 0 for idx, txo in psbt.output_iter(): o = psbt.outputs[idx] - if o.num_our_keys: + if o.sp_idxs: own_out_value += txo.nValue percentage = (float(own_out_value) / own_in_value) * 100.0 assert percentage >= self.min_pct_self_transfer, 'does not meet self transfer threshold, expected: %.2f, actual: %.2f' % (self.min_pct_self_transfer, percentage) @@ -410,8 +387,8 @@ class ApprovalRule: assert len(psbt.inputs) == len(psbt.outputs), 'unequal number of inputs and outputs' if "EQ_NUM_OWN_INS_OUTS" in self.patterns: - own_ins = sum([1 for i in psbt.inputs if i.num_our_keys]) - own_outs = sum([1 for o in psbt.outputs if o.num_our_keys]) + own_ins = sum([1 for i in psbt.inputs if i.sp_idxs]) + own_outs = sum([1 for o in psbt.outputs if o.sp_idxs]) assert own_ins == own_outs, 'unequal number of own inputs and outputs' if "EQ_OUT_AMOUNTS" in self.patterns: @@ -511,7 +488,7 @@ class HSMPolicy: # a list of paths we can accept for signing self.msg_paths = pop_deriv_list(j, 'msg_paths', ['any']) self.share_xpubs = pop_deriv_list(j, 'share_xpubs', ['any']) - self.share_addrs = pop_deriv_list(j, 'share_addrs', ['p2sh', 'any', 'msas']) + self.share_addrs = pop_deriv_list(j, 'share_addrs', ['any', 'msas']) # free text shown at top self.notes = pop_string(j, 'notes', 1, 80) @@ -596,7 +573,7 @@ class HSMPolicy: fd.write('\n') def plist(pl): - remap = {'any': '(any path)', 'p2sh': '(any P2SH)' } + remap = {'any': '(any path)', 'msas': '(any miniscript)' } return ' OR '.join(remap.get(i, i) for i in pl) fd.write('\nMessage signing:\n') @@ -626,7 +603,7 @@ class HSMPolicy: fd.write('- XPUB values will be shared, if path matches: m OR %s.\n' % plist(self.share_xpubs)) if self.share_addrs: - fd.write('- Address values values will be shared, if path matches: %s.\n' + fd.write('- Address values will be shared, if path matches: %s.\n' % plist(self.share_addrs)) if self.priv_over_ux: fd.write('- Status responses optimized for privacy.\n') @@ -819,7 +796,7 @@ class HSMPolicy: return match_deriv_path(self.share_xpubs, subpath) - def approve_address_share(self, subpath=None, is_p2sh=False, miniscript=False): + def approve_address_share(self, subpath=None, miniscript=False): # Are we allowing "show address" requests over USB? if not self.share_addrs: @@ -828,9 +805,6 @@ class HSMPolicy: if miniscript: return ('msas' in self.share_addrs) - if is_p2sh: - return ('p2sh' in self.share_addrs) - return match_deriv_path(self.share_addrs, subpath) @property @@ -960,7 +934,7 @@ class HSMPolicy: return 'y' except BaseException as exc: - sys.print_exception(exc) + # sys.print_exception(exc) err = "Rejected: " + (str(exc) or problem_file_line(exc)) self.refuse(log, err) @@ -1003,8 +977,7 @@ def hsm_status_report(): rv['approval_wait'] = True rv['users'] = Users.list() - rv['wallets'] = [ms.name for ms in MultisigWallet.get_all()] \ - + [msc.name for msc in MiniScriptWallet.get_all()] + rv['wallets'] = [msc.name for msc in MiniScriptWallet.iter_wallets()] rv['chain'] = settings.get('chain', 'BTC') diff --git a/shared/hsm_ux.py b/shared/hsm_ux.py index 5cc4fb91..f34f4370 100644 --- a/shared/hsm_ux.py +++ b/shared/hsm_ux.py @@ -67,7 +67,7 @@ Press %s to save policy and enable HSM mode.''' % (self.policy.hash(), confirm_c except BaseException as exc: self.failed = "Exception" - sys.print_exception(exc) + # sys.print_exception(exc) self.refused = True self.ux_done = True @@ -297,7 +297,7 @@ class hsmUxInteraction: # replacements for display.py:Display functions - def hack_fullscreen(self, msg, percent=None): + def hack_fullscreen(self, msg, percent=None, **kwargs): self.draw_busy(msg, percent) def hack_progress_bar(self, percent): self.draw_busy(None, percent) @@ -354,7 +354,7 @@ class hsmUxInteraction: await sleep_ms(100) except BaseException as exc: # just in case, keep going - sys.print_exception(exc) + # sys.print_exception(exc) continue # do the interactions, but don't let user actually press anything diff --git a/shared/imptask.py b/shared/imptask.py index 6979854c..297415eb 100644 --- a/shared/imptask.py +++ b/shared/imptask.py @@ -58,8 +58,8 @@ class ImportantTask: else: # uncaught exception in an unnamed (and unimportant) task print("UNNAMED: " + context["message"]) - sys.print_exception(context["exception"]) - print("... future: %r" % context.get("future", '?')) + sys.print_exception(context["exception"]) # VERY USEFUL on sim + #print("... future: %r" % context.get("future", '?')) def start_task(self, name, awaitable): # start a critical task and watch for it to never die diff --git a/shared/lcd_display.py b/shared/lcd_display.py index 7ae67cb4..de601c23 100644 --- a/shared/lcd_display.py +++ b/shared/lcd_display.py @@ -154,7 +154,7 @@ class Display: # otherwise: respect setting if on_battery is None: - on_battery = (get_batt_threshold() != None) + on_battery = (get_batt_threshold() is not None) if on_battery: # user-defined brightness when running on batteries. @@ -190,7 +190,7 @@ class Display: self.image(165, 0, 'tmp_%d' % kws['tmp']) xfp = kws.get('xfp', None) # expects an integer - if xfp != None: + if xfp is not None: x = 217 for ch in xfp2str(xfp).lower(): self.image(x, 0, 'ch_'+ch) @@ -268,7 +268,7 @@ class Display: if x is None or x < 0: w = self.width(msg) - if x == None: + if x is None: # center: also blanks rest of line x = max(0, (CHARS_W - w) // 2) end_x = x + w @@ -622,7 +622,8 @@ class Display: # title ... but we have no special font? Inverse! self.text(0, y, ' '+ln[1:]+' ', invert=True) if hint_icons: - # maybe show that [QR] can do something + # hint_icons not shown if is story without title + # maybe show that [QR,NFC] can do something self.text(-1, y, hint_icons, dark=True) elif ln and ln[0] == OUT_CTRL_ADDRESS: @@ -641,10 +642,10 @@ class Display: def _draw_addr(self, y, addr, prev_x=None): # Draw a single-line of an address - # - use prev_x=0 to start centered + # - use prev_x=0 to start centered if prev_x is None: # left justify (for stories) - prev_x = x = 1 + prev_x = x = 1 elif prev_x == 0: # center first line, following line(s) will be left-justified to match that prev_x = x = max(((CHARS_W - (len(addr) * 5) // 4) // 2), 0) @@ -655,7 +656,61 @@ class Display: return prev_x - def draw_qr_display(self, qr_data, msg, is_alnum, sidebar, idx_hint, invert, partial_bar=None, is_addr=False): + @staticmethod + def handle_qr_msg(msg, max_lines=False): + if len(msg) <= CHARS_W: + parts = [msg] + elif ' ' not in msg and (len(msg) <= (CHARS_W * 2)): + # fits in two lines, but has no spaces + hh = len(msg) // 2 + parts = [msg[0:hh], msg[hh:]] + else: + if not max_lines: + # do word wrap + parts = list(word_wrap(msg, CHARS_W)) + else: + # 2 lines max + parts = [msg[:30] + "⋯", "⋯" + msg[-30:]] + + return parts + + def draw_qr_lines(self, lines, is_addr): + y = CHARS_H - len(lines) + prev_x = 0 + for line in lines: + if not is_addr: + self.text(None, y, line) + else: + prev_x = self._draw_addr(y, line, prev_x=prev_x) + y += 1 + + def draw_qr_idx_hint(self, str_idx): + lh = len(str_idx) + assert lh <= 10 + if lh > 5: + # needs 2 lines + self.text(-1, 0, str_idx[:5]) + self.text(-1, 1, str_idx[5:]) + else: + self.text(-1, 0, str_idx) + + def draw_qr_error(self, idx_hint, msg=None): + x = 85 + y = 30 + w = 150 + self.clear() + self.dis.fill_rect(x, y, w, w, COL_TEXT) + self.dis.fill_rect(x + 1, y + 1, w - 2, w - 2) # Black + self.text(12, 3, "QR too big") + if msg: + lines = self.handle_qr_msg(msg, max_lines=True) + self.draw_qr_lines(lines, False) + + self.draw_qr_idx_hint(idx_hint) + self.show() + + def draw_qr_display(self, qr_data, msg, is_alnum, sidebar, idx_hint, invert, partial_bar=None, + is_addr=False, force_msg=False, is_change=False): # Show a QR code on screen w/ some text under it # - invert not supported on Q1 # - sidebar not supported here (see users.py) @@ -675,16 +730,7 @@ class Display: # p2wsh address would need 3 lines to show, so we won't num_lines = 0 elif msg: - if len(msg) <= CHARS_W: - parts = [msg] - elif ' ' not in msg and (len(msg) <= CHARS_W*2): - # fits in two lines, but has no spaces - hh = len(msg) // 2 - parts = [msg[0:hh], msg[hh:]] - else: - # do word wrap - parts = list(word_wrap(msg, CHARS_W)) - + parts = self.handle_qr_msg(msg) num_lines = len(parts) else: num_lines = 0 @@ -705,25 +751,21 @@ class Display: fullscreen = False trim_lines = 0 - if w == 77: - # v15 => 77px x 3: 77*3 = 231px - expand = 3 - num_lines = 0 - fullscreen = True - elif w in (109, 113, 117): - # v23 => 109px x 2 = 218px - # v24 => 113px x 2 = 226px - # v25 => 117px x 2 = 234px - expand = 2 - num_lines = 0 - fullscreen = True - elif expand == 1 and num_lines: - # Maybe loose the text lines? - expand2 = max(1, ACTIVE_H // (w+2)) - if expand2 > expand: - # v18,v19,v20,v21,v22 + # always try to show the biggest possible QR code if not force_msg + if not force_msg: + if num_lines: + # better with text dropped? + e2 = max(1, ACTIVE_H // (w + 2)) + if e2 > expand: + num_lines = 0 + expand = e2 + + # fullscreen ? + e3 = (ACTIVE_H + 20) // (w + 2) + if expand < e3: + expand = e3 + fullscreen = True num_lines = 0 - expand = expand2 # vert center in available space qw = (w+2) * expand @@ -757,24 +799,17 @@ class Display: if num_lines: # centered text under that - y = CHARS_H - num_lines - prev_x = 0 - for line in parts: - if not is_addr: - self.text(None, y, line) - else: - prev_x = self._draw_addr(y, line, prev_x=prev_x) - y += 1 + self.draw_qr_lines(parts, is_addr) if idx_hint: - lh = len(idx_hint) - assert lh <= 10 - if lh > 5: - # needs 2 lines - self.text(-1, 0, idx_hint[:5]) - self.text(-1, 1, idx_hint[5:]) - else: - self.text(-1, 0, idx_hint) + self.draw_qr_idx_hint(idx_hint) + + if is_addr and is_change: + for i, c in enumerate("CHANGE", start=4): + self.text(1, i, c) + + for i, c in enumerate("BACK", start=6): + self.text(-1, i, c) # pass a max brightness flag here, which will be cleared after next show self.show(max_bright=True) @@ -809,8 +844,12 @@ class Display: else: pat = '' # clear line - self.text(None, -3, pat) + if count == hdr.num_parts and count == 1: + # skip the BS, it's a simple one + self.progress_bar_show(1) + return + self.text(None, -3, pat) self.text(None, -2, 'Keep scanning more...' if count < hdr.num_parts else 'Got all parts!') self.text(None, -1, '%s: %d of %d parts' % (hdr.file_label(), count, hdr.num_parts), dark=True) diff --git a/shared/login.py b/shared/login.py index ed6b64a8..97da5b25 100644 --- a/shared/login.py +++ b/shared/login.py @@ -181,14 +181,22 @@ class LoginUX: async def we_are_ewaste(self, num_fails): msg = '''After %d failed PIN attempts this Coldcard is locked forever. \ By design, there is no way to reset or recover the secure element, and its contents \ -are now forever inaccessible. +are now forever inaccessible.\n\n''' % num_fails -Restore your seed words onto a new Coldcard.''' % num_fails + if has_qwerty: + msg += 'Calculator mode starts now.' + else: + msg += 'Restore your seed words onto a new Coldcard.' while 1: ch = await ux_show_story(msg, title='I Am Brick!', escape='6') if ch == '6': break + if has_qwerty: + from calc import login_repl + await login_repl() + + async def confirm_attempt(self, attempts_left, value): ch = await ux_show_story('''You have %d attempts left before this Coldcard BRICKS \ @@ -270,7 +278,7 @@ suffix break point is correct.\n\n''' return await self.interact() - async def get_new_pin(self, title, story=None, allow_clear=False): + async def get_new_pin(self, title=None, story=None): # Do UX flow to get new (or change) PIN. Always does the double-entry thing self.is_setting = True @@ -283,10 +291,6 @@ suffix break point is correct.\n\n''' first_pin = await self.interact() if first_pin is None: return None - if allow_clear and first_pin == '999999-999999': - # don't make them repeat the 'clear pin' value - return first_pin - self.is_repeat = True while 1: diff --git a/shared/main.py b/shared/main.py index 870bd7e1..afacb7e2 100644 --- a/shared/main.py +++ b/shared/main.py @@ -61,9 +61,7 @@ try: from psram import PSRAMWrapper glob.PSRAM = PSRAMWrapper() -except BaseException as exc: - sys.print_exception(exc) - # continue tho +except: pass # continue tho # Setup keypad/keyboard if version.has_qwerty: @@ -83,7 +81,6 @@ glob.settings = settings async def more_setup(): # Boot up code; splash screen is being shown - try: from files import CardSlot CardSlot.setup() @@ -91,6 +88,10 @@ async def more_setup(): # This "pa" object holds some state shared w/ bootloader about the PIN try: from pincodes import pa + # check for bricked system early + # bricked CC not going past this point + await pa.enforce_brick() + pa.setup(b'') # just to see where we stand. is_blank = pa.is_blank() except RuntimeError as e: diff --git a/shared/manifest.py b/shared/manifest.py index b569eb3b..6699aa78 100644 --- a/shared/manifest.py +++ b/shared/manifest.py @@ -1,6 +1,6 @@ # Freeze everything in this list. # - not optimized because we need asserts to work -# - for specific boards, see manifest_mk[34].py and manifest_q1.py +# - for specific boards, see manifest_{mk4,q1}.py freeze_as_mpy('', [ 'actions.py', 'address_explorer.py', @@ -8,6 +8,7 @@ freeze_as_mpy('', [ 'backups.py', 'bsms.py', 'callgate.py', + 'ccc.py', 'chains.py', 'choosers.py', 'compat7z.py', @@ -28,17 +29,24 @@ freeze_as_mpy('', [ 'login.py', 'main.py', 'menu.py', - 'miniscript.py', + "miniscript.py", + 'mk4.py', + 'msgsign.py', 'multisig.py', + 'ndef.py', + 'nfc.py', 'numpad.py', 'nvstore.py', 'opcodes.py', + 'ownership.py', 'paper.py', 'pincodes.py', + 'precomp_tag_hash.py', 'psbt.py', + 'psram.py', 'pwsave.py', - 'queues.py', 'qrs.py', + 'queues.py', 'random.py', 'seed.py', 'selftest.py', @@ -46,31 +54,33 @@ freeze_as_mpy('', [ 'sffile.py', 'ssd1306.py', 'stash.py', + 'tapsigner.py', + 'trick_pins.py', 'usb.py', 'utils.py', 'ux.py', + 'vdisk.py', 'version.py', - 'xor_seed.py', - 'tapsigner.py', 'wallet.py', - 'ownership.py', + 'web2fa.py', + 'xor_seed.py' ], opt=0) # Optimize data-like files, since no need to debug them. freeze_as_mpy('', [ - 'sigheader.py', - 'public_constants.py', 'charcodes.py', + 'public_constants.py', + 'sigheader.py', ], opt=3) # Maybe include test code. import os if int(os.environ.get('DEBUG_BUILD', 0)): freeze_as_mpy('', [ + 'dev_helper.py', 'h.py', - 'dev_helper.py', - 'usb_test_commands.py', 'sim_display.py', + 'usb_test_commands.py', ], opt=0) include("$(MPY_DIR)/extmod/uasyncio/manifest.py") diff --git a/shared/manifest_mk4.py b/shared/manifest_mk4.py index 9b062d46..b7ac0c1e 100644 --- a/shared/manifest_mk4.py +++ b/shared/manifest_mk4.py @@ -1,17 +1,11 @@ # Mk4 only files; would not be needed on Mk3 or earlier. freeze_as_mpy('', [ - 'ssd1306.py', - 'mempad.py', - 'psram.py', - 'mk4.py', - 'vdisk.py', - 'nfc.py', - 'ndef.py', - 'trick_pins.py', - 'ux_mk4.py', 'hsm.py', 'hsm_ux.py', + 'mempad.py', + 'ssd1306.py', 'users.py', + 'ux_mk4.py' ], opt=0) # Optimize data-like files, since no need to debug them. diff --git a/shared/manifest_q1.py b/shared/manifest_q1.py index 6d624b80..02370ac0 100644 --- a/shared/manifest_q1.py +++ b/shared/manifest_q1.py @@ -1,29 +1,24 @@ -# Q1/Mk4 only files; would not be needed on Mk3 or earlier. +# Q1 only files; would not be needed on Mk4 freeze_as_mpy('', [ - 'psram.py', - 'mk4.py', - 'q1.py', - 'keyboard.py', - 'scanner.py', - 'bbqr.py', - 'decoders.py', - 'lcd_display.py', - 'st7788.py', - 'gpu.py', - 'vdisk.py', - 'nfc.py', - 'ndef.py', - 'trick_pins.py', - 'ux_q1.py', 'battery.py', - 'notes.py', + 'bbqr.py', 'calc.py', + 'decoders.py', + 'gpu.py', + 'keyboard.py', + 'lcd_display.py', + 'notes.py', + 'q1.py', + 'scanner.py', + 'st7788.py', + 'teleport.py', + 'ux_q1.py' ], opt=0) # Optimize data-like files, since no need to debug them. freeze_as_mpy('', [ - 'graphics_q1.py', 'font_iosevka.py', 'gpu_binary.py', # remove someday? + 'graphics_q1.py', ], opt=3) diff --git a/shared/menu.py b/shared/menu.py index 15ee14c2..ccaa9e50 100644 --- a/shared/menu.py +++ b/shared/menu.py @@ -119,7 +119,7 @@ class ShortcutItem(MenuItem): super().__init__('SHORTCUT', shortcut=key, **kws) class NonDefaultMenuItem(MenuItem): - # Show a checkmark if setting is defined and not the default ... so know know it's set + # Show a checkmark if setting is defined and not the default def __init__(self, label, nvkey, prelogin=False, default_value=None, **kws): super().__init__(label, **kws) self.nvkey = nvkey @@ -182,7 +182,7 @@ class ToggleMenuItem(MenuItem): if self.nvkey == "chain": default = (self.get() == "BTC") else: - default = (self.get(None) == None) + default = (self.get(None) is None) if self.story and default: ch = await ux_show_story(self.story) if ch == 'x': return @@ -306,10 +306,6 @@ class MenuSystem: if fcn and fcn(): checked = True - if not has_qwerty and checked and (len(msg) > 14): - # on mk4 every label longer than 14 will overlap with checkmark - checked = False - if self.multi_selected is not None and (real_idx in self.multi_selected): # ignore length constraint above, we need to visually show that # smthg is selected - in any case @@ -335,9 +331,8 @@ class MenuSystem: if wrap: return True # Do wrap-around (by request from NVK) if longer than the screen itself (on Q), - # for mk4, limit is 16 which hits mostly the seed word menus. - limit = 10 if has_qwerty else 16 - return self.count > limit + # Mk4: same limit + return self.count > 10 def down(self): if self.cursor < self.count-1: @@ -382,7 +377,7 @@ class MenuSystem: self.up() # events - def on_cancel(self): + async def on_cancel(self): # override me if the_ux.pop(): # top of stack (main top-level menu) @@ -393,7 +388,7 @@ class MenuSystem: # if picked is None: # "go back" or cancel or something - self.on_cancel() + await self.on_cancel() else: await picked.activate(self, self.cursor) @@ -406,7 +401,7 @@ class MenuSystem: gc.collect() if self.multi_selected is not None: # multichoice - self.on_cancel() + await self.on_cancel() return ch await self.activate(ch) diff --git a/shared/miniscript.py b/shared/miniscript.py index 8dffa649..497d7bc3 100644 --- a/shared/miniscript.py +++ b/shared/miniscript.py @@ -2,762 +2,12 @@ # # Copyright (c) 2020 Stepan Snigirev MIT License embit/miniscript.py # -import ngu, ujson, uio, chains, ure, version -from ucollections import OrderedDict +import ngu from binascii import unhexlify as a2b_hex from binascii import hexlify as b2a_hex -from serializations import ser_compact_size, ser_string -from desc_utils import Key, read_until, fill_policy, append_checksum +from serializations import ser_compact_size +from desc_utils import Key, read_until from public_constants import MAX_TR_SIGNERS -from wallet import BaseStorageWallet -from menu import MenuSystem, MenuItem -from ux import ux_show_story, ux_confirm, ux_dramatic_pause -from files import CardSlot, CardMissingError, needs_microsd -from utils import problem_file_line, xfp2str, to_ascii_printable, swab32, show_single_address -from charcodes import KEY_QR, KEY_CANCEL, KEY_NFC, KEY_ENTER - - -class MiniscriptException(ValueError): - pass - - -class MiniScriptWallet(BaseStorageWallet): - key_name = "miniscript" - - def __init__(self, desc=None, policy=None, keys=None, key=None, - af=None, name=None, taproot=False, sh=False, wsh=False, - wpkh=False, chain_type=None): - super().__init__(chain_type=chain_type) - self._policy = policy - self._keys = keys - self._key = key - self._af = af - self._taproot = taproot - self._sh = sh - self._wsh = wsh - self._wpkh = wpkh - self._desc = desc - self.name = name - - @property - def policy(self): - if not self._policy: - self._policy = self.desc.storage_policy() - return self._policy - - @property - def keys(self): - if not self._keys: - self._keys = self.desc.keys - if self._keys is not None: - self._keys = [k.to_string() for k in self._keys] - return self._keys - - @property - def key(self): - if not self._key: - self._key = self.desc.key - if self._key is not None: - self._key = self._key.to_string() - return self._key - - @property - def addr_fmt(self): - if not self._af: - self._af = self.desc.addr_fmt - return self._af - - @property - def taproot(self): - if not self._taproot: - self._taproot = self.desc.taproot - return self._taproot - - @property - def sh(self): - if not self._sh: - self._sh = self.desc.sh - return self._sh - - @property - def wsh(self): - if not self._wsh: - self._wsh = self.desc.wsh - return self._wsh - - @property - def wpkh(self): - if not self._wpkh: - self._wpkh = self.desc.wpkh - return self._wpkh - - @property - def desc(self): - if self._desc is None: - from descriptor import Descriptor, Tapscript - - ts = None - ms = None - key = None - if self._key: - key = Key.from_string(self._key) - - filled_policy = fill_policy(self.policy, self.keys) - if self._taproot and self._policy: - # tapscript - ts = Tapscript.read_from(uio.BytesIO(filled_policy)) - elif self._policy: - # miniscript - ms = Miniscript.read_from(uio.BytesIO(filled_policy)) - self._desc = Descriptor(key=key, tapscript=ts, miniscript=ms, - taproot=self._taproot, sh=self._sh, - wsh=self._wsh, wpkh=self._wpkh) - self._desc.set_from_addr_fmt(self._af) - return self._desc - - def to_descriptor(self): - return self.desc - - def serialize(self): - policy = None - key = None - if self.desc.key: - key = self.desc.key.to_string() - - keys = [k.to_string() for k in self.desc.keys] - if self.desc.tapscript or self.desc.miniscript: - policy = self.desc.storage_policy() - - sh = self.desc.sh - wsh = self.desc.wsh - wpkh = self.desc.wpkh - taproot = self.desc.taproot - return ( - self.name, - self.chain_type, - self.desc.addr_fmt, - key, - keys, - policy, - sh, wsh, wpkh, taproot - ) - - @classmethod - def deserialize(cls, c, idx=-1): - name, ct, af, key, keys, policy, sh, wsh, wpkh, taproot = c - rv = cls(name=name, key=key, keys=keys, policy=policy, af=af, - taproot=taproot, sh=sh, wsh=wsh, wpkh=wpkh, - chain_type=ct) - rv.storage_idx = idx - return rv - - def xfp_paths(self): - if self._desc is None: - res = [] - if self._key: - ik = Key.from_string(self.key) - if ik.origin: - res.append(ik.origin.psbt_derivation()) - elif ik.is_provably_unspendable: - res.append([swab32(ik.node.my_fp())]) - - for k in self.keys: - k = Key.from_string(k) - if k.origin: - res.append(k.origin.psbt_derivation()) - return res - return self.desc.xfp_paths() - - @classmethod - def find_match(cls, xfp_paths, addr_fmt=None): - for rv in cls.iter_wallets(): - if addr_fmt is not None: - if rv.addr_fmt != addr_fmt: - continue - if rv.matching_subpaths(xfp_paths): - return rv - return None - - def matching_subpaths(self, xfp_paths): - my_xfp_paths = self.xfp_paths() - if len(xfp_paths) != len(my_xfp_paths): - return False - for x in my_xfp_paths: - prefix_len = len(x) - for y in xfp_paths: - if x == y[:prefix_len]: - break - else: - return False - return True - - def subderivation_indexes(self, xfp_paths): - # we already know that they do match - my_xfp_paths = self.desc.xfp_paths() - res = set() - for x in my_xfp_paths: - prefix_len = len(x) - for y in xfp_paths: - if x == y[:prefix_len]: - to_derive = tuple(y[prefix_len:]) - res.add(to_derive) - - assert res - if len(res) == 1: - branch, idx = list(res)[0] - else: - branch = [i[0] for i in res] - indexes = set([i[1] for i in res]) - assert len(indexes) == 1 - idx = list(indexes)[0] - - return branch, idx - - def derive_desc(self, xfp_paths): - branch, idx = self.subderivation_indexes(xfp_paths) - derived_desc = self.desc.derive(branch).derive(idx) - return derived_desc - - def validate_script(self, redeem_script, xfp_paths, script_pubkey=None): - derived_desc = self.derive_desc(xfp_paths) - assert derived_desc.miniscript.compile() == redeem_script, "script mismatch" - if script_pubkey: - assert script_pubkey == derived_desc.script_pubkey(), "spk mismatch" - return derived_desc - - def validate_script_pubkey(self, script_pubkey, xfp_paths, merkle_root=None): - derived_desc = self.derive_desc(xfp_paths) - derived_spk = derived_desc.script_pubkey() - assert derived_spk == script_pubkey, "spk mismatch" - if merkle_root: - assert derived_desc.tapscript.merkle_root == merkle_root, "psbt merkle root" - return derived_desc - - def ux_policy(self): - if self.taproot and self.policy: - return "Tapscript:\n\n" + self.policy - return self.policy - - async def _detail(self, new_wallet=False, is_duplicate=False, short=False): - - s = chains.addr_fmt_label(self.addr_fmt) + "\n\n" - if self.taproot: - s += self.taproot_internal_key_detail(short=short) - - s += self.ux_policy() - - story = s + "\n\nPress (1) to see extended public keys" - if new_wallet and not is_duplicate: - story += ", OK to approve, X to cancel." - return story - - async def show_detail(self, new_wallet=False, duplicates=None, short=False): - title = self.name - story = "" - if duplicates: - title = None - story += "This wallet is a duplicate of already saved wallet %s\n\n" % duplicates[0].name - elif new_wallet: - title = None - story += "Create new miniscript wallet?\n\nWallet Name:\n %s\n\n" % self.name - story += await self._detail(new_wallet, is_duplicate=duplicates, short=short) - while True: - ch = await ux_show_story(story, title=title, escape="1") - if ch == "1": - await self.show_keys() - - elif ch != "y": - return None - else: - return True - - def taproot_internal_key_detail(self, short=False): - if self.taproot: - key = Key.from_string(self.key) - s = "Taproot internal key:\n\n" - if key.is_provably_unspendable: - note = "provably unspendable" - if short: - s += note - else: - s += self.key - if type(key) is Key: - # it is unspendable, BUT not unspend( - s += "\n (%s)" % note - s += "\n\n" - else: - xfp, deriv, xpub = key.to_cc_data() - s += '%s:\n %s\n\n%s/%s\n\n' % (xfp2str(xfp), deriv, xpub, - key.derivation.to_string()) - return s - - async def show_keys(self): - msg = "" - if self.taproot: - msg = self.taproot_internal_key_detail() - msg += "Taproot tree keys:\n\n" - - orig_keys = OrderedDict() - for k in self.keys: - if isinstance(k, str): - k = Key.from_string(k) - if k.origin not in orig_keys: - orig_keys[k.origin] = [] - orig_keys[k.origin].append(k) - - for idx, k_lst in enumerate(orig_keys.values()): - subderiv = True if len(k_lst) == 1 else False - if idx: - msg += '\n---===---\n\n' - - msg += '@%s:\n %s\n\n' % (idx, k_lst[0].to_string(subderiv=subderiv)) - - await ux_show_story(msg) - - @classmethod - def from_file(cls, config, name=None): - from descriptor import Descriptor - if name is None: - desc_obj, cs = Descriptor.from_string(config.strip(), checksum=True) - name = cs - else: - name = to_ascii_printable(name) - desc_obj = Descriptor.from_string(config.strip()) - assert not desc_obj.is_basic_multisig, "Use Settings -> Multisig Wallets" - wal = cls(desc_obj, name=name, chain_type=desc_obj.keys[0].chain_type) - return wal - - def find_duplicates(self): - matches = [] - name_unique = True - for rv in self.iter_wallets(): - if self.name == rv.name: - name_unique = False - if self.key != rv.key: - continue - if self.policy != rv.policy: - continue - if len(self.keys) != len(rv.keys): - continue - if self.keys != rv.keys: - continue - - matches.append(rv) - - return matches, name_unique - - async def confirm_import(self): - nope, yes = (KEY_CANCEL, KEY_ENTER) if version.has_qwerty else ("x", "y") - dups, name_unique = self.find_duplicates() - if not name_unique: - await ux_show_story(title="FAILED", msg=("Miniscript wallet with name '%s'" - " already exists. All wallets MUST" - " have unique names.") % self.name) - return nope - to_save = await self.show_detail(new_wallet=True, duplicates=dups) - - ch = yes if to_save else nope - if to_save and not dups: - assert self.storage_idx == -1 - self.commit() - await ux_dramatic_pause("Saved.", 2) - - return ch - - def yield_addresses(self, start_idx, count, change=False, scripts=True, change_idx=0): - ch = chains.current_chain() - dd = self.desc.derive(None, change=change) - idx = start_idx - while count: - # make the redeem script, convert into address - d = dd.derive(idx) - addr = ch.render_address(d.script_pubkey()) - - script = "" - if scripts: - if d.tapscript: - script = d.tapscript.script_tree(d.tapscript.tree) - else: - script = b2a_hex(ser_string(d.miniscript.compile())).decode() - - if d.tapscript: - yield (idx, - addr, - ["[%s]" % str(k.origin) for k in d.keys], - script, - d.key.serialize(), - str(d.key.origin) if d.key.origin else "") - else: - yield (idx, - addr, - ["[%s]" % str(k.origin) for k in d.keys], - script, - None, - None) - - idx += 1 - count -= 1 - - def make_addresses_msg(self, msg, start, n, change=0): - from glob import dis - - addrs = [] - - for idx, addr, paths, _, ik, _ in self.yield_addresses(start, n, - change=bool(change), - scripts=False): - if idx == 0 and len(paths) <= 4 and not ik: - msg += '\n'.join(paths) + '\n =>\n' - else: - change_idx = set([int(p.split("/")[-2]) for p in paths]) - if len(change_idx) == 1: - msg += '.../%d/%d =>\n' % (list(change_idx)[0], idx) - else: - msg += '.../%d =>\n' % idx - - addrs.append(addr) - msg += show_single_address(addr) + '\n\n' - dis.progress_sofar(idx - start + 1, n) - - return msg, addrs - - def generate_address_csv(self, start, n, change): - part = [] - if self.taproot: - scr_h = "Taptree" - if self.desc.key.is_provably_unspendable: - part = ["Unspendable Internal Key"] - else: - part = ["Internal Key"] - - else: - scr_h = "Script" - - yield '"' + '","'.join( - ['Index', 'Payment Address', scr_h] + ['Derivation'] * len(self.keys) - + part - ) + '"\n' - for (idx, addr, derivs, script, ik, ikp) in self.yield_addresses(start, n, - change=bool(change)): - ln = '%d,"%s","%s","' % (idx, addr, script) - ln += '","'.join(derivs) - if ik: - # internal xonly key with its derivation (if any) - if ikp: - ln += '","[%s]%s' % (ikp, b2a_hex(ik).decode()) - else: - ln += '","%s' % (b2a_hex(ik).decode()) - ln += '"\n' - - yield ln - - def bitcoin_core_serialize(self): - # this will become legacy one day - # instead use <0;1> descriptor format - res = [] - for external in (True, False): - desc_obj = { - "desc": self.to_string(external, not external, unspend_compat=True), - "active": True, - "timestamp": "now", - "internal": not external, - "range": [0, 100], - } - res.append(desc_obj) - return res - - def to_string(self, external=True, internal=True, checksum=True, unspend_compat=False): - if self._key: - key = self._key - if "unspend(" in key and unspend_compat: - # for bitcoin core that does not support 'unspend(' descriptor notation - # serialize 'unspend(' as classic extended key - k = Key.from_string(self.key) - key = k.extended_public_key() - if k.derivation: - key += "/" + k.derivation.to_string(external, internal) - - multipath_rgx = ure.compile(r"<\d+;\d+>") - match = multipath_rgx.search(key) - if match: - mp = match.group(0) - ext, int = mp[1:-1].split(";") - if internal != external: - to_replace = ext if external else int - key = self._key.replace(mp, to_replace) - if self._taproot: - desc = "tr(%s" % key - if self.policy: - desc += "," - tree = fill_policy(self._policy, self._keys, - external, internal) - desc += tree - - res = desc + ")" - - elif self._policy: - res = fill_policy(self._policy, self._keys, - external, internal) - if self._wsh: - res = "wsh(%s)" % res - else: - if self._wpkh: - res = "wpkh(%s)" % self._key - else: - res = "pkh(%s)" % self._key - - if self._sh: - res = "sh(%s)" % res - - if checksum: - res = append_checksum(res) - return res - - async def export_wallet_file(self, mode="exported from", extra_msg=None, descriptor=False, - core=False, desc_pretty=True): - from glob import NFC, dis - from ux import import_export_prompt - - if core: - name = "Bitcoin Core miniscript" - fname_pattern = 'bitcoin-core-%s' % self.name - else: - name = "Miniscript" - fname_pattern = 'minsc-%s' % self.name - - fname_pattern = fname_pattern + ".txt" - - if core: - msg = "importdescriptors cmd" - dis.fullscreen('Wait...') - core_obj = self.bitcoin_core_serialize() - core_str = ujson.dumps(core_obj) - res = "importdescriptors '%s'\n" % core_str - # elif desc_pretty: - # pass TODO - else: - msg = self.name - int_ext = True - ch = await ux_show_story( - "To export receiving and change descriptors in one descriptor (<0;1> notation) press OK, " - "press (1) to export receiving and change descriptors separately.", escape='1') - if ch == "1": - int_ext = False - elif ch != "y": - return - - dis.fullscreen('Wait...') - if int_ext: - res = self.to_string() - else: - res = "%s\n%s" % ( - self.to_string(internal=False), - self.to_string(external=False), - ) - - ch = await import_export_prompt("%s file" % name) - if isinstance(ch, str): - if ch in "3"+KEY_NFC: - await NFC.share_text(res) - elif ch == KEY_QR: - try: - from ux import show_qr_code - await show_qr_code(res, msg=msg) - except: - if version.has_qwerty: - from ux_q1 import show_bbqr_codes - await show_bbqr_codes('U', res, msg) - return - - try: - with CardSlot(**ch) as card: - fname, nice = card.pick_filename(fname_pattern) - - # do actual write - with open(fname, 'w+') as fp: - fp.write(res) - # fp.seek(0) - # contents = fp.read() - # TODO re-enable once we know how to proceed with regards to with which key to sign - # from auth import write_sig_file - # h = ngu.hash.sha256s(contents.encode()) - # sig_nice = write_sig_file([(h, fname)]) - - msg = '%s file written:\n\n%s' % (name, nice) - # msg += '\n\nColdcard multisig signature file written:\n\n%s' % sig_nice - if extra_msg: - msg += extra_msg - - await ux_show_story(msg) - - except CardMissingError: - await needs_microsd() - return - except Exception as e: - await ux_show_story('Failed to write!\n\n%s\n%s' % (e, problem_file_line(e))) - return - -async def no_miniscript_yet(*a): - await ux_show_story("You don't have any miniscript wallets yet.") - -async def miniscript_delete(msc): - if not await ux_confirm("Delete miniscript wallet '%s'?\n\nFunds may be impacted." % msc.name): - await ux_dramatic_pause('Aborted.', 3) - return - - msc.delete() - await ux_dramatic_pause('Deleted.', 3) - -async def miniscript_wallet_delete(menu, label, item): - msc = item.arg - - await miniscript_delete(msc) - - from ux import the_ux - # pop stack - the_ux.pop() - - m = the_ux.top_of_stack() - m.update_contents() - -async def miniscript_wallet_detail(menu, label, item): - # show details of single multisig wallet - - msc = item.arg - - return await msc.show_detail(short=True) - -async def import_miniscript(*a): - # pick text file from SD card, import as multisig setup file - from actions import file_picker - from glob import dis - from ux import import_export_prompt - - ch = await import_export_prompt("miniscript wallet file", is_import=True) - if isinstance(ch, str): - if ch == KEY_QR: - await import_miniscript_qr() - elif ch == KEY_NFC: - await import_miniscript_nfc() - return - - def possible(filename): - with open(filename, 'rt') as fd: - for ln in fd: - if "sh(" in ln or "wsh(" in ln or "tr(" in ln: - # descriptor import - return True - - fn = await file_picker(suffix=['.txt', '.json'], min_size=100, - taster=possible, **ch) - if not fn: return - - try: - with CardSlot(**ch) as card: - with open(fn, 'rt') as fp: - data = fp.read() - except CardMissingError: - await needs_microsd() - return - - from auth import maybe_enroll_xpub - try: - possible_name = (fn.split('/')[-1].split('.'))[0] if fn else None - maybe_enroll_xpub(config=data, name=possible_name, miniscript=True) - except BaseException as e: - await ux_show_story('Failed to import.\n\n%s\n%s' % (e, problem_file_line(e))) - -async def import_miniscript_nfc(*a): - from glob import NFC - try: - return await NFC.import_miniscript_nfc() - except Exception as e: - await ux_show_story(title="ERROR", msg="Failed to import miniscript. %s" % str(e)) - -async def import_miniscript_qr(*a): - from auth import maybe_enroll_xpub - from ux_q1 import QRScannerInteraction - data = await QRScannerInteraction().scan_text('Scan Miniscript from a QR code') - if not data: - # press pressed CANCEL - return - - try: - maybe_enroll_xpub(config=data, miniscript=True) - except Exception as e: - await ux_show_story('Failed to import.\n\n%s\n%s' % (e, problem_file_line(e))) - -async def miniscript_wallet_export(menu, label, item): - # create a text file with the details; ready for import to next Coldcard - msc = item.arg[0] - kwargs = item.arg[1] - await msc.export_wallet_file(**kwargs) - -async def make_miniscript_wallet_descriptor_menu(menu, label, item): - # descriptor menu - msc = item.arg - if not msc: - return - - rv = [ - MenuItem('Export', f=miniscript_wallet_export, arg=(msc, {"core": False})), - MenuItem('Bitcoin Core', f=miniscript_wallet_export, arg=(msc, {"core": True})), - ] - return rv - -async def make_miniscript_wallet_menu(menu, label, item): - # details, actions on single multisig wallet - msc = MiniScriptWallet.get_by_idx(item.arg) - if not msc: return - - rv = [ - MenuItem('"%s"' % msc.name, f=miniscript_wallet_detail, arg=msc), - MenuItem('View Details', f=miniscript_wallet_detail, arg=msc), - MenuItem('Delete', f=miniscript_wallet_delete, arg=msc), - MenuItem('Descriptors', menu=make_miniscript_wallet_descriptor_menu, arg=msc), - ] - return rv - - -class MiniscriptMenu(MenuSystem): - @classmethod - def construct(cls): - import version - from menu import ShortcutItem - - exists, exists_other_chain = MiniScriptWallet.exists() - if not exists: - rv = [MenuItem(MiniScriptWallet.none_setup_yet(exists_other_chain), f=no_miniscript_yet)] - else: - rv = [] - for msc in MiniScriptWallet.get_all(): - rv.append(MenuItem('%s' % msc.name, - menu=make_miniscript_wallet_menu, - arg=msc.storage_idx)) - from glob import NFC - rv.append(MenuItem('Import', f=import_miniscript)) - rv.append(ShortcutItem(KEY_NFC, predicate=lambda: NFC is not None, - f=import_miniscript_nfc)) - rv.append(ShortcutItem(KEY_QR, predicate=lambda: version.has_qwerty, - f=import_miniscript_qr)) - return rv - - def update_contents(self): - # Reconstruct the list of wallets on this dynamic menu, because - # we added or changed them and are showing that same menu again. - tmp = self.construct() - self.replace_items(tmp) - -async def make_miniscript_menu(*a): - # list of all multisig wallets, and high-level settings/actions - from pincodes import pa - - if pa.is_secret_blank(): - await ux_show_story("You must have wallet seed before creating miniscript wallets.") - return - - rv = MiniscriptMenu.construct() - return MiniscriptMenu(rv) class Number: @@ -802,9 +52,8 @@ class KeyHash(Key): return super().parse_key(k, *args, **kwargs) def serialize(self, *args, **kwargs): - if self.taproot: - return ngu.hash.hash160(self.node.pubkey()[1:33]) - return ngu.hash.hash160(self.node.pubkey()) + start = 1 if self.taproot else 0 + return ngu.hash.hash160(self.node.pubkey()[start:33]) def __len__(self): return 21 # <20:pkh> @@ -861,22 +110,17 @@ class Miniscript: @property def keys(self): - return sum( - [arg.keys for arg in self.args if isinstance(arg, Miniscript)], - [k for k in self.args if isinstance(k, Key) or isinstance(k, KeyHash)], - ) + res = [] + for arg in self.args: + if isinstance(arg, Miniscript): + res += arg.keys + elif isinstance(arg, Key): # KeyHash is subclass of Key + res.append(arg) + return res def is_sane(self, taproot=False): err = "multi mixin" - # cannot have same keys in single miniscript - forbiden = (Sortedmulti_a, Multi_a) - keys = self.keys - # provably unspendable taproot internal key is not covered here - # all other keys (miniscript,tapscript) require key origin info - assert len(keys) == len(set(keys)), "Insane" - if taproot: - forbiden = (Sortedmulti, Multi) - + forbiden = (Sortedmulti, Multi) if taproot else (Sortedmulti_a, Multi_a) assert type(self) not in forbiden, err for arg in self.args: @@ -895,11 +139,10 @@ class Miniscript: def derive(self, idx, key_map=None, change=False): args = [] for arg in self.args: - if hasattr(arg, "derive"): - if isinstance(arg, Key) or isinstance(arg, KeyHash): - arg = self.key_derive(arg, idx, key_map, change=change) - else: - arg = arg.derive(idx, change=change) + if isinstance(arg, Key): # KeyHash is subclass of Key + arg = self.key_derive(arg, idx, key_map, change=change) + elif hasattr(arg, "derive"): + arg = arg.derive(idx, key_map, change) args.append(arg) return type(self)(*args) @@ -920,16 +163,16 @@ class Miniscript: if ":" in op: wrappers, op = op.split(":") if char != b"(": - raise MiniscriptException("Missing operator") + raise ValueError("Missing operator") if op not in OPERATOR_NAMES: - raise MiniscriptException("Unknown operator '%s'" % op) + raise ValueError("Unknown operator '%s'" % op) # number of arguments, classes of arguments, compile function, type, validity checker MiniscriptCls = OPERATORS[OPERATOR_NAMES.index(op)] args = MiniscriptCls.read_arguments(s, taproot=taproot) miniscript = MiniscriptCls(*args, taproot=taproot) for w in reversed(wrappers): if w not in WRAPPER_NAMES: - raise MiniscriptException("Unknown wrapper %s" % w) + raise ValueError("Unknown wrapper %s" % w) WrapperCls = WRAPPERS[WRAPPER_NAMES.index(w)] miniscript = WrapperCls(miniscript, taproot=taproot) return miniscript @@ -951,7 +194,7 @@ class Miniscript: elif char == b")": break else: - raise MiniscriptException( + raise ValueError( "Expected , or ), got: %s" % (char + s.read()) ) else: @@ -960,10 +203,10 @@ class Miniscript: if i < cls.NARGS - 1: char = s.read(1) if char != b",": - raise MiniscriptException("Missing arguments, %s" % char) + raise ValueError("Missing arguments, %s" % char) char = s.read(1) if char != b")": - raise MiniscriptException("Expected ) got %s" % (char + s.read())) + raise ValueError("Expected ) got %s" % (char + s.read())) return args def to_string(self, external=True, internal=True): @@ -1025,6 +268,23 @@ class PkH(OneArg): def __len__(self): return self.len_args() + 3 +class After(OneArg): + # CHECKLOCKTIMEVERIFY + NAME = "after" + ARGCLS = Number + TYPE = "B" + PROPS = "z" + + def inner_compile(self): + return self.carg + b"\xb1" + + def verify(self): + super().verify() + assert 0 < self.arg.num < 0x80000000, "%s out of range [1, 2147483647]" % self.NAME + + def __len__(self): + return self.len_args() + 1 + class Older(OneArg): # CHECKSEQUENCEVERIFY NAME = "older" @@ -1037,22 +297,18 @@ class Older(OneArg): def verify(self): super().verify() - if (self.arg.num < 1) or (self.arg.num >= 0x80000000): - raise MiniscriptException( - "%s should have an argument in range [1, 0x80000000)" % self.NAME - ) + # not consensus valid + # https://github.com/bitcoin/bitcoin/pull/33135 older(65536) is equivalent to older(1) + if self.arg.num & (1 << 22): + # time-based + assert 0x400000 < self.arg.num < 0x410000, "Time-based %s out of range [4194305, 4259839]" % self.NAME + else: + # block-based + assert 0 < self.arg.num < 0x10000, "Block-based %s out of range [1, 65535]" % self.NAME def __len__(self): return self.len_args() + 1 -class After(Older): - # CHECKLOCKTIMEVERIFY - NAME = "after" - - def inner_compile(self): - return self.carg + b"\xb1" - - class Sha256(OneArg): # SIZE <32> EQUALVERIFY SHA256 EQUAL NAME = "sha256" @@ -1106,14 +362,14 @@ class AndOr(Miniscript): # requires: X is Bdu; Y and Z are both B, K, or V super().verify() if self.args[0].type != "B": - raise MiniscriptException("andor: X should be 'B'") + raise ValueError("andor: X should be 'B'") px = self.args[0].properties if "d" not in px and "u" not in px: - raise MiniscriptException("andor: X should be 'du'") + raise ValueError("andor: X should be 'du'") if self.args[1].type != self.args[2].type: - raise MiniscriptException("andor: Y and Z should have the same types") + raise ValueError("andor: Y and Z should have the same types") if self.args[1].type not in "BKV": - raise MiniscriptException("andor: Y and Z should be B K or V") + raise ValueError("andor: Y and Z should be B K or V") @property def properties(self): @@ -1161,9 +417,9 @@ class AndV(Miniscript): # X is V; Y is B, K, or V super().verify() if self.args[0].type != "V": - raise MiniscriptException("and_v: X should be 'V'") + raise ValueError("and_v: X should be 'V'") if self.args[1].type not in "BKV": - raise MiniscriptException("and_v: Y should be B K or V") + raise ValueError("and_v: Y should be B K or V") @property def type(self): @@ -1203,9 +459,9 @@ class AndB(Miniscript): # X is B; Y is W super().verify() if self.args[0].type != "B": - raise MiniscriptException("and_b: X should be B") + raise ValueError("and_b: X should be B") if self.args[1].type != "W": - raise MiniscriptException("and_b: Y should be W") + raise ValueError("and_b: Y should be W") @property def properties(self): @@ -1253,12 +509,12 @@ class AndN(Miniscript): # requires: X is Bdu; Y and Z are both B, K, or V super().verify() if self.args[0].type != "B": - raise MiniscriptException("and_n: X should be 'B'") + raise ValueError("and_n: X should be 'B'") px = self.args[0].properties if "d" not in px and "u" not in px: - raise MiniscriptException("and_n: X should be 'du'") + raise ValueError("and_n: X should be 'du'") if self.args[1].type != "B": - raise MiniscriptException("and_n: Y should be B") + raise ValueError("and_n: Y should be B") @property def properties(self): @@ -1296,13 +552,13 @@ class OrB(Miniscript): # X is Bd; Z is Wd super().verify() if self.args[0].type != "B": - raise MiniscriptException("or_b: X should be B") + raise ValueError("or_b: X should be B") if "d" not in self.args[0].properties: - raise MiniscriptException("or_b: X should be d") + raise ValueError("or_b: X should be d") if self.args[1].type != "W": - raise MiniscriptException("or_b: Z should be W") + raise ValueError("or_b: Z should be W") if "d" not in self.args[1].properties: - raise MiniscriptException("or_b: Z should be d") + raise ValueError("or_b: Z should be d") @property def properties(self): @@ -1334,12 +590,12 @@ class OrC(Miniscript): # X is Bdu; Z is V super().verify() if self.args[0].type != "B": - raise MiniscriptException("or_c: X should be B") + raise ValueError("or_c: X should be B") if self.args[1].type != "V": - raise MiniscriptException("or_c: Z should be V") + raise ValueError("or_c: Z should be V") px = self.args[0].properties if "d" not in px or "u" not in px: - raise MiniscriptException("or_c: X should be du") + raise ValueError("or_c: X should be du") @property def properties(self): @@ -1370,12 +626,12 @@ class OrD(Miniscript): # X is Bdu; Z is B super().verify() if self.args[0].type != "B": - raise MiniscriptException("or_d: X should be B") + raise ValueError("or_d: X should be B") if self.args[1].type != "B": - raise MiniscriptException("or_d: Z should be B") + raise ValueError("or_d: Z should be B") px = self.args[0].properties if "d" not in px or "u" not in px: - raise MiniscriptException("or_d: X should be du") + raise ValueError("or_d: X should be du") @property def properties(self): @@ -1415,9 +671,9 @@ class OrI(Miniscript): # both are B, K, or V super().verify() if self.args[0].type != self.args[1].type: - raise MiniscriptException("or_i: X and Z should be the same type") + raise ValueError("or_i: X and Z should be the same type") if self.args[0].type not in "BKV": - raise MiniscriptException("or_i: X and Z should be B K or V") + raise ValueError("or_i: X and Z should be B K or V") @property def type(self): @@ -1459,21 +715,21 @@ class Thresh(Miniscript): # 1 <= k <= n; X1 is Bdu; others are Wdu super().verify() if self.args[0].num < 1 or self.args[0].num >= len(self.args): - raise MiniscriptException( + raise ValueError( "thresh: Invalid k! Should be 1 <= k <= %d, got %d" % (len(self.args) - 1, self.args[0].num) ) if self.args[1].type != "B": - raise MiniscriptException("thresh: X1 should be B") + raise ValueError("thresh: X1 should be B") px = self.args[1].properties if "d" not in px or "u" not in px: - raise MiniscriptException("thresh: X1 should be du") + raise ValueError("thresh: X1 should be du") for i, arg in enumerate(self.args[2:]): if arg.type != "W": - raise MiniscriptException("thresh: X%d should be W" % (i + 1)) + raise ValueError("thresh: X%d should be W" % (i + 1)) p = arg.properties if "d" not in p or "u" not in p: - raise MiniscriptException("thresh: X%d should be du" % (i + 1)) + raise ValueError("thresh: X%d should be du" % (i + 1)) @property def properties(self): @@ -1500,8 +756,14 @@ class Multi(Miniscript): N_MAX = 20 def inner_compile(self): + # scr = [arg.compile() for arg in self.args[1:]] + # optimization - it is all keys with known length (xonly keys not allowed here) + scr = [b'\x21' + arg.key_bytes() for arg in self.args[1:]] + if self.NAME == "sortedmulti": + scr.sort() return ( - b"".join([arg.compile() for arg in self.args]) + self.args[0].compile() + + b"".join(scr) + Number(len(self.args) - 1).compile() + b"\xae" ) @@ -1527,13 +789,6 @@ class Sortedmulti(Multi): # ... CHECKMULTISIG NAME = "sortedmulti" - def inner_compile(self): - return ( - self.args[0].compile() - + b"".join(sorted([arg.compile() for arg in self.args[1:]])) - + Number(len(self.args) - 1).compile() - + b"\xae" - ) class Multi_a(Multi): # CHECKSIG CHECKSIGADD ... CHECKSIGADD EQUALVERIFY @@ -1544,12 +799,19 @@ class Multi_a(Multi): def inner_compile(self): from opcodes import OP_CHECKSIGADD, OP_NUMEQUAL, OP_CHECKSIG script = b"" - for i, key in enumerate(self.args[1:]): - script += key.compile() + # scr = [arg.compile() for arg in self.args[1:]] + # optimization - it is all keys with known length (only xonly keys allowed here) + scr = [b"\x20" + arg.key_bytes() for arg in self.args[1:]] + if self.NAME == "sortedmulti_a": + scr.sort() + + for i, key in enumerate(scr): + script += key if i == 0: script += bytes([OP_CHECKSIG]) else: script += bytes([OP_CHECKSIGADD]) + script += self.args[0].compile() # M (threshold) script += bytes([OP_NUMEQUAL]) return script @@ -1563,19 +825,6 @@ class Sortedmulti_a(Multi_a): # CHECKSIG CHECKSIGADD ... CHECKSIGADD EQUALVERIFY NAME = "sortedmulti_a" - def inner_compile(self): - from opcodes import OP_CHECKSIGADD, OP_NUMEQUAL, OP_CHECKSIG - script = b"" - for i, key in enumerate(sorted([arg.compile() for arg in self.args[1:]])): - script += key - if i == 0: - script += bytes([OP_CHECKSIG]) - else: - script += bytes([OP_CHECKSIGADD]) - script += self.args[0].compile() # M (threshold) - script += bytes([OP_NUMEQUAL]) - return script - class Pk(OneArg): # CHECKSIG @@ -1661,7 +910,7 @@ class A(Wrapper): def verify(self): super().verify() if self.arg.type != "B": - raise MiniscriptException("a: X should be B") + raise ValueError("a: X should be B") @property def properties(self): @@ -1687,9 +936,9 @@ class S(Wrapper): def verify(self): super().verify() if self.arg.type != "B": - raise MiniscriptException("s: X should be B") + raise ValueError("s: X should be B") if "o" not in self.arg.properties: - raise MiniscriptException("s: X should be o") + raise ValueError("s: X should be o") @property def properties(self): @@ -1715,7 +964,7 @@ class C(Wrapper): def verify(self): super().verify() if self.arg.type != "K": - raise MiniscriptException("c: X should be K") + raise ValueError("c: X should be K") @property def properties(self): @@ -1738,6 +987,11 @@ class T(Wrapper): def __len__(self): return len(self.arg) + 1 + def verify(self): + super().verify() + if self.arg.type != "V": + raise ValueError("t: X must be of type V") + @property def properties(self): # z=zXzY; o=zXoY or zYoX; n=nX or zXnY; u=uY @@ -1768,9 +1022,9 @@ class D(Wrapper): def verify(self): super().verify() if self.arg.type != "V": - raise MiniscriptException("d: X should be V") + raise ValueError("d: X should be V") if "z" not in self.arg.properties: - raise MiniscriptException("d: X should be z") + raise ValueError("d: X should be z") @property def properties(self): @@ -1798,7 +1052,7 @@ class V(Wrapper): def verify(self): super().verify() if self.arg.type != "B": - raise MiniscriptException("v: X should be B") + raise ValueError("v: X should be B") @property def properties(self): @@ -1820,9 +1074,9 @@ class J(Wrapper): def verify(self): super().verify() if self.arg.type != "B": - raise MiniscriptException("j: X should be B") + raise ValueError("j: X should be B") if "n" not in self.arg.properties: - raise MiniscriptException("j: X should be n") + raise ValueError("j: X should be n") @property def properties(self): @@ -1847,7 +1101,7 @@ class N(Wrapper): def verify(self): super().verify() if self.arg.type != "B": - raise MiniscriptException("n: X should be B") + raise ValueError("n: X should be B") @property def properties(self): @@ -1873,7 +1127,7 @@ class L(Wrapper): # both are B, K, or V super().verify() if self.arg.type != "B": - raise MiniscriptException("or_i: X and Z should be the same type") + raise ValueError("or_i: X and Z should be the same type") @property def properties(self): diff --git a/shared/mk4.py b/shared/mk4.py index 17409e82..69b024ce 100644 --- a/shared/mk4.py +++ b/shared/mk4.py @@ -11,7 +11,8 @@ def make_flash_fs(): os.VfsLfs2.mkfs(fl) os.mount(fl, '/flash') - os.mkdir('/flash/settings') + os.chdir('/flash') + os.mkdir('settings') def make_psram_fs(): # Filesystem is wiped and rebuilt on each boot before this point, but @@ -57,8 +58,7 @@ def init0(): try: make_psram_fs() - except BaseException as exc: - sys.print_exception(exc) + except: pass if version.is_devmode: try: @@ -70,10 +70,13 @@ def init0(): rng_seeding() async def dev_enable_repl(*a): - # Mk4: Enable serial port connection. You'll have to break case open. + # Enable serial port connection. You'll have to break case open. + from ux import ux_show_story + from utils import wipe_if_deltamode wipe_if_deltamode() + if not version.is_devmode: return # allow REPL access ckcc.vcp_enabled(True) @@ -82,15 +85,4 @@ async def dev_enable_repl(*a): await ux_show_story("""\ The serial port has now been enabled.\n\n3.3v TTL on Tx/Rx/Gnd pads @ 115,200 bps.""") -def wipe_if_deltamode(): - # If in deltamode, give up and wipe self rather do - # a thing that might reveal true master secret... - - from pincodes import pa - - if not pa.is_deltamode(): - return - - callgate.fast_wipe() - # EOF diff --git a/shared/msgsign.py b/shared/msgsign.py new file mode 100644 index 00000000..144dc651 --- /dev/null +++ b/shared/msgsign.py @@ -0,0 +1,512 @@ +# (c) Copyright 2025 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# +# Signatures over text ... not transactions. +# +import stash, chains, sys, gc, ngu, ujson, version +from ubinascii import b2a_base64, a2b_base64 +from ubinascii import hexlify as b2a_hex +from ubinascii import unhexlify as a2b_hex +from uhashlib import sha256 +from public_constants import MSG_SIGNING_MAX_LENGTH +from public_constants import AF_CLASSIC, AF_P2WPKH, AF_P2WPKH_P2SH +from charcodes import KEY_QR, KEY_NFC, KEY_CANCEL +from ux import (ux_show_story, OK, ux_enter_bip32_index, ux_input_text, the_ux, + import_export_prompt, ux_aborted) +from utils import problem_file_line, to_ascii_printable, show_single_address +from files import CardSlot, CardMissingError, needs_microsd + +def rfc_signature_template(msg, addr, sig): + # RFC2440 style signatures, popular + # since the genesis block, but not really part of any BIP as far as I know. + # + return [ + "-----BEGIN BITCOIN SIGNED MESSAGE-----\n", + "%s\n" % msg, + "-----BEGIN BITCOIN SIGNATURE-----\n", + "%s\n" % addr, + "%s\n" % sig, + "-----END BITCOIN SIGNATURE-----\n" + ] + +def parse_armored_signature_file(contents): + # XXX limited parser: will fail w/ messages containing dashes + sep = "-----" + assert contents.count(sep) == 6, "Armor text MUST be surrounded by exactly five (5) dashes." + + temp = contents.split(sep) + msg = temp[2].strip() + addr_sig = temp[4].strip() + addr, sig_str = addr_sig.split() + + return msg, addr, sig_str + +def verify_signature(msg, addr, sig_str): + # Look at a base64 signature, and given address. Do full verification. + # - raise on errors + # - return warnings as string: can only be mismatch between addr format encoded in recid + warnings = "" + script = None + hash160 = None + invalid_addr_fmt_msg = "Invalid address format - must be one of p2pkh, p2sh-p2wpkh, or p2wpkh." + invalid_addr = "Invalid signature for message." + + if addr[0] in "1mn": + addr_fmt = AF_CLASSIC + decoded_addr = ngu.codecs.b58_decode(addr) + hash160 = decoded_addr[1:] # remove prefix + elif addr.startswith("bc1q") or addr.startswith("tb1q") or addr.startswith("bcrt1q"): + if len(addr) > 44: # testnet/mainnet max singlesig len 42, regtest 44 + # p2wsh + raise ValueError(invalid_addr_fmt_msg) + addr_fmt = AF_P2WPKH + _, _, hash160 = ngu.codecs.segwit_decode(addr) + elif addr[0] in "32": + addr_fmt = AF_P2WPKH_P2SH + decoded_addr = ngu.codecs.b58_decode(addr) + script = decoded_addr[1:] # remove prefix + else: + raise ValueError(invalid_addr_fmt_msg) + + try: + sig_bytes = a2b_base64(sig_str) + if not sig_bytes or len(sig_bytes) != 65: + # can return b'' in case of wrong, can also raise + raise ValueError("invalid encoding") + + header_byte = sig_bytes[0] + header_base = chains.current_chain().sig_hdr_base(addr_fmt) + if (header_byte - header_base) not in (0, 1, 2, 3): + # wrong header value only - this can still verify OK + warnings += "Specified address format does not match signature header byte format." + + # least two significant bits + rec_id = (header_byte - 27) & 0x03 + # need to normalize it to 31 base for ngu + new_header_byte = 31 + rec_id + sig = ngu.secp256k1.signature(bytes([new_header_byte]) + sig_bytes[1:]) + except ValueError as e: + raise ValueError("Parsing signature failed - %s." % str(e)) + + digest = chains.current_chain().hash_message(msg.encode('ascii')) + try: + rec_pubkey = sig.verify_recover(digest) + except ValueError as e: + raise ValueError("Invalid signature for msg - %s." % str(e)) + + rec_pubkey_bytes = rec_pubkey.to_bytes() + rec_hash160 = ngu.hash.hash160(rec_pubkey_bytes) + + if script: + target = bytes([0, 20]) + rec_hash160 + target = ngu.hash.hash160(target) + if target != script: + raise ValueError(invalid_addr) + else: + if rec_hash160 != hash160: + raise ValueError(invalid_addr) + + return warnings + +async def verify_armored_signed_msg(contents, digest_check=True): + # Verify on-disk checksums of files listed inside a signed file. + # - digest_check=False for NFC cases, where we do not have filesystem + from glob import dis + + dis.fullscreen("Verifying...") + + try: + msg, addr, sig_str = parse_armored_signature_file(contents) + except Exception as e: + e_line = problem_file_line(e) + await ux_show_story("Malformed signature file. %s %s" % (str(e), e_line), title="FAILURE") + return + + try: + sig_warn = verify_signature(msg, addr, sig_str) + except Exception as e: + await ux_show_story(str(e), title="ERROR") + return + + title = "CORRECT" + warn_msg = "" + err_msg = "" + story = "Good signature by address:\n%s" % show_single_address(addr) + + if digest_check: + digest_prob = verify_signed_file_digest(msg) + if digest_prob: + err, digest_warn = digest_prob + if digest_warn: + title = "WARNING" + wmsg_base = "not present. Contents verification not possible." + if len(digest_warn) == 1: + fname = digest_warn[0][0] + warn_msg += "'%s' is %s" % (fname, wmsg_base) + else: + warn_msg += "Files:\n" + "\n".join("> %s" % fname for fname, _ in digest_warn) + warn_msg += "\nare %s" % wmsg_base + + if err: + title = "ERROR" + for fname, calc, got in err: + err_msg += ("Referenced file '%s' has wrong contents.\n" + "Got:\n%s\n\nExpected:\n%s" % (fname, got, calc)) + + if sig_warn: + # we know not ours only because wrong recid header used & not BIP-137 compliant + story = "Correctly signed, but not by this Coldcard. %s" % sig_warn + + await ux_show_story('\n\n'.join(m for m in [err_msg, story, warn_msg] if m), title=title) + +async def verify_txt_sig_file(filename): + # copy message into memory + try: + with CardSlot() as card: + with card.open(filename, 'rt') as fd: + text = fd.read() + except CardMissingError: + await needs_microsd() + return + except Exception as e: + await ux_show_story('Error: ' + str(e)) + return + + await verify_armored_signed_msg(text) + +async def msg_sign_ux_get_subpath(addr_fmt): + # Ask for account number, and maybe change component of path for signature. + # - return full derivation path to be used. + purpose = chains.af_to_bip44_purpose(addr_fmt) + chain_n = chains.current_chain().b44_cointype + + acct = await ux_enter_bip32_index('Account Number:') or 0 + + ch = await ux_show_story(title="Change?", + msg="Press (0) to use internal/change address," + " %s to use external/receive address." % OK, escape="0") + change = 1 if ch == '0' else 0 + + idx = await ux_enter_bip32_index('Index Number:') or 0 + + return "m/%dh/%dh/%dh/%d/%d" % (purpose, chain_n, acct, change, idx) + + +def sign_export_contents(content_list, deriv, addr_fmt, pk=None): + # Return signed message over hashes of files. + msg2sign = make_signature_file_msg(content_list) + bitcoin_digest = chains.current_chain().hash_message(msg2sign) + sig_bytes, addr = sign_message_digest(bitcoin_digest, deriv, "Signing...", addr_fmt, pk=pk) + sig = b2a_base64(sig_bytes).decode().strip() + + return rfc_signature_template(addr=addr, msg=msg2sign.decode(), sig=sig) + +def verify_signed_file_digest(msg): + # Look inside a list of hashs and file names, and + # verify at their actual hashes and return list of issues if any. + parsed_msg = parse_signature_file_msg(msg) + if not parsed_msg: + # not our format + return + + try: + err, warn = [], [] + with CardSlot() as card: + for digest, fname in parsed_msg: + path = card.abs_path(fname) + if not card.exists(path): + warn.append((fname, None)) + continue + path = card.abs_path(fname) + + md = sha256() + with open(path, "rb") as f: + while True: + chunk = f.read(1024) + if not chunk: + break + md.update(chunk) + + h = b2a_hex(md.digest()).decode().strip() + if h != digest: + err.append((fname, h, digest)) + except: + # fail silently if issues with reading files or SD issues + # no digest checking + return + + return err, warn + +def write_sig_file(content_list, derive=None, addr_fmt=AF_CLASSIC, pk=None, sig_name=None): + if derive is None: + ct = chains.current_chain().b44_cointype + derive = "m/44'/%d'/0'/0/0" % ct + + fpath = content_list[0][1] + if len(content_list) > 1: + # we're signing contents of more files - need generic name for sig file + assert sig_name + sig_nice = sig_name + ".sig" + sig_fpath = fpath.rsplit("/", 1)[0] + "/" + sig_nice + else: + sig_fpath = fpath.rsplit(".", 1)[0] + ".sig" + sig_nice = sig_fpath.split("/")[-1] + + sig_gen = sign_export_contents([(h, f.split("/")[-1]) for h, f in content_list], + derive, addr_fmt, pk=pk) + + with open(sig_fpath, 'wt') as fd: + for i, part in enumerate(sig_gen): + fd.write(part) + + return sig_nice + +def validate_text_for_signing(text, only_printable=True): + # Check for some UX/UI traps in the message itself. + # - messages must be short and ascii only. Our charset is limited + # - too many spaces, leading/trailing can be an issue + # MSG_MAX_SPACES = 4 # impt. compared to -=- positioning + + result = to_ascii_printable(text, only_printable=only_printable) + + length = len(result) + assert length >= 2, "msg too short (min. 2)" + assert length <= MSG_SIGNING_MAX_LENGTH, "msg too long (max. %d)" % MSG_SIGNING_MAX_LENGTH + assert " " not in result, 'too many spaces together in msg(max. 3)' + # other confusion w/ whitepace + assert result[0] != ' ', 'leading space(s) in msg' + assert result[-1] != ' ', 'trailing space(s) in msg' + + # looks ok + return result + +def addr_fmt_from_subpath(subpath): + if not subpath: + af = "p2pkh" + elif subpath[:4] == "m/84": + af = "p2wpkh" + elif subpath[:4] == "m/49": + af = "p2sh-p2wpkh" + else: + af = "p2pkh" + return af + +def parse_msg_sign_request(data): + subpath = "" + addr_fmt = None + is_json = False + + # sparrow compat + if "signmessage" in data: + try: + mark, subpath, *msg_line = data.split(" ", 2) + assert mark == "signmessage" + # subpath will be verified & cleaned later + assert msg_line[0][:6] == "ascii:" + text = msg_line[0][6:] + return text, subpath, addr_fmt_from_subpath(subpath), is_json + except:pass + # === + + try: + data_dict = ujson.loads(data.strip()) + text = data_dict.get("msg", None) + if text is None: + raise AssertionError("MSG required") + subpath = data_dict.get("subpath", subpath) + addr_fmt = data_dict.get("addr_fmt", addr_fmt) + is_json = True + except ValueError: + lines = data.split("\n") + assert lines, "min 1 line" + assert len(lines) <= 3, "max 3 lines" + + if len(lines) == 1: + text = lines[0] + elif len(lines) == 2: + text, subpath = lines + else: + text, subpath, addr_fmt = lines + + if not addr_fmt: + addr_fmt = addr_fmt_from_subpath(subpath) + + if not subpath: + subpath = chains.STD_DERIVATIONS[addr_fmt] + subpath = subpath.format( + coin_type=chains.current_chain().b44_cointype, + account=0, change=0, idx=0 + ) + + return text, subpath, addr_fmt, is_json + + +def make_signature_file_msg(content_list): + # list of tuples consisting of (hash, file_name) + return b"\n".join([ + b2a_hex(h) + b" " + fname.encode() + for h, fname in content_list + ]) + +def parse_signature_file_msg(msg): + # only succeed for our format digest + 2 spaces + fname + try: + res = [] + lines = msg.split('\n') + for ln in lines: + d, fn = ln.split(' ') + # should not need to strip if our file format, so dont + # is hex? is 32 bytes long? + assert len(a2b_hex(d)) == 32 + res.append((d, fn)) + + return res + except: + return + +def sign_message_digest(digest, subpath, prompt, addr_fmt=AF_CLASSIC, pk=None): + # do the signature itself! + from glob import dis + + ch = chains.current_chain() + + if prompt: + dis.fullscreen(prompt, percent=.25) + + if pk is None: + with stash.SensitiveValues() as sv: + node = sv.derive_path(subpath) + dis.progress_sofar(50, 100) + pk = node.privkey() + addr = ch.address(node, addr_fmt) + else: + # if private key is provided, derivation subpath is ignored + # and given private key is used for signing. + node = ngu.hdnode.HDNode().from_chaincode_privkey(bytes(32), pk) + dis.progress_sofar(50, 100) + addr = ch.address(node, addr_fmt) + + dis.progress_sofar(75, 100) + + rv = ngu.secp256k1.sign(pk, digest, 0).to_bytes() + + # AF_CLASSIC header byte base 31 is returned by default from ngu - NOOP + if addr_fmt != AF_CLASSIC: + # ngu only produces header base for compressed p2pkh, anyways get only rec_id + rv = bytearray(rv) + rec_id = (rv[0] - 27) & 0x03 + rv[0] = rec_id + ch.sig_hdr_base(addr_fmt=addr_fmt) + + dis.progress_bar_show(1) + + return rv, addr + +async def ux_sign_msg(txt, approved_cb=None, kill_menu=True): + from menu import MenuSystem, MenuItem + + async def done(_1, _2, item): + from auth import approve_msg_sign + + text, af = item.arg + subpath = await msg_sign_ux_get_subpath(af) + + await approve_msg_sign(text, subpath, af, approved_cb=approved_cb, + kill_menu=kill_menu, only_printable=False) + + # pick address format + rv = [ + MenuItem(chains.addr_fmt_label(af), f=done, arg=(txt, af)) + for af in chains.SINGLESIG_AF + ] + the_ux.push(MenuSystem(rv)) + +async def msg_signing_done(signature, address, text): + ch = await import_export_prompt("Signed Msg") + if ch == KEY_CANCEL: + return + + if isinstance(ch, dict): + await sd_sign_msg_done(signature, address, text, "msg_sign", **ch) + elif version.has_qr and ch == KEY_QR: + from ux_q1 import qr_msg_sign_done + await qr_msg_sign_done(signature, address, text) + elif ch in KEY_NFC+"3": + from glob import NFC + if NFC: + await NFC.msg_sign_done(signature, address, text) + + +async def sign_with_own_address(subpath, addr_fmt): + # used for cases where we already have the key picked, but need the message: + # * address_explorer custom path + # * positive ownership test + + to_sign = await ux_input_text("", scan_ok=True, prompt="Enter MSG") # max len is 100 only here + if not to_sign: return + + from auth import approve_msg_sign + await approve_msg_sign(to_sign, subpath, addr_fmt, approved_cb=msg_signing_done, kill_menu=True) + +async def sd_sign_msg_done(signature, address, text, base=None, orig_path=None, + slot_b=None, force_vdisk=False): + from glob import dis + dis.fullscreen('Generating...') + + out_fn = None + sig = b2a_base64(signature).decode('ascii').strip() + + while 1: + # try to put back into same spot + # add -signed to end. + target_fname = base + '-signed.txt' + lst = [orig_path] + if orig_path: + lst.append(None) + + for path in lst: + try: + with CardSlot(readonly=True, slot_b=slot_b, force_vdisk=force_vdisk) as card: + out_full, out_fn = card.pick_filename(target_fname, path) + out_path = path + if out_full: break + except CardMissingError: + prob = 'Missing card.\n\n' + out_fn = None + + if not out_fn: + # need them to insert a card + prob = '' + else: + # attempt write-out + try: + dis.fullscreen("Saving...") + + with CardSlot(slot_b=slot_b, force_vdisk=force_vdisk) as card: + with card.open(out_full, 'wt') as fd: + # save in full RFC style + # gen length is 6 + gen = rfc_signature_template(addr=address, msg=text, sig=sig) + for i, part in enumerate(gen): + fd.write(part) + + # success and done! + break + + except OSError as exc: + prob = 'Failed to write!\n\n%s\n\n' % exc + # sys.print_exception(exc) + # fall through to try again + + # prompt them to input another card? + ch = await ux_show_story(prob + "Please insert an SDCard to receive signed message, " + "and press %s." % OK, title="Need Card") + if ch == 'x': + await ux_aborted() + return + + # done. + msg = "Created new file:\n\n%s" % out_fn + await ux_show_story(msg, title='File Signed') + + + +# EOF diff --git a/shared/multisig.py b/shared/multisig.py index a5546601..21fea250 100644 --- a/shared/multisig.py +++ b/shared/multisig.py @@ -1,1567 +1,62 @@ # (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. # -# multisig.py - support code for multisig signing and p2sh in general. +# multisig.py - ms coordinator code mostly + some utils # import stash, chains, ustruct, ure, uio, sys, ngu, uos, ujson, version +from public_constants import AF_P2WSH, AF_P2WSH_P2SH from ubinascii import hexlify as b2a_hex -from utils import xfp2str, str2xfp, cleanup_deriv_path, keypath_to_str, to_ascii_printable -from utils import str_to_keypath, problem_file_line, check_xpub, get_filesize, show_single_address -from ux import ux_show_story, ux_confirm, ux_dramatic_pause, ux_clear_keys -from ux import import_export_prompt, ux_enter_bip32_index, show_qr_code, ux_enter_number, OK, X +from utils import xfp2str, problem_file_line, get_filesize from files import CardSlot, CardMissingError, needs_microsd -from descriptor import Descriptor -from miniscript import Key, Sortedmulti, Number, Multi -from desc_utils import multisig_descriptor_template -from public_constants import AF_P2SH, AF_P2WSH_P2SH, AF_P2WSH, AFC_SCRIPT, MAX_SIGNERS, AF_P2TR -from menu import MenuSystem, MenuItem, NonDefaultMenuItem, start_chooser, ToggleMenuItem -from opcodes import OP_CHECKMULTISIG -from exceptions import FatalPSBTIssue +from ux import ux_show_story, ux_dramatic_pause, ux_enter_number, ux_enter_bip32_index +from public_constants import MAX_SIGNERS from glob import settings -from charcodes import KEY_NFC, KEY_CANCEL, KEY_QR -from serializations import disassemble -from wallet import BaseStorageWallet, MAX_BIP32_IDX +from charcodes import KEY_QR +from desc_utils import Key, KeyOriginInfo -# PSBT Xpub trust policies -TRUST_VERIFY = const(0) -TRUST_OFFER = const(1) -TRUST_PSBT = const(2) - -def disassemble_multisig_mn(redeem_script): - # pull out just M and N from script. Simple, faster, no memory. - - if redeem_script[-1] != OP_CHECKMULTISIG: - return None, None - - M = redeem_script[0] - 80 - N = redeem_script[-2] - 80 - - return M, N - -def disassemble_multisig(redeem_script): - # Take apart a standard multisig's redeem/witness script, and return M/N and public keys - # - only for multisig scripts, not general purpose - # - expect OP_1 (pk1) (pk2) (pk3) OP_3 OP_CHECKMULTISIG for 1 of 3 case - # - returns M, N, (list of pubkeys) - # - for very unlikely/impossible asserts, don't document reason; otherwise do. - M, N = disassemble_multisig_mn(redeem_script) - assert 1 <= M <= N <= MAX_SIGNERS, 'M/N range' - assert len(redeem_script) == 1 + (N * 34) + 1 + 1, 'bad len' - - # generator function - dis = disassemble(redeem_script) - - # expect M value first - ex_M, opcode = next(dis) - assert ex_M == M and opcode == None, 'bad M' - - # need N pubkeys - pubkeys = [] - for idx in range(N): - data, opcode = next(dis) - assert opcode == None and len(data) == 33, 'data' - assert data[0] == 0x02 or data[0] == 0x03, 'Y val' - pubkeys.append(data) - - assert len(pubkeys) == N - - # next is N value - ex_N, opcode = next(dis) - assert ex_N == N and opcode == None - - # finally, the opcode: CHECKMULTISIG - data, opcode = next(dis) - assert opcode == OP_CHECKMULTISIG - - # must have reached end of script at this point - try: - next(dis) - raise AssertionError("too long") - except StopIteration: - # expected, since we're reading past end - pass - - return M, N, pubkeys - -def make_redeem_script(M, nodes, subkey_idx, bip67=True): - # take a list of BIP-32 nodes, and derive Nth subkey (subkey_idx) and make - # a standard M-of-N redeem script for that. Applies BIP-67 sorting by default. - N = len(nodes) - assert 1 <= M <= N <= MAX_SIGNERS - - pubkeys = [] - for n in nodes: - copy = n.copy() - copy.derive(subkey_idx, False) - # 0x21 = 33 = len(pubkey) = OP_PUSHDATA(33) - pubkeys.append(b'\x21' + copy.pubkey()) - del copy - - if bip67: - pubkeys.sort() - - # serialize redeem script - pubkeys.insert(0, bytes([80 + M])) - pubkeys.append(bytes([80 + N, OP_CHECKMULTISIG])) - - return b''.join(pubkeys) - -class MultisigWallet(BaseStorageWallet): - # Capture the info we need to store long-term in order to participate in a - # multisig wallet as a co-signer. - # - can be saved to nvram - # - can be imported from a simple text file - # - can be displayed to user in a menu (and deleted) - # - required during signing to verify change outputs - # - can reconstruct any redeem script from this - # Challenges: - # - can be big, taking big % of 4k storage in nvram - # - complex object, want to have flexibility going forward - FORMAT_NAMES = [ - (AF_P2SH, 'p2sh'), - (AF_P2WSH, 'p2wsh'), - (AF_P2WSH_P2SH, 'p2sh-p2wsh'), # preferred - (AF_P2TR, 'p2tr'), - (AF_P2WSH_P2SH, 'p2wsh-p2sh'), # obsolete (now an alias) - ] - - # optional: user can short-circuit many checks (system wide, one power-cycle only) - disable_checks = False - key_name = "multisig" - - def __init__(self, name, m_of_n, xpubs, addr_fmt=AF_P2SH, chain_type=None, bip67=True): - super().__init__(chain_type=chain_type) - - self.name = name - assert len(m_of_n) == 2 - self.M, self.N = m_of_n - assert len(xpubs[0]) == 3 - self.xpubs = xpubs # list of (xfp(int), deriv, xpub(str)) - self.addr_fmt = addr_fmt # address format for wallet - self.bip67 = bip67 - - # calc useful cache value: numeric xfp+subpath, with lookup - self.xfp_paths = {} - for xfp, deriv, xpub in self.xpubs: - self.xfp_paths[xfp] = str_to_keypath(xfp, deriv) - - assert len(self.xfp_paths) == self.N, 'dup XFP' # not supported - - @classmethod - def render_addr_fmt(cls, addr_fmt): - for k, v in cls.FORMAT_NAMES: - if k == addr_fmt: - return v.upper() - return '?' - - def render_path(self, change_idx, idx): - # assuming shared derivations for all cosigners. Wrongish. - derivs, _ = self.get_deriv_paths() - if len(derivs) > 1: - deriv = '(various)' - else: - deriv = derivs[0] - return deriv + '/%d/%d' % (change_idx, idx) - - @classmethod - def get_trust_policy(cls): - - which = settings.get('pms', None) - exists, _ = cls.exists() - if which is None: - which = TRUST_VERIFY if exists else TRUST_OFFER - - return which - - def serialize(self): - # return a JSON-able object - - opts = dict() - if self.addr_fmt != AF_P2SH: - opts['ft'] = self.addr_fmt - if self.chain_type != 'BTC': - opts['ch'] = self.chain_type - - # Data compression: most legs will all use same derivation. - # put a int(0) in place and set option 'pp' to be derivation - # (used to be common_prefix assumption) - pp = list(sorted(set(d for _,d,_ in self.xpubs))) - if len(pp) == 1: - # generate old-format data, to preserve firmware downgrade path - xp = [(a, c) for a,deriv,c in self.xpubs] - opts['pp'] = pp[0] - else: - # allow for distinct deriv paths on each leg - opts['d'] = pp - xp = [(a, pp.index(deriv),c) for a,deriv,c in self.xpubs] - - # make list already, will become one after json ser/deser - res = [self.name, (self.M, self.N), xp, opts] - if not self.bip67: - # wallets that do not follow BIP-67 are backwards incompatible - res.append(0) - - return res - - @classmethod - def deserialize(cls, vals, idx=-1): - # take json object, make instance. - bip67 = 1 # default enabled, requires 5-element serialization to disable - if len(vals) == 5: - bip67 = vals[-1] - vals = vals[:-1] - - name, m_of_n, xpubs, opts = vals - - if len(xpubs[0]) == 2: - # promote from old format to new: assume common prefix is the derivation - # for all of them - # PROBLEM: we don't have enough info if no common prefix can be assumed - common_prefix = opts.get('pp', None) - if not common_prefix: - # TODO: this should raise a warning, not supported anymore - common_prefix = 'm' - common_prefix = common_prefix.replace("'", "h") - xpubs = [(a, common_prefix, b) for a,b in xpubs] - else: - # new format decompression - if 'd' in opts: - derivs = [p.replace("'", "h") for p in opts.get('d')] - xpubs = [(a, derivs[b], c) for a,b,c in xpubs] - - rv = cls(name, m_of_n, xpubs, addr_fmt=opts.get('ft', AF_P2SH), - chain_type=opts.get('ch', 'BTC'), bip67=bool(bip67)) - rv.storage_idx = idx - return rv - - @classmethod - def is_correct_chain(cls, o, curr_chain): - # for newer versions, last element can be bip67 marker - d = o[-1] if isinstance(o[-1], dict) else o[-2] - - if "ch" not in d: - # mainnet - ch = "BTC" - else: - ch = d["ch"] - - if ch == curr_chain.ctype: - return True - return False - - @classmethod - def iter_wallets(cls, M=None, N=None, addr_fmt=None): - # yield MS wallets we know about, that match at least right M,N if known. - # - this is only place we should be searching this list, please!! - lst = settings.get(cls.key_name, []) - c = chains.current_key_chain() - - for idx, rec in enumerate(lst): - if not cls.is_correct_chain(rec, c): - continue - - if M or N: - # peek at M/N - has_m, has_n = tuple(rec[1]) - if M is not None and has_m != M: continue - if N is not None and has_n != N: continue - - if addr_fmt is not None: - opts = rec[3] - af = opts.get('ft', AF_P2SH) - if af != addr_fmt: continue - - yield cls.deserialize(rec, idx) - - def get_xfp_paths(self): - # return list of lists [xfp, *deriv] - return list(self.xfp_paths.values()) - - @classmethod - def find_match(cls, M, N, xfp_paths, addr_fmt=None): - # Find index of matching wallet - # - xfp_paths is list of lists: [xfp, *path] like in psbt files - # - M and N must be known - # - returns instance, or None if not found - for rv in cls.iter_wallets(M, N, addr_fmt=addr_fmt): - if rv.matching_subpaths(xfp_paths): - return rv - - return None - - @classmethod - def find_candidates(cls, xfp_paths, addr_fmt=None, M=None): - # Return a list of matching wallets for various M values. - # - xpfs_paths should already be sorted - # - returns set of matches, of any M value - - # we know N, but not M at this point. - N = len(xfp_paths) - - matches = [] - for rv in cls.iter_wallets(M=M, addr_fmt=addr_fmt): - if rv.matching_subpaths(xfp_paths): - matches.append(rv) - - return matches - - def matching_subpaths(self, xfp_paths): - # Does this wallet use same set of xfp values, and - # the same prefix path per-each xfp, as indicated - # xfp_paths (unordered)? - # - could also check non-prefix part is all non-hardened - if len(xfp_paths) != len(self.xfp_paths): - # cannot be the same if len(w0.N) != len(w1.N) - # maybe check duplicates first? - return False - for x in xfp_paths: - if x[0] not in self.xfp_paths: - return False - prefix = self.xfp_paths[x[0]] - - if len(x) < len(prefix): - # PSBT specs a path shorter than wallet's xpub - #print('path len: %d vs %d' % (len(prefix), len(x))) - return False - - comm = len(prefix) - if tuple(prefix[:comm]) != tuple(x[:comm]): - # xfp => maps to wrong path - #print('path mismatch:\n%r\n%r\ncomm=%d' % (prefix[:comm], x[:comm], comm)) - return False - - return True - - def assert_matching(self, M, N, xfp_paths): - # compare in-memory wallet with details recovered from PSBT - # - xfp_paths must be sorted already - assert (self.M, self.N) == (M, N), "M/N mismatch" - assert len(xfp_paths) == N, "XFP count" - if self.disable_checks: return - assert self.matching_subpaths(xfp_paths), "wrong XFP/derivs" - - @classmethod - def quick_check(cls, M, N, xfp_xor): - # quicker? USB method. - rv = [] - for ms in cls.iter_wallets(M, N): - x = 0 - for xfp in ms.xfp_paths.keys(): - x ^= xfp - if x != xfp_xor: continue - - return True - - return False - - def has_similar(self): - # check if we already have a saved duplicate to this proposed wallet - # - return (name_change, diff_items, count_similar) where: - # - name_change is existing wallet that has exact match, different name - # - diff_items: text list of similarity/differences - # - count_similar: same N, same xfp+paths - - lst = self.get_xfp_paths() - c = self.find_match(self.M, self.N, lst, addr_fmt=self.addr_fmt) - if c: - # All details are same: M/N, paths, addr fmt - if sorted(self.xpubs) != sorted(c.xpubs): - # this also applies to non-BIP-67 type multisig wallets - # multi(2,A,B) is treated as duplicate of multi(2,B,A) - # consensus-wise they are different script/wallet but CC - # don't allow to import one if other already imported - return None, ['xpubs'], 0 - elif self.bip67 != c.bip67: - # treat same keys inside different desc multi/sortedmulti as duplicates - # sortedmulti(2,A,B) is considered same as multi(2,A,B) or multi(2,B,A) - # do not allow to import multi if sortedmulti with the same set of keys - # already imported and vice-versa - return None, ["BIP-67 clash"], 1 - elif self.name == c.name: - return None, [], 1 - else: - return c, ['name'], 0 - - similar = MultisigWallet.find_candidates(lst) - if not similar: - # no matches, good. - return None, [], 0 - - # See if the xpubs are changing, which is risky... other differences like - # name are okay. - diffs = set() - for c in similar: - if c.M != self.M: - diffs.add('M differs') - if c.addr_fmt != self.addr_fmt: - diffs.add('address type') - if c.name != self.name: - diffs.add('name') - if c.xpubs != self.xpubs: - diffs.add('xpubs') - - return None, diffs, len(similar) - - def delete(self): - # remove saved entry - # - important: not expecting more than one instance of this class in memory - assert self.storage_idx >= 0 - - # safety check - for existing in self.iter_wallets(M=self.M, N=self.N, addr_fmt=self.addr_fmt): - if existing.storage_idx != self.storage_idx: continue - break - else: - raise IndexError # consistency bug - - lst = settings.get(self.key_name, []) - del lst[self.storage_idx] - if lst: - settings.set(self.key_name, lst) - else: - settings.remove_key(self.key_name) - settings.save() - - self.storage_idx = -1 - - def xpubs_with_xfp(self, xfp): - # return set of indexes of xpubs with indicated xfp - return set(xp_idx for xp_idx, (wxfp, _, _) in enumerate(self.xpubs) - if wxfp == xfp) - - def yield_addresses(self, start_idx, count, change_idx=0): - # Assuming a suffix of /0/0 on the defined prefix's, yield - # possible deposit addresses for this wallet. - ch = chains.current_chain() - - assert self.addr_fmt, 'no addr fmt known' - - # setup - nodes = [] - paths = [] - for xfp, deriv, xpub in self.xpubs: - # load bip32 node for each cosigner - node = ch.deserialize_node(xpub, AF_P2SH) - node.derive(change_idx, False) - # indicate path used (for UX) - path = "[%s/%s/%d/{idx}]" % (xfp2str(xfp), deriv[2:], change_idx) - nodes.append(node) - paths.append(path) - - idx = start_idx - while count: - if idx > MAX_BIP32_IDX: - break - # make the redeem script, convert into address - script = make_redeem_script(self.M, nodes, idx, self.bip67) - addr = ch.p2sh_address(self.addr_fmt, script) - - yield idx, addr, [p.format(idx=idx) for p in paths], script - - idx += 1 - count -= 1 - - def make_addresses_msg(self, msg, start, n, change=0): - from glob import dis - - addrs = [] - - for idx, addr, paths, script in self.yield_addresses(start, n, change): - if idx == 0 and self.N <= 4: - msg += '\n'.join(paths) + '\n =>\n' - else: - msg += '.../%d/%d =>\n' % (change, idx) - - addrs.append(addr) - msg += show_single_address(addr) + '\n\n' - dis.progress_sofar(idx - start + 1, n) - - return msg, addrs - - def generate_address_csv(self, start, n, change): - yield '"' + '","'.join(['Index', 'Payment Address', - 'Redeem Script (%d of %d)' % (self.M, self.N)] - + (['Derivation'] * self.N)) + '"\n' - - for (idx, addr, derivs, script) in self.yield_addresses(start, n, change_idx=change): - ln = '%d,"%s","%s","' % (idx, addr, b2a_hex(script).decode()) - ln += '","'.join(derivs) - ln += '"\n' - - yield ln - - def validate_script(self, redeem_script, subpaths=None, xfp_paths=None): - # Check we can generate all pubkeys in the redeem script, raise on errors. - # - working from pubkeys in the script, because duplicate XFP can happen - # - if disable_checks is set better to handle in caller, but we're also neutered - # - # redeem_script: what we expect and we were given - # subpaths: pubkey => (xfp, *path) - # xfp_paths: (xfp, *path) in same order as pubkeys in redeem script - - subpath_help = [] - used = set() - ch = self.chain - - M, N, pubkeys = disassemble_multisig(redeem_script) - assert M==self.M and N == self.N, 'wrong M/N in script' - - if self.disable_checks: return ['UNVERIFIED'] - - for pk_order, pubkey in enumerate(pubkeys): - check_these = [] - - # TODO: this could be simpler now that XFP is unique per co-signer - if subpaths: - # in PSBT, we are given a map from pubkey to xfp/path, use it - # while remembering it's potentially one-2-many - assert pubkey in subpaths, "unexpected pubkey" - xfp, *path = subpaths[pubkey] - - for xp_idx, (wxfp, _, xpub) in enumerate(self.xpubs): - if wxfp != xfp: continue - if xp_idx in used: continue # only allow once - check_these.append((xp_idx, path)) - else: - # Without PSBT, USB caller must provide xfp+path - # in same order as they occur inside redeem script. - # Working solely from the redeem script's pubkeys, we - # wouldn't know which xpub to use, nor correct path for it. - xfp, *path = xfp_paths[pk_order] - - for xp_idx in self.xpubs_with_xfp(xfp): - if xp_idx in used: continue # only allow once - check_these.append((xp_idx, path)) - - here = None - too_shallow = False - for xp_idx, path in check_these: - if not self.bip67: - assert xp_idx == pk_order, "script key order" - - # matched fingerprint, try to make pubkey that needs to match - xpub = self.xpubs[xp_idx][-1] - - node = ch.deserialize_node(xpub, AF_P2SH); assert node - dp = node.depth() - - #print("%s => deriv=%s dp=%d len(path)=%d path=%s" % - # (xfp2str(xfp), self.xpubs[xp_idx][1], dp, len(path), path)) - - if not (0 <= dp <= len(path)): - # obscure case: xpub isn't deep enough to represent - # indicated path... not wrong really. - too_shallow = True - dp = 0 - - for sp in path[dp:]: - assert not (sp & 0x80000000), 'hard deriv' - node.derive(sp, False) # works in-place - - found_pk = node.pubkey() - - # Document path(s) used. Not sure this is useful info to user tho. - # - Do not show what we can't verify: we don't really know the hardened - # part of the path from fingerprint to here. - here = '[%s]' % xfp2str(xfp) - if dp != len(path): - here = here[:-1] + ('/_'*dp) + keypath_to_str(path[dp:], '/', 0) + "]" - - if found_pk != pubkey: - # Not a match but not an error by itself, since might be - # another dup xfp to look at still. - - #print('pk mismatch: %s => %s != %s' % ( - # here, b2a_hex(found_pk), b2a_hex(pubkey))) - continue - - subpath_help.append(here) - - used.add(xp_idx) - break - else: - msg = 'pk#%d wrong' % (pk_order+1) - if not check_these: - msg += ', unknown XFP' - elif here: - msg += ', tried: ' + here - if too_shallow: - msg += ', too shallow' - raise AssertionError(msg) - - if self.bip67 and pk_order: - # verify sorted order - assert bytes(pubkey) > bytes(pubkeys[pk_order-1]), 'BIP-67 violation' - - assert len(used) == self.N, 'not all keys used: %d of %d' % (len(used), self.N) - - return subpath_help - - @classmethod - def from_simple_text(cls, lines): - # standard multisig file format - more than one line - has_mine = 0 - M, N = -1, -1 - deriv = None - name = None - xpubs = [] - addr_fmt = AF_P2SH - my_xfp = settings.get('xfp') - for ln in lines: - # remove comments - comm = ln.find('#') - if comm == 0: - continue - if comm != -1: - if not ln[comm + 1:comm + 2].isdigit(): - ln = ln[0:comm] - - ln = ln.strip() - - if ':' not in ln: - if 'pub' in ln: - # pointless optimization: allow bare xpub if we can calc xfp - label = '00000000' - value = ln - else: - # complain? - # if ln: print("no colon: " + ln) - continue - else: - label, value = ln.split(':', 1) - label = label.lower() - - value = value.strip() - - if label == 'name': - name = value - elif label == 'policy': - try: - # accepts: 2 of 3 2/3 2,3 2 3 etc - mat = ure.search(r'(\d+)\D*(\d+)', value) - assert mat - M = int(mat.group(1)) - N = int(mat.group(2)) - assert 1 <= M <= N <= MAX_SIGNERS - except: - raise AssertionError('bad policy line') - - elif label == 'derivation': - # reveal the path derivation for following key(s) - try: - assert value, 'blank' - deriv = cleanup_deriv_path(value) - except BaseException as exc: - raise AssertionError('bad derivation line: ' + str(exc)) - - elif label == 'format': - # pick segwit vs. classic vs. wrapped version - value = value.lower() - for fmt_code, fmt_label in cls.FORMAT_NAMES: - if value == fmt_label: - addr_fmt = fmt_code - break - else: - raise AssertionError('bad format line') - elif len(label) == 8: - try: - xfp = str2xfp(label) - except: - # complain? - # print("Bad xfp: " + ln) - continue - - # deserialize, update list and lots of checks - is_mine, item = check_xpub(xfp, value, deriv, chains.current_key_chain().ctype, - my_xfp, cls.disable_checks) - xpubs.append(item) - if is_mine: - has_mine += 1 - - return name, addr_fmt, xpubs, has_mine, M, N - - @classmethod - def from_descriptor(cls, descriptor: str): - # excpect descriptor here if only one line, normal multisig file requires more lines - has_mine = 0 - my_xfp = settings.get('xfp') - xpubs = [] - - descriptor = Descriptor.from_string(descriptor) - assert descriptor.is_basic_multisig, "not multisig" # raises - addr_fmt = descriptor.addr_fmt - - M, N = descriptor.miniscript.m_n() - for key in descriptor.miniscript.keys: - assert key.derivation.is_external, "Invalid subderivation path - only 0/* or <0;1>/* allowed" - xfp = key.origin.cc_fp - deriv = key.origin.str_derivation() - xpub = key.extended_public_key() - deriv = cleanup_deriv_path(deriv) - is_mine, item = check_xpub(xfp, xpub, deriv, chains.current_key_chain().ctype, - my_xfp, cls.disable_checks) - xpubs.append(item) - if is_mine: - has_mine += 1 - - return None, addr_fmt, xpubs, has_mine, M, N, descriptor.is_sortedmulti - - def to_descriptor(self): - keys = [ - Key.from_cc_data(xfp, deriv, xpub) - for xfp, deriv, xpub in self.xpubs - ] - _cls = Sortedmulti if self.bip67 else Multi - miniscript = _cls(Number(self.M), *keys) - desc = Descriptor(miniscript=miniscript) - desc.set_from_addr_fmt(self.addr_fmt) - return desc - - @classmethod - def from_file(cls, config, name=None): - # Given a simple text file, parse contents and create instance (unsaved). - # format is: label: value - # where label is: - # name: nameforwallet - # policy: M of N - # format: p2sh (+etc) - # derivation: m/45h/0 (common prefix) - # (8digithex): xpub of cosigner - # - # Descriptor support - # * text file containing multisig descriptor - # - # quick checks: - # - name: 1-20 ascii chars - # - M of N line (assume N of N if not spec'd) - # - xpub: any bip32 serialization we understand, but be consistent - # - expect_chain = chains.current_key_chain().ctype - if Descriptor.is_descriptor(config): - # assume descriptor, classic config should not contain sertedmulti( and check for checksum separator - # ignore name - _, addr_fmt, xpubs, has_mine, M, N, bip67 = cls.from_descriptor(config) - if not bip67 and not settings.get("unsort_ms", 0): - # BIP-67 disabled, but unsort_ms not allowed - raise - raise AssertionError('Unsorted multisig "multi(...)" not allowed') - else: - # oldschool - bip67 = True - lines = [line for line in config.split('\n') if line] # remove empty lines - parsed_name, addr_fmt, xpubs, has_mine, M, N = cls.from_simple_text(lines) - if parsed_name: - # if name provided in file, use that instead of name inferred from filename - name = parsed_name - - assert len(xpubs), 'need xpubs' - - if M == N == -1: - # default policy: all keys - N = M = len(xpubs) - - if not name: - # provide a default name - name = '%d-of-%d' % (M, N) - - try: - name = to_ascii_printable(name) - assert 1 <= len(name) <= 20 - except: - raise AssertionError('name must be ascii, 1..20 long') - - assert 1 <= M <= N <= MAX_SIGNERS, 'M/N range' - assert N == len(xpubs), 'wrong # of xpubs, expect %d' % N - assert addr_fmt & AFC_SCRIPT, 'script style addr fmt' - - # check we're included... do not insert ourselves, even tho we - # have enough info, simply because other signers need to know my xpubkey anyway - assert has_mine != 0, 'my key not included' - assert has_mine == 1, 'my key included more than once' - - # done. have all the parts - return cls(name, (M, N), xpubs, addr_fmt=addr_fmt, - chain_type=expect_chain, bip67=bip67) - - def make_fname(self, prefix, suffix='txt'): - rv = '%s-%s.%s' % (prefix, self.name, suffix) - return rv.replace(' ', '_') - - async def export_electrum(self): - # Generate and save an Electrum JSON file. - from export import make_json_wallet - - def doit(): - rv = dict(seed_version=17, use_encryption=False, - wallet_type='%dof%d' % (self.M, self.N)) - - ch = self.chain - - # the important stuff. - for idx, (xfp, deriv, xpub) in enumerate(self.xpubs): - - node = None - if self.addr_fmt != AF_P2SH: - # CHALLENGE: we must do slip-132 format [yz]pubs here when not p2sh mode. - node = ch.deserialize_node(xpub, AF_P2SH); assert node - xp = ch.serialize_public(node, self.addr_fmt) - else: - xp = xpub - - rv['x%d/' % (idx+1)] = dict( - hw_type='coldcard', type='hardware', - ckcc_xfp=xfp, - label='Coldcard %s' % xfp2str(xfp), - derivation=deriv, xpub=xp) - - # sign export with first p2pkh key - return ujson.dumps(rv), False, False - - await make_json_wallet('Electrum multisig wallet', doit, - fname_pattern=self.make_fname('el', 'json')) - - async def export_wallet_file(self, mode="exported from", extra_msg=None, descriptor=False, - core=False, desc_pretty=True): - # create a text file with the details; ready for import to next Coldcard - from glob import NFC, dis - - my_xfp = xfp2str(settings.get('xfp')) - if core: - name = "Bitcoin Core" - fname_pattern = self.make_fname('bitcoin-core') - elif descriptor: - name = "Descriptor" - fname_pattern = self.make_fname('desc') - else: - name = "Coldcard" - fname_pattern = self.make_fname('export') - - hdr = '%s %s' % (mode, my_xfp) - label = "%s multisig setup" % name - - choice = await import_export_prompt("%s file" % label, is_import=False, - no_qr=not version.has_qwerty) - if choice == KEY_CANCEL: - return - - dis.fullscreen("Wait...") - if choice in (KEY_NFC, KEY_QR): - with uio.StringIO() as fp: - self.render_export(fp, hdr_comment=hdr, descriptor=descriptor, - core=core, desc_pretty=desc_pretty) - if choice == KEY_NFC: - await NFC.share_text(fp.getvalue()) - else: - try: - await show_qr_code(fp.getvalue()) - except (ValueError, RuntimeError): - if version.has_qwerty: - # do BBQr on Q - from ux_q1 import show_bbqr_codes - await show_bbqr_codes('U', fp.getvalue(), label) - return - - try: - with CardSlot(**choice) as card: - fname, nice = card.pick_filename(fname_pattern) - - # do actual write - with open(fname, 'w+') as fp: - self.render_export(fp, hdr_comment=hdr, descriptor=descriptor, - core=core, desc_pretty=desc_pretty) - # fp.seek(0) - # contents = fp.read() - # TODO re-enable once we know how to proceed with regards to with which key to sign - # from auth import write_sig_file - # h = ngu.hash.sha256s(contents.encode()) - # sig_nice = write_sig_file([(h, fname)]) - - msg = '%s file written:\n\n%s' % (label, nice) - # msg += '\n\nColdcard multisig signature file written:\n\n%s' % sig_nice - if extra_msg: - msg += extra_msg - - await ux_show_story(msg) - - except CardMissingError: - await needs_microsd() - return - except Exception as e: - await ux_show_story('Failed to write!\n\n%s\n%s' % (e, problem_file_line(e))) - return - - def render_export(self, fp, hdr_comment=None, descriptor=False, core=False, desc_pretty=True): - if descriptor: - # serialize descriptor - desc_obj = self.to_descriptor() - if core: - core_obj = desc_obj.bitcoin_core_serialize() - core_str = ujson.dumps(core_obj) - print("importdescriptors '%s'\n" % core_str, file=fp) - else: - if desc_pretty: - # TODO pretty serialize - desc = desc_obj.to_string(internal=False) - else: - desc = desc_obj.to_string(internal=False) - print("%s\n" % desc, file=fp) - else: - if hdr_comment: - print("# Coldcard Multisig setup file (%s)\n#" % hdr_comment, file=fp) - - print("Name: %s\nPolicy: %d of %d" % (self.name, self.M, self.N), file=fp) - - if self.addr_fmt != AF_P2SH: - print("Format: " + self.render_addr_fmt(self.addr_fmt), file=fp) - - last_deriv = None - for xfp, deriv, val in self.xpubs: - if last_deriv != deriv: - print("\nDerivation: %s\n" % deriv, file=fp) - last_deriv = deriv - - print('%s: %s' % (xfp2str(xfp), val), file=fp) - - @classmethod - def guess_addr_fmt(cls, npath): - # Assuming the bips are being respected, what address format will be used, - # based on indicated numeric subkey path observed. - # - return None if unsure, no errors - # - #( "m/45h", 'p2sh', AF_P2SH), - #( "m/48h/{coin}h/0h/1h", 'p2sh_p2wsh', AF_P2WSH_P2SH), - #( "m/48h/{coin}h/0h/2h", 'p2wsh', AF_P2WSH) - - top = npath[0] & 0x7fffffff - if top == npath[0]: - # non-hardened top? rare/bad - return - - if top == 45: - return AF_P2SH - - if top == 48: - if len(npath) < 4: return - - last = npath[3] & 0x7fffffff - if last == 1: - return AF_P2WSH_P2SH - if last == 2: - return AF_P2WSH - - @classmethod - def import_from_psbt(cls, M, N, xpubs_list): - # given the raw data from PSBT global header, offer the user - # the details, and/or bypass that all and just trust the data. - # - xpubs_list is a list of (xfp+path, binary BIP-32 xpub) - # - already know not in our records. - trust_mode = cls.get_trust_policy() - - if trust_mode == TRUST_VERIFY: - # already checked for existing import and wasn't found, so fail - raise FatalPSBTIssue("XPUBs in PSBT do not match any existing wallet") - - # build up an in-memory version of the wallet. - # - capture address format based on path used for my leg (if standards compliant) - - assert N == len(xpubs_list) - assert 1 <= M <= N <= MAX_SIGNERS, 'M/N range' - my_xfp = settings.get('xfp') - - expect_chain = chains.current_chain().ctype - xpubs = [] - has_mine = 0 - - for k, v in xpubs_list: - xfp, *path = ustruct.unpack_from('<%dI' % (len(k)//4), k, 0) - xpub = ngu.codecs.b58_encode(v) - is_mine, item = check_xpub(xfp, xpub, keypath_to_str(path, skip=0), - expect_chain, my_xfp, cls.disable_checks) - xpubs.append(item) - if is_mine: - has_mine += 1 - addr_fmt = cls.guess_addr_fmt(path) - - assert has_mine == 1 # 'my key not included' - - name = 'PSBT-%d-of-%d' % (M, N) - # this will always create sortedmulti multisig (BIP-67) - # because BIP-174 came years after wide spread acceptance of BIP-67 policy - ms = cls(name, (M, N), xpubs, chain_type=expect_chain, addr_fmt=addr_fmt or AF_P2SH) # TODO why legacy - - # may just keep in-memory version, no approval required, if we are - # trusting PSBT's today, otherwise caller will need to handle UX w.r.t new wallet - return ms, (trust_mode != TRUST_PSBT) - - def validate_psbt_xpubs(self, xpubs_list): - # The xpubs provided in PSBT must be exactly right, compared to our record. - # But we're going to use our own values from setup time anyway. - # Check: - # - chain codes match what we have stored already - # - pubkey vs. path will be checked later - # - xfp+path already checked when selecting this wallet - # - some cases we cannot check, so count those for a warning - # Any issue here is a fraud attempt in some way, not innocent. - # But it would not have tricked us and so the attack targets some other signer. - assert len(xpubs_list) == self.N - - for k, v in xpubs_list: - xfp, *path = ustruct.unpack_from('<%dI' % (len(k)//4), k, 0) - xpub = ngu.codecs.b58_encode(v) - - # cleanup and normalize xpub - tmp = [] - is_mine, item = check_xpub(xfp, xpub, keypath_to_str(path, skip=0), - self.chain_type, 0, self.disable_checks) - tmp.append(item) - (_, deriv, xpub_reserialized) = tmp[0] - assert deriv # because given as arg - - if self.disable_checks: - # allow wrong derivation paths in PSBT; but also allows usage when - # old pre-3.2.1 MS wallet lacks derivation details for all legs - continue - - # find in our records. - for (x_xfp, x_deriv, x_xpub) in self.xpubs: - if x_xfp != xfp: continue - # found matching XFP - assert deriv == x_deriv - - assert xpub_reserialized == x_xpub, 'xpub wrong (xfp=%s)' % xfp2str(xfp) - break - else: - assert False # not reachable, since we picked wallet based on xfps - - def get_deriv_paths(self): - # List of unique derivation paths being used. Often length one. - # - also a rendered single-value summary - derivs = sorted(set(d for _,d,_ in self.xpubs)) - - if len(derivs) == 1: - dsum = derivs[0] - else: - dsum = 'Varies (%d)' % len(derivs) - - return derivs, dsum - - async def confirm_import(self): - # prompt them about a new wallet, let them see details and then commit change. - M, N = self.M, self.N - - if M == N == 1: - exp = 'The one signer must approve spends.' - elif M == N: - exp = 'All %d co-signers must approve spends.' % N - elif M == 1: - exp = 'Any signature from %d co-signers will approve spends.' % N - else: - exp = '{M} signatures, from {N} possible co-signers, will be required to approve spends.'.format(M=M, N=N) - - # Look for duplicate stuff - name_change, diff_items, num_dups = self.has_similar() - - is_dup = False - if name_change: - story = 'Update NAME only of existing multisig wallet?' - elif num_dups and isinstance(diff_items, list): - # failures only - story = "Duplicate wallet." - if diff_items: - story += diff_items[0] - else: - story += ' All details are the same as existing!' - is_dup = True - elif diff_items: - # Concern here is overwrite when similar, but we don't overwrite anymore, so - # more of a warning about funny business. - story = '''\ -WARNING: This new wallet is similar to an existing wallet, but will NOT replace it. Consider deleting previous wallet first. Differences: \ -''' + ', '.join(diff_items) - else: - story = 'Create new multisig wallet?' - - derivs, dsum = self.get_deriv_paths() - - if not self.bip67 and not is_dup: - # do not need to warn if duplicate, won;t be allowed to import anyways - story += "\nWARNING: BIP-67 disabled! Unsorted multisig - order of keys in descriptor/backup is crucial" - - story += '''\n -Wallet Name: - {name} - -Policy: {M} of {N} - -{exp} - -Addresses: - {at} - -Derivation: - {dsum} - -Press (1) to see extended public keys, '''.format(M=M, N=N, name=self.name, exp=exp, dsum=dsum, - at=self.render_addr_fmt(self.addr_fmt)) - if not is_dup: - story += ('%s to approve, %s to cancel.' % (OK, X)) - else: - story += '%s to cancel' % X - - ux_clear_keys(True) - while 1: - ch = await ux_show_story(story, escape='1') - - if ch == '1': - await self.show_detail(verbose=False) - continue - - if ch == 'y' and not is_dup: - # save to nvram, may raise WalletOutOfSpace - if name_change: - name_change.delete() - - assert self.storage_idx == -1 - self.commit() - await ux_dramatic_pause("Saved.", 2) - break - - return ch - - async def show_detail(self, verbose=True): - # Show the xpubs; might be 2k or more rendered. - msg = uio.StringIO() - - if verbose: - if not self.bip67: - msg.write("WARNING: BIP-67 disabled! Unsorted multisig - order of keys in descriptor/backup is crucial.\n\n") - - vmsg = ('Policy: {M} of {N}\n' - 'Blockchain: {ctype}\n' - 'Addresses: {at}\n\n') - vmsg = vmsg.format(M=self.M, N=self.N, ctype=self.chain_type, - at=self.render_addr_fmt(self.addr_fmt)) - msg.write(vmsg) - - # order of keys in self.xpubs is same as order of keys in CC import format or descriptor - for idx, (xfp, deriv, xpub) in enumerate(self.xpubs): - if idx: - msg.write('\n---===---\n\n') - - msg.write('%s:\n %s\n\n%s\n' % (xfp2str(xfp), deriv, xpub)) - - if self.addr_fmt not in (AF_P2SH, AF_P2TR): - # SLIP-132 format [yz]pubs here when not p2sh mode. - # - has same info as proper bitcoin serialization, but looks much different - node = self.chain.deserialize_node(xpub, AF_P2SH) - xp = self.chain.serialize_public(node, self.addr_fmt) - - msg.write('\nSLIP-132 equiv:\n%s\n' % xp) - - return await ux_show_story(msg, title=self.name) - -async def no_ms_yet(*a): - # action for 'no wallets yet' menu item - await ux_show_story("You don't have any multisig wallets yet.") - -def disable_checks_chooser(): - ch = ['Normal', 'Skip Checks'] - - def xset(idx, text): - MultisigWallet.disable_checks = bool(idx) - - return int(MultisigWallet.disable_checks), ch, xset - -async def disable_checks_menu(*a): - - if not MultisigWallet.disable_checks: - ch = await ux_show_story('''\ -With many different wallet vendors and implementors involved, it can \ -be hard to create a PSBT consistent with the many keys involved. \ -With this setting, you can \ -disable the more stringent verification checks your Coldcard normally provides. - -USE AT YOUR OWN RISK. These checks exist for good reason! Signed txn may \ -not be accepted by network. - -This settings lasts only until power down. - -Press (4) to confirm entering this DANGEROUS mode. -''', escape='4') - - if ch != '4': return - - start_chooser(disable_checks_chooser) - - -def psbt_xpubs_policy_chooser(): - # Chooser for trust policy - ch = ['Verify Only', 'Offer Import', 'Trust PSBT'] - - def xset(idx, text): - settings.set('pms', idx) - - return MultisigWallet.get_trust_policy(), ch, xset - -async def trust_psbt_menu(*a): - # show a story then go into chooser - - ch = await ux_show_story('''\ -This setting controls what the Coldcard does \ -with the co-signer public keys (XPUB) that may \ -be provided inside a PSBT file. Three choices: - -- Verify Only. Do not import the xpubs found, but do \ -verify the correct wallet already exists on the Coldcard. - -- Offer Import. If it's a new multisig wallet, offer to import \ -the details and store them as a new wallet in the Coldcard. - -- Trust PSBT. Use the wallet data in the PSBT as a temporary, -multisig wallet, and do not import it. This permits some \ -deniability and additional privacy. - -When the XPUB data is not provided in the PSBT, regardless of the above, \ -we require the appropriate multisig wallet to already exist \ -on the Coldcard. Default is to 'Offer' unless a multisig wallet already \ -exists, otherwise 'Verify'.''') - - if ch == 'x': return - start_chooser(psbt_xpubs_policy_chooser) - -def unsort_ms_chooser(): - def xset(idx, text): - if idx: - settings.set('unsort_ms', idx) - else: - settings.remove_key('unsort_ms') - - return settings.get('unsort_ms', 0), ['Do Not Allow', 'Allow'], xset - -async def unsorted_ms_menu(*a): - - if not settings.get("unsort_ms", None): - ch = await ux_show_story( - 'Enable this to allow import and operation with' - ' "multi(...)" unsorted multisig wallets that DO NOT follow BIP-67.' - ' It is of CRUCIAL importance to backup multisig descriptor for unsorted wallets' - ' in order to preserve key ordering.' - ' Many popular wallets like Sparrow and Electrum do NOT support "multi(...)".' - '\n\nUSE AT YOUR OWN RISK. Disabling BIP-67 is discouraged!' - '\n\nPress (4) to confirm allowing "multi(...)"', escape='4') - - if ch != '4': return - - else: - # unsort_ms enabled - assume he is going to disable - # check any multi(...) imported - ms = settings.get("multisig", []) - multi_names = [m[0] for m in ms if len(m) == 5] - if multi_names: - # do not allow to disable if any multi(...) imported - # list by name what needs to be removed - await ux_show_story( - "Remove already saved multi(...) wallets first.\n\n%s" - % multi_names - ) - return - - start_chooser(unsort_ms_chooser) - -class MultisigMenu(MenuSystem): - - @classmethod - def construct(cls): - # Dynamic menu with user-defined names of wallets shown - - from bsms import make_ms_wallet_bsms_menu - - exists, exists_other_chain = MultisigWallet.exists() - if not exists: - rv = [MenuItem(MultisigWallet.none_setup_yet(exists_other_chain), f=no_ms_yet)] - else: - rv = [] - for ms in MultisigWallet.get_all(): - rv.append(MenuItem('%d/%d: %s' % (ms.M, ms.N, ms.name), - menu=make_ms_wallet_menu, arg=ms.storage_idx)) - from glob import NFC - rv.append(MenuItem('Import from File', f=import_multisig)) - rv.append(MenuItem('Import from QR', f=import_multisig_qr, - predicate=version.has_qwerty, shortcut=KEY_QR)) - rv.append(MenuItem('Import via NFC', f=import_multisig_nfc, - predicate=bool(NFC), shortcut=KEY_NFC)) - rv.append(MenuItem('Export XPUB', f=export_multisig_xpubs)) - rv.append(MenuItem('BSMS (BIP-129)', menu=make_ms_wallet_bsms_menu)) - rv.append(MenuItem('Create Airgapped', f=create_ms_step1)) - rv.append(MenuItem('Trust PSBT?', f=trust_psbt_menu)) - rv.append(MenuItem('Skip Checks?', f=disable_checks_menu)) - rv.append(NonDefaultMenuItem( - 'Unsorted Multisig?' if version.has_qwerty else 'Unsorted Multi?', - 'unsort_ms', f=unsorted_ms_menu)) - - return rv - - def update_contents(self): - # Reconstruct the list of wallets on this dynamic menu, because - # we added or changed them and are showing that same menu again. - tmp = self.construct() - self.replace_items(tmp) - - -async def make_multisig_menu(*a): - # list of all multisig wallets, and high-level settings/actions - from pincodes import pa - - if not pa.has_secrets(): - await ux_show_story("You must have wallet seed before creating multisig wallets.") - return - - rv = MultisigMenu.construct() - return MultisigMenu(rv) - -async def make_ms_wallet_menu(menu, label, item): - # details, actions on single multisig wallet - ms = MultisigWallet.get_by_idx(item.arg) - if not ms: return - - rv = [ - MenuItem('"%s"' % ms.name, f=ms_wallet_detail, arg=ms), - MenuItem('View Details', f=ms_wallet_detail, arg=ms), - MenuItem('Delete', f=ms_wallet_delete, arg=ms), - ] - if ms.bip67: - rv += [ - MenuItem('Coldcard Export', f=ms_wallet_ckcc_export, arg=(ms, {})), - MenuItem('Electrum Wallet', f=ms_wallet_electrum_export, arg=ms), - ] - # only way to export non-BIP-67 ms wallet is descriptors (+core export) - rv.append(MenuItem('Descriptors', menu=make_ms_wallet_descriptor_menu, arg=ms)) - return rv - -async def make_ms_wallet_descriptor_menu(menu, label, item): - # descriptor menu - ms = item.arg - if not ms: - return - - rv = [ - MenuItem('View Descriptor', f=ms_wallet_show_descriptor, arg=ms), - MenuItem('Export', f=ms_wallet_ckcc_export, - arg=(ms, {"descriptor": True, "desc_pretty": False})), - MenuItem('Bitcoin Core', f=ms_wallet_ckcc_export, - arg=(ms, {"descriptor": True, "core": True})), - ] - return rv - -async def ms_wallet_delete(menu, label, item): - ms = item.arg - - # delete - if not await ux_confirm("Delete this multisig wallet (%s)?\n\nFunds may be impacted." - % ms.name): - await ux_dramatic_pause('Aborted.', 3) - return - - ms.delete() - await ux_dramatic_pause('Deleted.', 3) - - # update/hide from menu - #menu.update_contents() - - from ux import the_ux - # pop stack - the_ux.pop() - - m = the_ux.top_of_stack() - m.update_contents() - -async def ms_wallet_ckcc_export(menu, label, item): - # create a text file with the details; ready for import to next Coldcard - ms = item.arg[0] - kwargs = item.arg[1] - await ms.export_wallet_file(**kwargs) - -async def ms_wallet_show_descriptor(menu, label, item): - from glob import dis - dis.fullscreen("Wait...") - ms = item.arg - desc = ms.to_descriptor() - desc_str = desc.to_string(internal=False) - ch = await ux_show_story("Press (1) to export in pretty human readable format.\n\n" + desc_str, escape="1") - if ch == "1": - await ms.export_wallet_file(descriptor=True, desc_pretty=True) - -async def ms_wallet_electrum_export(menu, label, item): - # create a JSON file that Electrum can use. Challenges: - # - file contains derivation paths for each co-signer to use - # - electrum is using BIP-43 with purpose=48 (purpose48_derivation) to make paths like: - # m/48h/1h/0h/2h - # - above is now called BIP-48 - # - other signers might not be coldcards (we don't know) - # solution: - # - when building air-gap, pick address type at that point, and matching path to suit - # - could check path prefix and addr_fmt make sense together, but meh. - ms = item.arg - from actions import electrum_export_story - - derivs, dsum = ms.get_deriv_paths() - - msg = 'The new wallet will have derivation path:\n %s\n and use %s addresses.\n' % ( - dsum, MultisigWallet.render_addr_fmt(ms.addr_fmt) ) - - if await ux_show_story(electrum_export_story(msg)) != 'y': - return - - await ms.export_electrum() - - -async def ms_wallet_detail(menu, label, item): - # show details of single multisig wallet - from glob import dis - ms = item.arg - dis.fullscreen("Wait...") - return await ms.show_detail() - - -async def export_multisig_xpubs(*a): - # WAS: Create a single text file with lots of docs, and all possible useful xpub values. - # THEN: Just create the one-liner xpub export value they need/want to support BIP-45 - # NOW: Export JSON with one xpub per useful address type and semi-standard derivation path - # - # Consumer for this file is supposed to be ourselves, when we build on-device multisig. - # - however some 3rd parties are making use of it as well. - # - from glob import NFC, dis - from ux import import_export_prompt - - xfp = xfp2str(settings.get('xfp', 0)) - chain = chains.current_chain() - - fname_pattern = 'ccxp-%s.json' % xfp - label = "Multisig XPUB" - - msg = '''\ -This feature creates a small file containing \ -the extended public keys (XPUB) you would need to join \ -a multisig wallet. - -Public keys for BIP-48 conformant paths are used: - -P2SH-P2WSH: - m/48h/{coin}h/{{acct}}h/1h -P2WSH: - m/48h/{coin}h/{{acct}}h/2h -P2TR: - m/48h/{coin}h/{{acct}}h/3h - -{ok} to continue. {x} to abort.'''.format(coin=chain.b44_cointype, ok=OK, x=X) - - ch = await ux_show_story(msg) - if ch != "y": - return - - acct_num = await ux_enter_bip32_index('Account Number:') or 0 - - choice = await import_export_prompt("%s file" % label, is_import=False, - no_qr=not version.has_qwerty) - - if choice == KEY_CANCEL: - return - - dis.fullscreen('Generating...') - - todo = [ - ("m/45h", 'p2sh', AF_P2SH), # iff acct_num == 0 - ("m/48h/{coin}h/{acct_num}h/1h", 'p2sh_p2wsh', AF_P2WSH_P2SH), - ("m/48h/{coin}h/{acct_num}h/2h", 'p2wsh', AF_P2WSH), - ("m/48h/{coin}h/{acct_num}h/3h", 'p2tr', AF_P2TR), - ] - - def render(fp): - fp.write('{\n') - with stash.SensitiveValues() as sv: - for deriv, name, fmt in todo: - if fmt == AF_P2SH and acct_num: - continue - dd = deriv.format(coin=chain.b44_cointype, acct_num=acct_num) - node = sv.derive_path(dd) - xp = chain.serialize_public(node, fmt) - fp.write(' "%s_deriv": "%s",\n' % (name, dd)) - fp.write(' "%s": "%s",\n' % (name, xp)) - xpub = chain.serialize_public(node) - descriptor_template = multisig_descriptor_template(xpub, dd, xfp, fmt) - if descriptor_template is None: - continue - fp.write(' "%s_desc": "%s",\n' % (name, descriptor_template)) - - fp.write(' "account": "%d",\n' % acct_num) - fp.write(' "xfp": "%s"\n}\n' % xfp) - - if choice in (KEY_NFC, KEY_QR): - with uio.StringIO() as fp: - render(fp) - if choice == KEY_NFC: - await NFC.share_json(fp.getvalue()) - elif version.has_qwerty: - from ux_q1 import show_bbqr_codes - await show_bbqr_codes('J', fp.getvalue(), label) - return - - try: - with CardSlot(**choice) as card: - fname, nice = card.pick_filename(fname_pattern) - # do actual write: manual JSON here so more human-readable. - with open(fname, 'w+') as fp: - render(fp) - # fp.seek(0) - # contents = fp.read() - # TODO re-enable once we know how to proceed with regards to with which key to sign - # from auth import write_sig_file - # h = ngu.hash.sha256s(contents.encode()) - # sig_nice = write_sig_file([(h, fname)]) - - except CardMissingError: - await needs_microsd() - return - except Exception as e: - await ux_show_story('Failed to write!\n\n\n'+str(e)) - return - - msg = '%s file written:\n\n%s' % (label, nice) - # msg += '\n\nMultisig XPUB signature file written:\n\n%s' % sig_nice - await ux_show_story(msg) - -async def validate_xpub_for_ms(obj, af_str, chain, my_xfp, xpubs): - # Read xpub and validate from JSON received via SD card or BBQr - # - obj => JSON object (mapping) - # - af_str => address format we expect/need - - # value in file is BE32, but we want LE32 internally - # - KeyError here handled by caller - xfp = str2xfp(obj['xfp']) - deriv = cleanup_deriv_path(obj[af_str + '_deriv']) - ln = obj.get(af_str) - - is_mine, item = check_xpub(xfp, ln, deriv, chain.ctype, my_xfp, xpubs) - xpubs.append(item) - return is_mine - -async def ms_coordinator_qr(af_str, my_xfp, chain): +async def ms_coordinator_qr(af_str, my_xfp): # Scan a number of JSON files from BBQr w/ derive, xfp and xpub details. # - from ux_q1 import QRScannerInteraction + from ux_q1 import QRScannerInteraction, decode_qr_result, QRDecodeExplained + + def convertor(got): + file_type, _, data = decode_qr_result(got, expect_bbqr=True) + if isinstance(data, bytes): + # we expect BBQr, but simple QR also possible here + data = data.decode() + + if file_type == 'U': + data = data.strip() + if data[0] == '{' and data[-1] == '}': + file_type = 'J' + if file_type == 'J': + try: + return ujson.loads(data) + except: + raise QRDecodeExplained('Unable to decode JSON data') + else: + for line in data.split("\n"): + if len(line) > 112 and ("pub" in line): + return line.strip() num_mine = 0 num_files = 0 - xpubs = [] + keys = [] msg = 'Scan Exported XPUB from Coldcard' while True: - vals = await QRScannerInteraction().scan_json(msg) - if vals is None: + key = await QRScannerInteraction().scan_general(msg, convertor, enter_quits=True) + if key is None: break - try: - is_mine = await validate_xpub_for_ms(vals, af_str, chain, my_xfp, xpubs) + if isinstance(key, dict): + k = Key.from_cc_json(key, af_str) + else: + k = Key.from_string(key) + + num_mine += k.validate(my_xfp) + keys.append(k) + except KeyError as e: # random JSON will end up here msg = "Missing value: %s" % str(e) @@ -1571,19 +66,17 @@ async def ms_coordinator_qr(af_str, my_xfp, chain): msg = "Failure: %s" % str(e) continue - if is_mine: - num_mine += 1 num_files += 1 msg = "Number of keys scanned: %d" % num_files - return xpubs, num_mine, num_files + return keys, num_mine, num_files -async def ms_coordinator_file(af_str, my_xfp, chain, slot_b=None): +async def ms_coordinator_file(af_str, my_xfp, slot_b=None): num_mine = 0 num_files = 0 - xpubs = [] + keys = [] try: with CardSlot(slot_b=slot_b) as card: for path in card.get_paths(): @@ -1592,7 +85,9 @@ async def ms_coordinator_file(af_str, my_xfp, chain, slot_b=None): # ignore subdirs continue - if not fn.startswith('ccxp-') or not fn.endswith('.json'): + if fn.endswith('.bsms'): + pass # allows files with [xfp/p/a/t/h]xpub + elif not fn.startswith('ccxp-') or not fn.endswith('.json'): # wrong prefix/suffix: ignore continue @@ -1608,13 +103,28 @@ async def ms_coordinator_file(af_str, my_xfp, chain, slot_b=None): try: with open(full_fname, 'rt') as fp: - vals = ujson.load(fp) + try: + # CC multisig XPUBs JSON expected + vals = ujson.load(fp) + except: + # try looking for BIP-380 key expression + fp.seek(0) + for line in fp.readlines(): + if len(line) > 112 and ("pub" in line): + vals = line.strip() + break - is_mine = await validate_xpub_for_ms(vals, af_str, chain, - my_xfp, xpubs) - if is_mine: - num_mine += 1 + try: + if isinstance(vals, dict): + k = Key.from_cc_json(vals, af_str) + else: + k = Key.from_string(vals) + except Exception as e: + # sys.print_exception(e) + raise + num_mine += k.validate(my_xfp) + keys.append(k) num_files += 1 except CardMissingError: @@ -1622,16 +132,31 @@ async def ms_coordinator_file(af_str, my_xfp, chain, slot_b=None): except Exception as exc: # show something for coders, but no user feedback - sys.print_exception(exc) + # sys.print_exception(exc) continue except CardMissingError: await needs_microsd() return - return xpubs, num_mine, num_files + return keys, num_mine, num_files -async def ondevice_multisig_create(mode='p2wsh', addr_fmt=AF_P2WSH, is_qr=False): + +def add_own_xpub(chain, acct_num, addr_fmt, secret=None): + # Build out what's required for using master secret (or another + # encoded secret) as a co-signer + deriv = "48h/%dh/%dh/%dh" % (chain.b44_cointype, acct_num, + 2 if addr_fmt == AF_P2WSH else 1) + + with stash.SensitiveValues(secret=secret) as sv: + the_xfp = xfp2str(sv.get_xfp()) + koi = KeyOriginInfo.from_string(the_xfp + "/" + deriv) + node = sv.derive_path(deriv, register=False) + key = Key(node, koi, chain_type=chain.ctype) + return key + + +async def ondevice_multisig_create(mode='p2wsh', addr_fmt=AF_P2WSH, is_qr=False, for_ccc=None): # collect all xpub- exports (must be >= 1) to make "air gapped" wallet # - function f specifies a way how to collect co-signer info - currently SD and QR (Q only) # - ask for M value @@ -1644,21 +169,21 @@ async def ondevice_multisig_create(mode='p2wsh', addr_fmt=AF_P2WSH, is_qr=False) my_xfp = settings.get('xfp') if is_qr: - xpubs, num_mine, num_files = await ms_coordinator_qr(mode, my_xfp, chain) + keys, num_mine, num_files = await ms_coordinator_qr(mode, my_xfp) else: - xpubs, num_mine, num_files = await ms_coordinator_file(mode, my_xfp, chain) + keys, num_mine, num_files = await ms_coordinator_file(mode, my_xfp) if CardSlot.both_inserted(): # handle dual slot usage: assumes slot A used by first call above - bxpubs, bnum_mine, bnum_files = await ms_coordinator_file(mode, my_xfp, - chain, True) - xpubs.extend(bxpubs) + bkeys, bnum_mine, bnum_files = await ms_coordinator_file(mode, my_xfp, + slot_b=True) + keys.extend(bkeys) num_mine += bnum_mine num_files += bnum_files # remove dups; easy to happen if you double-tap the export - xpubs = list(set(xpubs)) + keys = list(set(keys)) - if not xpubs or (len(xpubs) == 1 and num_mine): + if not keys or (len(keys) == 1 and num_mine): if is_qr: msg = "No XPUBs scanned. Exit." else: @@ -1666,45 +191,82 @@ async def ondevice_multisig_create(mode='p2wsh', addr_fmt=AF_P2WSH, is_qr=False) " Must have filename: ccxp-....json") await ux_show_story(msg) return - - # add myself if not included already ? - if not num_mine: + + if for_ccc: + secret, ccc_ms_count = for_ccc + # Always include 2 keys from CCC: own master (key A) and key C + # - force them to same derivation. + acct = await ux_enter_bip32_index('CCC Account Number:') or 0 + + dis.fullscreen("Wait...") + a = add_own_xpub(chain, acct, addr_fmt) # master: key A + c = add_own_xpub(chain, acct, addr_fmt, secret=secret) + + # problem: above file searching may find xpub export from key C + # (or our master seed, exported) .. we can't add them again, + # since xfp are not unique and that's probably not what they wanted + got_xfps = [a.origin.fingerprint, c.origin.fingerprint] + keys = [k for k in keys if k.origin.fingerprint not in got_xfps] + + if not keys: + await ux_show_story("Need at least one other co-signer (key B).") + return + + # master seed is always key0, key C is key1, k2..kn backup keys + keys = [a, c] + keys + num_mine += 2 + + elif not num_mine: + # add myself if not included already? As an option. ch = await ux_show_story("Add current Coldcard with above XFP ?", title="[%s]" % xfp2str(my_xfp)) if ch == "y": acct = await ux_enter_bip32_index('Account Number:') or 0 dis.fullscreen("Wait...") - deriv = "m/48h/%dh/%dh/%dh" % (chain.b44_cointype, acct, - 2 if addr_fmt == AF_P2WSH else 1) - with stash.SensitiveValues() as sv: - node = sv.derive_path(deriv) - xpubs.append((my_xfp, deriv, chain.serialize_public(node, AF_P2SH))) + keys.append(add_own_xpub(chain, acct, addr_fmt)) num_mine += 1 - N = len(xpubs) + N = len(keys) if (N > MAX_SIGNERS) or (N < 2): await ux_show_story("Invalid number of signers,min is 2 max is %d." % MAX_SIGNERS) return - # pick useful M value to start - M = await ux_enter_number("How many need to sign?(M)", N, can_cancel=True) - if not M: - await ux_dramatic_pause('Aborted.', 2) - return # user cancel + if for_ccc: + M = 2 + else: + # pick useful M value to start + M = await ux_enter_number("How many need to sign?(M)", N, can_cancel=True) + if not M: + await ux_dramatic_pause('Aborted.', 2) + return # user cancel dis.fullscreen("Wait...") # create appropriate object assert 1 <= M <= N <= MAX_SIGNERS - name = 'CC-%d-of-%d' % (M, N) - ms = MultisigWallet(name, (M, N), xpubs, chain_type=chain.ctype, addr_fmt=addr_fmt) + if for_ccc: + name = "Coldcard Co-sign" if version.has_qwerty else "CCC" + if ccc_ms_count: + # make name unique for each CCC wallet, but they can edit + name += " #%d" % (ccc_ms_count + 1) + else: + name = 'CC-%d-of-%d' % (M, N) + + from miniscript import Sortedmulti, Number + from wallet import MiniScriptWallet + from descriptor import Descriptor + + desc_obj = Descriptor(miniscript=Sortedmulti(Number(M), *keys), + addr_fmt=addr_fmt) + # no need to validate here - as all the keys are already validated + msc = MiniScriptWallet.from_descriptor_obj(name, desc_obj) if num_mine: from auth import NewMiniscriptEnrollRequest, UserAuthorizedAction - UserAuthorizedAction.active_request = NewMiniscriptEnrollRequest(ms) + UserAuthorizedAction.active_request = NewMiniscriptEnrollRequest(msc) # menu item case: add to stack from ux import the_ux @@ -1712,24 +274,26 @@ async def ondevice_multisig_create(mode='p2wsh', addr_fmt=AF_P2WSH, is_qr=False) else: # we cannot enroll multisig in which we do not participate # thou we can put descriptor on screen or on SD - await ms.export_wallet_file(descriptor=True, desc_pretty=False) + # cannot sign export if my key not included + await msc.export_wallet_file(sign=False) -async def create_ms_step1(*a): +async def create_ms_step1(*a, for_ccc=None): # Show story, have them pick address format. ch = None is_qr = False if version.has_qr: # They have a scanner, could do QR codes... - ch = await ux_show_story("Press "+ KEY_QR + " to scan multisg XPUBs from "\ - "QR codes (BBQr) or ENTER to use SD card(s).", title="QR or SD Card?") + ch = await ux_show_story("Press " + KEY_QR + " to scan multisig XPUBs from " + "QR codes (BBQr) or ENTER to use SD card(s).", + title="QR or SD Card?") if ch == KEY_QR: is_qr = True - ch = await ux_show_story("Press ENTER for default address format (P2WSH, segwit), "\ + ch = await ux_show_story("Press ENTER for default address format (P2WSH, segwit), " "otherwise, press (1) for P2SH-P2WSH.", title="Address Format", - escape="1") + escape="1") else: ch = await ux_show_story('''\ @@ -1747,81 +311,9 @@ Default is P2WSH addresses (segwit) or press (1) for P2SH-P2WSH.''', escape='1') return try: - return await ondevice_multisig_create(n, f, is_qr) + return await ondevice_multisig_create(n, f, is_qr, for_ccc=for_ccc) except Exception as e: + # sys.print_exception(e) await ux_show_story('Failed to create multisig.\n\n%s\n%s' % (e, problem_file_line(e)), title="ERROR") - - -async def import_multisig_nfc(*a): - from glob import NFC - # this menu option should not be available if NFC is disabled - try: - return await NFC.import_miniscript_nfc(legacy_multisig=True) - except Exception as e: - await ux_show_story(title="ERROR", msg="Failed to import multisig. %s" % str(e)) - -async def import_multisig_qr(*a): - from auth import maybe_enroll_xpub - from ux_q1 import QRScannerInteraction - data = await QRScannerInteraction().scan_text('Scan Multisig from a QR code') - if not data: - # pressed CANCEL - return - - try: - maybe_enroll_xpub(config=data) - except Exception as e: - await ux_show_story('Failed to import.\n\n%s\n%s' % (e, problem_file_line(e))) - -async def import_multisig(*a): - # pick text file from SD card, import as multisig setup file - from actions import file_picker - from glob import VD - - force_vdisk = False - if VD: - prompt = "Press (1) to import multisig wallet file from SD Card" - escape = "1" - if VD is not None: - prompt += ", press (2) to import from Virtual Disk" - escape += "2" - prompt += "." - ch = await ux_show_story(prompt, escape=escape) - if ch == "1": - force_vdisk=False - elif ch == "2": - force_vdisk = True - else: - return - - def possible(filename): - with open(filename, 'rt') as fd: - for ln in fd: - if "sh(" in ln or "wsh(" in ln: - # descriptor import - return True - if 'pub' in ln: - return True - - fn = await file_picker(suffix=['.txt', '.json'], min_size=100, max_size=350*200, - taster=possible, force_vdisk=force_vdisk) - if not fn: return - - try: - with CardSlot(force_vdisk=force_vdisk) as card: - with open(fn, 'rt') as fp: - data = fp.read() - except CardMissingError: - await needs_microsd() - return - - from auth import maybe_enroll_xpub - try: - possible_name = (fn.split('/')[-1].split('.'))[0] - maybe_enroll_xpub(config=data, name=possible_name) - except Exception as e: - #import sys; sys.print_exception(e) - await ux_show_story('Failed to import.\n\n%s\n%s' % (e, problem_file_line(e))) - # EOF diff --git a/shared/nfc.py b/shared/nfc.py index ee83ceb5..be66c500 100644 --- a/shared/nfc.py +++ b/shared/nfc.py @@ -107,13 +107,14 @@ class NFCHandler: from glob import dis here = bytes(256) end = 8196 - for pos in range(0, end, 256) : + for pos in range(0, end, 256): self.i2c.writeto_mem(I2C_ADDR_USER, pos, here, addrsize=16) - if pos == 256 and not full_wipe: break + if (pos == 256) and not full_wipe: break # 6ms per 16 byte row, worst case, so ~100ms here per iter! 3.2seconds total if full_wipe: dis.progress_bar_show(pos / end) + await self.wait_ready() # system config area (flash cells, but affect operation): table 12 @@ -224,6 +225,14 @@ class NFCHandler: self.set_rf_disable(1) + async def share_loop(self, n, **kws): + while 1: + done = await self.share_start(n, **kws) + if done: + # do not wipe if we are not done + await self.wipe(kws.get("is_secret", False)) + break + async def share_signed_txn(self, txid, file_offset, txn_len, txn_sha): # we just signed something, share it over NFC if txn_len >= MAX_NFC_SIZE: @@ -231,13 +240,20 @@ class NFCHandler: return n = ndef.ndefMaker() + line2 = None if txid is not None: n.add_text('Signed Transaction: ' + txid) n.add_custom('bitcoin.org:txid', a2b_hex(txid)) # want binary + line2 = self.txid_line2(txid) + n.add_custom('bitcoin.org:sha256', txn_sha) n.add_large_object('bitcoin.org:txn', file_offset, txn_len) - return await self.share_start(n) + return await self.share_loop(n, line2=line2) + + @staticmethod + def txid_line2(txid): + return "Signed TXID: %s⋯%s" % (txid[0:8], txid[-8:]) async def share_push_tx(self, url, txid, txn, txn_sha, line2=None): # Given a signed TXN, we convert to URL which a web backend can broadcast directly @@ -267,13 +283,9 @@ class NFCHandler: n.add_url(url, https=is_https) if line2 is None: - line2 = "Signed TXID: %s⋯%s" % (txid[0:8], txid[-8:]) + line2 = self.txid_line2(txid) - while 1: - done = await self.share_start(n, prompt="Tap to broadcast, CANCEL when done", - line2=line2) - - if done: break + await self.share_loop(n, prompt="Tap to broadcast, CANCEL when done", line2=line2) async def push_tx_from_file(self): # Pick (signed txn) file from SD card and broadcast via PushTx @@ -343,24 +355,19 @@ class NFCHandler: return n = ndef.ndefMaker() - n.add_text(label or 'Partly signed PSBT') + label = label or 'Partly signed PSBT' + n.add_text(label) n.add_custom('bitcoin.org:sha256', psbt_sha) n.add_large_object('bitcoin.org:psbt', file_offset, psbt_len) - return await self.share_start(n) - - async def share_deposit_address(self, addr, **kws): - n = ndef.ndefMaker() - n.add_text('Deposit Address') - n.add_custom('bitcoin.org:addr', addr.encode()) - return await self.share_start(n, **kws) + return await self.share_loop(n, line2=label) async def share_json(self, json_data, **kws): # a text file of JSON for programs to read n = ndef.ndefMaker() n.add_mime_data('application/json', json_data) - return await self.share_start(n, **kws) + return await self.share_loop(n, **kws) async def share_text(self, data, **kws): # share text from a list of values @@ -368,7 +375,7 @@ class NFCHandler: n = ndef.ndefMaker() n.add_text(data) - return await self.share_start(n, **kws) + return await self.share_loop(n, **kws) async def wait_ready(self): # block until chip ready to continue (ACK happens) @@ -394,11 +401,12 @@ class NFCHandler: self.write_dyn(GPO_CTRL_Dyn, 0x01) # GPO_EN self.read_dyn(IT_STS_Dyn) # clear interrupt - async def ux_animation(self, write_mode, allow_enter=True, prompt=None, line2=None): + async def ux_animation(self, write_mode, allow_enter=True, prompt=None, line2=None, + is_secret=False): # Run the pretty animation, and detect both when we are written, and/or key to exit/abort. # - similar when "read" and then removed from field # - return T if aborted by user - from glob import dis, numpad + from glob import dis await self.wait_ready() self.set_rf_disable(0) @@ -467,8 +475,6 @@ class NFCHandler: break self.set_rf_disable(1) - if not write_mode: - await self.wipe(False) return aborted @@ -476,9 +482,7 @@ class NFCHandler: # do the UX while we are sharing a value over NFC # - assumpting is people know what they are scanning # - x key to abort early, but also self-clears - await self.big_write(ndef_obj.bytes()) - return await self.ux_animation(False, **kws) async def start_nfc_rx(self, **kws): @@ -514,8 +518,7 @@ class NFCHandler: await self.wipe(False) return rv - - async def start_psbt_rx(self): + async def start_psbt_rx(self, miniscript_wallet=None): from auth import psbt_encoding_taster, TXN_INPUT_OFFSET from auth import UserAuthorizedAction, ApproveTransaction from ux import the_ux @@ -540,10 +543,7 @@ class NFCHandler: if urn == 'urn:nfc:ext:bitcoin.org:sha256' and len(msg) == 32: # probably produced by another Coldcard: SHA256 over expected contents psbt_sha = bytes(msg) - except Exception as e: - # dont crash when given garbage - import sys; sys.print_exception(e) - pass + except Exception: pass # dont crash when given garbage if psbt_in is None: await ux_show_story("Could not find PSBT in what was written.", title="Sorry!") @@ -564,44 +564,13 @@ class NFCHandler: # start signing UX UserAuthorizedAction.cleanup() - UserAuthorizedAction.active_request = ApproveTransaction(psbt_len, 0x0, psbt_sha=psbt_sha, - approved_cb=self.signing_done) + UserAuthorizedAction.active_request = ApproveTransaction( + psbt_len, psbt_sha=psbt_sha, input_method="nfc", + output_encoder=output_encoder, miniscript_wallet=miniscript_wallet, + ) # kill any menu stack, and put our thing at the top the_ux.push(UserAuthorizedAction.active_request) - async def signing_done(self, psbt): - # User approved the PSBT, and signing worked... share result over NFC (only) - from auth import TXN_OUTPUT_OFFSET, try_push_tx - from version import MAX_TXN_LEN - from sffile import SFFile - - txid = None - - # asssume they want final transaction when possible, else PSBT output - is_comp = psbt.is_complete() - - # re-serialize the PSBT back out (into PSRAM) - with SFFile(TXN_OUTPUT_OFFSET, max_size=MAX_TXN_LEN, message="Saving...") as fd: - if is_comp: - txid = psbt.finalize(fd) - else: - psbt.serialize(fd) - - self.result = (fd.tell(), fd.checksum.digest()) - - out_len, out_sha = self.result - - if is_comp: - if txid and await try_push_tx(out_len, txid, out_sha): - return # success, exit - - await self.share_signed_txn(txid, TXN_OUTPUT_OFFSET, out_len, out_sha) - else: - await self.share_psbt(TXN_OUTPUT_OFFSET, out_len, out_sha) - - # ? show txid on screen ? - # thank them? - @classmethod async def selftest(cls): # Check for chip present, field present .. and that it works @@ -610,7 +579,10 @@ class NFCHandler: n.setup() assert n.uid - aborted = await n.share_text("NFC is working: %s" % n.get_uid(), allow_enter=False) + nn = ndef.ndefMaker() + nn.add_text("NFC is working: %s" % n.get_uid()) + + aborted = await n.share_start(nn, allow_enter=False) assert not aborted, "Aborted" async def share_file(self): @@ -658,29 +630,6 @@ class NFCHandler: else: raise ValueError(ext) - async def import_multisig_nfc(self, *a): - # user is pushing a file downloaded from another CC over NFC - # - would need an NFC app in between for the sneakernet step - # get some data - def f(m): - if len(m) < 70: - return - m = m.decode() - - # multi( catches both multi( and sortedmulti( - if 'pub' in m or "multi(" in m: - return m - - winner = await self._nfc_reader(f, 'Unable to find multisig descriptor.') - - if winner: - from auth import maybe_enroll_xpub - try: - maybe_enroll_xpub(config=winner) - except Exception as e: - #import sys; sys.print_exception(e) - await ux_show_story('Failed to import.\n\n%s\n%s' % (e, problem_file_line(e))) - async def import_ephemeral_seed_words_nfc(self, *a): def f(m): sm = m.decode().strip().split(" ") @@ -692,21 +641,11 @@ class NFCHandler: if winner: try: from seed import set_ephemeral_seed_words - await set_ephemeral_seed_words(winner, meta='NFC Import') + await set_ephemeral_seed_words(winner, origin='NFC Import') except Exception as e: #import sys; sys.print_exception(e) await ux_show_story('Failed to import.\n\n%s\n%s' % (e, problem_file_line(e))) - async def confirm_share_loop(self, string): - while True: - # added loop here as NFC send can fail, or not send the data - # and in that case one would have to start from beginning (send us cmd, approve, etc.) - # => get chance to check if you received the data and if something went wrong - retry just send - await self.share_text(string) - ch = await ux_show_story(title="Shared", msg="Press %s to share again, otherwise %s to stop." % (OK, X)) - if ch != "y": - break - async def address_show_and_share(self): from auth import show_address @@ -752,16 +691,15 @@ class NFCHandler: await approve_msg_sign(None, None, None, approved_cb=self.msg_sign_done, msg_sign_request=winner) - async def msg_sign_done(self, signature, address, text): - from auth import rfc_signature_template_gen + from msgsign import rfc_signature_template sig = b2a_base64(signature).decode('ascii').strip() - armored_str = "".join(rfc_signature_template_gen(addr=address, msg=text, sig=sig)) - await self.confirm_share_loop(armored_str) + armored_str = "".join(rfc_signature_template(addr=address, msg=text, sig=sig)) + await self.share_text(armored_str) async def verify_sig_nfc(self): - from auth import verify_armored_signed_msg + from msgsign import verify_armored_signed_msg f = lambda x: x.decode().strip() if b"SIGNED MESSAGE" in x else None winner = await self._nfc_reader(f, 'Unable to find signed message.') @@ -769,21 +707,26 @@ class NFCHandler: if winner: await verify_armored_signed_msg(winner, digest_check=False) - async def verify_address_nfc(self): - # Get an address or complete bip-21 url even and search it... slow. + async def read_address(self): + # Read an address or BIP-21 url and parse out addr (just one) from utils import decode_bip21_text def f(m): m = m.decode() what, vals = decode_bip21_text(m) if what == 'addr': - return vals[1] + return vals winner = await self._nfc_reader(f, 'Unable to find address from NFC data.') - if winner: + return winner + + async def verify_address_nfc(self): + # Get an address or complete bip-21 url even and search it... slow. + _, addr, args = await self.read_address() + if addr: from ownership import OWNERSHIP - await OWNERSHIP.search_ux(winner) + await OWNERSHIP.search_ux(addr, args) async def read_extended_private_key(self): f = lambda x: x.decode().strip() if b"prv" in x else None @@ -835,7 +778,7 @@ class NFCHandler: return await self._nfc_reader(f, 'Unable to find BSMS data in NDEF data') - async def import_miniscript_nfc(self, legacy_multisig=False): + async def import_miniscript_nfc(self): def f(m): if len(m) < 70: return m = m.decode() @@ -849,7 +792,7 @@ class NFCHandler: from auth import maybe_enroll_xpub try: - maybe_enroll_xpub(config=winner, miniscript=not legacy_multisig) + maybe_enroll_xpub(config=winner) except Exception as e: await ux_show_story('Failed to import.\n\n%s\n%s' % (e, problem_file_line(e))) diff --git a/shared/notes.py b/shared/notes.py index cc109c8e..d1fd1f76 100644 --- a/shared/notes.py +++ b/shared/notes.py @@ -13,7 +13,7 @@ from files import CardMissingError, needs_microsd, CardSlot from charcodes import KEY_QR, KEY_NFC, KEY_CANCEL from charcodes import KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6 from lcd_display import CHARS_W -from utils import problem_file_line, url_decode +from utils import problem_file_line, url_unquote, wipe_if_deltamode # title, username and such are limited that they fit on the one line both in # text entry (W-2) and also in menu display (W-3) @@ -21,11 +21,16 @@ from utils import problem_file_line, url_decode ONE_LINE = CHARS_W-2 async def make_notes_menu(*a): - from pincodes import pa - if pa.is_deltamode(): - import callgate - callgate.fast_wipe() + + if pa.hobbled_mode: + # Read only version of menu system + # - used when spending policy in effect + # - must have some notes already, or unreachable + assert NoteContent.count() + rv = NotesMenu(NotesMenu.construct_readonly()) + rv.readonly = True + return rv if not settings.get('secnap', False): # Explain feature, and then enable if interested. Drop them into menu. @@ -110,6 +115,8 @@ async def get_a_password(old_value, min_len=0, max_len=128): class NotesMenu(MenuSystem): + readonly = False + @classmethod def construct(cls): # Dynamic menu with user-defined names of notes shown @@ -122,6 +129,8 @@ class NotesMenu(MenuSystem): if not cnt: rv = news + [ MenuItem('Disable Feature', f=cls.disable_notes) ] else: + wipe_if_deltamode() + rv = [] for note in NoteContent.get_all(): rv.append(MenuItem('%d: %s' % (note.idx+1, note.title), menu=note.make_menu)) @@ -137,6 +146,18 @@ class NotesMenu(MenuSystem): return rv + @classmethod + def construct_readonly(cls): + # When only allowed to view, no export/add new/delete. + wipe_if_deltamode() + + rv = [] + for note in NoteContent.get_all(): + rv.append(MenuItem('%d: %s' % (note.idx+1, note.title), + menu=note.make_menu, arg=True)) # readonly=True + + return rv + @classmethod async def export_all(cls, *a): await start_export(NoteContent.get_all()) @@ -165,7 +186,7 @@ class NotesMenu(MenuSystem): if got.startswith('otpauth://totp/'): # see - tmp.title = url_decode(got[15:]).split('?', 1)[0] + tmp.title = url_unquote(got[15:]).split('?', 1)[0] elif got.startswith('otpauth-migration://offline'): # see tmp.title = 'Google Auth' @@ -179,7 +200,6 @@ class NotesMenu(MenuSystem): await tmp._save_ux(menu) await cls.drill_to(menu, tmp) - def update_contents(self): # Reconstruct the list of notes on this dynamic menu, because # we added or changed them and are showing that same menu again. @@ -209,8 +229,8 @@ class NotesMenu(MenuSystem): async def drill_to(cls, menu, item): # make it so looks like we drilled down into the new note menu.goto_idx(item.idx) - m = MenuSystem(await item.make_menu()) - the_ux.push(m) + m = await item._make_menu() + the_ux.push(MenuSystem(m)) class NoteContentBase: @@ -278,7 +298,7 @@ class NoteContentBase: await ux_dramatic_pause('Deleted.', 3) - async def share_nfc(self, menu, _, item): + async def share_nfc(self, a, b, item): # share something via NFC -- if small enough and enabled from glob import NFC @@ -288,12 +308,26 @@ class NoteContentBase: if len(v) < 8000: # see MAX_NFC_SIZE await NFC.share_text(v) + async def view_qr(self, k): + # full screen QR + try: + await show_qr_code(getattr(self, k), msg=self.title, is_secret=True) + except Exception as exc: + # - not all data can be a QR (non-text, binary, zeros) + # - might be too big for single QR + # - may be a RuntimeError(n) where n is line number inside uqr + await ux_show_story("Unable to display as QR.\n\nError: " + str(exc)) + + async def view_qr_menu(self, a, b, item): + await self.view_qr(item.arg) + async def _save_ux(self, menu): is_new = self.save() if not is_new: # change our own menu contents - menu.replace_items(await self.make_menu()) + mi = await self._make_menu() + menu.replace_items(mi) # update parent parent = the_ux.parent_of(menu) @@ -322,7 +356,7 @@ class NoteContentBase: await start_export([self]) async def sign_txt_msg(self, a, b, item): - from auth import ux_sign_msg, msg_signing_done + from msgsign import ux_sign_msg, msg_signing_done txt = item.arg await ux_sign_msg(txt, approved_cb=msg_signing_done, kill_menu=False) @@ -335,24 +369,35 @@ class PasswordContent(NoteContentBase): flds = ['title', 'user', 'password', 'site', 'misc' ] type_label = 'password' - async def make_menu(self, *a): + async def _make_menu(self, readonly=False): rv = [MenuItem('"%s"' % self.title, f=self.view)] if self.user: rv.append(MenuItem('↳ %s' % self.user, f=self.view)) if self.site: rv.append(MenuItem('↳ %s' % self.site, f=self.view)) - #if self.misc: rv.append(MenuItem('↳ (notes)', f=self.view)) - return rv + [ + # if self.misc: rv.append(MenuItem('↳ (notes)', f=self.view)) + rv += [ MenuItem('View Password', f=self.view_pw), MenuItem('Send Password', f=self.send_pw, predicate=lambda: settings.get('du', True)), - MenuItem('Export', f=self.export), - MenuItem('Edit Metadata', f=self.edit), - MenuItem('Delete', f=self.delete), - MenuItem('Change Password', f=self.change_pw), - self.sign_misc_menu_item(), - ShortcutItem(KEY_QR, f=self.view_qr), - ShortcutItem(KEY_NFC, f=self.share_nfc, arg='password'), ] + if not readonly: + rv += [ + MenuItem('Export', f=self.export), + MenuItem('Edit Metadata', f=self.edit), + MenuItem('Delete', f=self.delete), + MenuItem('Change Password', f=self.change_pw), + ] + rv += [ + self.sign_misc_menu_item(), + ShortcutItem(KEY_QR, f=self.view_qr_menu, arg=self.type_label), + ShortcutItem(KEY_NFC, f=self.share_nfc, arg=self.type_label), + ] + + return rv + + async def make_menu(self, a, b, item): + items = await self._make_menu(readonly=item.arg) + return MenuSystem(items) async def view(self, *a): pl = len(self.password) @@ -392,7 +437,7 @@ class PasswordContent(NoteContentBase): ch = await ux_show_story(msg, title=self.title, escape=KEY_QR, hint_icons=KEY_QR) if ch == KEY_QR: - await self.view_qr() + await self.view_qr(self.type_label) async def send_pw(self, *a): # use USB to send it -- weak at present @@ -404,10 +449,6 @@ class PasswordContent(NoteContentBase): "we cannot type at this time.") await single_send_keystrokes(self.password) - async def view_qr(self, *a): - # full screen QR - await show_qr_code(self.password, msg=self.title) - async def edit(self, menu, _, item): # Edit, also used for add new @@ -471,34 +512,34 @@ class NoteContent(NoteContentBase): flds = ['title', 'misc'] type_label = 'note' - async def make_menu(self, *a): + async def _make_menu(self, readonly=False): # Details and actions for this Note - return [ + rv = [ MenuItem('"%s"' % self.title, f=self.view), MenuItem('View Note', f=self.view), - MenuItem('Edit', f=self.edit), - MenuItem('Delete', f=self.delete), - MenuItem('Export', f=self.export), + ] + if not readonly: + rv += [ + MenuItem('Edit', f=self.edit), + MenuItem('Delete', f=self.delete), + MenuItem('Export', f=self.export), + ] + rv += [ self.sign_misc_menu_item(), - ShortcutItem(KEY_QR, f=self.view_qr), + ShortcutItem(KEY_QR, f=self.view_qr_menu, arg="misc"), ShortcutItem(KEY_NFC, f=self.share_nfc, arg='misc'), ] + return rv + + async def make_menu(self, a, b, item): + items = await self._make_menu(readonly=item.arg) + return MenuSystem(items) async def view(self, *a): ch = await ux_show_story(self.misc, title=self.title, escape=KEY_QR, hint_icons=KEY_QR) if ch == KEY_QR: - await self.view_qr() - - async def view_qr(self, *a): - # full screen QR - try: - await show_qr_code(self.misc, msg=self.title) - except Exception as exc: - # - not all data can be a QR (non-text, binary, zeros) - # - might be too big for single QR - # - may be a RuntimeError(n) where n is line number inside uqr - await ux_show_story("Unable to display as QR.\n\nError: "+str(exc)) + await self.view_qr("misc") async def edit(self, menu, _, item): # Edit, also used for add new @@ -541,16 +582,16 @@ class NoteContent(NoteContentBase): async def start_export(notes): # Save out notes/passwords from glob import NFC - from auth import write_sig_file + from msgsign import write_sig_file import ujson as json from ux_q1 import show_bbqr_codes singular = (len(notes) == 1) item = notes[0].type_label if singular else 'all notes & passwords' - choice = await import_export_prompt(item, is_import=False, title="Data Export", no_nfc=True, - footnotes="\n\nWARNING: No encryption happens here. " - "Your secrets will be cleartext.") + choice = await import_export_prompt(item, title="Data Export", no_nfc=True, + footnotes="WARNING: No encryption happens here." + " Your secrets will be cleartext.") if choice == KEY_CANCEL: return @@ -579,7 +620,7 @@ async def start_export(notes): await needs_microsd() return except Exception as e: - await ux_show_story('Failed to write!\n\n\n'+str(e)) + await ux_show_story('Failed to write!\n\n'+str(e)) return msg = 'Export file written:\n\n%s\n\nSignature file written:\n\n%s' % ( @@ -608,14 +649,11 @@ async def import_from_other(menu, *a): else: def contains_json(fname): if not fname.endswith('.json'): return False - print(fname) try: obj = json.load(open(fname, 'rt')) assert 'coldcard_notes' in obj return True - except Exception as exc: - import sys; sys.print_exception(exc) - pass + except: pass fn = await file_picker(min_size=8, max_size=100000, taster=contains_json, **choice) if not fn: return @@ -624,7 +662,13 @@ async def import_from_other(menu, *a): records = json.load(open(fn, 'rt')) # We have some JSON, parsed now. - # - should dedup, but we aren't + await import_from_json(records) + + await ux_dramatic_pause('Saved.', 3) + menu.update_contents() + +async def import_from_json(records): + # should dedup, but we aren't try: assert 'coldcard_notes' in records, 'Incorrect format' @@ -634,14 +678,11 @@ async def import_from_other(menu, *a): was = list(settings.get('notes', [])) was.extend(new) - settings.put('notes', was) + settings.set('notes', was) + settings.set('secnap', True) settings.save() except Exception as e: await ux_show_story(title="Failure", msg=str(e) + '\n\n' + problem_file_line(e)) - - await ux_dramatic_pause('Saved.', 3) - menu.update_contents() - # EOF diff --git a/shared/nvstore.py b/shared/nvstore.py index 0331fc99..f162dc6d 100644 --- a/shared/nvstore.py +++ b/shared/nvstore.py @@ -32,8 +32,8 @@ from utils import call_later_ms # batt_to = (when on battery only) idle timeout period # _age = internal verison number for data (see below) # tested = selftest has been completed successfully -# multisig = list of defined multisig wallets (complex) -# miniscript = list of defined miniscript wallets (complex) +# multisig = list of defined multisig wallets (complex) [before removal of MultisigWallet] +# miniscript = list of defined miniscript wallets, including multisig (complex) # pms = trust/import/distrust xpubs found in PSBT files # fee_limit = (int) percentage of tx value allowed as max fee # axi = index of last selected address in explorer @@ -64,7 +64,11 @@ from utils import call_later_ms # b85max = (bool) allow max BIP-32 int value in BIP-85 derivations # ptxurl = (str) URL for PushTx feature, clear to disable feature # hmx = (bool) Force display of current XFP in home menu, even w/o tmp seed active -# unsort_ms = (bool) Allow unsorted multisig with BIP-67 disabled +# ccc = (complex) If present, CCC feature is enabled and key details stored here. +# ktrx = (privkey) Key teleport Rx has been started, this will be our keypair +# aemscsv = (bool) opt-in enable more verbose CSV output for miniscript wallets with Derivations and Scripts +# sssp = (complex) If present, a (single signer) spending-policy is defined (maybe disabled) +# lfr = (string) If present, the reason why Spending Policy blocked last transaction # Stored w/ key=00 for access before login # _skip_pin = hard code a PIN value (dangerous, only for debug) @@ -78,7 +82,7 @@ from utils import call_later_ms # terms_ok = customer has signed-off on the terms of sale # settings linked to seed -# LINKED_SETTINGS = ["multisig","miniscript", "tp", "ovc", "xfp", "xpub", "words"] +# LINKED_SETTINGS = ["miniscript", "tp", "ovc", "xfp", "xpub", "words"] # settings that does not make sense to copy to temporary secret # LINKED_SETTINGS += ["sd2fa", "usr", "axi", "hsmcmd"] # prelogin settings - do not need to be part of other saved settings @@ -88,7 +92,9 @@ KEEP_IF_BLANK_SETTINGS = ["wa", "sighshchk", "emu", "rz", "b39skip", "axskip", "del", "pms", "idle_to", "batt_to", "bright"] -SEEDVAULT_FIELDS = ['seeds', 'seedvault', 'xfp', 'words', "bkpw"] +# key value pairs saved directly to master seed settings +# held in RAM for tmp seed sessions +MASTER_FIELDS = ['seeds', 'seedvault', 'xfp', 'words', "bkpw", "sssp"] NUM_SLOTS = const(100) SLOTS = range(NUM_SLOTS) @@ -278,10 +284,11 @@ class SettingsObject: def leaving_master_seed(self): # going from master seed to a tmp seed, so capture a few values we need. + self.save_if_dirty() SettingsObject.master_nvram_key = self.nvram_key - for fn in SEEDVAULT_FIELDS: + for fn in MASTER_FIELDS: curr = self.current.get(fn, None) if curr is not None: SettingsObject.master_sv_data[fn] = curr @@ -297,7 +304,7 @@ class SettingsObject: SettingsObject.master_sv_data.clear() SettingsObject.master_nvram_key = None - def master_set(self, key, value): + def master_set(self, key, value, master_only=False): # Set a value, and it must be saved under the master seed's # Concern is we may be changing a setting from a tmp seed mode # - always does a save @@ -308,6 +315,7 @@ class SettingsObject: self.set(key, value) self.save() else: + assert not master_only # harder, slower: have to load, change and write master = SettingsObject(nvram_key=SettingsObject.master_nvram_key) master.load() @@ -316,7 +324,7 @@ class SettingsObject: del master # track our copies - if key in SEEDVAULT_FIELDS: + if key in MASTER_FIELDS: SettingsObject.master_sv_data[key] = value def master_get(self, kn, default=None): @@ -328,7 +336,7 @@ class SettingsObject: return self.get(kn, default) # LIMITATION: only supporting a few values we know we will need - assert kn in SEEDVAULT_FIELDS + assert kn in MASTER_FIELDS res = SettingsObject.master_sv_data.get(kn, default) if res is None: return default @@ -414,7 +422,7 @@ class SettingsObject: if previous: for k in KEEP_IF_BLANK_SETTINGS: - if k in previous and k not in self.current: + if (k in previous) and (k not in self.current): self.current[k] = previous[k] # nfc, usb, vidsk handling diff --git a/shared/ownership.py b/shared/ownership.py index e98dd10f..968eb22b 100644 --- a/shared/ownership.py +++ b/shared/ownership.py @@ -2,7 +2,7 @@ # # ownership.py - store a cache of hashes related to addresses we might control. # -import os, sys, chains, ngu, struct, version +import os, chains, ngu, struct, version from glob import settings from ucollections import namedtuple from ubinascii import hexlify as b2a_hex @@ -12,8 +12,7 @@ from public_constants import AFC_SCRIPT, AF_P2WPKH_P2SH, AF_P2SH, AF_P2WSH_P2SH, # Track many addresses, but in compressed form # - map from random Bech32/Base58 payment address to (wallet) + keypath -# - only normal (external, not change) addresses, and won't consider -# any keypath that does not end in 0/* +# - won't consider any keypath that does not end in <0;1>/* # - store only hints, since we can re-construct any address and want to fully verify # - try to keep private between different duress wallets, and seed vaults # - storing bulk data into LFS, not settings @@ -40,7 +39,7 @@ OWNERSHIP_MAGIC = 0x10A0 # "Address Ownership" v1.0 # target 3 flash blocks, max file size => 764 addresses MAX_ADDRS_STORED = const(764) # =((3*512) - OWNERSHIP_FILE_HDR_LEN) // HASH_ENC_LEN -BONUS_GAP_LIMIT = const(20) +BONUS_AFTER_MATCH = const(20) # number of addresses to still generate after match found def encode_addr(addr, salt): # Convert text address to something we can store while preserving privacy. @@ -57,6 +56,7 @@ class AddressCacheFile: self.salt = h[32:] self.count = 0 self.hdr = None + self.fd = None self.peek() @@ -66,9 +66,6 @@ class AddressCacheFile: rv += ' (change)' return rv - def exists(self): - return bool(self.count) - def peek(self): # see what we have on-disk; just reads header. try: @@ -82,7 +79,7 @@ class AddressCacheFile: except OSError: return except Exception as exc: - sys.print_exception(exc) + # sys.print_exception(exc) self.count = 0 self.hdr = None return @@ -106,15 +103,14 @@ class AddressCacheFile: self.fd.write(hdr) def append(self, addr): - if addr is None: - # close file, done - self.fd.close() - del self.fd - return - - assert '_' not in addr self.fd.write(encode_addr(addr, self.salt)) + def close(self): + # close file, done + if self.fd is not None: + self.fd.close() + self.fd = None + def fast_search(self, addr): # Do the easy part of the searching, using the existing file's contents. # - generates candidate path subcomponents; might be false positive @@ -122,6 +118,7 @@ class AddressCacheFile: from glob import dis if not self.hdr or not self.count: + # cache empty return with open(self.fname, 'rb') as fd: @@ -133,7 +130,7 @@ class AddressCacheFile: chk = encode_addr(addr, self.salt) for idx in range(self.count): if buf[idx*HASH_ENC_LEN : (idx*HASH_ENC_LEN)+HASH_ENC_LEN] == chk: - yield (self.change_idx, idx) + yield self.change_idx, idx dis.progress_sofar(idx, self.count) @@ -149,100 +146,115 @@ class AddressCacheFile: # - return subpath for a hit or None from glob import dis - bonus = 0 match = None start_idx = self.count count = MAX_ADDRS_STORED - start_idx if count <= 0: - return None + return match self.setup(self.change_idx, start_idx) - # change_idx is used as flag here + bonus = None for idx,here,*_ in self.wallet.yield_addresses(start_idx, count, self.change_idx): - - if here == addr: - # Found it! But keep going a little for next time. - match = (self.change_idx, idx) - self.append(here) self.count += 1 - if match: + + if bonus: + if bonus >= BONUS_AFTER_MATCH: + # do (at most) 20 more - limited by 'start_idx' & 'count' + break bonus += 1 - if match and bonus >= BONUS_GAP_LIMIT: - self.append(None) - return match - dis.progress_sofar(idx-start_idx, count) + if here == addr: + # match but keep going + match = (self.change_idx, idx) + bonus = 1 - self.append(None) + dis.progress_sofar(idx - start_idx, count) - return None + self.close() + return match class OwnershipCache: @classmethod - def saver(cls, wallet, change_idx, start_idx): - # when we are generating many addresses for export, capture them + def saver(cls, wallet, change_idx, start_idx, count): + # when we are generating many addresses for export, capture them (if suitable) # as we go with this function - # - not change -- only main addrs + if not count: + return + if change_idx not in (0, 1): + return + if start_idx >= MAX_ADDRS_STORED: + return + file = AddressCacheFile(wallet, change_idx) + current_pos = file.count - if file.exists(): - # don't save to existing file, has some already - return None + if start_idx > current_pos: + # nothing to do here, we are missing some addresses in the middle + return + if (start_idx + count) <= current_pos: + # we already have all these addresses + return - try: - file.setup(change_idx, start_idx) - except: - # in some cases we don't want to save anything, not an error - return None + file.setup(change_idx, current_pos) - return file.append + def doit(addr, idx): + if addr is None: + file.close() + elif (idx < MAX_ADDRS_STORED) and idx >= current_pos: + file.append(addr) + + return doit @classmethod - def search(cls, addr): - # Find it! - # - returns wallet object, and tuple2 of final 2 subpath components + def filter(cls, addr, args): + # Filter possible candidates! # - if you start w/ testnet, we'll follow that - from multisig import MultisigWallet - from miniscript import MiniScriptWallet + from wallet import MiniScriptWallet from glob import dis ch = chains.current_chain() + args = args or {} addr_fmt = ch.possible_address_fmt(addr) if not addr_fmt: # might be valid address over on testnet vs mainnet raise UnknownAddressExplained('That address is not valid on ' + ch.name) + # user has specified specific (named) wallet + named_wal = args.get("wallet", None) + if named_wal: + # quick search without deserialization + res = list(MiniScriptWallet.iter_wallets(name=named_wal)) + if not res: + raise UnknownAddressExplained("Wallet '%s' not defined." % named_wal) + + # only return desired named wallet, no other wallets are searched + return res + possibles = [] - - msc_exists = MiniScriptWallet.exists()[0] - - if addr_fmt == AF_P2TR and msc_exists: + if addr_fmt == AF_P2TR: possibles.extend([w for w in MiniScriptWallet.iter_wallets() if w.addr_fmt == AF_P2TR]) - if addr_fmt & AFC_SCRIPT: - # multisig or script at least.. must exist already - possibles.extend(MultisigWallet.iter_wallets(addr_fmt=addr_fmt)) - msc = [w for w in MiniScriptWallet.iter_wallets() if w.addr_fmt == addr_fmt] - possibles.extend(msc) - + # multisig or script at least... must exist already + afs = [addr_fmt] if addr_fmt == AF_P2SH: # might look like P2SH but actually be AF_P2WSH_P2SH - possibles.extend(MultisigWallet.iter_wallets(addr_fmt=AF_P2WSH_P2SH)) - msc = [w for w in MiniScriptWallet.iter_wallets() if w.addr_fmt == AF_P2WSH_P2SH] - possibles.extend(msc) + # wrapped segwit is more used than legacy + afs = [AF_P2WSH_P2SH, AF_P2SH] # Might be single-sig p2wpkh wrapped in p2sh ... but that was a transition # thing that hopefully is going away, so if they have any multisig wallets, # defined, assume that that's the only p2sh address source. addr_fmt = AF_P2WPKH_P2SH + possibles.extend(MiniScriptWallet.iter_wallets(addr_fmts=afs)) + try: # Construct possible single-signer wallets, always at least account=0 case from wallet import MasterSingleSigWallet @@ -255,80 +267,103 @@ class OwnershipCache: if af == addr_fmt and acct_num: w = MasterSingleSigWallet(addr_fmt, account_idx=acct_num) possibles.append(w) - except (KeyError, ValueError): pass # if not single sig address format + except (KeyError, ValueError): + pass # if not single sig address format if not possibles: # can only happen w/ scripts; for single-signer we have things to check raise UnknownAddressExplained( "No suitable multisig/miniscript wallets are currently defined.") + # ordering here + return possibles + + @classmethod + def search_wallet_cache(cls, addr, cf): + # - returns wallet object, and tuple2 of final 2 subpath components # "quick" check first, before doing any generations + # external chain first, then internal (change) + for maybe in cf.fast_search(addr): + ok = cf.check_match(addr, maybe) + if ok: + return cf.wallet, maybe + return None, None - count = 0 - phase2 = [] - for change_idx in (0, 1): - files = [AddressCacheFile(w, change_idx) for w in possibles] - for f in files: - if dis.has_lcd: - dis.fullscreen('Searching wallet(s)...', line2=f.nice_name()) - else: - dis.fullscreen('Searching...') - - for maybe in f.fast_search(addr): - ok = f.check_match(addr, maybe) - if not ok: continue # false positive - will happen - - # found winner. - return f.wallet, maybe - - if f.count < MAX_ADDRS_STORED: - phase2.append(f) - - count += f.count + @classmethod + def search_build_wallet(cls, addr, cf): # maybe we haven't calculated all the addresses yet, so do that # - very slow, but only needed once; any negative (failed) search causes this # - could stop when match found, but we go a bit beyond that for next time # - we could search all in parallel, rather than serially because # more likely to find a match with low index... but seen as too much memory - - for f in phase2: - b4 = f.count - if dis.has_lcd: - dis.fullscreen("Generating addresses...", line2=f.nice_name()) - else: - dis.fullscreen("Generating...") - - result = f.build_and_search(addr) - if result: - # found it, so report it and stop - return f.wallet, result - - count += f.count - b4 + result = cf.build_and_search(addr) + if result: + # found it, so report it and stop + return cf.wallet, result # possible phase 3: other seedvault... slow, rare and not implemented - - raise UnknownAddressExplained('Searched %d candidates without finding a match.' % count) + return None, None @classmethod - async def search_ux(cls, addr): + def search(cls, addr, args=None): + from glob import dis + + dis.fullscreen("Wait...") + + matches = OWNERSHIP.filter(addr, args) + + # build cache files for both external & internal chain + cachefs = [] + for w in matches: + cachefs.append(AddressCacheFile(w, 0)) + cachefs.append(AddressCacheFile(w, 1)) + + for cf in cachefs: + msg = "Searching wallet(s)..." if dis.has_lcd else "Searching..." + dis.fullscreen(msg, line2=cf.nice_name()) + wallet, subpath = OWNERSHIP.search_wallet_cache(addr, cf) + if wallet: + # first arg from_cache=True + return True, wallet, subpath + + # nothing found in existing cache files + c = 0 + for cf in cachefs: + msg = "Generating addresses..." if dis.has_lcd else "Generating..." + dis.fullscreen(msg, line2=cf.nice_name()) + wallet, subpath = OWNERSHIP.search_build_wallet(addr, cf) + c += cf.count + if wallet: + # first arg from_cache=False + return False, wallet, subpath + + else: + raise UnknownAddressExplained('Searched %d candidate addresses in %d wallet(s)' + ' without finding a match.' % (c, len(matches))) + + @classmethod + async def search_ux(cls, addr, args): # Provide a simple UX. Called functions do fullscreen, progress bar stuff. from ux import ux_show_story, show_qr_code from charcodes import KEY_QR - from multisig import MultisigWallet - from miniscript import MiniScriptWallet + from wallet import MiniScriptWallet from public_constants import AFC_BECH32, AFC_BECH32M try: - wallet, subpath = OWNERSHIP.search(addr) - is_complex = isinstance(wallet, MultisigWallet) or isinstance(wallet, MiniScriptWallet) + _, wallet, subpath = cls.search(addr, args) + is_complex = isinstance(wallet, MiniScriptWallet) - sp = None msg = show_single_address(addr) - msg += '\n\nFound in wallet:\n ' + wallet.name + msg += '\n\nFound in wallet:\n' + wallet.name + + msg += '\n\nDerivation path:\n' if hasattr(wallet, "render_path"): sp = wallet.render_path(*subpath) - msg += '\nDerivation path:\n ' + sp + msg += sp + else: + sp = None + msg += ".../%d/%d" % subpath if is_complex: esc = "" @@ -354,7 +389,7 @@ class OwnershipCache: msg=addr, is_addrs=True ) elif not is_complex and (ch == "0"): # only singlesig - from auth import sign_with_own_address + from msgsign import sign_with_own_address await sign_with_own_address(sp, wallet.addr_fmt) else: break diff --git a/shared/paper.py b/shared/paper.py index 8358827a..745f36d7 100644 --- a/shared/paper.py +++ b/shared/paper.py @@ -5,13 +5,12 @@ # import ujson, ngu, chains from ubinascii import hexlify as b2a_hex -from utils import imported +from utils import imported, problem_file_line from public_constants import AF_CLASSIC, AF_P2WPKH, AF_P2TR from ux import ux_show_story, ux_dramatic_pause from files import CardSlot, CardMissingError, needs_microsd from actions import file_picker from menu import MenuSystem, MenuItem -from stash import blank_object background_msg = '''\ Coldcard will pick a random private key (which has no relation to your seed words), \ @@ -85,6 +84,12 @@ class PaperWalletMaker: from glob import dis, VD try: + import ngu + from msgsign import write_sig_file + from chains import current_chain + from serializations import hash160 + from stash import blank_object + if not have_key: # get some random bytes await ux_dramatic_pause("Picking key...", 2) @@ -167,7 +172,6 @@ class PaperWalletMaker: nice_sig = None if af != AF_P2TR: - from auth import write_sig_file nice_sig = write_sig_file(sig_cont, pk=privkey, sig_name=basename, addr_fmt=AF_P2WPKH if self.is_segwit else AF_CLASSIC) @@ -182,8 +186,7 @@ class PaperWalletMaker: await needs_microsd() return except Exception as e: - from utils import problem_file_line - await ux_show_story('Failed to write!\n\n\n'+problem_file_line(e)) + await ux_show_story('Failed to write!\n\n'+problem_file_line(e)) return story = "Done! Created file(s):\n\n%s" % nice_txt diff --git a/shared/pincodes.py b/shared/pincodes.py index a4a70a40..bf2c9665 100644 --- a/shared/pincodes.py +++ b/shared/pincodes.py @@ -3,8 +3,7 @@ # pincodes.py - manage PIN code (which map to wallet seeds) # import ustruct, ckcc, version, chains, stash -# from ubinascii import hexlify as b2a_hex -from callgate import enter_dfu +from callgate import enter_dfu, get_is_bricked from bip39 import wordlist_en # See ../stm32/bootloader/pins.h for source of these constants. @@ -127,17 +126,14 @@ class PinAttempt: self.private_state = 0 # opaque data, but preserve self.cached_main_pin = bytearray(32) + # If set, a spending policy is in effect, and so even tho we know the master + # seed, we are not going to let them see it, nor sign things we dont like, etc. + self.hobbled_mode = False - assert MAX_PIN_LEN == 32 # update FMT otherwise - assert ustruct.calcsize(PIN_ATTEMPT_FMT_V1) == PIN_ATTEMPT_SIZE_V1 - assert ustruct.calcsize(PIN_ATTEMPT_FMT_V2_ADDITIONS) == PIN_ATTEMPT_SIZE - PIN_ATTEMPT_SIZE_V1 - - # check for bricked system early - import callgate - if callgate.get_is_bricked(): - # die right away if it's not going to work - print("SE bricked") - callgate.enter_dfu(3) + #assert MAX_PIN_LEN == 32 # update FMT otherwise + #assert ustruct.calcsize(PIN_ATTEMPT_FMT_V1) == PIN_ATTEMPT_SIZE_V1 + #assert ustruct.calcsize(PIN_ATTEMPT_FMT_V2_ADDITIONS) \ + # == PIN_ATTEMPT_SIZE - PIN_ATTEMPT_SIZE_V1 def __repr__(self): return '' % ( @@ -177,7 +173,7 @@ class PinAttempt: old_pin = self.pin assert len(new_pin) <= MAX_PIN_LEN - assert old_pin != None + assert old_pin is not None assert len(old_pin) <= MAX_PIN_LEN else: new_pin = b'' @@ -339,10 +335,6 @@ class PinAttempt: return self.state_flags - def delay(self): - # obsolete since Mk3, but called from login.py - self.roundtrip(1) - def login(self): # test we have the PIN code right, and unlock access if so. chk = self.roundtrip(2) @@ -418,9 +410,13 @@ class PinAttempt: # Main secret has changed: reset the settings+their key, # and capture xfp/xpub # if None is provided as raw_secret -> restore to main seed + import glob from glob import settings, dis stash.SensitiveValues.clear_cache() + # invalidate descriptor cache - upon new secret load + glob.DESC_CACHE = {} + bypass_tmp = False stash.bip39_passphrase = bool(bip39pw) @@ -533,10 +529,24 @@ class PinAttempt: from trick_pins import TC_DELTA_MODE return bool(self.delay_required & TC_DELTA_MODE) + def get_tc_values(self): # Mk4 only # return (tc_flags, tc_arg) return self.delay_required, self.delay_achieved + + @staticmethod + async def enforce_brick(): + # check for bricked system early + if get_is_bricked(): + try: + # regardless of settings, become a forever calculator after brickage. + while version.has_qwerty: + from calc import login_repl + await login_repl() + finally: + # die right away if it's not going to work + enter_dfu(3) # singleton diff --git a/shared/precomp_tag_hash.py b/shared/precomp_tag_hash.py new file mode 100644 index 00000000..7ba0a7c9 --- /dev/null +++ b/shared/precomp_tag_hash.py @@ -0,0 +1,12 @@ +# (c) Copyright 2025 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# +# taproot precomputed tag hashes +# +# SHA256(TapLeaf) +TAP_LEAF_H = b'\xae\xea\x8f\xdcB\x08\x981\x05sKX\x08\x1d\x1e&8\xd3_\x1c\xb5@\x08\xd4\xd3W\xca\x03\xbex\xe9\xee' +# SHA256(TapBranch) +TAP_BRANCH_H = b'\x19A\xa1\xf2\xe5n\xb9_\xa2\xa9\xf1\x94\xbe\\\x01\xf7!o3\xed\x82\xb0\x91F4\x90\xd0[\xf5\x16\xa0\x15' +# SHA256(TapTweak) +TAP_TWEAK_H = b'\xe8\x0f\xe1c\x9c\x9c\xa0P\xe3\xaf\x1b9\xc1C\xc6>B\x9c\xbc\xeb\x15\xd9@\xfb\xb5\xc5\xa1\xf4\xafW\xc5\xe9' +# SHA256(TapSighash) +TAP_SIGHASH_H = b'\xf4\nH\xdfK*p\xc8\xb4\x92K\xf2eFa\xed=\x95\xfdf\xa3\x13\xeb\x87#u\x97\xc6(\xe4\xa01' \ No newline at end of file diff --git a/shared/psbt.py b/shared/psbt.py index 80458cc1..aca0a88c 100644 --- a/shared/psbt.py +++ b/shared/psbt.py @@ -2,24 +2,27 @@ # # psbt.py - understand PSBT file format: verify and generate them # +import stash, gc, history, sys, ngu, ckcc, version, chains +from ucollections import OrderedDict from ustruct import unpack_from, unpack, pack from ubinascii import hexlify as b2a_hex -from utils import xfp2str, B2A, keypath_to_str, validate_derivation_path_length -from utils import seconds2human_readable, datetime_from_timestamp, datetime_to_str, problem_file_line -import stash, gc, history, sys, ngu, ckcc, chains +from utils import xfp2str, B2A, keypath_to_str, validate_derivation_path_length, problem_file_line +from utils import seconds2human_readable, datetime_from_timestamp, datetime_to_str from uhashlib import sha256 from uio import BytesIO +from charcodes import KEY_ENTER from sffile import SizerFile -from chains import taptweak, tapleaf_hash -from miniscript import MiniScriptWallet -from multisig import MultisigWallet, disassemble_multisig_mn +from chains import taptweak, tapleaf_hash, NLOCK_IS_TIME, AF_TO_STR_AF +from wallet import MiniScriptWallet, TRUST_PSBT, TRUST_VERIFY from exceptions import FatalPSBTIssue, FraudulentChangeOutput from serializations import ser_compact_size, deser_compact_size, hash160 from serializations import CTxIn, CTxInWitness, CTxOut, ser_string, COutPoint from serializations import ser_sig_der, uint256_from_str, ser_push_data from serializations import SIGHASH_ALL, SIGHASH_SINGLE, SIGHASH_NONE, SIGHASH_ANYONECANPAY from serializations import ALL_SIGHASH_FLAGS, SIGHASH_DEFAULT +from opcodes import OP_CHECKMULTISIG, OP_RETURN from glob import settings +from precomp_tag_hash import TAP_TWEAK_H, TAP_SIGHASH_H from public_constants import ( PSBT_GLOBAL_UNSIGNED_TX, PSBT_GLOBAL_XPUB, PSBT_IN_NON_WITNESS_UTXO, PSBT_IN_WITNESS_UTXO, @@ -34,7 +37,9 @@ from public_constants import ( PSBT_GLOBAL_TX_MODIFIABLE, PSBT_GLOBAL_OUTPUT_COUNT, PSBT_GLOBAL_INPUT_COUNT, PSBT_GLOBAL_FALLBACK_LOCKTIME, PSBT_GLOBAL_TX_VERSION, PSBT_IN_PREVIOUS_TXID, PSBT_IN_OUTPUT_INDEX, PSBT_IN_SEQUENCE, PSBT_IN_REQUIRED_TIME_LOCKTIME, - PSBT_IN_REQUIRED_HEIGHT_LOCKTIME, MAX_PATH_DEPTH, MAX_SIGNERS + PSBT_IN_REQUIRED_HEIGHT_LOCKTIME, MAX_SIGNERS, + AF_P2WSH, AF_P2WSH_P2SH, AF_P2SH, AF_P2TR, AF_P2WPKH, AF_CLASSIC, AF_P2WPKH_P2SH, + AFC_SEGWIT, AF_BARE_PK ) psbt_tmp256 = bytearray(256) @@ -99,6 +104,17 @@ def _skip_n_objs(fd, n, cls): return rv +def disassemble_multisig_mn(redeem_script): + # pull out just M and N from script. Simple, faster, no memory. + + if not redeem_script or (redeem_script[-1] != OP_CHECKMULTISIG): + return None, None + + M = redeem_script[0] - 80 + N = redeem_script[-2] - 80 + + return M, N + def calc_txid(fd, poslen, body_poslen=None): # Given the (pos,len) of a transaction in a file, return the txid for that txn. # - doesn't validate data @@ -209,59 +225,65 @@ class psbtProxy: if ks is None: break if ks == 0: break + key_pos = fd.tell() + 1 # first element is ktype + key = fd.read(ks) vs = deser_compact_size(fd) - assert vs != None, 'eof' + assert vs is not None, 'eof' kt = key[0] if kt in self.no_keys: - assert len(key) == 1 # not expecting key + assert len(key) == 1 # not expecting key # storing offset and length only! Mostly. if kt in self.short_values: actual = fd.read(vs) - self.store(kt, bytes(key), actual) else: # skip actual data for now # TODO: could this be stored more compactly? proxy = (fd.tell(), vs) fd.seek(vs, 1) + # store just coords for both key & val + if kt == PSBT_PROPRIETARY: + ident, subtype, _ = decode_prop_key(key[1:]) + # examine only Coinkite proprietary keys + if (ident == PSBT_PROP_CK_ID) and (subtype == PSBT_ATTESTATION_SUBTYPE): + # prop key for attestation does not have keydata because the + # value is a recoverable signature (already contains pubkey) + # just save what we can handle + self.attestation = proxy - self.store(kt, bytes(key), proxy) + self.store(kt, (key_pos, ks-1), proxy) + + def coord_write(self, out_fd, val, ktype=None): + pos, ll = val + if ktype is None: + out_fd.write(ser_compact_size(ll)) + else: + out_fd.write(ser_compact_size(ll+1)) + out_fd.write(bytes([ktype])) + + self.fd.seek(pos) + while ll: + t = self.fd.read(min(64, ll)) + out_fd.write(t) + ll -= len(t) def write(self, out_fd, ktype, val, key=b''): # serialize helper: write w/ size and key byte - out_fd.write(ser_compact_size(1 + len(key))) - out_fd.write(bytes([ktype]) + key) + if isinstance(key, tuple): + self.coord_write(out_fd, key, ktype) + else: + out_fd.write(ser_compact_size(1 + len(key))) + out_fd.write(bytes([ktype]) + key) if isinstance(val, tuple): - (pos, ll) = val - out_fd.write(ser_compact_size(ll)) - self.fd.seek(pos) - while ll: - t = self.fd.read(min(64, ll)) - out_fd.write(t) - ll -= len(t) - - elif isinstance(val, list): - # for subpaths lists (LE32 ints) - if ktype in (PSBT_IN_BIP32_DERIVATION, PSBT_OUT_BIP32_DERIVATION): - out_fd.write(ser_compact_size(len(val) * 4)) - for i in val: - out_fd.write(pack(' [xfp, *path] (self.subpaths) # - creates dictionary: pubkey => [leaf_hash_list, xfp, *path] (self.taproot_subpaths) - # - will be single entry for non-p2sh ins and outs - if self.num_our_keys != None: - # already been here once - return self.num_our_keys - - num_our = self.parse_non_taproot_subpaths(my_xfp, warnings) - num_our_taproot = self.parse_taproot_subpaths(my_xfp, warnings) - - self.num_our_keys = num_our + num_our_taproot - return self.num_our_keys - + if self.taproot_subpaths: + return self.parse_taproot_subpaths(my_xfp, warnings, cosign_xfp) + elif self.subpaths: + return self.parse_non_taproot_subpaths(my_xfp, warnings, cosign_xfp) + #return None in/output does not have any key-path info # Track details of each output of PSBT # class psbtOutputProxy(psbtProxy): no_keys = { PSBT_OUT_REDEEM_SCRIPT, PSBT_OUT_WITNESS_SCRIPT, PSBT_OUT_TAP_INTERNAL_KEY, PSBT_OUT_TAP_TREE } - blank_flds = ('unknown', 'subpaths', 'redeem_script', 'witness_script', - 'is_change', 'num_our_keys', 'amount', 'script', 'attestation', - 'taproot_internal_key', 'taproot_subpaths', 'taproot_tree') + blank_flds = ('unknown', 'subpaths', 'redeem_script', 'witness_script', 'sp_idxs', + 'is_change', 'amount', 'script', 'attestation', 'proprietary', + 'taproot_internal_key', 'taproot_subpaths', 'taproot_tree', 'ik_idx') def __init__(self, fd, idx): super().__init__() @@ -381,6 +402,7 @@ class psbtOutputProxy(psbtProxy): #self.taproot_subpaths = None # a dictionary if non-empty #self.taproot_internal_key = None #self.taproot_tree = None + #self.ik_idx = None # index of taproot internal key in taproot_subpaths #self.redeem_script = None #self.witness_script = None #self.script = None @@ -391,30 +413,29 @@ class psbtOutputProxy(psbtProxy): self.parse(fd) - def parse_taproot_tree(self): - if not self.taproot_tree: - return - length = self.taproot_tree[1] - - res = [] - while length: - tree = BytesIO(self.get(self.taproot_tree)) - depth = tree.read(1) - leaf_version = tree.read(1)[0] - assert (leaf_version & ~TAPROOT_LEAF_MASK) == 0 - script_len, nb = deser_compact_size(tree, ret_num_bytes=True) - script = tree.read(script_len) - res.append((depth, leaf_version, script)) - length -= (2 + nb + script_len) - - return res + # not needed + # def parse_taproot_tree(self): + # length = self.taproot_tree[1] + # + # res = [] + # while length: + # tree = BytesIO(self.get(self.taproot_tree)) + # depth = tree.read(1) + # leaf_version = tree.read(1)[0] + # assert (leaf_version & ~TAPROOT_LEAF_MASK) == 0 + # script_len, nb = deser_compact_size(tree, ret_num_bytes=True) + # script = tree.read(script_len) + # res.append((depth, leaf_version, script)) + # length -= (2 + nb + script_len) + # + # return res def store(self, kt, key, val): # do not forget that key[0] includes kt (type) if kt == PSBT_OUT_BIP32_DERIVATION: if not self.subpaths: - self.subpaths = {} - self.subpaths[key[1:]] = val + self.subpaths = [] + self.subpaths.append((key,val)) elif kt == PSBT_OUT_REDEEM_SCRIPT: self.redeem_script = val elif kt == PSBT_OUT_WITNESS_SCRIPT: @@ -424,34 +445,27 @@ class psbtOutputProxy(psbtProxy): elif kt == PSBT_OUT_AMOUNT: self.amount = val elif kt == PSBT_PROPRIETARY: - prefix, subtype, keydata = decode_prop_key(key[1:]) - # examine only Coinkite proprietary keys - if prefix == PSBT_PROP_CK_ID: - if subtype == PSBT_ATTESTATION_SUBTYPE: - # prop key for attestation does not have keydata because the - # value is a recoverable signature (already contains pubkey) - self.attestation = self.get(val) + self.proprietary = self.proprietary or [] + self.proprietary.append((key, val)) elif kt == PSBT_OUT_TAP_INTERNAL_KEY: self.taproot_internal_key = val elif kt == PSBT_OUT_TAP_BIP32_DERIVATION: - if not self.taproot_subpaths: - self.taproot_subpaths = {} - self.taproot_subpaths[key[1:]] = val + self.taproot_subpaths = self.taproot_subpaths or [] + self.taproot_subpaths.append((key, val)) elif kt == PSBT_OUT_TAP_TREE: self.taproot_tree = val else: - self.unknown = self.unknown or {} - if key in self.unknown: - raise FatalPSBTIssue("Duplicate key. Key for unknown value already provided in output.") - self.unknown[key] = val + self.unknown = self.unknown or [] + pos, length = key + self.unknown.append(((pos-1, length+1), val)) def serialize(self, out_fd, is_v2): wr = lambda *a: self.write(out_fd, *a) if self.subpaths: - for k in self.subpaths: - wr(PSBT_OUT_BIP32_DERIVATION, self.subpaths[k], k) + for k, v in self.subpaths: + wr(PSBT_OUT_BIP32_DERIVATION, v, k) if self.redeem_script: wr(PSBT_OUT_REDEEM_SCRIPT, self.redeem_script) @@ -463,8 +477,8 @@ class psbtOutputProxy(psbtProxy): wr(PSBT_OUT_TAP_INTERNAL_KEY, self.taproot_internal_key) if self.taproot_subpaths: - for k in self.taproot_subpaths: - wr(PSBT_OUT_TAP_BIP32_DERIVATION, self.taproot_subpaths[k], k) + for k, v in self.taproot_subpaths: + wr(PSBT_OUT_TAP_BIP32_DERIVATION, v, k) if self.taproot_tree: wr(PSBT_OUT_TAP_TREE, self.taproot_tree) @@ -473,14 +487,15 @@ class psbtOutputProxy(psbtProxy): wr(PSBT_OUT_SCRIPT, self.script) wr(PSBT_OUT_AMOUNT, self.amount) - if self.attestation: - wr(PSBT_PROPRIETARY, self.attestation, encode_prop_key(PSBT_PROP_CK_ID, PSBT_ATTESTATION_SUBTYPE)) + if self.proprietary: + for k, v in self.proprietary: + wr(PSBT_PROPRIETARY, v, k) if self.unknown: - for k, v in self.unknown.items(): - wr(k[0], v, k[1:]) + for k, v in self.unknown: + wr(None, v, k) - def validate(self, out_idx, txo, my_xfp, active_multisig, active_miniscript, parent): + def determine_my_change(self, out_idx, txo, parsed_subpaths, parent): # Do things make sense for this output? # NOTE: We might think it's a change output just because the PSBT @@ -490,184 +505,114 @@ class psbtOutputProxy(psbtProxy): # any output info provided better be right, or fail as "fraud" # - full key derivation and validation is done during signing, and critical. # - we raise fraud alarms, since these are not innocent errors - # - if self.taproot_internal_key: - assert self.taproot_internal_key[1] == 32 # "PSBT_OUT_TAP_INTERNAL_KEY length != 32" - - num_ours = self.parse_subpaths(my_xfp, parent.warnings) - - if num_ours == 0: - # - not considered fraud because other signers looking at PSBT may have them - # - user will see them as normal outputs, which they are from our PoV. - return # - must match expected address for this output, coming from unsigned txn - addr_type, addr_or_pubkey, is_segwit = txo.get_address() + af, addr_or_pubkey = txo.get_address() - if self.subpaths and len(self.subpaths) == 1 and not active_miniscript: # miniscript can have one key only - # p2pk, p2pkh, p2wpkh cases - expect_pubkey, = self.subpaths.keys() - elif self.taproot_subpaths and len(self.taproot_subpaths) == 1: - expect_pubkey, = self.taproot_subpaths.keys() - else: - # p2wsh/p2sh cases need full set of pubkeys, and therefore redeem script - expect_pubkey = None + if (not self.sp_idxs) or (af in [OP_RETURN, None]): + # num_ours == 0 + # - not considered fraud because other signers looking at PSBT may have them + # - user will see them as normal outputs, which they are from our PoV. + # OP_RETURN + # - nothing we can do with anchor outputs + # UNKNOWN + # - scripts that we do not understand + return af - if addr_type == 'p2pk': - # output is public key (not a hash, much less common) + msc = parent.active_miniscript + if msc and MiniScriptWallet.disable_checks: + # Without validation, we have to assume all outputs + # will be taken from us, and are not really change. + return af + + # certain short-cuts + if msc: + if af in [AF_CLASSIC, AF_P2WPKH, AF_BARE_PK]: + # signing with miniscript wallet - single sig outputs definitely not change + return af + + elif parent.active_singlesig and (af == AF_P2WSH): + # we are signing single sig inputs - p2wsh is def not a change + return af + + def fraud(idx, af, err=""): + raise FraudulentChangeOutput(idx, "%s change output is fraudulent\n\n%s" % ( + AF_TO_STR_AF[af], err + )) + + if af == AF_BARE_PK: + # output is compressed public key (not a hash, much less common) + # uncompressed public keys not supported! assert len(addr_or_pubkey) == 33 + assert len(parsed_subpaths) == 1 + target, = parsed_subpaths.keys() - if addr_or_pubkey != expect_pubkey: - raise FraudulentChangeOutput(out_idx, "P2PK change output is fraudulent") - - self.is_change = True - return - - # Figure out what the hashed addr should be - pkh = addr_or_pubkey - - if addr_type == 'p2sh': - # P2SH or Multisig output - - # Can be both, or either one depending on address type - redeem_script = self.get(self.redeem_script) if self.redeem_script else None - witness_script = self.get(self.witness_script) if self.witness_script else None - - if expect_pubkey: - # num_ours == 1 and len(subpaths) == 1, single sig, we only allow p2sh-p2wpkh - if not redeem_script: - # Perhaps an omission, so let's not call fraud on it - # But definately required, else we don't know what script we're sending to. - raise FatalPSBTIssue("Missing redeem script for output #%d" % out_idx) - - target_spk = bytes([0xa9, 0x14]) + hash160(redeem_script) + bytes([0x87]) - if not is_segwit and len(redeem_script) == 22 and \ - redeem_script[0] == 0 and redeem_script[1] == 20 and \ - txo.scriptPubKey == target_spk: - # it's actually segwit p2wpkh inside p2sh - pkh = redeem_script[2:22] - expect_pkh = hash160(expect_pubkey) - else: - # unknown or wrong script - # p2sh-p2pkh also fall into this category - expect_pkh = None - - else: - if not redeem_script and not witness_script: - if active_miniscript: - # TODO - # this should be also acceptable for any other script type, we do not need - # redeem/witness script - # scriptPubkey can be compared against script that we build - if exact match change - # if not not change - definitely not FatalPSBTIssue - # - # without this I cannot sign with liana as they do not provide witness/redeem - try: - active_miniscript.validate_script_pubkey(txo.scriptPubKey, - list(self.subpaths.values())) - self.is_change = True - return - except Exception as e: - raise FraudulentChangeOutput(out_idx, "Change output scriptPubkey: %s" % e) - else: - # Perhaps an omission, so let's not call fraud on it - # But definately required, else we don't know what script we're sending to. - raise FatalPSBTIssue("Missing redeem/witness script for output #%d" % out_idx) - - # it cannot be change if it doesn't precisely match our multisig setup - if not active_multisig and not active_miniscript: - # - might be a p2sh output for another wallet that isn't us - # - not fraud, just an output with more details than we need. - self.is_change = False - return - - if active_multisig: - # Multisig change output, for wallet we're supposed to be a part of. - # - our key must be part of it - # - must look like input side redeem script (same fingerprints) - # - assert M/N structure of output to match any inputs we have signed in PSBT! - # - assert all provided pubkeys are in redeem script, not just ours - # - we get all of that by re-constructing the script from our wallet details - if MultisigWallet.disable_checks: - # Without validation, we have to assume all outputs - # will be taken from us, and are not really change. - self.is_change = False - return - # redeem script must be exactly what we expect - # - pubkeys will be reconstructed from derived paths here - # - BIP-45, BIP-67 rules applied (BIP-67 optional from now - depending on imported descriptor) - # - p2sh-p2wsh needs witness script here, not redeem script value - # - if details provided in output section, must our match multisig wallet - try: - active_multisig.validate_script(witness_script or redeem_script, - subpaths=self.subpaths) - except BaseException as exc: - raise FraudulentChangeOutput(out_idx, - "P2WSH or P2SH change output script: %s" % exc) - else: - # active miniscript - try: - active_miniscript.validate_script(witness_script or redeem_script, - list(self.subpaths.values()), - script_pubkey=txo.scriptPubKey) - except BaseException as exc: - raise FraudulentChangeOutput(out_idx, - "P2WSH or P2SH change output script: %s" % exc) - - if is_segwit: - # p2wsh case - # - need witness script and check it's hash against proposed p2wsh value - assert len(addr_or_pubkey) == 32 - expect_wsh = ngu.hash.sha256s(witness_script) - if expect_wsh != addr_or_pubkey: - raise FraudulentChangeOutput(out_idx, "P2WSH witness script has wrong hash") - - self.is_change = True - return - - if witness_script: - # p2sh-p2wsh case (because it had witness script) - expect_rs = b'\x00\x20' + ngu.hash.sha256s(witness_script) - - if redeem_script and expect_rs != redeem_script: - # iff they provide a redeeem script, then it needs to match - # what we expect it to be - raise FraudulentChangeOutput(out_idx, - "P2SH-P2WSH redeem script provided, and doesn't match") - - expect_pkh = hash160(expect_rs) - else: - # old BIP-16 style; looks like payment addr - expect_pkh = hash160(redeem_script) - - elif addr_type == 'p2pkh': + elif af in (AF_CLASSIC, AF_P2WPKH): + # P2PKH & P2WPKH (public key has, whether witness v0 or legacy) # input is hash160 of a single public key assert len(addr_or_pubkey) == 20 - expect_pkh = hash160(expect_pubkey) - elif addr_type == "p2tr": - if expect_pubkey is None and len(self.taproot_subpaths) > 1: - if active_miniscript: - try: - active_miniscript.validate_script_pubkey( - b"\x51\x20" + pkh, - [v[1:] for v in self.taproot_subpaths.values() if len(v[1:]) > 1] - ) - self.is_change = True - return - except Exception as e: - raise FraudulentChangeOutput(out_idx, "Change output scriptPubkey: %s" % e) - expect_pkh = None - else: - expect_pkh = taptweak(expect_pubkey) - else: - # we don't know how to "solve" this type of input - return + assert len(parsed_subpaths) == 1 + target, = parsed_subpaths.keys() + target = hash160(target) - if pkh != expect_pkh: - raise FraudulentChangeOutput(out_idx, "Change output is fraudulent") + elif af in (AF_P2SH, AF_P2WSH): # both p2sh & p2wsh covered here + if msc: + # scriptPubkey can be compared against script that we build + # if exact match change if not - not change + # no need for redeem/witness script + # for instance liana & core do not provide witness/redeem + try: + xfp_paths = list(parsed_subpaths.values()) + # if subpaths do not match, it is not desired wallet - so no change + # but also not a fraud + if msc.matching_subpaths(xfp_paths): + msc.validate_script_pubkey(txo.scriptPubKey, xfp_paths) + self.is_change = True + except AssertionError as e: + # sys.print_exception(e) + fraud(out_idx, af, e) + return af + + # we do not have active miniscript - must be single sig otherwise, not a change + if len(parsed_subpaths) == 1 and (af == AF_P2SH): + expect_pubkey, = parsed_subpaths.keys() + target_spk, _ = chains.current_chain().script_pubkey(AF_P2WPKH_P2SH, + pubkey=expect_pubkey) + af = AF_P2WPKH_P2SH + if txo.scriptPubKey != target_spk: + fraud(out_idx, af, "spk mismatch") + # it's actually segwit p2wpkh inside p2sh + target = target_spk[2:-1] + else: + # done, not a change, subpaths > 1 or p2wsh (and not active miniscript) + return af + + elif af == AF_P2TR: + if msc: + try: + xfp_paths = [v[1:] for v in parsed_subpaths.values() if len(v[1:]) > 1] + if msc.matching_subpaths(xfp_paths): + msc.validate_script_pubkey(txo.scriptPubKey, xfp_paths) + self.is_change = True + except AssertionError as e: + fraud(out_idx, af, e) + return af + + if len(parsed_subpaths) == 1: + expect_pubkey, = parsed_subpaths.keys() + target = taptweak(expect_pubkey) + else: + # done, not a change, subpaths > 1 (and not active miniscript) + return af + + # only basic single signature, non-miniscript scripts get here + assert parent.active_singlesig + if addr_or_pubkey != target: + fraud(out_idx, af) # We will check pubkey value at the last second, during signing. self.is_change = True + return af # Track details of each input of PSBT @@ -684,12 +629,13 @@ class psbtInputProxy(psbtProxy): PSBT_IN_TAP_INTERNAL_KEY, PSBT_IN_TAP_MERKLE_ROOT} blank_flds = ( - 'unknown', 'utxo', 'witness_utxo', 'sighash', 'redeem_script', 'witness_script', - 'fully_signed', 'is_segwit', 'is_multisig', 'is_p2sh', 'num_our_keys', - 'required_key', 'scriptSig', 'amount', 'scriptCode', 'previous_txid', - 'prevout_idx', 'sequence', 'req_time_locktime', 'req_height_locktime', 'taproot_key_sig', - 'taproot_merkle_root', 'taproot_script_sigs', 'taproot_scripts', "use_keypath", "subpaths", - "taproot_subpaths", "taproot_internal_key", "part_sig" + 'unknown', 'witness_utxo', 'sighash', 'redeem_script', 'witness_script', 'sp_idxs', + 'fully_signed', 'af', 'is_miniscript', "subpaths", 'utxo', 'utxo_spk', + 'amount', 'previous_txid', 'part_sigs', 'added_sigs', 'prevout_idx', 'sequence', + 'req_time_locktime', 'req_height_locktime', + 'taproot_merkle_root', 'taproot_script_sigs', 'taproot_scripts', 'use_keypath', + 'taproot_subpaths', 'taproot_internal_key', 'taproot_key_sig', 'tr_added_sigs', + 'ik_idx', ) def __init__(self, fd, idx): @@ -697,34 +643,35 @@ class psbtInputProxy(psbtProxy): #self.utxo = None #self.witness_utxo = None - # self.part_sig = {} + #self.part_sigs = [] + #self.added_sigs = [] # signatures that we added (current siging session) #self.sighash = None - # self.subpaths = {} # will be empty if taproot + #self.subpaths = [] # will be empty if taproot #self.redeem_script = None #self.witness_script = None # Non-zero if one or more of our signing keys involved in input - #self.num_our_keys = None + #self.sp_idxs = list of indexes leading to our key in self.subpaths # things we've learned #self.fully_signed = False # we can't really learn this until we take apart the UTXO's scriptPubKey - #self.is_segwit = None - #self.is_multisig = None - #self.is_p2sh = False + #self.af = None # string representation of address format aka. script type - #self.required_key = None # which of our keys will be used to sign input - #self.scriptSig = None #self.amount = None - #self.scriptCode = None # only expected for segwit inputs + #self.utxo_spk = None # scriptPubKey for input utxo - # self.taproot_subpaths = {} # will be empty if non-taproot - # self.taproot_internal_key = None # will be empty if non-taproot - # self.taproot_key_sig = None # will be empty if non-taproot - # self.taproot_merkle_root = None # will be empty if non-taproot - # self.taproot_script_sigs = None # will be empty if non-taproot - # self.taproot_scripts = None # will be empty if non-taproot + # === will be empty if non-taproot === + # self.taproot_subpaths = {} + # self.taproot_internal_key = None + # self.taproot_key_sig = None + # self.taproot_merkle_root = None + # self.taproot_script_sigs = None + # self.taproot_scripts = None + # self.use_keypath = None # signing taproot inputs that have script path with internal key + # self.ik_idx = None # index of taproot internal key in taproot_subpaths + # === #self.previous_txid = None #self.prevout_idx = None @@ -734,31 +681,30 @@ class psbtInputProxy(psbtProxy): self.parse(fd) - def parse_taproot_script_sigs(self): - # not needed at this point as we do not support tapscript - # parsing this field without actual tapscript support is just a waste of memory - parsed_taproot_script_sigs = {} - for key in self.taproot_script_sigs: - assert len(key) == 64 # "PSBT_IN_TAP_SCRIPT_SIG key length != 64" - assert self.taproot_script_sigs[key][1] in (64, 65) # "PSBT_IN_TAP_SCRIPT_SIG signature length != 64 or 65" - xonly, script_hash = key[:32], key[32:] - parsed_taproot_script_sigs[(xonly, script_hash)] = self.get(self.taproot_script_sigs[key]) - self.taproot_script_sigs = parsed_taproot_script_sigs + @property + def is_segwit(self): + return self.af & AFC_SEGWIT - def parse_taproot_scripts(self): - # not needed at this point as we do not support tapscript - # parsing this field without actual tapscript support is just a waste of memory - parsed_taproot_scripts = {} - for key in self.taproot_scripts: - assert len(key) > 32 # "PSBT_IN_TAP_LEAF_SCRIPT control block is too short" - assert (len(key) - 1) % 32 == 0 # "PSBT_IN_TAP_LEAF_SCRIPT control block is not valid" - script = self.get(self.taproot_scripts[key]) - assert len(script) != 0 # "PSBT_IN_TAP_LEAF_SCRIPT cannot be empty" - leaf_script = (script[:-1], int(script[-1])) - if leaf_script not in self.taproot_scripts: - parsed_taproot_scripts[leaf_script] = set() - parsed_taproot_scripts[leaf_script].add(key) - self.taproot_scripts = parsed_taproot_scripts + def get_taproot_script_sigs(self): + # returns set of (xonly, script) provided via PSBT_IN_TAP_SCRIPT_SIG + # we do not parse control blocks (k) not needed + parsed_taproot_script_sigs = set() + for k, v in self.taproot_script_sigs or []: + key = self.get(k) + xonly, script_hash = key[:32], key[32:] + parsed_taproot_script_sigs.add((xonly, script_hash)) + + return parsed_taproot_script_sigs + + def get_taproot_scripts(self): + # returns set of scripts provided via PSBT_IN_TAP_LEAF_SCRIPT + # we do not parse control blocks (k) not needed + t_scr = {} + for k, v in self.taproot_scripts or []: + script = self.get(v) + t_scr[script[:-1]] = script[-1] # only script, and script version + + return t_scr def has_relative_timelock(self, txin): # https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki @@ -786,61 +732,6 @@ class psbtInputProxy(psbtProxy): return is_timebased, res - def validate(self, idx, txin, my_xfp, parent): - # Validate this txn input: given deserialized CTxIn and maybe witness - - # TODO: tighten these - if self.witness_script: - assert self.witness_script[1] >= 30 - if self.redeem_script: - assert self.redeem_script[1] >= 22 - - if self.taproot_internal_key: - assert self.taproot_internal_key[1] == 32 # "PSBT_IN_TAP_INTERNAL_KEY length != 32" - - if self.taproot_script_sigs: - self.parse_taproot_script_sigs() - - if self.taproot_scripts: - self.parse_taproot_scripts() - - # require path for each addr, check some are ours - - # rework the pubkey => subpath mapping - self.parse_subpaths(my_xfp, parent.warnings) - - if self.part_sig: - # How complete is the set of signatures so far? - # - assuming PSBT creator doesn't give us extra data not required - # - seems harmless if they fool us into thinking already signed; we do nothing - # - could also look at pubkey needed vs. sig provided - # - could consider structure of MofN in p2sh cases - self.fully_signed = len(self.part_sig) >= len(self.subpaths) - else: - # No signatures at all yet for this input (typical non multisig) - self.fully_signed = False - - if self.taproot_key_sig: - assert self.taproot_key_sig[1] in (64, 65) # "PSBT_IN_TAP_KEY_SIG length != 64 or 65" - if self.taproot_key_sig[1] == 65: - taproot_sig = self.get(self.taproot_key_sig) - if self.sighash: - assert taproot_sig[64] == self.sighash # "PSBT_IN_SIGHASH_TYPE != PSBT_IN_TAP_KEY_SIG[64]" - self.fully_signed = True - - if self.utxo: - # Important: they might be trying to trick us with an un-related - # funding transaction (UTXO) that does not match the input signature we're making - # (but if it's segwit, the ploy wouldn't work, Segwit FtW) - # - challenge: it's a straight dsha256() for old serializations, but not for newer - # segwit txn's... plus I don't want to deserialize it here. - try: - observed = uint256_from_str(calc_txid(self.fd, self.utxo)) - except: - raise AssertionError("Trouble parsing UTXO given for input #%d" % idx) - - assert txin.prevout.hash == observed, "utxo hash mismatch for input #%d" % idx - def handle_none_sighash(self): if self.sighash is None: self.sighash = SIGHASH_DEFAULT if self.taproot_subpaths else SIGHASH_ALL @@ -901,242 +792,240 @@ class psbtInputProxy(psbtProxy): return utxo - def determine_my_signing_key(self, my_idx, utxo, my_xfp, psbt): + def determine_my_signing_key(self, my_idx, addr_or_pubkey, my_xfp, psbt, parsed_subpaths, utxo): # See what it takes to sign this particular input # - type of script # - which pubkey needed - # - scriptSig value # - also validates redeem_script when present - merkle_root = None - self.amount = utxo.nValue + merkle_root = redeem_script = None - if (not self.subpaths and not self.taproot_subpaths) or self.fully_signed: - # without xfp+path we will not be able to sign this input - # - okay if fully signed - # - okay if payjoin or other multi-signer (not multisig) txn - self.required_key = None + if self.af == OP_RETURN: return - self.is_multisig = False - self.is_miniscript = False - self.is_p2sh = False - which_key = None + if self.af is None: + # If this is reached, we do not understand the output well + # enough to allow the user to authorize the spend, so fail hard. + raise FatalPSBTIssue('Unhandled scriptPubKey: ' + b2a_hex(addr_or_pubkey).decode()) - addr_type, addr_or_pubkey, addr_is_segwit = utxo.get_address() - if addr_is_segwit and not self.is_segwit: - self.is_segwit = True + if psbt.active_miniscript or psbt.active_singlesig: + # we have already set one of these - sow we can use some short-cuts + if psbt.active_miniscript and (self.af in (AF_CLASSIC, AF_P2WPKH, AF_BARE_PK)): + # signing with miniscript wallet - ignore single sig utxos + self.sp_idxs = None + return + elif psbt.active_singlesig and (self.af == AF_P2WSH): + # we are signing single sig inputs - ignore p2wsh utxos + self.sp_idxs = None + return - if addr_type == 'p2sh': - # multisig input - self.is_p2sh = True + if self.af == AF_BARE_PK: + # input is single compressed public key (less common) + # uncompressed public keys not supported! + assert len(addr_or_pubkey) == 33 + for i, pubkey in enumerate(parsed_subpaths): + if pubkey == addr_or_pubkey: + assert i == self.sp_idxs[0] + break + else: + # pubkey provided is just wrong vs. UTXO + raise FatalPSBTIssue('Input #%d: pubkey wrong' % my_idx) + + elif self.af in (AF_CLASSIC, AF_P2WPKH): + # P2PKH & P2WPKH + # input is hash160 of a single public key + + for i, pubkey in enumerate(parsed_subpaths): + if hash160(pubkey) == addr_or_pubkey: + assert i == self.sp_idxs[0] + break + else: + # none of the pubkeys provided hashes to that address + raise FatalPSBTIssue('Input #%d: pubkey vs. address wrong' % my_idx) + + elif self.af in (AF_P2WSH, AF_P2SH): # we must have the redeem script already (else fail) ks = self.witness_script or self.redeem_script if not ks: raise FatalPSBTIssue("Missing redeem/witness script for input #%d" % my_idx) redeem_script = self.get(ks) - self.scriptSig = redeem_script + native_v0 = (self.af == AF_P2WSH) + + if not native_v0 and (len(redeem_script) == 22) and \ + redeem_script[0] == 0 and redeem_script[1] == 20 and \ + len(parsed_subpaths) == 1: + + for i, pubkey in enumerate(parsed_subpaths): + target_spk, _ = chains.current_chain().script_pubkey(AF_P2WPKH_P2SH, + pubkey=pubkey) + if target_spk == utxo.scriptPubKey: + # it's actually segwit p2wpkh inside p2sh + self.af = AF_P2WPKH_P2SH + assert i == self.sp_idxs[0] - # new cheat: psbt creator probably telling us exactly what key - # to use, by providing exactly one. This is ideal for p2sh wrapped p2pkh - if len(self.subpaths) == 1: - which_key, = self.subpaths.keys() else: # Assume we'll be signing with any key we know - # - limitation: we cannot be two legs of a multisig # - but if partial sig already in place, ignore that one - for pubkey, path in self.subpaths.items(): - if self.part_sig and (pubkey in self.part_sig): - # pubkey has already signed, so ignore - continue + self.is_miniscript = True + # values will always be coords for both pubkey and signature at this point + done_keys = set() + if self.part_sigs: + done_keys = {self.get(k) for k,_ in self.part_sigs} - if path[0] == my_xfp: + for i, (pubkey, path) in enumerate(parsed_subpaths.items()): + if pubkey in done_keys: + # pubkey has already signed, so - do not sign again + if i in self.sp_idxs: + # remove from sp_idxs so we do not attempt to sign again + self.sp_idxs.remove(i) + + elif path[0] == my_xfp: # slight chance of dup xfps, so handle - if not which_key: - which_key = set() + assert i in self.sp_idxs - which_key.add(pubkey) + if self.witness_script and (not native_v0) and (self.redeem_script[1] == 34): + # bugfix + self.af = AF_P2WSH_P2SH + assert self.redeem_script[1] == 34 - if not addr_is_segwit and \ - len(redeem_script) == 22 and \ - redeem_script[0] == 0 and redeem_script[1] == 20: - # it's actually segwit p2pkh inside p2sh - addr_type = 'p2sh-p2wpkh' - addr = redeem_script[2:22] - self.is_segwit = True - else: - # multiple keys involved, we probably can't do the finalize step - M, N = disassemble_multisig_mn(redeem_script) - if M is None and N is None: - self.is_miniscript = True - else: - self.is_multisig = True + if self.af in (AF_P2WSH, AF_P2WSH_P2SH): + # for both P2WSH & P2SH-P2WSH + if not self.witness_script: + raise FatalPSBTIssue('Need witness script for input #%d' % my_idx) - if self.witness_script and not self.is_segwit and (self.is_miniscript or self.is_multisig): - # bugfix - addr_type = 'p2sh-p2wsh' - self.is_segwit = True - - elif addr_type == 'p2pkh': - # input is hash160 of a single public key - self.scriptSig = utxo.scriptPubKey - addr = addr_or_pubkey - - for pubkey in self.subpaths: - if hash160(pubkey) == addr: - which_key = pubkey - break - else: - # none of the pubkeys provided hashes to that address - raise FatalPSBTIssue('Input #%d: pubkey vs. address wrong' % my_idx) - - elif addr_type == 'p2tr': - pubkey = addr_or_pubkey - merkle_root = None if self.taproot_merkle_root is None else self.get(self.taproot_merkle_root) - if len(self.taproot_subpaths) == 1: + elif self.af == AF_P2TR: + if len(parsed_subpaths) == 1: # keyspend without a script path - assert merkle_root is None, "merkle_root should not be defined for simple keyspend" - xonly_pubkey, lhs_path = list(self.taproot_subpaths.items())[0] - lhs, path = lhs_path[0], lhs_path[1:] # meh - should be a tuple + assert self.taproot_merkle_root is None, "merkle_root should not be defined for simple keyspend" + assert self.ik_idx is not None + xonly_pubkey, lhs_path = list(parsed_subpaths.items())[0] + lhs, path = lhs_path[0], lhs_path[1:] assert not lhs, "LeafHashes have to be empty for internal key" - if path[0] == my_xfp: - output_key = taptweak(xonly_pubkey) - if output_key == pubkey: - which_key = xonly_pubkey + assert self.sp_idxs[0] == 0 + assert taptweak(xonly_pubkey) == addr_or_pubkey else: # tapscript (is always miniscript wallet) self.is_miniscript = True - for xonly_pubkey, lhs_path in self.taproot_subpaths.items(): - lhs, path = lhs_path[0], lhs_path[1:] # meh - should be a tuple - # ignore keys that does not have correct xfp specified in PSBT - if path[0] == my_xfp: - assert merkle_root is not None, "Merkle root not defined" - if not lhs: - output_key = taptweak(xonly_pubkey, merkle_root) - if output_key == pubkey: - which_key = xonly_pubkey - # if we find a possibiity to spend keypath (internal_key) - we do keypath - # even though script path is available - self.use_keypath = True - break - else: - internal_key = self.get(self.taproot_internal_key) - output_pubkey = taptweak(internal_key, merkle_root) - if not which_key: - which_key = set() - if pubkey == output_pubkey: - which_key.add(xonly_pubkey) - elif addr_type == 'p2pk': - # input is single public key (less common) - self.scriptSig = utxo.scriptPubKey - assert len(addr_or_pubkey) == 33 + if self.taproot_merkle_root is not None: + merkle_root = self.get(self.taproot_merkle_root) - if addr_or_pubkey in self.subpaths: - which_key = addr_or_pubkey + for i, (xonly_pubkey, lhs_path) in enumerate(parsed_subpaths.items()): + if i not in self.sp_idxs: + # # ignore keys that does not have correct xfp specified in PSBT + continue + + lhs, path = lhs_path[0], lhs_path[1:] + assert path[0] == my_xfp + assert merkle_root is not None, "Merkle root not defined" + if self.ik_idx == i: + assert not lhs + output_key = taptweak(xonly_pubkey, merkle_root) + if output_key == addr_or_pubkey: + # if we find a possibility to spend keypath (internal_key) - we do keypath + # even though script path is available + self.sp_idxs = [i] + self.use_keypath = True + break # done ignoring all other possibilities + else: + internal_key = self.get(self.taproot_internal_key) + output_pubkey = taptweak(internal_key, merkle_root) + if addr_or_pubkey == output_pubkey: + assert i in self.sp_idxs + + if self.is_miniscript: + if not self.sp_idxs: return + if psbt.active_singlesig: + # if we already considered single signature inputs for signing + # do not even consider to sign with miniscript wallet(s) + # maybe we removed + self.sp_idxs = None + return # required key is None + + if self.af == AF_P2TR: + xfp_paths = [item[1:] + for item in parsed_subpaths.values() + if len(item[1:]) > 1] else: - # pubkey provided is just wrong vs. UTXO - raise FatalPSBTIssue('Input #%d: pubkey wrong' % my_idx) + xfp_paths = list(parsed_subpaths.values()) - else: - # we don't know how to "solve" this type of input - pass - - if self.is_multisig and which_key: - # We will be signing this input, so - # - find which wallet it is or - # - check it's the right M/N to match redeem script - - #print("redeem: %s" % b2a_hex(redeem_script)) - xfp_paths = list(self.subpaths.values()) - xfp_paths.sort() - - if not psbt.active_multisig: - # search for multisig wallet - wal = MultisigWallet.find_match(M, N, xfp_paths) - if not wal: - raise FatalPSBTIssue('Unknown multisig wallet') - - psbt.active_multisig = wal + if psbt.active_miniscript: + if not MiniScriptWallet.disable_checks: + if not psbt.active_miniscript.matching_subpaths(xfp_paths): + # not input from currently selected wallet + self.sp_idxs = None + return else: - # check consistent w/ already selected wallet - psbt.active_multisig.assert_matching(M, N, xfp_paths) - - # validate redeem script, by disassembling it and checking all pubkeys - try: - psbt.active_multisig.validate_script(redeem_script, subpaths=self.subpaths) - except BaseException as exc: - sys.print_exception(exc) - raise FatalPSBTIssue('Input #%d: %s' % (my_idx, exc)) - - if self.is_miniscript and which_key: - try: - xfp_paths = [item[1:] for item in self.taproot_subpaths.values() if len(item[1:]) > 1] - except AttributeError: - xfp_paths = list(self.subpaths.values()) - - xfp_paths.sort() - if not psbt.active_miniscript: - wal = MiniScriptWallet.find_match(xfp_paths) + # if we do have actual script at hand, guess M/N for better matching + # basic multisig matching + M, N = disassemble_multisig_mn(redeem_script) + wal = MiniScriptWallet.find_match(xfp_paths, self.af, M, N) if not wal: - raise FatalPSBTIssue('Unknown miniscript wallet') + # not an input from wallet that we have enrolled + self.sp_idxs = None + return + psbt.active_miniscript = wal - assert psbt.active_miniscript try: - # contains PSBT merkle root verification - psbt.active_miniscript.validate_script_pubkey(utxo.scriptPubKey, - xfp_paths, merkle_root) + # contains PSBT merkle root verification (if taproot) + if not MiniScriptWallet.disable_checks: + psbt.active_miniscript.validate_script_pubkey(self.utxo_spk, + xfp_paths, merkle_root) except BaseException as e: + # sys.print_exception(e) raise FatalPSBTIssue('Input #%d: %s\n\n' % (my_idx, e) + problem_file_line(e)) - if not which_key and DEBUG: - print("no key: input #%d: type=%s segwit=%d a_or_pk=%s scriptPubKey=%s" % ( - my_idx, addr_type, self.is_segwit or 0, - b2a_hex(addr_or_pubkey), b2a_hex(utxo.scriptPubKey))) + else: + # single signature utxo + if psbt.active_miniscript: + # complex wallet is active - so this is not for us to sign + self.sp_idxs = None + return - self.required_key = which_key + psbt.active_singlesig = True - if self.is_segwit and addr_type != 'p2tr': - if ('pkh' in addr_type): - # This comment from : - # - # Please note that for a P2SH-P2WPKH, the scriptCode is always 26 - # bytes including the leading size byte, as 0x1976a914{20-byte keyhash}88ac, - # NOT the redeemScript nor scriptPubKey - # - # Also need this scriptCode for native segwit p2pkh - # - assert not self.is_multisig - self.scriptCode = b'\x19\x76\xa9\x14' + addr + b'\x88\xac' - elif not self.scriptCode: - # Segwit P2SH. We need the witness script to be provided. - if not self.witness_script: - raise FatalPSBTIssue('Need witness script for input #%d' % my_idx) + def segwit_v0_scriptCode(self): + # only v0 segwit + # only needed for sighash + assert self.is_segwit and (self.af != AF_P2TR) + if self.af == AF_P2WPKH: + return b'\x19\x76\xa9\x14' + self.utxo_spk[2:2+20] + b'\x88\xac' + elif self.af == AF_P2WPKH_P2SH: + return b'\x19\x76\xa9\x14' + self.get(self.redeem_script)[2:22] + b'\x88\xac' + elif self.af in (AF_P2WSH, AF_P2WSH_P2SH): + # "scriptCode is witnessScript preceeded by a + # compactSize integer for the size of witnessScript" + return ser_string(self.get(self.witness_script)) - # "scriptCode is witnessScript preceeded by a - # compactSize integer for the size of witnessScript" - self.scriptCode = ser_string(self.get(self.witness_script)) - - # Could probably free self.subpaths and self.redeem_script now, but only if we didn't - # need to re-serialize as a PSBT. + def get_scriptSig(self): + if self.af in [AF_BARE_PK, AF_CLASSIC]: + return self.utxo_spk + elif self.af in (AF_P2SH, AF_P2WSH_P2SH, AF_P2WPKH_P2SH): + return self.get(self.redeem_script) + else: + return b"" def store(self, kt, key, val): # Capture what we are interested in. - if kt == PSBT_IN_NON_WITNESS_UTXO: self.utxo = val elif kt == PSBT_IN_WITNESS_UTXO: self.witness_utxo = val elif kt == PSBT_IN_PARTIAL_SIG: - if self.part_sig is None: - self.part_sig = {} - self.part_sig[key[1:]] = val + # taproot inputs do not have part sigs + # only populate the attribute if present + if not self.part_sigs: + self.part_sigs = [] + # do not load anything (both key and val are coordinates) + # actual signatures (71 bytes) we do not need them until finalization + # public keys are enough for validation we will get them as needed + self.part_sigs.append((key, val)) elif kt == PSBT_IN_BIP32_DERIVATION: if self.subpaths is None: - self.subpaths = {} - self.subpaths[key[1:]] = val + self.subpaths = [] + self.subpaths.append((key, val)) elif kt == PSBT_IN_REDEEM_SCRIPT: self.redeem_script = val elif kt == PSBT_IN_WITNESS_SCRIPT: @@ -1147,20 +1036,18 @@ class psbtInputProxy(psbtProxy): self.taproot_internal_key = val elif kt == PSBT_IN_TAP_BIP32_DERIVATION: if self.taproot_subpaths is None: - self.taproot_subpaths = {} - self.taproot_subpaths[key[1:]] = val + self.taproot_subpaths = [] + self.taproot_subpaths.append((key, val)) elif kt == PSBT_IN_TAP_KEY_SIG: self.taproot_key_sig = val elif kt == PSBT_IN_TAP_MERKLE_ROOT: self.taproot_merkle_root = val elif kt == PSBT_IN_TAP_SCRIPT_SIG: - if self.taproot_script_sigs is None: - self.taproot_script_sigs = {} - self.taproot_script_sigs[key[1:]] = val + self.taproot_script_sigs = self.taproot_script_sigs or [] + self.taproot_script_sigs.append((key, val)) elif kt == PSBT_IN_TAP_LEAF_SCRIPT: - if self.taproot_scripts is None: - self.taproot_scripts = {} - self.taproot_scripts[key[1:]] = val + self.taproot_scripts = self.taproot_scripts or [] + self.taproot_scripts.append((key, val)) elif kt == PSBT_IN_PREVIOUS_TXID: self.previous_txid = val elif kt == PSBT_IN_OUTPUT_INDEX: @@ -1173,10 +1060,9 @@ class psbtInputProxy(psbtProxy): self.req_height_locktime = unpack("= 1 - xfp_paths.append(h) + parsed_xpubs.append((xp, h)) if h[0] == self.my_xfp: has_mine += 1 @@ -1521,63 +1434,57 @@ class psbtObject(psbtProxy): if not has_mine: raise FatalPSBTIssue('My XFP not involved') - candidates = MultisigWallet.find_candidates(xfp_paths) + # don't want to guess M if not needed, but we need it + af, M, N = self.guess_M_of_N() + if not N: + # not multisig, but we can still verify: + # - miniscript cannot be imported from PSBT (we lack descriptor in PSBT) + # - XFP should be one of ours (checked above). + # - too slow to re-derive it here, so nothing more to validate at this point + return - if len(candidates) == 1: + assert N == len(self.xpubs) + + # Validate good match here. The xpubs must be exactly right, but + # we're going to use our own values from setup time anyway and not trusting + # new values without user interaction. + # Check: + # - chain codes match what we have stored already + # - pubkey vs. path will be checked later + # - xfp+path already checked above when selecting wallet + # Any issue here is a fraud attempt in some way, not innocent. + wal = MiniScriptWallet.find_match([i[1] for i in parsed_xpubs], af, M, N) + + if wal: # exact match (by xfp+deriv set) .. normal case - self.active_multisig = candidates[0] + self.active_miniscript = wal + # now proper check should follow - matching actual master pubkeys + # but is it needed?, we just matched the wallet + # and are going to use our own data for verification anyway + if not self.active_miniscript.disable_checks: + self.active_miniscript.validate_psbt_xpubs(parsed_xpubs) + else: - # don't want to guess M if not needed, but we need it - M, N = self.guess_M_of_N() + trust_mode = MiniScriptWallet.get_trust_policy() + # already checked for existing import and wasn't found, so fail + assert trust_mode != TRUST_VERIFY, "XPUBs in PSBT do not match any existing wallet" - if not N: - # not multisig, but we can still verify: - # - XFP should be one of ours (checked above). - # - too slow to re-derive it here, so nothing more to validate at this point - return - - assert N == len(xfp_paths) - - for c in candidates: - if c.M == M and c.N == N: - self.active_multisig = c - break - # if not active_multisig set in this loop - # appropriate candidate was not found - # --> continue to import from psbt prompt - - del candidates - - if not self.active_multisig: # Maybe create wallet, for today, forever, or fail, etc. - proposed, need_approval = MultisigWallet.import_from_psbt(M, N, self.xpubs) - if need_approval: + proposed = MiniScriptWallet.import_from_psbt(af, M, N, parsed_xpubs) + if trust_mode != TRUST_PSBT: # do a complex UX sequence, which lets them save new wallet from glob import hsm_active if hsm_active: raise FatalPSBTIssue("MS enroll not allowed in HSM mode") ch = await proposed.confirm_import() - if ch != 'y': + if ch not in 'y'+KEY_ENTER: raise FatalPSBTIssue("Refused to import new wallet") - self.active_multisig = proposed - else: - # Validate good match here. The xpubs must be exactly right, but - # we're going to use our own values from setup time anyway and not trusting - # new values without user interaction. - # Check: - # - chain codes match what we have stored already - # - pubkey vs. path will be checked later - # - xfp+path already checked above when selecting wallet - # Any issue here is a fraud attempt in some way, not innocent. - self.active_multisig.validate_psbt_xpubs(self.xpubs) + self.active_miniscript = proposed - if not self.active_multisig: - # not clear if an error... might be part-way to importing, and - # the data is optional anyway, etc. If they refuse to import, - # we should not reach this point (ie. raise something to abort signing) - return + # must have wallet at this point + assert self.active_miniscript def ux_relative_timelocks(self, tb, bb): # visualize 10 largest timelock to user @@ -1606,11 +1513,11 @@ class psbtObject(psbtProxy): # Block height relative lock-time if num_bb == 1: idx, val = bb[0] - msg = "Input %d. has relative block height timelock of %d blocks" % ( + msg = "Input %d. has relative block height timelock of %d blocks\n" % ( idx, val ) elif all(bb[0][1] == i[1] for i in bb): - msg = "%d inputs have relative block height timelock of %d blocks" % ( + msg = "%d inputs have relative block height timelock of %d blocks\n" % ( num_bb, bb[0][1] ) else: @@ -1628,11 +1535,11 @@ class psbtObject(psbtProxy): if num_tb == 1: idx, val = tb[0] val = seconds2human_readable(val) - msg = "Input %d. has relative time-based timelock of:\n %s" % ( + msg = "Input %d. has relative time-based timelock of:\n %s\n" % ( idx, val ) elif all(tb[0][1] == i[1] for i in tb): - msg = "%d inputs have relative time-based timelock of:\n %s" % ( + msg = "%d inputs have relative time-based timelock of:\n %s\n" % ( num_tb, seconds2human_readable(tb[0][1]) ) else: @@ -1646,6 +1553,15 @@ class psbtObject(psbtProxy): self.ux_notes.append(("Time-based RTL", msg)) + def validate_unkonwn(self, obj, label): + # find duplicate unknown values in different PSBT parts + if not obj.unknown: + return + + if len({self.get(k) for k,_ in obj.unknown}) < len(obj.unknown): + raise FatalPSBTIssue("Duplicate key. Key for unknown value" + " already provided in %s." % label) + async def validate(self): # Do a first pass over the txn. Raise assertions, be terse tho because # these messages are rarely seen. These are syntax/fatal errors. @@ -1670,56 +1586,442 @@ class psbtObject(psbtProxy): assert not self.has_goc, "v0 requires exclusion of global output count" assert not self.has_gtv, "v0 requires exclusion of global txn version" assert self.txn, "v0 requires inclusion of global unsigned tx" - assert self.txn[1] > 63, 'txn too short' + assert self.txn[1] > 61, 'txn too short' assert self.fallback_locktime is None, "v0 requires exclusion of global fallback locktime" assert self.txn_modifiable is None, "v0 requires exclusion of global txn modifiable" - for idx, txo in self.output_iter(): - out = self.outputs[idx] + assert len(self.inputs) == self.num_inputs, 'ni mismatch' + + assert self.num_outputs >= 1, 'need outputs' + + self.validate_unkonwn(self, "global namespace") + + inp_have_subpath = False + for i in self.inputs: + if i.subpaths or i.taproot_subpaths: + inp_have_subpath = True + if self.is_v2: # v2 requires inclusion - assert out.amount - assert out.script + assert i.prevout_idx is not None + assert i.previous_txid + if i.req_time_locktime is not None: + assert i.req_time_locktime >= NLOCK_IS_TIME + if i.req_height_locktime is not None: + assert 0 < i.req_height_locktime < NLOCK_IS_TIME else: # v0 requires exclusion - assert out.amount is None - assert out.script is None + assert i.prevout_idx is None + assert i.previous_txid is None + assert i.sequence is None + assert i.req_time_locktime is None + assert i.req_height_locktime is None + if i.witness_script: + assert i.witness_script[1] >= 30 + if i.redeem_script: + assert i.redeem_script[1] >= 22 + + if i.taproot_internal_key: + assert i.taproot_internal_key[1] == 32 # "PSBT_IN_TAP_INTERNAL_KEY length != 32" + + if i.taproot_key_sig: + # "PSBT_IN_TAP_KEY_SIG length != 64 or 65" + assert i.taproot_key_sig[1] in (64, 65) + + if i.part_sigs: + for k, v in i.part_sigs: + assert k[1] == 33 + # valid signature can also be 60 bytes or less (needs grinding) + # 69 bytes - where both r & s are 31 bytes + # 73 -> high-s & high-r + assert v[1] <= 73, "DER sig len" + + if i.taproot_script_sigs: + for k, v in i.taproot_script_sigs: + # PSBT_IN_TAP_SCRIPT_SIG + 32 bytes xonly pubkey + leafhash 32 bytes + assert k[1] == 64 + # The 64 or 65 byte Schnorr signature for this pubkey and leaf combination + assert v[1] in (64, 65) + + if i.taproot_scripts: + for k, v in i.taproot_scripts: + assert k[1] > 32 # "PSBT_IN_TAP_LEAF_SCRIPT control block is too short" + assert (k[1] - 1) % 32 == 0 # "PSBT_IN_TAP_LEAF_SCRIPT control block is not valid" + assert v[1] != 0 # "PSBT_IN_TAP_LEAF_SCRIPT cannot be empty" + + if i.sighash and (i.sighash not in ALL_SIGHASH_FLAGS): + raise FatalPSBTIssue("Unsupported sighash flag 0x%x" % i.sighash) + + self.validate_unkonwn(i, "input") + + for o in self.outputs: + if self.is_v2: + # v2 requires inclusion + assert o.amount + assert o.script + else: + # v0 requires exclusion + assert o.amount is None + assert o.script is None + + if o.taproot_internal_key: + assert o.taproot_internal_key[1] == 32 # "PSBT_OUT_TAP_INTERNAL_KEY length != 32" + + self.validate_unkonwn(o, "output") + + if not inp_have_subpath: + # Can happen w/ Electrum in watch-mode on XPUB. It doesn't know XFP and + # so doesn't insert that into PSBT. + # or PSBT provider forgot to include subpaths + raise FatalPSBTIssue('PSBT inputs do not contain any key path information.') + + # if multisig xpub details provided, they better be right and/or offer import + if self.xpubs: + await self.handle_xpubs() + + if DEBUG: + print("PSBT: %d inputs, %d output" % (self.num_inputs, self.num_outputs)) + + def consider_outputs(self, len_pths, hard_p, prefix_pths, idx_max, cosign_xfp=None): + from glob import dis + # scan ouputs: + # - is it a change address, defined by redeem script (p2sh) or key we know is ours + # - mark change outputs, so perhaps we don't show them to users + total_out = 0 + total_change = 0 + num_op_return = 0 + num_op_return_size = 0 + num_unknown_scripts = 0 + zero_val_outs = 0 # only those that are not OP_RETURN are considered + self.num_change_outputs = 0 + + validate_inp_pths = False + path_len = None + max_gap = idx_max + 200 + + # We aren't seeing shared input path lengths. + # They are probably doing weird stuff, so leave them alone + # and do not validate against inputs paths + if len(len_pths) == 1: + path_len = 0 + for pl in len_pths: + path_len = pl + break + if path_len > 2: + validate_inp_pths = True + + dis.fullscreen("Validating...", line2="Outputs") + + for idx, txo in self.output_iter(): + dis.progress_sofar(idx, self.num_outputs) + output = self.outputs[idx] + + parsed_subpaths = output.parse_subpaths(self.my_xfp, self.warnings, cosign_xfp) + + # perform output validation + af = output.determine_my_change(idx, txo, parsed_subpaths, self) + assert txo.nValue >= 0, "negative output value: o%d" % idx + total_out += txo.nValue + + if (txo.nValue == 0) and (af != OP_RETURN): + # OP_RETURN outputs have nValue=0 standard + zero_val_outs += 1 + + if output.is_change: + self.num_change_outputs += 1 + total_change += txo.nValue + + if validate_inp_pths: + # Enforce some policy on change outputs: + # - need to "look like" they are going to same wallet as inputs came from + # - range limit last two path components (numerically) + # - same pattern of hard/not hardened components + # - MAX_PATH_DEPTH already enforced before this point + # - (single-sig only) check ther is only 0,1 at change index + is_cmplx = (len(parsed_subpaths) > 1) + for i, xpath in enumerate(parsed_subpaths.values()): + if i not in output.sp_idxs: continue + p = xpath[2:] if output.taproot_subpaths else xpath[1:] + + iss = None + if len(p) != path_len: + iss = "has wrong path length (%d not %d)" % (len(p), path_len) + elif tuple(bool(i & 0x80000000) for i in p) not in hard_p: + iss = "has different hardening pattern" + elif tuple(p[:-2]) not in prefix_pths: + iss = "goes to diff path prefix" + elif not is_cmplx and ((p[-2] & 0x7fffffff) not in {0,1}): + iss = "2nd last component not 0 or 1" + elif (p[-1] & 0x7fffffff) > max_gap: + iss = "last component beyond reasonable gap" + + if iss: + msg = "Output#%d: %s: %s" % (idx, iss, keypath_to_str(p, skip=0)) + if len(hard_p) == 1 and len(prefix_pths) == 1: + # message can be more verbose + # fastest way to get first element from the set + # without modifying the set is for-loop + for hp in hard_p: + break + for pp in prefix_pths: + break + msg += " not %s/{0~1}%s/{0~%d}%s expected" % ( + keypath_to_str(pp, skip=0), + "'" if hp[-2] else "", + max_gap, + "'" if hp[-1] else "" + ) + self.warnings.append(('Troublesome Change Outs', msg)) + + if af == OP_RETURN: + num_op_return += 1 + if len(txo.scriptPubKey) > 83: + num_op_return_size += 1 + + elif af is None: + num_unknown_scripts += 1 + + if self.total_value_out is None: + self.total_value_out = total_out + else: + assert self.total_value_out == total_out, \ + '%s != %s' % (self.total_value_out, total_out) + + if self.total_change_value is None: + self.total_change_value = total_change + else: + assert self.total_change_value == total_change, \ + '%s != %s' % (self.total_change_value, total_change) + + # check fee is reasonable + the_fee = self.calculate_fee() + if the_fee is None: + return + if the_fee < 0: + raise FatalPSBTIssue("Outputs worth more than inputs!") + + if self.total_value_out: + per_fee = the_fee * 100 / self.total_value_out + else: + per_fee = 100 + + fee_limit = settings.get('fee_limit', DEFAULT_MAX_FEE_PERCENTAGE) + + if fee_limit != -1 and per_fee >= fee_limit: + raise FatalPSBTIssue("Network fee bigger than %d%% of total amount (it is %.0f%%)." + % (fee_limit, per_fee)) + if per_fee >= 5: + self.warnings.append(('Big Fee', 'Network fee is more than ' + '5%% of total value (%.1f%%).' % per_fee)) + + if (num_op_return > 1) or num_op_return_size: + mm = "" + if num_op_return > 1: + mm += "\nMultiple OP_RETURN outputs: %d" % num_op_return + if num_op_return_size: + mm += "\nOP_RETURN > 80 bytes" + self.warnings.append( + ("OP_RETURN", + "TX may not be relayed by some nodes.%s" % mm)) + + if num_unknown_scripts: + self.warnings.append( + ('Output?', + 'Sending to %d not well understood script(s).' % num_unknown_scripts) + ) + + if zero_val_outs: + self.warnings.append( + ('Zero Value', + 'Non-standard zero value output(s).') + ) + + self.consolidation_tx = (self.num_change_outputs == self.num_outputs) + dis.progress_bar_show(1) + + if DEBUG: + print("PSBT change outputs: %d out of %d" % ( + self.num_change_outputs, len(self.outputs) + )) + + def consider_inputs(self, cosign_xfp=None): + # Look at the UTXO's that we are spending. Do we have them? Do the + # hashes match, and what values are we getting? + # Important: parse incoming UTXO to build total input value + # check nSequences & nLockTime and warn about TX level locktimes + from glob import dis + + foreign = [] + total_in = 0 + presigned_inputs = set() # time based relative locks tb_rel_locks = [] # block height based relative locks bb_rel_locks = [] smallest_nsequence = 0xffffffff - # this parses the input TXN in-place - for idx, txin in self.input_iter(): - inp = self.inputs[idx] - if self.is_v2: - # v2 requires inclusion - assert inp.prevout_idx is not None - assert inp.previous_txid - if inp.req_time_locktime is not None: - assert inp.req_time_locktime >= 500000000 - if inp.req_height_locktime is not None: - assert 0 < inp.req_height_locktime < 500000000 - else: - # v0 requires exclusion - assert inp.prevout_idx is None - assert inp.previous_txid is None - assert inp.sequence is None - assert inp.req_time_locktime is None - assert inp.req_height_locktime is None - self.inputs[idx].validate(idx, txin, self.my_xfp, self) + # collect some input path data from subapths + # later used for change outputs path validation + length_p = set() + hard_pattern = set() + prefix_p = set() + idx_max = 0 + my_cnt = 0 + + dis.fullscreen("Validating...", line2="Inputs") + + for i, txi in self.input_iter(): + dis.progress_sofar(i, self.num_inputs) + inp = self.inputs[i] + + if inp.part_sigs: + # How complete is the set of signatures so far? + # - assuming PSBT creator doesn't give us extra data not required + # - seems harmless if they fool us into thinking already signed; we do nothing + # - could also look at pubkey needed vs. sig provided + # - could consider structure of MofN in p2sh cases + if len(inp.part_sigs) >= len(inp.subpaths): + inp.fully_signed = True + + if inp.taproot_key_sig: + inp.fully_signed = True + + if inp.utxo: + # Important: they might be trying to trick us with an un-related + # funding transaction (UTXO) that does not match the input signature we're making + # (but if it's segwit, the ploy wouldn't work, Segwit FtW) + # - challenge: it's a straight dsha256() for old serializations, but not for newer + # segwit txn's... plus I don't want to deserialize it here. + try: + observed = uint256_from_str(calc_txid(self.fd, inp.utxo)) + except: + raise AssertionError("Trouble parsing UTXO given for input #%d" % i) + + assert txi.prevout.hash == observed, "utxo hash mismatch for input #%d" % i + if self.txn_version >= 2: - has_rtl = self.inputs[idx].has_relative_timelock(txin) + has_rtl = inp.has_relative_timelock(txi) if has_rtl: if has_rtl[0]: - tb_rel_locks.append((idx, has_rtl[1])) + tb_rel_locks.append((i, has_rtl[1])) else: - bb_rel_locks.append((idx, has_rtl[1])) + bb_rel_locks.append((i, has_rtl[1])) - if txin.nSequence < smallest_nsequence: - smallest_nsequence = txin.nSequence + if txi.nSequence < smallest_nsequence: + smallest_nsequence = txi.nSequence + + parsed_subpaths = inp.parse_subpaths(self.my_xfp, self.warnings, cosign_xfp) + + if not inp.has_utxo(): + if inp.sp_idxs and not inp.fully_signed: + # we cannot proceed if the input is ours and there is no UTXO + raise FatalPSBTIssue('Missing own UTXO(s). Cannot determine value being signed') + + # input clearly not ours + foreign.append(i) + continue + + # pull out just the CTXOut object + # very expensive for non-witness utxo (whole tx) + # less expensive for witness UTXO (just necessary TxOut) + # + utxo = inp.get_utxo(txi.prevout.n) + inp.amount = utxo.nValue + assert inp.amount >= 0, "negative input value: i%d" % i + total_in += inp.amount + + inp.af, addr_or_pubkey = utxo.get_address() + # save scriptPubKey of utxo for later use + # needed for P2WPKH scriptCode calculation + # needed for P2PK & P2PKH scriptSig (when finalizing) + # needed for each input if we sign at least one P2TR input + inp.utxo_spk = utxo.scriptPubKey + + if inp.sp_idxs: + my_cnt += 1 + if inp.fully_signed: + presigned_inputs.add(i) + if inp.sp_idxs and (not inp.fully_signed): + # Look at what kind of input this will be, and therefore what + # type of signing will be required, and which key we need. + # - also validates redeem_script when present + # - also finds appropriate miniscript wallet to be used + inp.determine_my_signing_key(i, addr_or_pubkey, self.my_xfp, self, + parsed_subpaths, utxo) + + # determine_my_signing_key may have removed sp_idxs + # meaning we're not going to sign this input - other wallet in use + if not inp.sp_idxs: + continue + + # parsed subpaths are OrderedDict - matches sp_idxs + for ii, xpath in enumerate(parsed_subpaths.values()): + if ii not in inp.sp_idxs: continue + p = xpath[2:] if inp.taproot_subpaths else xpath[1:] + length_p.add(len(p)) # ignore xfp + hard_pattern.add(tuple(bool(i & 0x80000000) for i in p)) + prefix_p.add(tuple(p[:-2])) + + index = p[-1] & 0x7fffffff + if index > idx_max: + idx_max = index + + # iff to UTXO is segwit, then check it's value, and also + # capture that value, since it's supposed to be immutable + if inp.af and inp.is_segwit: + history.verify_amount(txi.prevout, inp.amount, i) + + if inp.af == AF_P2TR: + # based on this we know whether we can drop inp.utxo_xpk + # attribute after creating sighash + self.my_tr_in = True + + if not my_cnt: + raise FatalPSBTIssue('None of the keys involved in this transaction ' + 'belong to this Coldcard (need %s).' % xfp2str(self.my_xfp)) + + if not foreign: + # no foreign inputs, we can calculate the total input value + assert total_in > 0, "zero value txn" + self.total_value_in = total_in + else: + # 1+ inputs don't belong to us, we can't calculate the total input value + # OK for multi-party transactions (coinjoin etc.) + self.total_value_in = None + self.warnings.append( + ("Unable to calculate fee", "Some input(s) haven't provided UTXO(s): " + seq_to_str(foreign)) + ) + + if len(presigned_inputs) == self.num_inputs: + # Maybe wrong f cases? Maybe they want to add their + # own signature, even tho N of M is satisfied?! + raise FatalPSBTIssue('Transaction looks completely signed already?') + + # We should know pubkey required for each input now. + # - but we may not be the signer for those inputs, which is fine. + # - TODO: but what if not SIGHASH_ALL + no_keys = set( + n + for n,inp in enumerate(self.inputs) + if (not inp.sp_idxs) and (not inp.fully_signed) + ) + if len(no_keys) == self.num_inputs: + # nothing to sign for us + raise FatalPSBTIssue("Nothing to sign here") + + if no_keys: + # This is seen when you re-sign same signed file by accident (multisig) + # - case of len(no_keys)==num_inputs is handled by consider_inputs + self.warnings.append(('Limited Signing', + "We are not signing these inputs, because we either don't know the key," + " inputs belong to different wallet, or we have already signed: " + seq_to_str(no_keys))) + + if presigned_inputs: + # this isn't really even an issue for some complex usage cases + self.warnings.append(('Partly Signed Already', + 'Some input(s) provided were already completely signed by other parties: ' + + seq_to_str(presigned_inputs))) if isinstance(self.lock_time, int) and self.lock_time > 0: if smallest_nsequence == 0xffffffff: @@ -1729,7 +2031,7 @@ class psbtObject(psbtProxy): )) else: msg = "This tx can only be spent after " - if self.lock_time < 500000000: + if self.lock_time < NLOCK_IS_TIME: msg += "block height of %d" % self.lock_time else: try: @@ -1745,101 +2047,39 @@ class psbtObject(psbtProxy): # create UX for users about tx level relative timelocks (nSequence) self.ux_relative_timelocks(tb_rel_locks, bb_rel_locks) - assert len(self.inputs) == self.num_inputs, 'ni mismatch' - - # if multisig xpub details provided, they better be right and/or offer import - if self.xpubs: - await self.handle_xpubs() - - assert self.num_outputs >= 1, 'need outputs' + if MiniScriptWallet.disable_checks: + self.warnings.append(('Danger', 'Some miniscript checks are disabled.')) if DEBUG: - our_keys = sum(1 for i in self.inputs if i.num_our_keys) + print("PSBT inputs: %d inputs contain our key, %d fully-signed" % ( + my_cnt, len(presigned_inputs))) - print("PSBT: %d inputs, %d output, %d fully-signed, %d ours" % ( - self.num_inputs, self.num_outputs, - sum(1 for i in self.inputs if i and i.fully_signed), our_keys)) + dis.progress_bar_show(1) - def consider_outputs(self): - # scan ouputs: - # - is it a change address, defined by redeem script (p2sh) or key we know is ours - # - mark change outputs, so perhaps we don't show them to users - total_out = 0 - total_change = 0 - self.num_change_outputs = 0 - - for idx, txo in self.output_iter(): - output = self.outputs[idx] - # perform output validation - output.validate(idx, txo, self.my_xfp, self.active_multisig, self.active_miniscript, self) - total_out += txo.nValue - if output.is_change: - self.num_change_outputs += 1 - total_change += txo.nValue - - if self.total_value_out is None: - self.total_value_out = total_out - else: - assert self.total_value_out == total_out, \ - '%s != %s' % (self.total_value_out, total_out) - - if self.total_change_value is None: - self.total_change_value = total_change - else: - assert self.total_change_value == total_change, \ - '%s != %s' % (self.total_change_value, total_change) - - # check fee is reasonable - if self.total_value_out == 0: - per_fee = 100 - else: - the_fee = self.calculate_fee() - if the_fee is None: - return - if the_fee < 0: - raise FatalPSBTIssue("Outputs worth more than inputs!") - - per_fee = the_fee * 100 / self.total_value_out - - fee_limit = settings.get('fee_limit', DEFAULT_MAX_FEE_PERCENTAGE) - - if fee_limit != -1 and per_fee >= fee_limit: - raise FatalPSBTIssue("Network fee bigger than %d%% of total amount (it is %.0f%%)." - % (fee_limit, per_fee)) - if per_fee >= 5: - self.warnings.append(('Big Fee', 'Network fee is more than ' - '5%% of total value (%.1f%%).' % per_fee)) - - self.consolidation_tx = (self.num_change_outputs == self.num_outputs) - - # Enforce policy related to change outputs - self.consider_dangerous_change(self.my_xfp) + # useful info from all our parsed paths - will be validated against change outputs + return length_p, hard_pattern, prefix_p, idx_max def consider_dangerous_sighash(self): # Check sighash flags are legal, useful, and safe. Warn about # some risks if user has enabled special sighash values. - + # can only be run after consider_outputs is done sh_unusual = False none_sh = False + for inp in self.inputs: + if inp.sp_idxs and not inp.fully_signed: + if inp.sighash: + if inp.sighash is not None: + if inp.sighash not in (SIGHASH_ALL, SIGHASH_DEFAULT): + sh_unusual = True - for input in self.inputs: - # only if it is our input - one that will be eventually sign - if input.num_our_keys: - if input.sighash is not None: - # All inputs MUST have SIGHASH that we are able to sign. - if input.sighash not in ALL_SIGHASH_FLAGS: - raise FatalPSBTIssue("Unsupported sighash flag 0x%x" % input.sighash) - - if input.sighash not in (SIGHASH_ALL, SIGHASH_DEFAULT): - sh_unusual = True - - if input.sighash in (SIGHASH_NONE, SIGHASH_NONE|SIGHASH_ANYONECANPAY): - none_sh = True + if inp.sighash in (SIGHASH_NONE, SIGHASH_NONE | SIGHASH_ANYONECANPAY): + none_sh = True if sh_unusual and not settings.get("sighshchk"): if self.consolidation_tx: # policy: all inputs must be sighash ALL in purely consolidation txn - raise FatalPSBTIssue("Only sighash ALL is allowed for pure consolidation transactions.") + raise FatalPSBTIssue("Only sighash ALL/DEFAULT is allowed" + " for pure consolidation transactions.") if none_sh: # sighash NONE or NONE|ANYONECANPAY is proposed: block @@ -1854,221 +2094,12 @@ class psbtObject(psbtProxy): ("Caution", "Some inputs have unusual SIGHASH values not used in typical cases.") ) - def consider_dangerous_change(self, my_xfp): - # Enforce some policy on change outputs: - # - need to "look like" they are going to same wallet as inputs came from - # - range limit last two path components (numerically) - # - same pattern of hard/not hardened components - # - MAX_PATH_DEPTH already enforced before this point - # - in_paths = [] - for inp in self.inputs: - if inp.fully_signed: continue - if not inp.required_key: continue - if inp.subpaths: - for path in inp.subpaths.values(): - if path[0] == my_xfp: - in_paths.append(path[1:]) - if inp.taproot_subpaths: - for path in inp.taproot_subpaths.values(): - # xfp is on index 1, on index 0 -> leaf hashes - if path[1] == my_xfp: - in_paths.append(path[2:]) - - if not in_paths: - # We aren't adding any signatures? Can happen but we're going to be - # showing a warning about that elsewhere. - return - - shortest = min(len(i) for i in in_paths) - longest = max(len(i) for i in in_paths) - if shortest != longest or shortest <= 2: - # We aren't seeing shared input path lengths. - # They are probbably doing weird stuff, so leave them alone. - return - - # Assumption: hard/not hardened depths will match for all address in wallet - def hard_bits(p): - return [bool(i & 0x80000000) for i in p] - - # Assumption: common wallets modulate the last two components only - # of the path. Typically m/.../change/index where change is {0, 1} - # and index changes slowly over lifetime of wallet (increasing) - path_len = shortest - path_prefix = in_paths[0][0:-2] - idx_max = max(i[-1]&0x7fffffff for i in in_paths) + 200 - hard_pattern = hard_bits(in_paths[0]) - - def check_output_path(path): - if len(path) != path_len: - iss = "has wrong path length (%d not %d)" % (len(path), path_len) - elif hard_bits(path) != hard_pattern: - iss = "has different hardening pattern" - elif path[0:len(path_prefix)] != path_prefix: - iss = "goes to diff path prefix" - # elif (path[-2] & 0x7fffffff) not in {0, 1}: - # iss = "2nd last component not 0 or 1" - elif (path[-1] & 0x7fffffff) > idx_max: - iss = "last component beyond reasonable gap" - else: - # looks OK - iss = None - return iss - - def problem_fmt_str(nout, iss, path): - return "Output#%d: %s: %s not %s/{0~1}%s/{0~%d}%s expected" % ( - nout, - iss, - keypath_to_str(path, skip=0), - keypath_to_str(path_prefix, skip=0), - "'" if hard_pattern[-2] else "", - idx_max, - "'" if hard_pattern[-1] else "", - ) - - probs = [] - for nout, out in enumerate(self.outputs): - if not out.is_change: continue - # it's a change output, okay if a p2sh change; we're looking at paths - if out.subpaths: - for path in out.subpaths.values(): - if path[0] != my_xfp: - # possible in p2sh case - continue - path = path[1:] - iss = check_output_path(path) - if iss is None: - continue - probs.append(problem_fmt_str(nout, iss, path)) - break - if out.taproot_subpaths: - for path in out.taproot_subpaths.values(): - if path[1] != my_xfp: - continue - path = path[2:] - iss = check_output_path(path) - if iss is None: - continue - probs.append(problem_fmt_str(nout, iss, path)) - break - - for p in probs: - self.warnings.append(('Troublesome Change Outs', p)) - - def consider_inputs(self): - # Look at the UTXO's that we are spending. Do we have them? Do the - # hashes match, and what values are we getting? - # Important: parse incoming UTXO to build total input value - foreign = [] - total_in = 0 - - for i, txi in self.input_iter(): - inp = self.inputs[i] - if inp.fully_signed: - self.presigned_inputs.add(i) - - if not inp.has_utxo(): - if inp.num_our_keys and not inp.fully_signed: - # we cannot proceed if the input is ours and there is no UTXO - raise FatalPSBTIssue('Missing own UTXO(s). Cannot determine value being signed') - else: - # input clearly not ours - foreign.append(i) - continue - - # pull out just the CTXOut object (expensive) - utxo = inp.get_utxo(txi.prevout.n) - - assert utxo.nValue > 0 - total_in += utxo.nValue - - # Look at what kind of input this will be, and therefore what - # type of signing will be required, and which key we need. - # - also validates redeem_script when present - # - also finds appropriate multisig wallet to be used - inp.determine_my_signing_key(i, utxo, self.my_xfp, self) - - # iff to UTXO is segwit, then check it's value, and also - # capture that value, since it's supposed to be immutable - if inp.is_segwit: - history.verify_amount(txi.prevout, inp.amount, i) - - del utxo - - # XXX scan witness data provided, and consider those ins signed if not multisig? - - if not foreign: - # no foreign inputs, we can calculate the total input value - assert total_in > 0 - self.total_value_in = total_in - else: - # 1+ inputs don't belong to us, we can't calculate the total input value - # OK for multi-party transactions (coinjoin etc.) - self.total_value_in = None - self.warnings.append( - ("Unable to calculate fee", "Some input(s) haven't provided UTXO(s): " + seq_to_str(foreign)) - ) - - if len(self.presigned_inputs) == self.num_inputs: - # Maybe wrong for multisig cases? Maybe they want to add their - # own signature, even tho N of M is satisfied?! - raise FatalPSBTIssue('Transaction looks completely signed already?') - - # We should know pubkey required for each input now. - # - but we may not be the signer for those inputs, which is fine. - # - TODO: but what if not SIGHASH_ALL - no_keys = set(n for n,inp in enumerate(self.inputs) - if inp.required_key == None and not inp.fully_signed) - if no_keys: - # This is seen when you re-sign same signed file by accident (multisig) - # - case of len(no_keys)==num_inputs is handled by consider_keys - self.warnings.append(('Limited Signing', - 'We are not signing these inputs, because we do not know the key: ' + - seq_to_str(no_keys))) - - if self.presigned_inputs: - # this isn't really even an issue for some complex usage cases - self.warnings.append(('Partly Signed Already', - 'Some input(s) provided were already completely signed by other parties: ' + - seq_to_str(self.presigned_inputs))) - - if MultisigWallet.disable_checks: - self.warnings.append(('Danger', 'Some multisig checks are disabled.')) - def calculate_fee(self): # what miner's reward is included in txn? if self.total_value_in is None: return None return self.total_value_in - self.total_value_out - def consider_keys(self): - # check we possess the right keys for the inputs - cnt = sum(1 for i in self.inputs if i.num_our_keys) - if cnt: return - - # collect a list of XFP's given in file that aren't ours - others = set() - for inp in self.inputs: - if inp.subpaths: - for path in inp.subpaths.values(): - others.add(path[0]) - if inp.taproot_subpaths: - for path in inp.taproot_subpaths.values(): - # xfp is on index 1, on index 0 -> leaf hashes - others.add(path[1]) - - if not others: - # Can happen w/ Electrum in watch-mode on XPUB. It doesn't know XFP and - # so doesn't insert that into PSBT. - raise FatalPSBTIssue('PSBT does not contain any key path information.') - - others.discard(self.my_xfp) - msg = ', '.join(xfp2str(i) for i in others) - - raise FatalPSBTIssue('None of the keys involved in this transaction ' - 'belong to this Coldcard (need %s, found %s).' - % (xfp2str(self.my_xfp), msg)) - @classmethod def read_psbt(cls, fd): # read in a PSBT file. Captures fd and keeps it open. @@ -2128,12 +2159,12 @@ class psbtObject(psbtProxy): wr(PSBT_GLOBAL_VERSION, pack(' single key - which_key = inp.required_key + assert len(inp.sp_idxs) == 1 + sp_idx = inp.sp_idxs[0] - assert not inp.part_sig, "already done??" + assert not inp.added_sigs, "already done??" assert not inp.taproot_key_sig, "already done taproot??" - if inp.subpaths and inp.subpaths.get(which_key) and inp.subpaths[which_key][0] == self.my_xfp: - skp = keypath_to_str(inp.subpaths[which_key]) - # get node required - node = sv.derive_path(skp, register=False) - # expensive test, but works... and important - pu = node.pubkey() - elif inp.taproot_subpaths and inp.taproot_subpaths.get(which_key) \ - and inp.taproot_subpaths[which_key][1] == self.my_xfp: - - skp = keypath_to_str(inp.taproot_subpaths[which_key][1:]) # ignore leaf hashes - # get node required - node = sv.derive_path(skp, register=False) - # expensive test, but works... and important - pu = node.pubkey()[1:] + if inp.taproot_subpaths: schnorrsig = True + pubk = inp.taproot_subpaths[sp_idx][0] + sp = inp.taproot_subpaths[sp_idx][1][2] else: - # we don't have the key for this subkey - # (redundant, required_key wouldn't be set) - continue + pubk = inp.subpaths[sp_idx][0] + sp = inp.subpaths[sp_idx][1] - assert pu == which_key, \ + int_pth = self.handle_zero_xfp(self.parse_xfp_path(sp), self.my_xfp, None) + skp = keypath_to_str(int_pth) + # get node required + node = sv.derive_path(skp, register=False) + # expensive test, but works... and important + pu = node.pubkey() + if schnorrsig: + pu = pu[1:] + + assert pu == self.get(pubk), \ "Path (%s) led to wrong pubkey for input#%d"%(skp, in_idx) - to_sign.append(node) + to_sign.append((node, pubk)) # track wallet usage - subp = inp.taproot_subpaths[which_key] if schnorrsig else inp.subpaths[which_key] - OWNERSHIP.note_subpath_used(subp) + OWNERSHIP.note_subpath_used(int_pth) + + # normal operation with valid sighash + if not inp.is_segwit: + # Hash by serializing/blanking various subparts of the transaction + txi.scriptSig = inp.get_scriptSig() + digest = self.make_txn_sighash(in_idx, txi, inp.sighash) + else: + # Hash the inputs and such in totally new ways, based on BIP-143 + if not inp.taproot_subpaths: + digest = self.make_txn_segwit_sighash(in_idx, txi, inp.amount, + inp.segwit_v0_scriptCode(), + inp.sighash) + elif not tr_sh: + # taproot keyspend + digest = self.make_txn_taproot_sighash(in_idx, hash_type=inp.sighash) + # else: + # sighashes for tapscript spend are calculated later if sv.deltamode: # Current user is actually a thug with a slightly wrong PIN, so we # do have access to the private keys and could sign txn, but we # are going to silently corrupt our signatures. - digest = bytes(range(32)) - else: - if not inp.is_segwit: - # Hash by serializing/blanking various subparts of the transaction - digest = self.make_txn_sighash(in_idx, txi, inp.sighash) - else: - # Hash the inputs and such in totally new ways, based on BIP-143 - if not inp.taproot_subpaths: - digest = self.make_txn_segwit_sighash(in_idx, txi, inp.amount, inp.scriptCode, inp.sighash) - elif tr_sh: - pass # later() - else: - digest = self.make_txn_taproot_sighash(in_idx, hash_type=inp.sighash) + digest = ngu.hash.sha256d(digest) + + # we no longer need utxo_spk if: + # - none of the inputs that we're signing is P2TR + # - this input is not P2PK or P2PKH, otherwise we need utxo_spk for scriptSig + if not self.my_tr_in and (inp.af not in (AF_BARE_PK, AF_CLASSIC)): + try: + del inp.utxo_spk + except AttributeError: pass # may not have UTXO # The precious private key we need - if not inp.taproot_script_sigs: - inp.taproot_script_sigs = {} - - if not inp.part_sig: - inp.part_sig = {} - - for i, node in enumerate(to_sign): + for i, (node, pk_coord) in enumerate(to_sign): sk = node.privkey() - kp = ngu.secp256k1.keypair(sk) - pk = node.pubkey() - xonly_pk = kp.xonly_pubkey().to_bytes() - - # print("privkey %s" % b2a_hex(sk).decode('ascii')) - # print(" pubkey %s" % b2a_hex(pk).decode('ascii')) - # print(" digest %s" % b2a_hex(digest).decode('ascii')) - # Do the ACTUAL signature ... finally!!! if schnorrsig: + kp = ngu.secp256k1.keypair(sk) + xonly_pk = kp.xonly_pubkey().to_bytes() if tr_sh: # in tapscript keys are not tweaked, just sign with the key in the script + taproot_script_sigs = inp.get_taproot_script_sigs() + inp.tr_added_sigs = inp.tr_added_sigs or {} + for taproot_script, leaf_ver in tr_sh[i]: _key = (xonly_pk, tapleaf_hash(taproot_script, leaf_ver)) - if _key in inp.taproot_script_sigs: - continue + if _key in taproot_script_sigs: + continue # already done ? digest = self.make_txn_taproot_sighash(in_idx, hash_type=inp.sighash, scriptpath=True, script=taproot_script, leaf_ver=leaf_ver) + + if sv.deltamode: + digest = ngu.hash.sha256d(digest) + sig = ngu.secp256k1.sign_schnorr(sk, digest, ngu.random.bytes(32)) - if inp.sighash != SIGHASH_DEFAULT: - sig += bytes([inp.sighash]) # in the common case of SIGHASH_DEFAULT, encoded as '0x00', a space optimization MUST be made by # 'omitting' the sighash byte, resulting in a 64-byte signature with SIGHASH_DEFAULT assumed - inp.taproot_script_sigs[_key] = sig + if inp.sighash != SIGHASH_DEFAULT: + sig += bytes([inp.sighash]) + + # separate container for PSBT_IN_TAP_SCRIPT_SIG that we added + inp.tr_added_sigs[_key] = sig else: # BIP 341 states: "If the spending conditions do not require a script path, # the output key should commit to an unspendable script path instead of having no script path. # This can be achieved by computing the output key point as Q = P + int(hashTapTweak(bytes(P)))G." - internal_key = xonly_pk - tweak = internal_key - if inp.taproot_merkle_root is not None: + tweak = xonly_pk + if inp.taproot_merkle_root and inp.use_keypath: # we have a script path but internal key is spendable by us # merkle root needs to be added to tweak with internal key # merkle root was already verified against registered script in determine_my_signing_key tweak += self.get(inp.taproot_merkle_root) - tweak = ngu.secp256k1.tagged_sha256(b"TapTweak", tweak) + + tweak = ngu.hash.sha256t(TAP_TWEAK_H, tweak, True) kpt = kp.xonly_tweak_add(tweak) sig = ngu.secp256k1.sign_schnorr(kpt, digest, ngu.random.bytes(32)) if inp.sighash != SIGHASH_DEFAULT: sig += bytes([inp.sighash]) + # in the common case of SIGHASH_DEFAULT, encoded as '0x00', a space optimization MUST be made by # 'omitting' the sighash byte, resulting in a 64-byte signature with SIGHASH_DEFAULT assumed inp.taproot_key_sig = sig + + del kpt + + del kp else: - # We need to grind sometimes to get a positive R - # value that will encode (after DER) into a shorter string. - # - saves on miner's fee (which might be expected/required) - # - blends in with Bitcoin Core signatures which do this from 0.17.0 - - n = 0 # retry num - while True: - # time to produce signature on stm32: ~25.1ms - result = ngu.secp256k1.sign(sk, digest, n).to_bytes() - - if result[1] < 0x80: - # - no need to check for low S value as those are generated by default - # by secp256k1 lib - # - to produce 71 bytes long signature (both low S low R values), - # we need on average 2 retries - # - worst case ~25 grinding iterations need to be performed total - break - - n += 1 - - # DER serialization after we have low S and low R values in our signature - r = result[1:33] - s = result[33:65] - der_sig = ser_sig_der(r, s, inp.sighash) - inp.part_sig[pk] = der_sig - # memory cleanup - del result, r, s + der_sig = self.ecdsa_grind_sign(sk, digest, inp.sighash) + inp.added_sigs = inp.added_sigs or [] + inp.added_sigs.append((pk_coord, der_sig)) # private key no longer required stash.blank_object(sk) stash.blank_object(node) del sk, node - success.add(in_idx) - gc.collect() - if self.is_v2: self.set_modifiable_flag(inp) - # drop sighash if default (SIGHASH_ALL) - if inp.sighash == SIGHASH_ALL: + if drop_sighash: + # only drop after modifiable is set, in case of PSBTv2 + # SIGHASH_DEFAULT if taproot + # SIGHASH_ALL if non-taproot inp.sighash = None + del to_sign + gc.collect() + # done. dis.progress_bar_show(1) @@ -2530,7 +2604,7 @@ class psbtObject(psbtProxy): fd = self.fd old_pos = fd.tell() - out_type = SIGHASH_ALL if (hash_type == 0) else (hash_type & 3) + out_type = SIGHASH_ALL if (hash_type == SIGHASH_DEFAULT) else (hash_type & 3) in_type = hash_type & SIGHASH_ANYONECANPAY if not self.hashValues and in_type != SIGHASH_ANYONECANPAY: @@ -2543,10 +2617,8 @@ class psbtObject(psbtProxy): hashPrevouts.update(txi.prevout.serialize()) hashSequence.update(pack("= M: + return True + return False + def is_complete(self): # Are all the inputs (now) signed? - # some might have been given as signed - signed = len(self.presigned_inputs) - # plus we added some signatures - for inp in self.inputs: - if inp.is_multisig or (inp.is_miniscript and not inp.use_keypath): - # but we can't combine/finalize multisig/miniscript stuff, so will never't be 'final' + for i, inp in enumerate(self.inputs): + if inp.fully_signed: + # was fully signed before (fully signed works with part_sigs only) + continue + elif inp.taproot_key_sig: + continue + elif inp.is_miniscript and self.active_miniscript: + if self.miniscript_input_complete(inp): + continue return False - if inp.part_sig and len(inp.part_sig) == len(inp.subpaths): - signed += 1 - if inp.taproot_key_sig: - signed += 1 - return signed == self.num_inputs + ll = len(inp.added_sigs) if inp.added_sigs else 0 + ll += len(inp.part_sigs) if inp.part_sigs else 0 + if inp.subpaths and (len(inp.subpaths) == ll): + continue + + # input is not signed - and therefore tx is not complete + return False + + return True + + def multisig_signatures(self, inp): + assert self.active_miniscript + desc = self.active_miniscript.to_descriptor() + assert desc.is_basic_multisig + M, N = desc.miniscript.m_n() + + # collect all signatures and parse them if some just coords + full_sigs = {} + if inp.added_sigs: + # what we add is always in memory (not coordinates to PSRAM) + for pk_coord, sig in inp.added_sigs: + full_sigs[self.get(pk_coord)] = sig + + if inp.part_sigs: + # what others added is always just coordinates + for k, v in inp.part_sigs: + full_sigs[self.get(k)] = self.get(v) + # === + + if desc.is_sortedmulti: + # BIP-67 easy just sort by public keys + sigs = [sig for pk, sig in sorted(full_sigs.items())] + else: + # need to respect the order of keys in actual descriptor + sigs = [] + for key in desc.keys: + for k, v in inp.subpaths: + pk = self.get(k) + xfp = self.handle_zero_xfp(self.parse_xfp_path(v), self.my_xfp, None)[0] + # if xfp matches but pk not in all_sigs -> signer haven't signed + # it is ok in threshold multisig - just skip + if (key.origin.cc_fp == xfp) and (pk in full_sigs): + sigs.append(full_sigs[pk]) + break + + # save space and only provide necessary amount of signatures (smaller tx, less fees) + return sigs[:M] + + def singlesig_signature(self, inp): + # return signature that we added + # or one signature from partial sigs if input is fully sign + if inp.added_sigs: + assert len(inp.added_sigs) == 1 + return self.get(inp.added_sigs[0][0]), inp.added_sigs[0][1] + + if inp.part_sigs: + assert len(inp.part_sigs) == 1 + pk, sig = inp.part_sigs[0] + return self.get(pk), self.get(sig) + + def miniscript_xfps_needed(self): + # provide the set of xfp's that still need to sign PSBT + # - used to find which multisig-signer needs to go next + rv = set() + done_keys = set() + + for inp in self.inputs: + if inp.fully_signed: + continue + + if inp.taproot_subpaths: + if inp.taproot_key_sig: + # already signed + continue + + # only get this once for each input + if inp.taproot_script_sigs: + for xo, _ in inp.get_taproot_script_sigs(): + done_keys.add(xo) + + if inp.tr_added_sigs: + for (xo, _) in inp.tr_added_sigs: + done_keys.add(xo) + + for i, (k, v) in enumerate(inp.taproot_subpaths): + xpk = self.get(k) + if inp.ik_idx == i: + # internal key + if self.active_miniscript.ik_u: + # no way to sign with unspend + continue + else: + if xpk in done_keys: + continue + + # add xfp + xfp = self.handle_zero_xfp(self.parse_xfp_path(v[2]), self.my_xfp, None)[0] + rv.add(xfp) + + else: + if inp.part_sigs: + for k, _ in inp.part_sigs: + done_keys.add(self.get(k)) + + if inp.added_sigs: + for k, _ in inp.added_sigs: + done_keys.add(self.get(k)) + + for k, v in inp.subpaths: + if self.get(k) not in done_keys: + xfp = self.handle_zero_xfp(self.parse_xfp_path(v), self.my_xfp, None)[0] + rv.add(xfp) + + return rv def finalize(self, fd): # Stream out the finalized transaction, with signatures applied - # - assumption is it's complete already. + # - raise if not complete already # - returns the TXID of resulting transaction # - but in segwit case, needs to re-read to calculate it # - fd must be read/write and seekable to support txid calc @@ -2756,30 +2953,39 @@ class psbtObject(psbtProxy): for in_idx, txi in self.input_iter(): inp = self.inputs[in_idx] - if inp.is_segwit: - - if inp.is_p2sh: - # multisig (p2sh) segwit still requires the script here. - txi.scriptSig = ser_string(inp.scriptSig) + # first check - if no signature(s) - fail soon + if inp.is_miniscript and not inp.use_keypath: + assert self.miniscript_input_complete(inp), 'Incomplete signature set on input #%d' % in_idx + else: + # single signature + if inp.af == AF_P2TR: + assert inp.taproot_key_sig, 'No signature on input #%d' % in_idx else: - # major win for segwit (p2pkh): no redeem script bloat anymore - txi.scriptSig = b'' + ssig = self.singlesig_signature(inp) + assert ssig, 'No signature on input #%d' % in_idx + + if inp.is_segwit: + # p2sh-p2wsh & p2sh-p2wpkh still need redeem here (redeem is witness scriptPubKey) + txi.scriptSig = inp.get_scriptSig() + # for p2wpkh & p2wsh inp.scriptSig is b'' (no redeem script bloat anymore) - do not ser_string + if txi.scriptSig: + txi.scriptSig = ser_string(inp.get_scriptSig()) # Actual signature will be in witness data area - else: # insert the new signature(s), assuming fully signed txn. - assert inp.part_sig, 'No signature on input #%d' % in_idx - assert len(inp.part_sig) < 2, 'More signatures on input #%d' % in_idx - assert not inp.is_multisig, 'Multisig PSBT combine not supported' + if inp.is_miniscript: + # p2sh multisig (non-segwit) + sigs = self.multisig_signatures(inp) + ss = b"\x00" + for sig in sigs: + ss += ser_push_data(sig) - pubkey, der_sig = list(inp.part_sig.items())[0] - - s = b'' - s += ser_push_data(der_sig) - s += ser_push_data(pubkey) - - txi.scriptSig = s + ss += ser_push_data(self.get(inp.redeem_script)) + txi.scriptSig = ss + else: + pubkey, der_sig = ssig + txi.scriptSig = ser_push_data(der_sig) + ser_push_data(pubkey) fd.write(txi.serialize()) @@ -2800,20 +3006,23 @@ class psbtObject(psbtProxy): for in_idx, wit in self.input_witness_iter(): inp = self.inputs[in_idx] - if inp.is_segwit and (inp.part_sig or inp.taproot_key_sig): + if inp.is_segwit: # put in new sig: wit is a CTxInWitness assert not wit.scriptWitness.stack, 'replacing non-empty?' - assert not inp.is_multisig, 'Multisig PSBT combine not supported' - - # TODO tapscript can also be non multisig, we are not able to finalize that - yet if inp.taproot_key_sig: # segwit v1 (taproot) + w = inp.taproot_key_sig + if isinstance(w, tuple): + w = self.get(w) # can be 65 bytes if sighash != SIGHASH_DEFAULT (0x00) - assert len(inp.taproot_key_sig) in (64, 65) - wit.scriptWitness.stack = [inp.taproot_key_sig] + assert len(w) in (64, 65) + wit.scriptWitness.stack = [w] + elif inp.is_miniscript: + sigs = self.multisig_signatures(inp) + wit.scriptWitness.stack = [b""] + sigs + [self.get(inp.witness_script)] else: # segwit v0 - pubkey, der_sig = list(inp.part_sig.items())[0] + pubkey, der_sig = self.singlesig_signature(inp) assert pubkey[0] in {0x02, 0x03} and len(pubkey) == 33, "bad v0 pubkey" wit.scriptWitness.stack = [der_sig, pubkey] diff --git a/shared/qrs.py b/shared/qrs.py index 277da035..6afd5e2b 100644 --- a/shared/qrs.py +++ b/shared/qrs.py @@ -3,11 +3,11 @@ # qrs.py - QR Display related UX # import framebuf, uqr -from ux import UserInteraction, ux_wait_keyup, the_ux -from charcodes import (KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN, KEY_HOME, KEY_NFC, - KEY_END, KEY_PAGE_UP, KEY_PAGE_DOWN, KEY_ENTER, KEY_CANCEL) +from ux import UserInteraction, ux_wait_keyup, the_ux from version import has_qwerty - +from exceptions import QRTooBigError +from charcodes import (KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN, KEY_HOME, KEY_NFC, + KEY_END, KEY_ENTER, KEY_CANCEL) # TODO: This class has a terrible API! @@ -17,7 +17,9 @@ MAX_V11_CHAR_LIMIT = const(321) class QRDisplaySingle(UserInteraction): # Show a single QR code for (typically) a list of addresses, or a single value. - def __init__(self, addrs, is_alnum, start_n=0, sidebar=None, msg=None, is_addrs=False): + def __init__(self, addrs, is_alnum, start_n=0, sidebar=None, msg=None, + is_addrs=False, force_msg=False, allow_nfc=True, is_secret=False, + change_idxs=None, can_raise=True): self.is_alnum = is_alnum self.idx = 0 # start with first address self.invert = False # looks better, but neither mode is ideal @@ -27,6 +29,12 @@ class QRDisplaySingle(UserInteraction): self.is_addrs = is_addrs self.msg = msg self.qr_data = None + self.force_msg = force_msg + self.allow_nfc = allow_nfc + # only used for NFC sharing secret material - full chip wipe if is_secret=True + self.is_secret = is_secret + self.change_idxs = change_idxs or [] + self.can_raise = can_raise def calc_qr(self, msg): # Version 2 would be nice, but can't hold what we need, even at min error correction, @@ -57,6 +65,11 @@ class QRDisplaySingle(UserInteraction): # numbers, letters, etc. return str(self.start_n + self.idx) if len(self.addrs) > 1 else None + def is_change(self): + if self.idx in self.change_idxs: + return True + return False + def redraw(self): # Redraw screen. from glob import dis @@ -64,6 +77,15 @@ class QRDisplaySingle(UserInteraction): # what we are showing inside the QR body = self.addrs[self.idx] + idx_hint = self.idx_hint() + + msg = None + if self.msg: + msg = self.msg + else: + if isinstance(body, str): + # sanity check + msg = body # make the QR, if needed. if not self.qr_data: @@ -72,12 +94,19 @@ class QRDisplaySingle(UserInteraction): self.calc_qr(body) except Exception: dis.busy_bar(False) - raise + if not self.can_raise: + dis.draw_qr_error(idx_hint, msg) + return + + # other code paths require raise to switch to BBQr + raise QRTooBigError # draw display dis.busy_bar(False) - dis.draw_qr_display(self.qr_data, self.msg or body, self.is_alnum, - self.sidebar, self.idx_hint(), self.invert, is_addr=self.is_addrs) + dis.draw_qr_display(self.qr_data, msg, self.is_alnum, + self.sidebar, idx_hint, self.invert, + is_addr=self.is_addrs, force_msg=self.force_msg, + is_change=self.is_change()) async def interact_bare(self): from glob import NFC, dis @@ -92,13 +121,15 @@ class QRDisplaySingle(UserInteraction): self.redraw() continue elif NFC and (ch == '3' or ch == KEY_NFC): - # Share any QR over NFC! - await NFC.share_text(self.addrs[self.idx]) - self.redraw() + if not self.allow_nfc: + # not a valid as text over NFC sometimes; treat as cancel + break + else: + # Share any QR over NFC! + await NFC.share_text(self.addrs[self.idx], is_secret=self.is_secret) + self.redraw() continue elif ch in 'xy'+KEY_ENTER+KEY_CANCEL: - if dis.has_lcd: - dis.real_clear() # bugfix break elif len(self.addrs) == 1: continue @@ -120,6 +151,10 @@ class QRDisplaySingle(UserInteraction): self.qr_data = None self.redraw() + # bugfix + if dis.has_lcd: + dis.real_clear() + async def interact(self): await self.interact_bare() the_ux.pop() diff --git a/shared/queues.py b/shared/queues.py index bea6301a..f27223fb 100644 --- a/shared/queues.py +++ b/shared/queues.py @@ -72,7 +72,7 @@ class Queue: return len(self._queue) def empty(self): # Return True if the queue is empty, False otherwise. - return len(self._queue) == 0 + return not self._queue def full(self): # Return True if there are maxsize items in the queue. # Note: if the Queue was initialized with maxsize=0 (the default) or diff --git a/shared/scanner.py b/shared/scanner.py index 02dd939c..4dd91c79 100644 --- a/shared/scanner.py +++ b/shared/scanner.py @@ -201,7 +201,7 @@ class QRScanner: if not rv: continue if rv[0:2] == 'B$' and bbqr.collect(rv): - # BBQr protocol detected; collect more data + # BBQr protocol detected, accepted need to collect more data continue break diff --git a/shared/seed.py b/shared/seed.py index 2d95ea35..b2a47a01 100644 --- a/shared/seed.py +++ b/shared/seed.py @@ -10,30 +10,46 @@ # - 'abandon' * 17 + 'agent' # - 'abandon' * 11 + 'about' # -import ngu, uctypes, bip39, random, stash, version +import ngu, uctypes, bip39, random, version, ure, chains from ucollections import OrderedDict from menu import MenuItem, MenuSystem -from utils import xfp2str, parse_extended_key, swab32, pad_raw_secret, problem_file_line +from utils import xfp2str, swab32 +from utils import deserialize_secret, problem_file_line, wipe_if_deltamode from uhashlib import sha256 from ux import ux_show_story, the_ux, ux_dramatic_pause, ux_confirm, OK, X -from ux import PressRelease, ux_input_numbers, ux_input_text, show_qr_code +from ux import PressRelease, ux_input_text, show_qr_code from actions import goto_top_menu -from stash import SecretStash, ZeroSecretException +from stash import SecretStash, SensitiveValues from ubinascii import hexlify as b2a_hex from pwsave import PassphraseSaver, PassphraseSaverMenu from glob import settings, dis from pincodes import pa from nvstore import SettingsObject -from files import CardMissingError, needs_microsd, CardSlot -from charcodes import KEY_QR, KEY_ENTER, KEY_CANCEL, KEY_CLEAR - +from files import CardMissingError, needs_microsd +from charcodes import KEY_QR, KEY_ENTER, KEY_CANCEL, KEY_NFC +from uasyncio import sleep_ms +from ucollections import namedtuple # seed words lengths we support: 24=>256 bits, and recommended VALID_LENGTHS = (24, 18, 12) # bit flag that means "also include bare prefix as a valid word" _PREFIX_MARKER = const(1<<26) - + +# what we store (in JSON as a tuple) for each seed vault key. +# - 'encoded' is hex, and has is trimmed of right side zeros +VaultEntry = namedtuple('VaultEntry', 'xfp encoded label origin') + +def not_hobbled_mode(): + # used as menu predicate and similar + return not pa.hobbled_mode + +def seed_vault_iter(): + # iterate over all seeds in the vault; returns VaultEntry instances. + # raw vault entries are list type when json.loaded from flash + for lst in settings.master_get("seeds", []): + yield VaultEntry(*lst) + def letter_choices(sofar='', depth=0, thres=5): # make a list of word completions based on indicated prefix if not sofar: @@ -138,23 +154,62 @@ class WordNestMenu(MenuSystem): done_cb = None def __init__(self, num_words=None, has_checksum=True, done_cb=commit_new_words, - items=None, is_commit=False): + items=None, is_commit=False, menu_cbf=None, prefix="", words=None): if num_words is not None: WordNestMenu.target_words = num_words WordNestMenu.has_checksum = has_checksum WordNestMenu.words = [] - assert done_cb WordNestMenu.done_cb = done_cb is_commit = True + if words: + WordNestMenu.words = words + if not items: - items = [MenuItem(i, menu=self.next_menu) for i in letter_choices()] + ch = letter_choices(prefix) + if menu_cbf: + items = [MenuItem(i, f=menu_cbf) for i in ch] + else: + items = [MenuItem(i, menu=self.next_menu) for i in ch] self.is_commit = is_commit super(WordNestMenu, self).__init__(items) + @classmethod + async def get_n_words(cls, num_words): + rv = [] + for _ in range(num_words): + rv = await cls.get_word(rv, num_words) + + return rv + + @classmethod + async def get_word(cls, words=None, target_words=None): + # Just block until N words are provided. May only work before menus start? + from glob import numpad + + async def menu_done_cbf(menu, b, c): + # duplicates some of the logic of next_menu + if c.label[-1] == '-': + lc = c.label[0:-1] + else: + cls.words.append(c.label) + numpad.abort_ux() + return + + m = cls(prefix=lc, menu_cbf=menu_done_cbf) + the_ux.push(m) + await the_ux.interact() + + m = cls(num_words=target_words, menu_cbf=menu_done_cbf, has_checksum=False, words=words) + + the_ux.push(m) + await the_ux.interact() + + return cls.words + @staticmethod async def next_menu(self, idx, choice): @@ -215,7 +270,7 @@ class WordNestMenu(MenuSystem): while isinstance(the_ux.top_of_stack(), cls): the_ux.pop() - def on_cancel(self): + async def on_cancel(self): # user pressed cancel on a menu (so he's going upwards) # - if it's a step where we added to the word list, undo that. # - but keep them in our system until: @@ -273,9 +328,16 @@ individual words if you wish.''') async def show_words(words, prompt=None, escape=None, extra='', ephemeral=False): - msg = (prompt or 'Record these %d secret words!\n') % len(words) - from ux import ux_render_words + from glob import NFC + + if prompt: + title = None + msg = prompt + else: + m = 'Record these %d secret words!' % len(words) + title, msg = (m, "") if version.has_qwerty else (None, m+"\n") + msg += ux_render_words(words) msg += '\n\nPlease check and double check your notes.' @@ -283,22 +345,30 @@ async def show_words(words, prompt=None, escape=None, extra='', ephemeral=False) # user can skip quiz for ephemeral secrets msg += " There will be a test!" + escape = (escape or '') + '1' if not version.has_qwerty: - escape = (escape or '') + '1' - extra += 'Press (1) to view as QR Code. ' - else: - escape = (escape or '') + KEY_QR - extra += 'Press '+ KEY_QR + ' to view as QR Code. ' + title = None + extra += 'Press (1) to view as QR Code' + if NFC: + extra += ", (3) to share via NFC" + escape += "3" + extra += "." if extra: msg += '\n\n' msg += extra while 1: - ch = await ux_show_story(msg, escape=escape, sensitive=True) - if ch == '1' or ch == KEY_QR: - await show_qr_code(' '.join(w[0:4] for w in words), True) + rv = ' '.join(w[0:4] for w in words) + ch = await ux_show_story(msg, title=title, escape=escape, sensitive=True, + hint_icons=KEY_QR+(KEY_NFC if NFC else '')) + if ch in ('1'+KEY_QR): + await show_qr_code(rv, True, is_secret=True) continue + if NFC and (ch in "3"+KEY_NFC): + await NFC.share_text(rv, is_secret=True) + continue + break return ch @@ -411,15 +481,17 @@ async def new_from_dice(nwords): await commit_new_words(words) def in_seed_vault(encoded): - # Test if indicated xfp (or currently active XFP) is in the seed vault already. - seeds = settings.master_get("seeds", []) - if seeds: - ss = stash.SecretStash.storage_serialize(encoded) - if ss in [s[1] for s in seeds]: + # Test if indicated secret is in the seed vault already. + hss = None + for rec in seed_vault_iter(): + if not hss: + hss = SecretStash.storage_serialize(encoded) + if hss == rec.encoded: return True + return False -async def add_seed_to_vault(encoded, meta=None): +async def add_seed_to_vault(encoded, origin=None, label=None): if not settings.master_get("seedvault", False): # seed vault disabled @@ -434,6 +506,10 @@ async def add_seed_to_vault(encoded, meta=None): if in_seed_vault(encoded): return + # stay "read only" in hobbled mode + if pa.hobbled_mode: + return + main_xfp = settings.master_get("xfp", 0) # parse encoded @@ -459,10 +535,9 @@ async def add_seed_to_vault(encoded, meta=None): return # Save it into master settings - seeds.append((new_xfp_str, - stash.SecretStash.storage_serialize(encoded), - xfp_ui, - meta)) + rec = VaultEntry(xfp=new_xfp_str, encoded=SecretStash.storage_serialize(encoded), + label=(label or xfp_ui), origin=origin) + seeds.append(list(rec)) settings.master_set("seeds", seeds) @@ -471,9 +546,10 @@ async def add_seed_to_vault(encoded, meta=None): return True async def set_ephemeral_seed(encoded, chain=None, summarize_ux=True, bip39pw='', - is_restore=False, meta=None): - if not is_restore: - await add_seed_to_vault(encoded, meta=meta) + is_restore=False, origin=None, label=None): + # Capture tmp seed into vault, if so enabled, and regardless apply it as new tmp. + if not is_restore and not_hobbled_mode(): + await add_seed_to_vault(encoded, origin=origin, label=label) dis.fullscreen("Wait...") applied, err_msg = pa.tmp_secret(encoded, chain=chain, bip39pw=bip39pw) @@ -490,11 +566,11 @@ async def set_ephemeral_seed(encoded, chain=None, summarize_ux=True, bip39pw='', return applied -async def set_ephemeral_seed_words(words, meta): +async def set_ephemeral_seed_words(words, origin): dis.progress_bar_show(0.1) encoded = seed_words_to_encoded_secret(words) dis.progress_bar_show(0.5) - await set_ephemeral_seed(encoded, meta=meta) + await set_ephemeral_seed(encoded, origin=origin) goto_top_menu() async def ephemeral_seed_generate_from_dice(nwords): @@ -511,7 +587,7 @@ async def ephemeral_seed_generate_from_dice(nwords): words = await approve_word_list(seed, nwords, ephemeral=True) if words: dis.fullscreen("Applying...") - await set_ephemeral_seed_words(words, meta='Dice') + await set_ephemeral_seed_words(words, origin='Dice') def generate_seed(): # Generate 32 bytes of best-quality high entropy TRNG bytes. @@ -534,7 +610,7 @@ async def make_new_wallet(nwords): async def ephemeral_seed_import(nwords): async def import_done_cb(words): dis.fullscreen("Applying...") - await set_ephemeral_seed_words(words, meta='Imported') + await set_ephemeral_seed_words(words, origin='Imported') if version.has_qwerty: from ux_q1 import seed_word_entry @@ -548,17 +624,17 @@ async def ephemeral_seed_generate(nwords): words = await approve_word_list(seed, nwords, ephemeral=True) if words: dis.fullscreen("Applying...") - await set_ephemeral_seed_words(words, meta="TRNG Words") + await set_ephemeral_seed_words(words, origin="TRNG Words") async def set_seed_extended_key(extended_key): encoded, chain = xprv_to_encoded_secret(extended_key) set_seed_value(encoded=encoded, chain=chain) goto_top_menu(first_time=True) -async def set_ephemeral_seed_extended_key(extended_key, meta=None): +async def set_ephemeral_seed_extended_key(extended_key, origin=None): encoded, chain = xprv_to_encoded_secret(extended_key) dis.fullscreen("Applying...") - await set_ephemeral_seed(encoded=encoded, chain=chain, meta=meta) + await set_ephemeral_seed(encoded=encoded, chain=chain, origin=origin) goto_top_menu() async def approve_word_list(seed, nwords, ephemeral=False): @@ -627,17 +703,25 @@ def seed_words_to_encoded_secret(words): return nv def xprv_to_encoded_secret(xprv): - node, chain, _ = parse_extended_key(xprv, private=True) - if node is None: - raise ValueError("Failed to parse extended private key.") + # read an xprv/tprv/etc and return BIP-32 node and what chain it's on. + # - can handle any garbage line + # - returns (node, chain) + # - people are using SLIP132 so we need this + ln = xprv.strip() + pat = ure.compile('.prv[A-Za-z0-9]+') + found = pat.search(ln) + assert found, "not extended privkey" + # serialize, and note version code + node, chain, addr_fmt, is_private = chains.slip132_deserialize(found.group(0)) + assert node, "wrong extended privkey" nv = SecretStash.encode(xprv=node) node.blank() return nv, chain # need to know chain def set_seed_value(words=None, encoded=None, chain=None): - # Save the seed words (or other encoded private key) into secure element, - # and reboot. BIP-39 passphrase is not set at this point (empty string). + # Save the seed words (or other encoded private key) into secure element. + # BIP-39 passphrase is not set at this point (empty string). if words: nv = seed_words_to_encoded_secret(words) else: @@ -662,13 +746,12 @@ def set_seed_value(words=None, encoded=None, chain=None): async def calc_bip39_passphrase(pw, bypass_tmp=False): from glob import dis, settings - from pincodes import pa dis.fullscreen("Working...") current_xfp = settings.get("xfp", 0) - with stash.SensitiveValues(bip39pw=pw, bypass_tmp=bypass_tmp) as sv: + with SensitiveValues(bip39pw=pw, bypass_tmp=bypass_tmp) as sv: # can't do it without original seed words (late, but caller has checked) assert sv.mode == 'words', sv.mode nv = SecretStash.encode(xprv=sv.node) @@ -679,7 +762,7 @@ async def calc_bip39_passphrase(pw, bypass_tmp=False): async def set_bip39_passphrase(pw, bypass_tmp=False, summarize_ux=True): nv, xfp, parent_xfp = await calc_bip39_passphrase(pw, bypass_tmp=bypass_tmp) ret = await set_ephemeral_seed(nv, summarize_ux=summarize_ux, bip39pw=pw, - meta="BIP-39 Passphrase on [%s]" % xfp2str(parent_xfp)) + origin="BIP-39 Passphrase on [%s]" % xfp2str(parent_xfp)) dis.draw_status(bip39=int(bool(pw)), xfp=xfp, tmp=1) return ret @@ -709,7 +792,7 @@ async def remember_ephemeral_seed(): # address cache, settings from tmp seeds / seedvault seeds # rebuild fs as we want to save current tmp settings immediately from files import wipe_flash_filesystem - wipe_flash_filesystem(True) + wipe_flash_filesystem() dis.draw_status(bip39=0, tmp=0) dis.fullscreen('Saving...') @@ -820,7 +903,7 @@ class SeedVaultMenu(MenuSystem): from glob import dis dis.fullscreen("Applying...") - xfp, encoded = item.arg + encoded = item.arg # 72 bytes binary await set_ephemeral_seed(encoded, is_restore=True) @@ -832,15 +915,15 @@ class SeedVaultMenu(MenuSystem): esc = "" tmp_val = False - idx, xfp_str, encoded = item.arg + idx, rec, encoded = item.arg current_active = (pa.tmp_value == bytes(encoded)) - msg = "Remove seed from seed vault " + msg = "Remove seed from seed vault" if pa.tmp_value and current_active: tmp_val = True msg += "?\n\n" else: - msg += ("and delete its settings?\n\n" + msg += (" and delete its settings?\n\n" "Press %s to continue, press (1) to " "only remove from seed vault and keep " "encrypted settings for later use.\n\n") % OK @@ -848,9 +931,11 @@ class SeedVaultMenu(MenuSystem): msg += "WARNING: Funds will be lost if wallet is not backed-up elsewhere." - ch = await ux_show_story(title="[" + xfp_str + "]", msg=msg, escape=esc) + ch = await ux_show_story(title="[" + rec.xfp + "]", msg=msg, escape=esc) if ch == "x": return + assert not_hobbled_mode() + dis.fullscreen("Saving...") wipe_slot = not current_active and (ch != "1") @@ -862,6 +947,7 @@ class SeedVaultMenu(MenuSystem): xs.blank() del xs + # CAUTION: will get shadow copy if in tmp seed mode already seeds = settings.master_get("seeds", []) try: @@ -882,13 +968,13 @@ class SeedVaultMenu(MenuSystem): @staticmethod async def _detail(menu, label, item): - xfp_str, encoded, name, meta = item.arg + rec, encoded = item.arg - # - first byte represents type of secret (internal encoding flag) + # - first byte represents type of secret (internal encoding flags) txt = SecretStash.summary(encoded[0]) - detail = "Name:\n%s\n\nMaster XFP:\n%s\n\nOrigin:\n%s\n\nSecret Type:\n%s" \ - % (name, xfp_str, meta, txt) + detail = "Name:\n%s\n\nMaster XFP: %s\nSecret Type: %s\n\nOrigin:\n%s\n\n" \ + % (rec.label, rec.xfp, txt, rec.origin) await ux_show_story(detail) @@ -898,30 +984,30 @@ class SeedVaultMenu(MenuSystem): from glob import dis from ux import ux_input_text - idx, xfp_str = item.arg + assert not_hobbled_mode() - seeds = settings.master_get("seeds", []) - chk_xfp, encoded, old_name, meta = seeds[idx] - assert chk_xfp == xfp_str + idx, old = item.arg + new_label = await ux_input_text(old.label, confirm_exit=False, max_len=40) - new_name = await ux_input_text(old_name, confirm_exit=False, max_len=40) - - if not new_name: + if not new_label: return dis.fullscreen("Saving...") + seeds = settings.master_get("seeds", []) # save it - seeds[idx] = (chk_xfp, encoded, new_name, meta) - + seeds[idx] = (old.xfp, old.encoded, new_label, old.origin) # need to load and work on master secrets, will be slow if on tmp seed settings.master_set("seeds", seeds) # update label in sub-menu - menu.items[0].label = new_name - menu.items[0].arg = menu.items[0].arg[0:2] + (new_name,) + menu.items[0].arg[3:] + menu.items[0].label = new_label + # take old arg, in rename we cannot change encoded value, so it can be used without + # the need to deserialize it again + _, encoded = menu.items[0].arg + menu.items[0].arg = VaultEntry(*seeds[idx]), encoded - # .. and name in parent menu too + # and name in parent menu too parent = the_ux.parent_of(menu) if parent: parent.update_contents() @@ -930,6 +1016,8 @@ class SeedVaultMenu(MenuSystem): async def _add_current_tmp(*a): from pincodes import pa + assert not_hobbled_mode() + assert pa.tmp_value main_xfp = settings.master_get("xfp", 0) @@ -949,10 +1037,9 @@ class SeedVaultMenu(MenuSystem): seeds = settings.master_get("seeds", []) # Save it into master settings - seeds.append((new_xfp_str, - stash.SecretStash.storage_serialize(pa.tmp_value), - xfp_ui, - "unknown origin")) + seeds.append(list(VaultEntry(new_xfp_str, + SecretStash.storage_serialize(pa.tmp_value), + xfp_ui, "unknown origin"))) settings.master_set("seeds", seeds) @@ -966,34 +1053,36 @@ class SeedVaultMenu(MenuSystem): # Dynamic menu with user-defined names of seeds shown from pincodes import pa - if pa.is_deltamode(): - # attacker has re-enabled SeedVault in Settings - import callgate - callgate.fast_wipe() - - rv = [] add_current_tmp = MenuItem("Add current tmp", f=cls._add_current_tmp) - seeds = settings.master_get("seeds", []) + seeds = list(seed_vault_iter()) if not seeds: rv.append(MenuItem('(none saved yet)')) - if pa.tmp_value: - rv.append(add_current_tmp) - rv.append(MenuItem("Temporary Seed", menu=make_ephemeral_seed_menu)) + if not_hobbled_mode(): + if pa.tmp_value: + rv.append(add_current_tmp) + rv.append(MenuItem("Temporary Seed", menu=make_ephemeral_seed_menu)) else: + wipe_if_deltamode() + tmp_in_sv = False - for i, (xfp_str, encoded, name, meta) in enumerate(seeds): + for i, rec in enumerate(seeds): is_active = False - encoded = pad_raw_secret(encoded) + + # de-serialize encoded secret + encoded = deserialize_secret(rec.encoded) if encoded == pa.tmp_value: is_active = tmp_in_sv = True + submenu = [ - MenuItem(name, f=cls._detail, arg=(xfp_str, encoded, name, meta)), - MenuItem('Use This Seed', f=cls._set, arg=(xfp_str, encoded)), - MenuItem('Rename', f=cls._rename, arg=(i, xfp_str)), - MenuItem('Delete', f=cls._remove, arg=(i, xfp_str, encoded)), + MenuItem(rec.label, f=cls._detail, arg=(rec, encoded)), + MenuItem('Use This Seed', f=cls._set, arg=encoded), + MenuItem('Rename', f=cls._rename, arg=(i, rec), + predicate=not_hobbled_mode), + MenuItem('Delete', f=cls._remove, arg=(i, rec, encoded), + predicate=not_hobbled_mode), ] if is_active: submenu[1] = MenuItem("Seed In Use") @@ -1004,14 +1093,14 @@ class SeedVaultMenu(MenuSystem): # DO NOT offer any modification api (rename/delete) submenu = submenu[:2] - item = MenuItem('%2d: %s' % (i+1, name), menu=MenuSystem(submenu)) + item = MenuItem('%2d: %s' % (i+1, rec.label), menu=MenuSystem(submenu)) if is_active: item.is_chosen = lambda: True rv.append(item) if pa.tmp_value: - if seeds and (not tmp_in_sv): + if seeds and (not tmp_in_sv) and not_hobbled_mode(): # give em chance to store current active rv.append(add_current_tmp) @@ -1026,6 +1115,44 @@ class SeedVaultMenu(MenuSystem): tmp = self.construct() self.replace_items(tmp) +class SeedVaultChooserMenu(MenuSystem): + def __init__(self, words_only=False): + self.result = None + + items = [] + for i, rec in enumerate(seed_vault_iter()): + if words_only and not SecretStash.is_words(deserialize_secret(rec.encoded)): + continue + + item = MenuItem('%2d: %s' % (i+1, rec.label), arg=rec, f=self.picked) + items.append(item) + + if not items: + items.append(MenuItem("(none suitable)")) + + super().__init__(items) + + async def picked(self, menu, idx, mi): + assert menu == self + + # show as "checked", for a touch + menu.chosen = idx + menu.show() + await sleep_ms(100) + + self.result = mi.arg + the_ux.pop() # causes interact to stop + + @classmethod + async def pick(cls, **kws): + # nice simple blocking menu present and pick + m = cls(**kws) + + the_ux.push(m) + await m.interact() + + return m.result + class EphemeralSeedMenu(MenuSystem): @staticmethod @@ -1044,8 +1171,9 @@ class EphemeralSeedMenu(MenuSystem): def construct(cls): from glob import NFC from actions import nfc_recv_ephemeral, import_xprv - from actions import restore_temporary, scan_any_qr + from actions import restore_backup, scan_any_qr from tapsigner import import_tapsigner_backup_file + from xor_seed import xor_restore_start from charcodes import KEY_QR import_ephemeral_menu = [ @@ -1062,32 +1190,31 @@ class EphemeralSeedMenu(MenuSystem): ] rv = [ - MenuItem("Generate Words", menu=gen_ephemeral_menu), + MenuItem("Generate Words", menu=gen_ephemeral_menu, predicate=not_hobbled_mode), MenuItem('Import from QR Scan', predicate=version.has_qr, shortcut=KEY_QR, f=scan_any_qr, arg=(True, True)), MenuItem("Import Words", menu=import_ephemeral_menu), MenuItem("Import XPRV", f=import_xprv, arg=True), # ephemeral=True MenuItem("Tapsigner Backup", f=import_tapsigner_backup_file, arg=True), # ephemeral=True - MenuItem("Coldcard Backup", f=restore_temporary), + MenuItem("Coldcard Backup", f=restore_backup, arg=True), # tmp=True + MenuItem("Restore Seed XOR", f=xor_restore_start), ] return rv async def make_ephemeral_seed_menu(*a): + if (not pa.tmp_value) and (not settings.master_get("seedvault", False)): # force a warning on them, unless they are already doing it. - ch = await ux_show_story( + if not await ux_confirm( "Temporary seed is a secret completely separate " "from the master seed, typically held in device RAM and " "not persisted between reboots in the Secure Element. " - "Enable the Seed Vault feature to store these secrets longer-term." - "\n\nPress (4) to prove you read to the end" - " of this message and accept all consequences.", + "Enable the Seed Vault feature to store these secrets longer-term.", title="WARNING", - escape="4" - ) - if ch != "4": + confirm_key="4" + ): return rv = EphemeralSeedMenu.construct() @@ -1193,7 +1320,7 @@ class PassphraseMenu(MenuSystem): return PassphraseSaverMenu(items) - def on_cancel(self): + async def on_cancel(self): if not version.has_qwerty: # zip to cancel item when they fail to exit via X button self.goto_idx(self.count - 1) @@ -1208,7 +1335,9 @@ class PassphraseMenu(MenuSystem): @classmethod async def add_numbers(cls, *a): # Mk4 only: add some digits (quick, easy) - pw = await ux_input_numbers(cls.pp_sofar) + from ux_mk4 import ux_input_digits + + pw = await ux_input_digits(cls.pp_sofar) if pw is not None: cls.pp_sofar = pw cls.check_length() @@ -1287,7 +1416,7 @@ async def apply_pass_value(new_pp): return await set_ephemeral_seed(nv, summarize_ux=False, bip39pw=new_pp, - meta="BIP-39 Passphrase on [%s]" % parent_xfp_str) + origin="BIP-39 Passphrase on [%s]" % parent_xfp_str) if ch == '1': try: diff --git a/shared/selftest.py b/shared/selftest.py index 8600328e..4550b171 100644 --- a/shared/selftest.py +++ b/shared/selftest.py @@ -194,6 +194,7 @@ async def test_secure_element(): dis.fullscreen("Wait...") set_genuine() ux_clear_keys() + dis.busy_bar(False) ng = get_genuine() assert ng != gg # "Could not invert LED" @@ -321,14 +322,25 @@ async def test_microsd(): from files import CardSlot import os + def _is_inserted(slot_num): + if num_sd_slots > 1: + if slot_num == 0: + return CardSlot.sd_detect() == 0 + elif slot_num == 1: + return CardSlot.sd_detect2() == 0 + else: + assert False + else: + return CardSlot.is_inserted() + async def wait_til_state(num, want): title = 'MicroSD Card' if num_sd_slots > 1: title += ' ' + chr(65+num) - label_test(title +':', 'Remove' if CardSlot.is_inserted() else 'Insert') + label_test(title +':', 'Remove' if _is_inserted(num) else 'Insert') while 1: - if want == CardSlot.is_inserted(): return + if want == _is_inserted(num): return await sleep_ms(100) if ux_poll_key(): raise RuntimeError("MicroSD test aborted") @@ -336,23 +348,23 @@ async def test_microsd(): for slot_num in range(num_sd_slots): # test presence switch for ph in range(7): - await wait_til_state(slot_num, not CardSlot.is_inserted()) + await wait_til_state(slot_num, not _is_inserted(slot_num)) - if ph >= 2 and CardSlot.is_inserted(): + if ph >= 2 and _is_inserted(slot_num): # debounce await sleep_ms(100) - if CardSlot.is_inserted(): break + if _is_inserted(slot_num): break if ux_poll_key(): raise RuntimeError("MicroSD test aborted") label_test('MicroSD Card:', 'Testing') # card inserted - assert CardSlot.is_inserted() #, "SD not present?" + assert _is_inserted(slot_num) #, "SD not present?" with CardSlot(slot_b=slot_num) as card: - _, fn = card.pick_filename('test-delme.txt') + fn, _ = card.pick_filename('test-delme.txt') with open(fn, 'wt') as fd: fd.write("Hello") @@ -365,9 +377,7 @@ async def test_microsd(): await wait_til_state(slot_num, False) - async def start_selftest(): - try: if version.has_battery: await test_battery() @@ -403,6 +413,5 @@ async def start_selftest(): except (RuntimeError, AssertionError) as e: e = str(e) or problem_file_line(e) await ux_show_story("Test failed:\n" + str(e), 'FAIL') - # EOF diff --git a/shared/serializations.py b/shared/serializations.py index ce2f34b2..df28bae6 100755 --- a/shared/serializations.py +++ b/shared/serializations.py @@ -19,6 +19,7 @@ from ubinascii import hexlify as b2a_hex import ustruct as struct import ngu from opcodes import * +from public_constants import AF_CLASSIC, AF_P2WPKH, AF_P2SH, AF_P2WSH, AF_BARE_PK, AF_P2TR # single-shot hash functions sha256 = ngu.hash.sha256s @@ -62,12 +63,15 @@ def deser_compact_size(f, ret_num_bytes=False): num_bytes = 1 if nit == 253: nit = struct.unpack("= 253 num_bytes += 2 elif nit == 254: nit = struct.unpack("= 0x1_0000 num_bytes += 4 elif nit == 255: nit = struct.unpack("= 0x1_0000_0000 num_bytes += 8 if ret_num_bytes: return nit, num_bytes @@ -87,7 +91,6 @@ def deser_uint256(f): r += t << (i * 32) return r - def ser_uint256(u): rs = b"" for i in range(8): @@ -95,7 +98,6 @@ def ser_uint256(u): u >>= 32 return rs - def uint256_from_str(s): r = 0 t = struct.unpack("> 24) & 0xFF v = (c & 0xFFFFFF) << (8 * (nbytes - 3)) return v - def deser_vector(f, c): nit = deser_compact_size(f) r = [] @@ -119,7 +119,6 @@ def deser_vector(f, c): r.append(t) return r - # ser_function_name: Allow for an alternate serialization function on the # entries in the vector (we use this for serializing the vector of transactions # for a witness block). @@ -132,7 +131,6 @@ def ser_vector(l, ser_function_name=None): r += i.serialize() return r - def deser_uint256_vector(f): nit = deser_compact_size(f) r = [] @@ -141,29 +139,22 @@ def deser_uint256_vector(f): r.append(t) return r - def ser_uint256_vector(l): r = ser_compact_size(len(l)) for i in l: r += ser_uint256(i) return r - def deser_string_vector(f): nit = deser_compact_size(f) - r = [] - for i in range(nit): - t = deser_string(f) - r.append(t) - return r - + return [deser_string(f) for _ in range(nit)] def ser_string_vector(l): r = ser_compact_size(len(l)) for sv in l: r += ser_string(sv) - return r + return r def deser_int_vector(f): nit = deser_compact_size(f) @@ -173,7 +164,6 @@ def deser_int_vector(f): r.append(t) return r - def ser_int_vector(l): r = ser_compact_size(len(l)) for i in l: @@ -184,16 +174,18 @@ def ser_push_data(dd): # "compile" data to be pushed on the script stack # - will be minimal sized, but only supports size ranges we're likely to see ll = len(dd) - assert 2 <= ll <= 255 - - if ll <= 75: + if ll < 0x4c: return bytes([ll]) + dd # OP_PUSHDATAn + data + elif ll <= 0xff: + return bytes([0x4c, ll]) + dd # 0x4c = 76 => OP_PUSHDATA1 + size + data + elif ll <= 0xffff: + return bytes([0x4d]) + struct.pack(b' OP_PUSHDATA2 else: - return bytes([76, ll]) + dd # 0x4c = 76 => OP_PUSHDATA1 + size + data + assert False def ser_push_int(n): # push a small integer onto the stack - from opcodes import OP_0, OP_1, OP_16, OP_PUSHDATA1 + from opcodes import OP_0, OP_1 if n == 0: return bytes([OP_0]) @@ -227,11 +219,13 @@ def disassemble(script): #print('dis %d: number=%d' % (offset, (c - OP_1 + 1))) yield (c - OP_1 + 1, None) elif c == OP_PUSHDATA1: - cnt = script[offset]; offset += 1 + cnt = script[offset] + offset += 1 yield (script[offset:offset+cnt], None) offset += cnt elif c == OP_PUSHDATA2: - cnt = struct.unpack_from("H", script, offset) + # up to 65535 bytes + cnt, = struct.unpack_from("H", script, offset) offset += 2 yield (script[offset:offset+cnt], None) offset += cnt @@ -244,11 +238,12 @@ def disassemble(script): # OP_0 included here #print('dis %d: opcode=%d' % (offset, c)) yield (None, c) - except: + except Exception as e: + # import sys;sys.print_exception(e) raise ValueError("bad script") -def ser_sig_der(r, s, sighash_type=1): +def ser_sig_der(r, s, sighash_type=SIGHASH_ALL): # Take R and S values from a signature and encode into DER format. sig = b"\x30" @@ -365,38 +360,48 @@ class CTxOut(object): return r def get_address(self): - # Detect type of output from scriptPubKey, and return 3-tuple: - # (addr_type_code, addr, is_segwit) + # Detect type of output from scriptPubKey, and return 2-tuple: + # (addr_type_code, pubkey/pubkeyhash/scripthash) # 'addr' is byte string, either 20 or 32 long + if self.is_p2tr(): + return AF_P2TR, self.scriptPubKey[2:2+32] - if len(self.scriptPubKey) == 22 and \ - self.scriptPubKey[0] == 0 and self.scriptPubKey[1] == 20: - # aka. P2WPKH - return 'p2pkh', self.scriptPubKey[2:2+20], True + if self.is_p2wpkh(): + return AF_P2WPKH, self.scriptPubKey[2:2+20] - if len(self.scriptPubKey) == 34 and \ - self.scriptPubKey[0] == 81 and self.scriptPubKey[1] == 32: - # aka. P2TR - return 'p2tr', self.scriptPubKey[2:2+32], True - - if len(self.scriptPubKey) == 34 and \ - self.scriptPubKey[0] == 0 and self.scriptPubKey[1] == 32: - # aka. P2WSH - return 'p2sh', self.scriptPubKey[2:2+32], True + if self.is_p2wsh(): + return AF_P2WSH, self.scriptPubKey[2:2+32] if self.is_p2pkh(): - return 'p2pkh', self.scriptPubKey[3:3+20], False + return AF_CLASSIC, self.scriptPubKey[3:3+20] if self.is_p2sh(): - return 'p2sh', self.scriptPubKey[2:2+20], False + # can be: + # * bare P2SH + # * P2SH-P2WPKH + # * P2SH-P2WSH + return AF_P2SH, self.scriptPubKey[2:2+20] if self.is_p2pk(): # rare, pay to full pubkey - return 'p2pk', self.scriptPubKey[2:2+33], False + return AF_BARE_PK, self.scriptPubKey[2:2+33] - # If this is reached, we do not understand the output well - # enough to allow the user to authorize the spend, so fail hard. - raise ValueError('scriptPubKey template fail: ' + b2a_hex(self.scriptPubKey).decode()) + if self.scriptPubKey[0] == OP_RETURN: + return OP_RETURN, self.scriptPubKey + + return None, self.scriptPubKey + + def is_p2tr(self): + return len(self.scriptPubKey) == 34 and \ + (OP_1 <= self.scriptPubKey[0] <= OP_16) and self.scriptPubKey[1] == 0x20 + + def is_p2wpkh(self): + return len(self.scriptPubKey) == 22 and \ + self.scriptPubKey[0] == 0 and self.scriptPubKey[1] == 0x14 + + def is_p2wsh(self): + return len(self.scriptPubKey) == 34 and \ + self.scriptPubKey[0] == 0 and self.scriptPubKey[1] == 0x20 def is_p2sh(self): return len(self.scriptPubKey) == 23 and self.scriptPubKey[0] == 0xa9 \ @@ -501,7 +506,7 @@ class CTransaction(object): self.nVersion = struct.unpack(" number of words @@ -138,9 +140,34 @@ class SecretStash: return 'master', ms, hd + @staticmethod + def is_words(secret): + # return False or number of words: 12, 18, 24 + marker = secret[0] + if marker & 0x80: + return len_to_numwords(_len_from_marker(marker)) + return False + + @staticmethod + def decode_words(secret, bin_mode=False): + # Give a list of BIP-39 words from an encoded secret. Must be "words" type. + # - if bin_mode, return binary string representing the words, based on BIP-39 + ll = _len_from_marker(secret[0]) + + # note: + # - byte length > number of words + # - not storing checksum + assert ll in [16, 24, 32] + + # make master secret, using the memonic words, and passphrase (or empty string) + seed_bits = secret[1:1+ll] + + return bip39.b2a_words(seed_bits).split() if not bin_mode else seed_bits + @staticmethod def storage_serialize(secret): # make it a JSON-compatible field + # - converse: utils.deserialize_secret() return B2A(bytes(secret).rstrip(b"\x00")) @staticmethod @@ -153,7 +180,7 @@ class SecretStash: if marker & 0x80: # seed phrase - ll = len_from_marker(marker) + ll = _len_from_marker(marker) return '%d words' % len_to_numwords(ll) if marker == 0x00: @@ -177,7 +204,7 @@ class SensitiveValues: _cache_secret = None _cache_used = None - def __init__(self, secret=None, bip39pw='', bypass_tmp=False): + def __init__(self, secret=None, bip39pw='', bypass_tmp=False, enforce_delta=False): self.spots = [] self._bip39pw = bip39pw @@ -195,7 +222,12 @@ class SensitiveValues: if not pa.has_secrets(): raise ZeroSecretException + self.deltamode = pa.is_deltamode() + if self.deltamode and enforce_delta: + # wipe self before fetching secret + import callgate + callgate.fast_wipe() if self._cache_secret and not bypass_tmp: # they are using new BIP39 passphrase but we already have raw secret @@ -326,6 +358,9 @@ class SensitiveValues: return xfp + def get_xfp(self): + return swab32(self.node.my_fp()) + def register(self, item): # Caller can add his own sensitive (derived?) data to our wiper # typically would be byte arrays or byte strings, but also @@ -388,13 +423,4 @@ class SensitiveValues: self.register(pk) return pk - def encoded_secret(self): - # we do not support master as secret - only extended keys and mnemonics - if self.mode == "xprv": - nv = SecretStash.encode(xprv=self.node) - else: - assert self.mode == "words" - nv = SecretStash.encode(seed_phrase=self.raw) - return nv - # EOF diff --git a/shared/tapsigner.py b/shared/tapsigner.py index 76f9d11b..9bce68d4 100644 --- a/shared/tapsigner.py +++ b/shared/tapsigner.py @@ -33,7 +33,7 @@ async def import_tapsigner_backup_file(_1, _2, item): from pincodes import pa assert pa.is_secret_blank() # "must not have secret" - meta = "from " + origin = "from " label = "TAPSIGNER encrypted backup file" choice = await import_export_prompt(label, is_import=True) @@ -67,9 +67,9 @@ async def import_tapsigner_backup_file(_1, _2, item): continue break else: - fn = await file_picker(suffix="aes", min_size=100, max_size=160, **choice) + fn = await file_picker(suffix=".aes", min_size=100, max_size=160, **choice) if not fn: return - meta += (" (%s)" % fn) + origin += (" (%s)" % fn) try: with CardSlot(**choice) as card: with open(fn, 'rb') as fp: @@ -103,6 +103,6 @@ async def import_tapsigner_backup_file(_1, _2, item): await ux_show_story(title="FAILURE", msg=str(e)) continue - await import_extended_key_as_secret(extended_key, ephemeral, meta=meta) + await import_extended_key_as_secret(extended_key, ephemeral, origin=origin) # EOF diff --git a/shared/teleport.py b/shared/teleport.py new file mode 100644 index 00000000..44d5487d --- /dev/null +++ b/shared/teleport.py @@ -0,0 +1,789 @@ +# (c) Copyright 2025 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# +# teleport.py - Magically transport extremely sensitive data between the +# secure environment of two Q's. +# +import ngu, aes256ctr, bip39, json, ndef, chains +from utils import xfp2str, deserialize_secret +from ubinascii import unhexlify as a2b_hex +from ubinascii import hexlify as b2a_hex +from glob import settings, dis +from ux import ux_show_story, ux_confirm, the_ux, ux_dramatic_pause +from ux_q1 import show_bbqr_codes, QRScannerInteraction, ux_input_text +from charcodes import KEY_QR, KEY_NFC, KEY_CANCEL +from bbqr import b32encode, b32decode +from menu import MenuItem, MenuSystem +from notes import NoteContentBase +from sffile import SFFile +from wallet import MiniScriptWallet +from stash import SensitiveValues, SecretStash, blank_object, bip39_passphrase + +# One page github-hosted static website that shows QR based on URL contents pushed by NFC +KT_DOMAIN = 'keyteleport.com' + +# No length/size worries with simple secrets, but massive notes and big PSBT, +# with lots of UTXO, cannot be passed via NFC URL, because we are limited by +# NFC chip (8k) and URL length (4k or less) inside. BBQr is not limited however. +# - but the website is ready to make animated BBQr nicely +NFC_SIZE_LIMIT = const(4096) + +def short_bbqr(type_code, data): + # Short-circuit basic BBQr encoding here: always Base32, single part: 1 of 1 + # - used only for NFC link, where website may split again into parts + hdr = 'B$2%s0100' % type_code + + return hdr + b32encode(data) + +def txt_grouper(txt): + # split into 2-char groups and add spaces -- to make it easier to read/remember + return ' '.join(txt[n:n+2] for n in range(0, len(txt), 2)) + +async def nfc_push_kt(qrdata): + # NFC push to send them to our QR-rendering website + + url = KT_DOMAIN + '/#' + qrdata + + n = ndef.ndefMaker() + n.add_url(url, https=True) + + from glob import NFC + await NFC.share_loop(n, prompt="View QR on web", line2=KT_DOMAIN) + +async def kt_start_rx(*a): + # menu item to "start a receive" operation + + rx_key = settings.get("ktrx") + + if rx_key: + # Maybe re-use same one? Vaguely risky? Concern is they are confused and + # we don't want to lose the pubkey if they should be scanning not here. + ch = await ux_show_story('''Looks like last attempt wasn't completed. \ +You need to do QR scan of data from the sender to move to the next step. \ +We will re-use same values as last try, unless you press (R) for new values to be picked.''', + title='Reuse Pubkey?', escape='r'+KEY_QR, hint_icons=KEY_QR) + + if ch == KEY_QR: + # help them scan now! + x = QRScannerInteraction() + await x.scan_anything(expect_secret=False, tmp=False) + return + elif ch == 'r': + # wipe and restart; sender's work might be lost + rx_key = None + else: + # keep old keypair -- they might be confused + kp = ngu.secp256k1.keypair(a2b_hex(rx_key)) + + if not rx_key: + # pick a random key pair, just for this session + kp = ngu.secp256k1.keypair() + + settings.set("ktrx", b2a_hex(kp.privkey())) + settings.save() + + short_code, payload = generate_rx_code(kp) + + msg = '''To receive sensitive data from another COLDCARD, \ +share this Receiver Password with sender: + + %s = %s + +and show the QR on next screen to the sender. ENTER or %s to show here''' % ( + short_code, txt_grouper(short_code), KEY_QR) + + await tk_show_payload('R', payload, 'Key Teleport: Receive', msg, cta='Show to Sender') + +def generate_rx_code(kp): + # Receiver-side password: given a pubkey (33 bytes, compressed format) + # - construct an 8-digit decimal "password" + # - it's a AES key, but only 26 bits worth + pubkey = bytearray(kp.pubkey().to_bytes()) # default: compressed format + #assert len(pubkey) == 33 + + # - want the code to be deterministic, but I also don't want to save it + nk = ngu.hash.sha256d(kp.privkey() + b'COLCARD4EVER') + + # first byte will be 0x02 or 0x03 (Y coord) -- remove those known 7 bits + pubkey[0] ^= nk[20] & 0xfe + + num = '%08d' % (int.from_bytes(nk[4:8], 'big') % 1_0000_0000) + + # encryption after baby key stretch + kk = ngu.hash.sha256s(num.encode()) + enc = aes256ctr.new(kk).cipher(pubkey) + + return num, enc + +def decrypt_rx_pubkey(code, payload): + # given a 8-digit numeric code, make the key and then decrypt/checksum check + # - every value works, there is no fail. + kk = ngu.hash.sha256s(code.encode()) + rx_pubkey = bytearray(aes256ctr.new(kk).cipher(payload)) + + # first byte will be 0x02 or 0x03 but other 7 bits are noise + rx_pubkey[0] &= 0x01 + rx_pubkey[0] |= 0x02 + + # validate that it's on the curve... otherwise the code is wrong + try: + ngu.secp256k1.pubkey(rx_pubkey) + + return rx_pubkey + except: + return None + +async def tk_show_payload(type_code, payload, title, msg, cta=None): + # show the QR and/or NFC + # - MAYBE: make easier/faster to pick NFC from QR screen and vice-versa + from glob import NFC + + hints = KEY_QR + if NFC and len(payload) < NFC_SIZE_LIMIT: + hints += KEY_NFC + msg += ' or %s to view on your phone' % KEY_NFC + + msg += '. CANCEL to stop.' + + # simply show the QR + while 1: + ch = await ux_show_story(msg, title=title, hint_icons=hints) + + if ch == KEY_NFC and NFC: + await nfc_push_kt(short_bbqr(type_code, payload)) + elif ch == KEY_QR or ch == 'y': + # NOTE: CTA rarely seen, but maybe sometimes? + await show_bbqr_codes(type_code, payload, msg=cta) + elif ch == 'x': + return + +async def kt_start_send(rx_data): + # a QR was scanned and it held (most of) a pubkey + # - they want to send to this guy + # - ask them what to send, etc + + while 1: + # - ask for the sender's password -- nearly any value will be accepted + code = await ux_input_text('', confirm_exit=False, hex_only=True, max_len=8, + prompt='Teleport Password (number)', min_len=8, b39_complete=False, scan_ok=False, + placeholder='########', funct_keys=None, force_xy=None) + if not code: return + + rx_pubkey = decrypt_rx_pubkey(code, rx_data) + + if rx_pubkey: + break + + # I think only about 50% odds of catching an incorrect code. Not sure. + ch = await ux_show_story( + "Incorrect Teleport Password. You can try again or CANCEL to stop.") + if ch == 'x': return + + msg = '''You can now Key Teleport secrets! Choose what to share on next screen.\ +\n +WARNING: Receiver will have full access to all Bitcoin controlled by these keys!''' + + ch = await ux_show_story(msg, title="Key Teleport: Send") + if ch != 'y': return + + # pick what to send from a series of submenus + menu = SecretPickerMenu(rx_pubkey) + the_ux.push(menu) + +async def kt_do_send(rx_pubkey, dtype, raw=None, obj=None, prefix=b'', rx_label='the receiver', kp=None): + # We are rendering a QR and showing it to them for sending to another Q + dis.fullscreen("Wait...") + cleartext = dtype.encode() + (raw or json.dumps(obj).encode()) + dis.progress_bar_show(0.1) + + # Pick and show noid key to sender + noid_key, txt = pick_noid_key() + + dis.progress_bar_show(0.25) + + # all new EC key + my_keypair = kp or ngu.secp256k1.keypair() + + dis.progress_bar_show(0.75) + + payload = prefix + encode_payload(my_keypair, rx_pubkey, noid_key, cleartext, + for_psbt=bool(prefix)) + + dis.progress_bar_show(1) + + msg = "Share this password with %s, via some different channel:"\ + "\n\n %s = %s\n\n" % (rx_label, txt, txt_grouper(txt)) + msg += "ENTER to view QR" + + await tk_show_payload('S' if not prefix else 'E', payload, + 'Teleport Password', msg, cta='Show to Receiver') + + if not prefix: + # not PSBT case ... reset menus, we are deep! + from actions import goto_top_menu + goto_top_menu() + +def pick_noid_key(): + # pick an 40 bit password, shown as base32 + # - on rx, libngu base32 decoder will convert '018' into 'OLB' + # - but a little tempted to removed vowels here? + k = ngu.random.bytes(5) + txt = b32encode(k).upper() + + return k, txt + +async def kt_decode_rx(is_psbt, payload): + # we are getting data back from a sender, decode it. + dis.fullscreen("Wait...") + + prompt = 'Teleport Password (text)' + + if not is_psbt: + rx_key = settings.get("ktrx") + if not rx_key: + await ux_show_story("Not expecting any teleports. You need to start over.") + + await kt_start_rx() # help them to start over? idk maybe not. + return + + his_pubkey = payload[0:33] + body = payload[33:] + pair = ngu.secp256k1.keypair(a2b_hex(rx_key)) + + ses_key, body = decode_step1(pair, his_pubkey, body) + else: + # Multisig PSBT: will need to iterate over a few wallets and each N-1 possible senders + if not MiniScriptWallet.exists(): + await ux_show_story("Incoming PSBT requires miniscript wallet(s) to be already setup, but you have none.") + return + + ses_key, body, sender_xfp = MiniScriptWallet.kt_search_rxkey(payload) + + if sender_xfp is not None: + prompt = 'Teleport Password from [%s]' % xfp2str(sender_xfp) + + if not ses_key: + # when ECDH fails, it's truncation or wrong RX key (due to sender using old rx key, + # or the numeric code the sender entered was wrong, etc) + await ux_show_story("QR code was damaged, "+ + ("numeric password was wrong, " if not is_psbt else "")+ + "or it was sent to a different user. " + "Sender must start again.", title="Teleport Fail") + return + + while 1: + # ask for noid key + pw = await ux_input_text('', confirm_exit=False, hex_only=False, max_len=8, + prompt=prompt, min_len=8, b39_complete=False, scan_ok=False, + placeholder='********', funct_keys=None, force_xy=None) + if not pw: return + + dis.fullscreen("Wait...") + try: + assert len(pw) == 8 + noid_key = b32decode(pw) # case insenstive, and smart about confused chars + final = decode_step2(ses_key, noid_key, body) + if final is not None: + break + except: pass + + ch = await ux_show_story( + "Incorrect Teleport Password. You can try again or CANCEL to stop.") + if ch == 'x': return + # will ask again + + # success w/ decoding. but maybe something goes wrong or they reject a confirm step + # so keep the rx key alive still + + await kt_accept_values(chr(final[0]), final[1:]) + +async def kt_accept_values(dtype, raw): + # We got some secret, decode it more, and save it. + ''' + - `s` - secret, encoded per stash.py + - `r` - raw XPRV mode - 64 bytes follow which are the chain code then master privkey + - `x` - XPRV mode, full details - 4 bytes (XPRV) + base58 *decoded* binary-XPRV follows + - `n` - one or many notes export (JSON array) + - `v` - seed vault export (JSON: one secret key but includes includes name, source of key) + - `p` - binary PSBT to be signed + - `b` - complete system backup file (text, internal format) + ''' + from flow import has_se_secrets, goto_top_menu + from pincodes import pa + + enc = None + origin = 'Teleported' + label = None + + if pa.hobbled_mode and dtype != 'p': + await ux_show_story('Only PSBT for multisig accepted in this mode.', title='FAILED') + return + + + if dtype == 's': + # words / bip 32 master / xprv, etc + enc = bytearray(72) + enc[0:len(raw)] = raw + + elif dtype == 'x': + # it's an XPRV, but in binary.. some extra data we throw away here; sigh + # XXX no way to send this .. but was thinking of address explorer + txt = ngu.codecs.b58_encode(raw) + node, ch, _, _ = chains.slip132_deserialize(txt) + assert ch.name == chains.current_chain().name, 'wrong chain' + enc = SecretStash.encode(xprv=node) + + elif dtype == 'p': + # raw PSBT -- much bigger more complex + from auth import sign_transaction, TXN_INPUT_OFFSET + + psbt_len = len(raw) + + # copy into PSRAM + with SFFile(TXN_INPUT_OFFSET, max_size=psbt_len) as out: + out.write(raw) + + # This will take over UX w/ the signing process + # flags=None --> whether to finalize is decided based on psbt.is_complete + sign_transaction(psbt_len, flags=None) + return + + elif dtype == 'b': + # full system backup, including master: text lines + from backups import text_bk_parser, restore_tmp_from_dict_ll, restore_from_dict, extract_raw_secret + + vals = text_bk_parser(raw) + assert vals # empty? + + raw_sec, _ = extract_raw_secret(vals) + + from flow import has_secrets + + if has_secrets(): + # restores as tmp secret and/or offers to save to SeedVault + # need to remove key before I get into tmp seed settings + # so even if this errors out, new ktrx is needed + settings.remove_key("ktrx") + prob = await restore_tmp_from_dict_ll(vals, raw_sec) + else: + # we have no secret, so... reboot if it works, else errors shown, etc. + prob = await restore_from_dict(vals, raw_sec) + + if prob: + await ux_show_story(prob, title='FAILED') + else: + # force new rx key because this tfr worked + # only has effect if in master seed settings + settings.remove_key("ktrx") + return + + elif dtype in 'nv': + # all are JSON things + js = json.loads(raw) + + if dtype == 'v': + # one key export from a seed vault + # - watch for incompatibility here if we ever change VaultEntry + from seed import VaultEntry + rec = VaultEntry(*js) + enc = deserialize_secret(rec.encoded) + origin = rec.origin + label = rec.label + elif dtype == 'n': + # import secure note(s) + from notes import import_from_json, make_notes_menu, NoteContent + + settings.remove_key("ktrx") # force new rx key after this point + await import_from_json(dict(coldcard_notes=js)) + + await ux_dramatic_pause('Imported.', 2) + + # force them into notes submenu so they can see result right away + # - highlight to last note, which should be the just-added one(s) + goto_top_menu() + nm = await make_notes_menu() + nm.goto_idx(NoteContent.count()-1) + the_ux.push(nm) + + return + else: + raise ValueError(dtype) + + # key material is arriving; offer to use as main secret, or tmp, or seed vault? + settings.remove_key("ktrx") # force new rx key after this point + assert enc + + from seed import set_ephemeral_seed, set_seed_value + + if not has_se_secrets(): + # unit has nothing, so this will be the master seed + set_seed_value(encoded=enc) + ok = True + else: + ok = await set_ephemeral_seed(enc, origin=origin, label=label) + + if ok: + goto_top_menu() + +def noid_stretch(session_key, noid_key): + # TODO: measure timing of this on real Q + return ngu.hash.pbkdf2_sha512(session_key, noid_key, 5000)[0:32] + +def encode_payload(my_keypair, his_pubkey, noid_key, body, for_psbt=False): + # do all the encryption for sender + assert len(his_pubkey) == 33 + assert len(noid_key) == 5 + + # this can fail with ValueError: secp256k1_ec_pubkey_parse + # if the user has provided the wrong value for numeric password + # - better to catch this sooner in decrypt_rx_pubkey + session_key = my_keypair.ecdh_multiply(his_pubkey) + + # stretch noid key out -- will be slow + pk = noid_stretch(session_key, noid_key) + + b1 = aes256ctr.new(pk).cipher(body) + b1 += ngu.hash.sha256s(body)[-2:] + + b2 = aes256ctr.new(session_key).cipher(b1) + b2 += ngu.hash.sha256s(b1)[-2:] + + if for_psbt: + # no need to share pubkey for PSBT files + return b2 + + return my_keypair.pubkey().to_bytes() + b2 + +def decode_step1(my_keypair, his_pubkey, body): + # Do ECDH and remove top layer of encryption + try: + assert len(body) >= 3 + + session_key = my_keypair.ecdh_multiply(his_pubkey) + + rv = aes256ctr.new(session_key).cipher(body[:-2]) + chk = ngu.hash.sha256s(rv)[-2:] + + assert chk == body[-2:] # likely means wrong rx key, or truncation + except: + return None, None + + return session_key, rv + +def decode_step2(session_key, noid_key, body): + # After we have the noid key, can decode true payload + assert len(noid_key) == 5 + + pk = noid_stretch(session_key, noid_key) + + msg = aes256ctr.new(pk).cipher(body[:-2]) + chk = ngu.hash.sha256s(msg)[-2:] + + return msg if chk == body[-2:] else None + + +async def kt_incoming(type_code, payload): + # incoming BBQr was scanned (via main menu, etc) + + from pincodes import pa + if pa.hobbled_mode and type_code != 'E': + # only PSBT rx is supported in hobbled mode + # fail silently, this is second check, see decoders.py + return + + if type_code == 'R': + # they want to send to this guy + return await kt_start_send(payload) + + elif type_code == 'S': + # we are receiving something, let's try to decode + return await kt_decode_rx(False, payload) + + elif type_code == 'E': + # incoming PSBT! + return await kt_decode_rx(True, payload) + + else: + raise ValueError(type_code) + + +class SecretPickerMenu(MenuSystem): + def __init__(self, rx_pubkey): + self.rx_pubkey = rx_pubkey + + # this menu should be unreachable in hobbled mode. + from pincodes import pa + assert not pa.hobbled_mode + + from flow import word_based_seed, is_tmp, has_se_secrets + has_notes = bool(NoteContentBase.count()) + has_sv = bool(settings.get('seedvault', False)) + + # Q-only feature, so menu can be W I D E + # - in increasing order of importance & sensitivity! + # - pinned-virgin mode is supported, so might not have any secrets to share yet, + # but can do secret notes still + m = [ + MenuItem('Quick Text Message', f=self.quick_note), + MenuItem('Single Note / Password', predicate=has_notes, menu=self.pick_note_submenu), + MenuItem('Export All Notes & Passwords', predicate=has_notes, f=self.picked_note), + ] + + if has_sv: + m.append( MenuItem('From Seed Vault', menu=self.pick_vault_submenu) ) + + msg = None + if is_tmp(): + # tmp seed, or maybe bip39 is in effect + # - share the current master secret, not the real master + msg = 'Temp Secret (words)' if word_based_seed() else ( + 'XPRV from Words+Passphrase' if bip39_passphrase else 'Temp XPRV Secret') + elif has_se_secrets(): + # sharing real master secret + msg = 'Master Seed Words' if word_based_seed() else 'Master XPRV' + + if msg: + m.append( MenuItem(msg, f=self.share_master_secret) ) + m.append( MenuItem("Full COLDCARD Backup", f=self.share_full_backup) ) + + super().__init__(m) + + async def pick_vault_submenu(self, *a): + # pick a secret from seed vault + from seed import SeedVaultChooserMenu + rec = await SeedVaultChooserMenu.pick() + if rec: + await kt_do_send(self.rx_pubkey, 'v', obj=list(rec)) + + async def pick_note_submenu(self, *a): + # Make a submenu to select a single note/password + rv = [] + for note in NoteContentBase.get_all(): + rv.append(MenuItem('%d: %s' % (note.idx+1, note.title), f=self.picked_note, arg=note)) + + return rv + + async def quick_note(self, _, _2, item): + # accept a text string, and send as a note + from notes import NoteContent + txt = await ux_input_text('', max_len=100, + prompt='Enter your message', min_len=1, b39_complete=True, scan_ok=True, + placeholder='Attack at dawn.') + + if not txt: return + + n = NoteContent(dict(title="Quick Note", misc=txt)) + await kt_do_send(self.rx_pubkey, 'n', obj=[n.serialize()]) + + async def picked_note(self, _, _2, item): + # exporting note(s) + + if item.arg is None: + # export all + body = [n.serialize() for n in NoteContentBase.get_all()] + else: + # single note/password + body = [item.arg.serialize()] + + await kt_do_send(self.rx_pubkey, 'n', obj=body) + + async def share_full_backup(self, *a): + # context, and warn them + ch = await ux_show_story("Sending complete backup, including master secret, " + "seed vault (if any), miniscript wallets, notes/passwords, and all settings! " + "The receiving " + "COLDCARD must already have the master seed wiped to be able to install " + "everything, otherwise only master secret and miniscripts are saved into a tmp seed. " + "OK to proceed?") + if ch != 'y': return + + from backups import render_backup_contents + + dis.fullscreen("Buiding Backup...") + + # renders a text file, with rather a lot of comments; strip them + bkup = render_backup_contents(bypass_tmp=True) + out = [] + for ln in bkup.split('\n'): + if not ln: continue + if ln[0] == '#': continue + out.append(ln) + + await kt_do_send(self.rx_pubkey, 'b', raw=b'\n'.join(ln.encode() for ln in out)) + + async def share_master_secret(self, _, _2, item): + # altho menu items look different we are sharing same thing: + # - up to 72 bytes from secure elements + + dis.fullscreen("Wait...") + + with SensitiveValues(bypass_tmp=False, enforce_delta=True) as sv: + raw = bytearray(sv.secret) + xfp = xfp2str(sv.get_xfp()) + + # rtrim zeros + while raw[-1] == 0: + raw = raw[0:-1] + + summary = SecretStash.summary(raw[0]) + + from pincodes import pa + scale = 'your MASTER secret' if not pa.tmp_value else 'a temporary secret' + + msg = "Sharing %s [%s] (%s)." % (scale, xfp, summary) + msg += "\n\nWARNING: Allows full control over all associated Bitcoin!" + + if not await ux_confirm(msg): + blank_object(raw) + return + + await kt_do_send(self.rx_pubkey, 's', raw=raw) + + +async def kt_send_psbt(psbt, psbt_len): + # We just finished adding our signature to an incomplete PSBT. + # User wants to send to one or more other senders for them to complete signing. + + # who remains to sign? look at inputs + # all_xfps is set, no need to list one master xfp more than once - assuming CC can sign it all + assert psbt.active_miniscript + ms = psbt.active_miniscript + all_xfps = {x for x,*p in ms.to_descriptor().xfp_paths(skip_unspend_ik=True)} + + need = [x for x in psbt.miniscript_xfps_needed() if x in all_xfps] + # maybe it's not really a PSBT where we know the other signers? might be + # a weird coinjoin we don't fully understand + if not need: + await ux_show_story("No more signers?") + return + + # move out of PSRAM + from auth import TXN_OUTPUT_OFFSET + + with SFFile(TXN_OUTPUT_OFFSET, psbt_len) as fd: + bin_psbt = fd.read(psbt_len) + + my_xfp = settings.get('xfp') + + # if my_xfp in need: + # - we haven't signed yet? let's do that now .. except we've lost some of the + # data we need such as filename to save back into. + # - so just keep going instead... maybe they want to be last signer? + + # Make them pick a single next signer. It's not helpful to do multiple at once + # here, since we need signatures to be added serially so that last + # signer can do finalization. We don't have a general purpose combiner. + + async def done_cb(m, idx, item): + m.next_xfp = item.arg + the_ux.pop() + + ci = [] + next_signer = None + for idx, x in enumerate(all_xfps): + txt = '[%s] Co-signer #%d' % (xfp2str(x), idx+1) + f = done_cb + if x == my_xfp: + txt += ': YOU' + f = None + if x in need: + # we haven't signed ourselves yet, so allow that + from auth import sign_transaction, TXN_INPUT_OFFSET + + async def sign_now(*a): + # this will reset the UX stack: + # flags=None --> whether to finalize is decided based on psbt.is_complete + sign_transaction(psbt_len, flags=None) + + f = sign_now + + elif x not in need: + txt += ': DONE' + f = None + + mi = MenuItem(txt, f=f, arg=x) + + if x not in need: + # show check if we've got sig + mi.is_chosen = lambda: True + elif next_signer is None: + next_signer = idx + + ci.append(mi) + + m = MenuSystem(ci) + m.next_xfp = None + m.goto_idx(next_signer) # position cursor on next candidate + the_ux.push(m) + await m.interact() + + if m.next_xfp: + assert m.next_xfp != my_xfp + ri, rx_pubkey, kp = ms.kt_make_rxkey(m.next_xfp) + await kt_do_send(rx_pubkey, 'p', raw=bin_psbt, prefix=ri, kp=kp, + rx_label='[%s] co-signer' % xfp2str(m.next_xfp)) + + return True + + return None + +async def kt_send_file_psbt(*a): + # Menu item: choose a PSBT file from SD card, and send to co-signers. + # Heavy code re-use here. Need to find the multisig wallet associated w/ file, + # so we need to parse it and we must be one of the co-signers. + + from actions import is_psbt, file_picker + from auth import sign_psbt_file, TXN_INPUT_OFFSET + from version import MAX_TXN_LEN + from ux import import_export_prompt + from psbt import psbtObject + + # choose any PSBT from SD + picked = await import_export_prompt("PSBT", is_import=True, no_nfc=True, no_qr=True) + if picked == KEY_CANCEL: + return + choices = await file_picker(suffix='.psbt', min_size=50, ux=False, + max_size=MAX_TXN_LEN, taster=is_psbt, **picked) + if not choices: + # error msg already shown + return + + if len(choices) == 1: + # single - skip the menu + label,path,fn = choices[0] + input_psbt = path + '/' + fn + else: + # multiples - make them pick one + input_psbt = await file_picker(choices=choices) + if not input_psbt: + return + + # read into PSRAM from wherever + psbt_len = await sign_psbt_file(input_psbt, just_read=True, **picked) + + dis.fullscreen("Validating...") + try: + dis.progress_sofar(1, 4) + with SFFile(TXN_INPUT_OFFSET, length=psbt_len, message='Reading...') as fd: + # NOTE: psbtObject captures the file descriptor and uses it later + psbt = psbtObject.read_psbt(fd) + + await psbt.validate() # might do UX: accept multisig import + + dis.progress_sofar(2, 4) + psbt.consider_inputs() + dis.progress_sofar(3, 4) + + except Exception as exc: + # not going to do full reporting here, use our other code for that! + await ux_show_story("Cannot validate PSBT?\n\n"+str(exc), "PSBT Load Failed") + return + finally: + dis.progress_bar_show(1) + + if not psbt.active_miniscript: + await ux_show_story("We are not part of this wallet.", "Cannot Teleport PSBT") + return + + await kt_send_psbt(psbt, psbt_len=psbt_len) + +# EOF diff --git a/shared/trick_pins.py b/shared/trick_pins.py index 1d7a19c6..8dc89b5d 100644 --- a/shared/trick_pins.py +++ b/shared/trick_pins.py @@ -12,6 +12,8 @@ from menu import MenuSystem, MenuItem from ux import ux_show_story, ux_confirm, ux_dramatic_pause, ux_enter_number, the_ux from stash import SecretStash from drv_entro import bip85_derive +from glob import settings + # see from mk4-bootloader/se2.h NUM_TRICKS = const(14) @@ -32,7 +34,7 @@ TC_WORD_WALLET = const(0x1000) TC_XPRV_WALLET = const(0x0800) TC_DELTA_MODE = const(0x0400) TC_REBOOT = const(0x0200) -TC_RFU = const(0x0100) +TC_FW_DEFINED = const(0x0100) # for our use, not implemented in bootrom TC_BLANK_WALLET = const(0x0080) TC_COUNTDOWN = const(0x0040) # tc_arg = minutes of delay @@ -40,6 +42,10 @@ TC_COUNTDOWN = const(0x0040) # tc_arg = minutes of delay # tc_args encoding: # TC_WORD_WALLET -> BIP-85 index, 1001..1003 for 24 words, 2001..2003 for 12-words +# If TC_FW_DEFINED is true, then we can do anything with this PIN at the firmware +# level. First application is to unlock spending stuff. +TCA_SP_UNLOCK = const(0x0001) # spending policy unlock + # special "pin" used as catch-all for wrong pins WRONG_PIN_CODE = '!p' @@ -94,22 +100,6 @@ class TrickPinMgmt: def __init__(self): assert uctypes.sizeof(TRICK_SLOT_LAYOUT) == 128 - self.reload() - - def reload(self): - # we track known PINS as a dictionary: - # pin (in ascii) => (slot_num, tc_flags, arg) - from glob import settings - self.tp = settings.get('tp', {}) - - def save_record(self): - # commit changes back to settings - from glob import settings - if self.tp: - settings.set('tp', self.tp) - else: - settings.remove_key('tp') - settings.save() def roundtrip(self, method_num, slot_buf=None): from pincodes import pa @@ -129,26 +119,36 @@ class TrickPinMgmt: return rc + def get_all(self): + return settings.get("tp", {}) + + def commit(self, trick_pins): + settings.set("tp", trick_pins) + settings.save() + def clear_all(self): # get rid of them all self.roundtrip(0) - self.tp = {} - self.save_record() + settings.remove_key('tp') + settings.save() def forget_pin(self, pin): # forget about settings for a PIN - self.tp.pop(pin, None) - self.save_record() + t_pins = self.get_all() + t_pins.pop(pin, None) + self.commit(t_pins) def restore_pin(self, new_pin): # remember/restore PIN that we "forgot", return T if worked - b, slot = tp.get_by_pin(new_pin) + b, slot = self.get_by_pin(new_pin) if slot is None: return False record = (slot.slot_num, slot.tc_flags, 0xffff if slot.tc_flags & TC_DELTA_MODE else slot.tc_arg) - self.tp[new_pin] = record - self.save_record() + + t_pins = self.get_all() + t_pins[new_pin] = record + self.commit(t_pins) return True @@ -221,17 +221,18 @@ class TrickPinMgmt: # pick a free slot sn = self.find_empty_slots(1 if not secret else 1+(len(secret)//32)) - if sn == None: + if sn is None: # we are full raise RuntimeError("no space left") slot.slot_num = sn + t_pins = self.get_all() if new_pin is not None: slot.pin_len = len(new_pin) slot.pin[0:slot.pin_len] = new_pin if new_pin != pin: - self.tp.pop(pin.decode(), None) + t_pins.pop(pin.decode(), None) pin = new_pin if tc_flags is not None: @@ -265,14 +266,18 @@ class TrickPinMgmt: assert rc == 0 # record key details. - self.tp[pin.decode()] = record - self.save_record() + t_pins[pin.decode()] = record + self.commit(t_pins) return b, slot def all_tricks(self): # put them in order, with "wrong" last - return sorted(self.tp.keys(), key=lambda i: i if (i != WRONG_PIN_CODE) else 'Z') + return sorted(self.get_all().keys(), key=lambda i: i if (i != WRONG_PIN_CODE) else 'Z') + + def define_unlock_pin(self, new_pin): + # user is setting the bypass PIN for first time. + self.update_slot(new_pin.encode(), new=True, tc_flags=TC_FW_DEFINED, tc_arg=TCA_SP_UNLOCK) def was_countdown_pin(self): # was the trick pin just used? if so how much delay needed (or zero if not) @@ -284,24 +289,51 @@ class TrickPinMgmt: else: return 0 + def was_sp_unlock(self): + # was a trick pin just used that enables acess to spending policy? + # - ok if it's also a trick PIN .. a wiping bypass for example + from pincodes import pa + tc_flags, tc_arg = pa.get_tc_values() + return bool(tc_flags & TC_FW_DEFINED) and (tc_arg == TCA_SP_UNLOCK) + + def has_sp_unlock(self): + # if spending policy defined, this PIN allows adjustment + # - not TRICK bypass choices, like ones that wipe + # - could be multiple, but only first returned. + for k, (sn,flags,arg) in self.get_all().items(): + if (flags == TC_FW_DEFINED) and (arg == TCA_SP_UNLOCK): + return k + return None + + def delete_sp_unlock_pins(self): + # remove all bypass pins, they are done w/ feature + for k, (sn,flags,arg) in self.get_all().items(): + if (flags & TC_FW_DEFINED) and (arg == TCA_SP_UNLOCK): + self.clear_slots([sn]) + self.forget_pin(k) + + def get_deltamode_pins(self): # iterate over all delta-mode PIN's defined. - for k, (sn,flags,args) in self.tp.items(): + for k, (sn,flags,args) in self.get_all().items(): if flags & TC_DELTA_MODE: yield k def get_duress_pins(self): # iterate over all duress wallets - for k, (sn,flags,args) in self.tp.items(): + for k, (sn,flags,args) in self.get_all().items(): if flags & (TC_WORD_WALLET | TC_XPRV_WALLET): yield k def check_new_main_pin(self, pin): # user is trying to change main PIN to new value; check for issues # - dups bad but also: delta mode pin might not work w/ longer main true pin + # - deciding whether TP already exists must be done via comms with SE2 + # as checking only self.tp is not sufficient for hidden TPs or after fast wipe # - return error msg or None assert isinstance(pin, str) - if pin in self.tp: + b, slot = self.get_by_pin(pin) + if slot is not None: return 'That PIN is already in use as a Trick PIN.' for d_pin in self.get_deltamode_pins(): @@ -319,8 +351,9 @@ class TrickPinMgmt: def backup_duress_wallets(self, sv): # for backup file, yield (label, path, pairs-of-data) done = set() + t_pins = self.get_all() for pin in self.get_duress_pins(): - sn, flags, arg = self.tp[pin] + sn, flags, arg = t_pins[pin] if (flags, arg) in done: continue @@ -330,7 +363,7 @@ class TrickPinMgmt: label = "Duress: BIP-85 Derived wallet" nwords = 12 if ((arg // 1000) == 2) else 24 path = "BIP85(words=%d, index=%d)" % (nwords, arg) - b, slot = tp.get_by_pin(pin) + b, slot = self.get_by_pin(pin) words = bip39.b2a_words(slot.xdata[0:(32 if nwords==24 else 16)]) d = [ ('duress_%d_words' % arg, words) ] @@ -369,10 +402,15 @@ class TrickPinMgmt: # might need to construct a BIP-85 or XPRV secret to match path, new_secret = construct_duress_secret(flags, arg) - b, slot = tp.update_slot(pin.encode(), new=True, - tc_flags=flags, tc_arg=arg, secret=new_secret) - except Exception as exc: - sys.print_exception(exc) # not visible + self.update_slot(pin.encode(), new=True, tc_flags=flags, + tc_arg=arg, secret=new_secret) + except: pass + + @staticmethod + async def err_unique_pin(pin): + # standardized error UX + return await ux_show_story( + "That PIN (%s) is already in use. All PIN codes must be unique." % pin) tp = TrickPinMgmt() @@ -401,7 +439,6 @@ class TrickPinMenu(MenuSystem): if bool(pa.tmp_value): return [MenuItem('Not Available')] - tp.reload() tricks = tp.all_tricks() if self.current_pin in tricks: @@ -489,7 +526,7 @@ class TrickPinMenu(MenuSystem): tc_arg=tc_arg, secret=new_secret) await ux_dramatic_pause("Saved.", 1) except BaseException as exc: - sys.print_exception(exc) + # sys.print_exception(exc) await ux_show_story("Failed: %s" % exc) self.update_contents() @@ -518,8 +555,7 @@ class TrickPinMenu(MenuSystem): have.remove(existing_pin) if (new_pin == self.current_pin) or (new_pin in have): - await ux_show_story("That PIN (%s) is already in use. All PIN codes must be unique." % new_pin) - return + return await tp.err_unique_pin(new_pin) # check if we "forgot" this pin, and read it back if we did. # - important this is after the above checks so we don't reveal any trick pin used @@ -604,6 +640,9 @@ the seed phrase, but still a somewhat riskier mode. For this mode only, trick PIN must be same length as true PIN and \ differ only in final 4 positions (ignoring dash).\ ''', flags=TC_DELTA_MODE), + StoryMenuItem('Policy Unlock', "Adds (another?) Spending Policy unlock PIN.", flags=TC_FW_DEFINED, arg=TCA_SP_UNLOCK), + StoryMenuItem('Policy Unlock & Wipe' if version.has_qwerty else 'P.U. & Wipe', + "Pretends correct Spending Policy unlock PIN given, but silently wipes seed before asking for main PIN.", flags=TC_FW_DEFINED|TC_WIPE, arg=TCA_SP_UNLOCK), ] m = MenuSystem(FirstMenu) m.goto_idx(1) @@ -632,23 +671,31 @@ setting) the Coldcard will always brick after 13 failed PIN attempts.''') # xxxxxxxxxxxxxxxx MenuItem('[%s WRONG PIN]' % rel), StoryMenuItem('Wipe, Stop', "Seed is wiped and a message is shown.", - arg=num, flags=TC_WIPE), + arg=num, flags=TC_WIPE), StoryMenuItem('Wipe & Reboot', "Seed is wiped and Coldcard reboots without notice.", - arg=num, flags=TC_WIPE|TC_REBOOT), + arg=num, flags=TC_WIPE|TC_REBOOT), StoryMenuItem('Silent Wipe', "Seed is silently wiped and Coldcard acts as if PIN code was just wrong.", - arg=num, flags=TC_WIPE|TC_FAKE_OUT), - StoryMenuItem('Brick Self', "Become a brick instantly and forever.", flags=TC_BRICK, arg=num), - StoryMenuItem('Last Chance', "Wipe seed, then give one more try and then brick if wrong PIN.", arg=num, flags=TC_WIPE|TC_BRICK), - StoryMenuItem('Just Reboot', "Reboot when this happens. Doesn't do anything else.", arg=num, flags=TC_REBOOT), + arg=num, flags=TC_WIPE|TC_FAKE_OUT), + StoryMenuItem('Brick Self', "Become a brick instantly and forever.", + arg=num, flags=TC_BRICK,), + StoryMenuItem('Last Chance', "Wipe seed, then give one more try and then brick if wrong PIN.", + arg=num, flags=TC_WIPE|TC_BRICK), + StoryMenuItem('Just Reboot', "Reboot when this happens. Doesn't do anything else.", + arg=num, flags=TC_REBOOT), ]) m.goto_idx(1) the_ux.push(m) async def clear_all(self, m,l,item): + if not await ux_confirm("Remove ALL TRICK PIN codes and special wrong-pin handling?"): return + if tp.has_sp_unlock(): + if not await ux_confirm("You will not be able to bypass spending policy anymore."): + return + if any(tp.get_duress_pins()): if not await ux_confirm("Any funds on the duress wallet(s) have been moved already?"): return @@ -657,7 +704,7 @@ setting) the Coldcard will always brick after 13 failed PIN attempts.''') m.update_contents() async def hide_pin(self, m,l, item): - pin, slot_num, flags = item.arg + pin, slot_num, flags, arg = item.arg if flags & TC_DELTA_MODE: await ux_show_story('''Delta mode PIN will be hidden if trick PIN menu is shown \ @@ -665,12 +712,14 @@ to attacker, and we need to update this record if the main PIN is changed, so we hiding this item.''') return - if pin != WRONG_PIN_CODE: + if (flags == TC_FW_DEFINED) and (arg == TCA_SP_UNLOCK): + msg = "It will still be possible to change or disable the spending policy if this PIN is known." + elif pin == WRONG_PIN_CODE: + msg = "This will hide what happens with wrong PINs from the menus but it will still be in effect." + else: msg = '''This will hide the PIN from the menus but it will still be in effect. You can restore it by trying to re-add the same PIN (%s) again later.''' % pin - else: - msg = "This will hide what happens with wrong PINs from the menus but it will still be in effect." if not await ux_confirm(msg): return @@ -706,16 +755,20 @@ You can restore it by trying to re-add the same PIN (%s) again later.''' % pin self.pop_submenu() # too lazy to get redraw right except BaseException as exc: - sys.print_exception(exc) + # sys.print_exception(exc) await ux_show_story("Failed: %s" % exc) async def delete_pin(self, m,l, item): - pin, slot_num, flags = item.arg + pin, slot_num, flags, arg = item.arg if flags & (TC_WORD_WALLET | TC_XPRV_WALLET): if not await ux_confirm("Any funds on this duress wallet have been moved already?"): return + if (flags == TC_FW_DEFINED) and (arg == TCA_SP_UNLOCK): + if not await ux_confirm("Changes to the spending policy will not be possible anymore."): + return + if pin == WRONG_PIN_CODE: msg = "Remove special handling of wrong PINs?" else: @@ -743,11 +796,9 @@ You can restore it by trying to re-add the same PIN (%s) again later.''' % pin ch = await ux_show_story('''\ This will temporarily load the secrets associated with this trick wallet \ -so you may perform transactions with it. Reboot the Coldcard to restore \ -normal operation.''') +so you may perform transactions with it.''') if ch != 'y': return - from pincodes import pa, AE_SECRET_LEN b, slot = tp.get_by_pin(pin) assert slot @@ -771,7 +822,7 @@ normal operation.''') # switch over to new secret! dis.fullscreen("Applying...") - await set_ephemeral_seed(encoded, meta=name) + await set_ephemeral_seed(encoded, origin=name) goto_top_menu() async def countdown_details(self, m, l, item): @@ -784,7 +835,7 @@ normal operation.''') # "arg" can be out-of-date, if they edited timer value after parent was # rendered, where arg was captured into item.arg ... so don't use it. - cd_val = tp.tp[pin][2] + cd_val = tp.get_all()[pin][2] msg = 'Shows login countdown (%s)' % lgto_map.get(cd_val, '???').strip() if flags & TC_WIPE: @@ -800,16 +851,14 @@ normal operation.''') def adjust_countdown_chooser(): # 'disabled' choice not appropriate for this case - ch = lgto_ch[1:] va = lgto_va[1:] def set_it(idx, text): new_val = va[idx] # save it try: - b, slot = tp.update_slot(pin.encode(), tc_flags=flags, tc_arg=new_val) - except BaseException as exc: - sys.print_exception(exc) + tp.update_slot(pin.encode(), tc_flags=flags, tc_arg=new_val) + except: pass return va.index(cd_val), lgto_ch[1:], set_it @@ -833,7 +882,8 @@ Wallet is XPRV-based and derived from a fixed path.''' % pin if ch != '6': return b, s = tp.get_by_pin(pin) - if s == None: + if s is None: + title = None # could not find in SE2. Our settings vs. SE2 are not in sync. msg = "Not found in SE2. Delete and remake." else: @@ -845,21 +895,22 @@ Wallet is XPRV-based and derived from a fixed path.''' % pin ch, pk = s.xdata[0:32], s.xdata[32:64] node.from_chaincode_privkey(ch, pk) - msg, *_ = render_master_secrets('xprv', None, node) + title, msg, *_ = render_master_secrets('xprv', None, node) elif flags & TC_WORD_WALLET: raw = s.xdata[0:(32 if nwords == 24 else 16)] - msg, *_ = render_master_secrets('words', raw, None) + title, msg, *_ = render_master_secrets('words', raw, None) else: raise ValueError(hex(flags)) - await ux_show_story(msg, sensitive=True) + await ux_show_story(msg, title=title, sensitive=True) async def pin_submenu(self, menu, label, item): # drill down into a sub-menu per existing PIN # - data display only, no editing; just clear and redo pin = item.arg - slot_num, flags, arg = tp.tp[pin] if (pin in tp.tp) else (-1, 0, 0) + t_pins = tp.get_all() + slot_num, flags, arg = t_pins[pin] if (pin in t_pins) else (-1, 0, 0) rv = [] @@ -878,6 +929,8 @@ Wallet is XPRV-based and derived from a fixed path.''' % pin rv.append(MenuItem("↳Pretends Wrong")) elif flags & TC_DELTA_MODE: rv.append(MenuItem("↳Delta Mode")) + elif (flags & TC_FW_DEFINED) and (arg == TCA_SP_UNLOCK): + rv.append(MenuItem("↳Unlock Policy")) # width issues on Mk4 for m, msg in [ (TC_WIPE, '↳Wipes seed'), @@ -891,8 +944,8 @@ Wallet is XPRV-based and derived from a fixed path.''' % pin rv.append(MenuItem("Activate Wallet", f=self.activate_wallet, arg=(pin, flags, arg))) rv.extend([ - MenuItem('Hide Trick', f=self.hide_pin, arg=(pin, slot_num, flags)), - MenuItem('Delete Trick', f=self.delete_pin, arg=(pin, slot_num, flags)), + MenuItem('Hide Trick', f=self.hide_pin, arg=(pin, slot_num, flags, arg)), + MenuItem('Delete Trick', f=self.delete_pin, arg=(pin, slot_num, flags, arg)), ]) if pin != WRONG_PIN_CODE: rv.append( @@ -903,6 +956,7 @@ Wallet is XPRV-based and derived from a fixed path.''' % pin class StoryMenuItem(MenuItem): def __init__(self, label, story, flags=0, **kws): + # arg= .. handled by super self.story = story self.flags = flags super().__init__(label, **kws) diff --git a/shared/usb.py b/shared/usb.py index 7158f7dd..fd4d6a41 100644 --- a/shared/usb.py +++ b/shared/usb.py @@ -2,16 +2,17 @@ # # usb.py - USB related things # -import ckcc, pyb, callgate, sys, ux, ngu, stash, aes256ctr +import ckcc, pyb, callgate, sys, ux, ngu, stash, aes256ctr, ujson from uasyncio import sleep_ms, core from uhashlib import sha256 -from public_constants import MAX_MSG_LEN, MAX_BLK_LEN, AFC_SCRIPT +from public_constants import MAX_MSG_LEN, MAX_BLK_LEN from public_constants import STXN_FLAGS_MASK from ustruct import pack, unpack_from from ckcc import watchpoint, is_simulator from utils import problem_file_line, call_later_ms from version import supports_hsm, is_devmode, MAX_TXN_LEN, MAX_UPLOAD_LEN -from exceptions import FramingError, CCBusyError, HSMDenied, HSMCMDDisabled +from exceptions import FramingError, CCBusyError, HSMDenied, HSMCMDDisabled, SpendPolicyViolation +from pincodes import pa # Unofficial, unpermissioned... numbers COINKITE_VID = 0xd13e @@ -52,8 +53,8 @@ HSM_WHITELIST = frozenset({ 'smsg', # limited by policy 'blkc', 'hsts', # report status values 'stok', 'smok', # completion check: sign txn or msg - 'xpub', 'msck', # quick status checks - 'p2sh', 'show', 'msas', # limited by HSM policy + 'xpub', # quick status checks + 'show', 'msas', # limited by HSM policy 'user', # auth HSM user, other user cmds not allowed 'gslr', # read storage locker; hsm mode only, limited usage }) @@ -68,6 +69,21 @@ HSM_DISABLE_CMDS = frozenset({ "hsms", }) +# spending policy active: blacklist some commands +# - 'pass' may be allowed if 'okeys' is enabled +HOBBLED_CMDS = frozenset({ + 'enrl', # no new multisigs during policy enforcement + 'back', # no backups + 'bagi', 'dfu_', # just in case + + "user", # same as HSM_DISABLE_CMDS + "rmur", + "nwur", + "gslr", + "hsts", + "hsms", +}) + # singleton instance of USBHandler() handler = None @@ -117,6 +133,16 @@ def is_vcp_active(): return cur and ('VCP' in cur) and en + +def get_miniscript_by_name(name_bytes): + from wallet import MiniScriptWallet + + for w in MiniScriptWallet.iter_wallets(): + if w.name == str(name_bytes, 'ascii'): + return True, w + else: + return False, b'err_Miniscript wallet not found' + class USBHandler: def __init__(self): self.dev = pyb.USB_HID() @@ -169,6 +195,7 @@ class USBHandler: msg_len = 0 while 1: + success = False yield core._io_queue.queue_read(self.blockable) try: @@ -212,14 +239,14 @@ class USBHandler: # this saves memory over a simple slice (confirmed) args = memoryview(self.msg)[4:msg_len] resp = await self.handle(self.msg[0:4], args) - msg_len = 0 + success = True except CCBusyError: # auth UX is doing something else resp = b'busy' - msg_len = 0 + except SpendPolicyViolation: + resp = b'err_Spending policy in effect' except HSMDenied: resp = b'err_Not allowed in HSM mode' - msg_len = 0 except HSMCMDDisabled: # do NOT change below error msg as other applications depend on it resp = b'err_HSM commands disabled' @@ -227,16 +254,14 @@ class USBHandler: except (ValueError, AssertionError) as exc: # some limited invalid args feedback #print("USB request caused assert: ", end='') - #sys.print_exception(exc) + # sys.print_exception(exc) msg = str(exc) if not msg: msg = 'Assertion ' + problem_file_line(exc) resp = b'err_' + msg.encode()[0:80] - msg_len = 0 except MemoryError: # prefer to catch at higher layers, but sometimes can't resp = b'err_Out of RAM' - msg_len = 0 except FramingError as exc: raise exc except Exception as exc: @@ -245,9 +270,15 @@ class USBHandler: print("USB request caused this: ", end='') sys.print_exception(exc) resp = b'err_Confused ' + problem_file_line(exc) - msg_len = 0 - # aways send a reply if they get this far + if not success: + # do not let the progress screen hang on "Receiving..." + from ux import restore_menu + restore_menu() + + msg_len = 0 + + # always send a reply if they get this far await self.send_response(resp) except FramingError as exc: @@ -342,7 +373,7 @@ class USBHandler: except: raise FramingError('decode') - if cmd[0].isupper() and is_devmode: + if is_devmode and cmd[0].isupper(): # special hacky commands to support testing w/ the simulator try: from usb_test_commands import do_usb_command @@ -355,7 +386,18 @@ class USBHandler: if cmd not in HSM_WHITELIST: raise HSMDenied - if not settings.get('hsmcmd', False): + if pa.hobbled_mode: + # block some commands when we are hobbled. + if cmd in HOBBLED_CMDS: + raise SpendPolicyViolation + + if cmd in {'pwok', 'pass'}: + from ccc import sssp_spending_policy + if not sssp_spending_policy('okeys'): + raise SpendPolicyViolation + + elif not settings.get('hsmcmd', False): + # block these HSM-related command if not using feature if cmd in HSM_DISABLE_CMDS: raise HSMCMDDisabled @@ -432,39 +474,6 @@ class USBHandler: sign_msg(msg, subpath, addr_fmt) return None - if cmd == 'p2sh': - # show P2SH (probably multisig) address on screen (also provides it back) - # - must provide redeem script, and list of [xfp+path] - from auth import start_show_p2sh_address - - if hsm_active and not hsm_active.approve_address_share(is_p2sh=True): - raise HSMDenied - - # new multsig goodness, needs mapping from xfp->path and M values - addr_fmt, M, N, script_len = unpack_from(' reboot and try login again + # - default is logout and (if applicable) power down. + import callgate # save if anything pending from glob import settings @@ -469,36 +461,49 @@ def clean_shutdown(style=0): callgate.show_logout(style) def call_later_ms(delay, cb, *args, **kws): - import uasyncio - async def doit(): await uasyncio.sleep_ms(delay) await cb(*args, **kws) uasyncio.create_task(doit()) -def txtlen(s): - # width of string in chars, accounting for - # double-wide characters which happen on Q. - rv = len(s) - - if DOUBLE_WIDE: - rv += sum(1 for ch in s if ch in DOUBLE_WIDE) - - return rv def word_wrap(ln, w): # Generate the lines needed to wrap one line into X "width"-long lines. # - tests in testing/test_unit.py - - if txtlen(ln) <= w: - yield ln + if ln and (ln[0] == OUT_CTRL_NOWRAP): + # no need to wrap this line - as requested by caller + yield ln[1:] return - while ln: - # find a space in (width) first part of remainder - sp = ln.rfind(' ', 0, w-1) - if sp == -1: + while True: + # ln_len considers DOUBLE_WIDTH chars + ln_len = 0 + sp = None + for idx, ch in enumerate(ln): + if ch == ' ': + # split point on space if possible + sp = idx + + ln_len += 1 + if ch in DOUBLE_WIDE: + ln_len += 1 + + if ln_len > w: + # if one of .,:; is last -> allow one more character + # even if only half visible on Mk4 + # on Q it's OK as (CHARS_W-1) is used as w + if ch in ".,:;": + idx += 1 + sp = None + + break + + else: + yield ln + return + + if sp is None: if ln[0] == OUT_CTRL_ADDRESS: # special handling for lines w/ payment address in them # - add same marker to newly split lines @@ -514,70 +519,29 @@ def word_wrap(ln, w): return # bad-break the line - sp = min(txtlen(ln), w) - nsp = sp - if ln[nsp:nsp+1] == ' ': + sp = nsp = idx + if ln[sp:nsp+1] == " ": nsp += 1 else: # split on found space nsp = sp+1 left = ln[0:sp] - ln = ln[nsp:] - - if txtlen(left) + 1 + txtlen(ln) <= w: - # not clear when this would happen? final bit?? - left = left + ' ' + ln - ln = '' - yield left + ln = ln[nsp:] + if not ln: return -def parse_extended_key(ln, private=False): - # read an xpub/ypub/etc and return BIP-32 node and what chain it's on. - # - can handle any garbage line - # - returns (node, chain, addr_fmt) - # - people are using SLIP132 so we need this - node, chain, addr_fmt = None, None, None - if ln is None: - return node, chain, addr_fmt - - ln = ln.strip() - if private: - rgx = r'.prv[A-Za-z0-9]+' - else: - rgx = r'.pub[A-Za-z0-9]+' - - pat = ure.compile(rgx) - found = pat.search(ln) - # serialize, and note version code - try: - node, chain, addr_fmt, is_private = chains.slip32_deserialize(found.group(0)) - except: - pass - - return node, chain, addr_fmt - -def chunk_writer(fd, body): - from glob import dis - dis.fullscreen("Saving...") - body_len = len(body) - chunk = body_len // 10 - for idx, i in enumerate(range(0, body_len, chunk)): - fd.write(body[i:i + chunk]) - dis.progress_bar_show(idx / 10) - dis.progress_bar_show(1) - - -def pad_raw_secret(raw_sec_str): +def deserialize_secret(text_sec_str): # Chip can hold 72-bytes as a secret - # every secret has 0th byte as marker - # then secret and padded to zero to AE_SECRET_LEN + # - has 0th byte as marker, secret and zero padding to AE_SECRET_LEN + # - also does hex to binary conversion + # - converse of: SecretStash.storage_serialize() from pincodes import AE_SECRET_LEN raw = bytearray(AE_SECRET_LEN) - if len(raw_sec_str) % 2: - raw_sec_str += '0' - x = a2b_hex(raw_sec_str) + if len(text_sec_str) % 2: + text_sec_str += '0' + x = a2b_hex(text_sec_str) raw[0:len(x)] = x return raw @@ -626,7 +590,7 @@ def txid_from_fname(fname): except: pass return None -def url_decode(u): +def url_unquote(u): # expand control chars from %XX and '+' # - equiv to urllib.parse.unquote_plus # - ure.sub is missing, so not being clever here. @@ -646,29 +610,38 @@ def url_decode(u): return u +def url_quote(u): + # convert non-text chars into %hex for URL usage + # - urllib.parse.quote() but w/o as much thought + return ''.join( (ch if 33 <= ord(ch) <= 127 else '%%%02x' % ord(ch)) \ + for ch in u) + def decode_bip21_text(got): # Assume text is a BIP-21 payment address (url), with amount, description # and url protocol prefix ... all optional except the address. # - also will detect correctly encoded & checksummed xpubs + # - always verifies checksum of data it finds proto, args, addr = None, None, None - # remove URL protocol: if present - if ':' in got: - proto, got = got.split(':', 1) - + # remove query params first - if any # looks like BIP-21 payment URL if '?' in got: - addr, args = got.split('?', 1) + got, args = got.split('?', 1) # full URL decode here, but assuming no repeated keys parts = args.split('&') args = dict() for p in parts: k, v = p.split('=', 1) - args[k] = url_decode(v) + args[k] = url_unquote(v) - # assume it's an bare address for now + # remove URL protocol: if present + if ':' in got: + proto, got = got.split(':', 1) + assert proto.lower() == "bitcoin" + + # assume it's a bare address for now if not addr: addr = got @@ -676,10 +649,12 @@ def decode_bip21_text(got): try: raw = ngu.codecs.b58_decode(addr) - # it's valid base58 - # an address, P2PKH or xpub (xprv checked above) + # It's valid base58: could be + # an address, P2PKH or xpub/xprv if addr[1:4] == 'pub': return 'xpub', (addr,) + if addr[1:4] == 'prv': + return 'xprv', (addr,) return 'addr', (proto, addr, args) except: @@ -694,87 +669,6 @@ def decode_bip21_text(got): raise ValueError('not bip-21') -def check_xpub(xfp, xpub, deriv, expect_chain, my_xfp, disable_checks=False): - # Shared code: consider an xpub for inclusion into a wallet - # return T if it's our own key and parsed details in form (xfp, deriv, xpub) - # - deriv can be None, and in very limited cases can recover derivation path - # - could enforce all same depth, and/or all depth >= 1, but - # seems like more restrictive than needed, so "m" is allowed - import stash - from public_constants import AF_P2SH - try: - # Note: addr fmt detected here via SLIP-132 isn't useful - node, chain, _ = parse_extended_key(xpub) - except: - raise AssertionError('unable to parse xpub') - - try: - assert node.privkey() == None # 'no privkeys plz' - except ValueError: - pass - - if expect_chain == "XRT": - # HACK but there is no difference extended_keys - just bech32 hrp - assert chain.ctype == "XTN" - else: - assert chain.ctype == expect_chain, 'wrong chain' - - depth = node.depth() - - if depth == 1: - if not xfp: - # allow a shortcut: zero/omit xfp => use observed parent value - xfp = swab32(node.parent_fp()) - else: - # generally cannot check fingerprint values, but if we can, do so. - if not disable_checks: - assert swab32(node.parent_fp()) == xfp, 'xfp depth=1 wrong' - - assert xfp, 'need fingerprint' # happens if bare xpub given - - # In most cases, we cannot verify the derivation path because it's hardened - # and we know none of the private keys involved. - if depth == 1: - # but derivation is implied at depth==1 - kn, is_hard = node.child_number() - if is_hard: kn |= 0x80000000 - guess = keypath_to_str([kn], skip=0) - - if deriv: - if not disable_checks: - assert guess == deriv, '%s != %s' % (guess, deriv) - else: - deriv = guess # reachable? doubt it - - assert deriv, 'empty deriv' # or force to be 'm'? - assert deriv[0] == 'm' - - # path length of derivation given needs to match xpub's depth - if not disable_checks: - p_len = deriv.count('/') - if p_len: - # only check this for keys that have origin derivation - # originless keys are expected to be blinded - assert p_len == depth, 'deriv %d != %d xpub depth (xfp=%s)' % ( - p_len, depth, xfp2str(xfp) - ) - else: - # depth can be more than zero here - keys can be blinded - assert xfp == swab32(node.my_fp()), "xpub xfp wrong %s" % xfp2str(xfp) - - if xfp == my_xfp: - # it's supposed to be my key, so I should be able to generate pubkey - # - might indicate collision on xfp value between co-signers, - # and that's not supported - with stash.SensitiveValues() as sv: - chk_node = sv.derive_path(deriv) - assert node.pubkey() == chk_node.pubkey(), \ - "[%s/%s] wrong pubkey" % (xfp2str(xfp), deriv[2:]) - - # serialize xpub w/ BIP-32 standard now. - # - this has effect of stripping SLIP-132 confusion away - return xfp == my_xfp, (xfp, deriv, chain.serialize_public(node, AF_P2SH)) - def encode_seed_qr(words): return ''.join('%04d' % bip39.get_word_index(w) for w in words) @@ -787,4 +681,65 @@ def chunk_address(addr): # useful to show payment addresses specially return [addr[i:i+4] for i in range(0, len(addr), 4)] +def cleanup_payment_address(s): + # Cleanup a payment address, or raise if bad checksum + # - later matching is string-based, so just doing basic syntax check here + # - must be checksumed-base58 or bech32 + try: + ngu.codecs.b58_decode(s) + assert len(s) < 40 # or else it's an xpub/xprv + return s + except: pass + + try: + ngu.codecs.segwit_decode(s) + return s.lower() + except: pass + + raise ValueError('bad address value: ' + s) + +def truncate_address(addr): + # Truncates address to width of screen, replacing middle chars + if not version.has_qwerty: + # - 16 chars screen width + # - but 2 lost at left (menu arrow, corner arrow) + # - want to show not truncated on right side + return addr[0:6] + '⋯' + addr[-6:] + else: + # tons of space on Q1 + return addr[0:12] + '⋯' + addr[-12:] + +def wipe_if_deltamode(): + # If in deltamode, give up and wipe self rather do + # a thing that might reveal true master secret... + from pincodes import pa + + if pa.is_deltamode(): + import callgate + callgate.fast_wipe() + +def chunk_checksum(fd, chunk=1024): + # reads from open file descriptor + md = sha256() + while True: + data = fd.read(chunk) + if not data: + break + md.update(data) + + return md.digest() + +def xor(*args): + # bit-wise xor between all args + vlen = len(args[0]) + # all have to be same length + assert all(len(e) == vlen for e in args) + rv = bytearray(vlen) + + for i in range(vlen): + for a in args: + rv[i] ^= a[i] + + return rv + # EOF diff --git a/shared/ux.py b/shared/ux.py index fe1cd4dd..36646ee6 100644 --- a/shared/ux.py +++ b/shared/ux.py @@ -6,8 +6,9 @@ from uasyncio import sleep_ms from queues import QueueEmpty import utime, gc, version from utils import word_wrap -from charcodes import (KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN, KEY_HOME, KEY_NFC, KEY_QR, - KEY_END, KEY_PAGE_UP, KEY_PAGE_DOWN, KEY_ENTER, KEY_CANCEL, OUT_CTRL_TITLE) +from version import has_qwerty, num_sd_slots, has_qr +from charcodes import (KEY_UP, KEY_DOWN, KEY_HOME, KEY_NFC, KEY_QR, KEY_END, KEY_PAGE_UP, + KEY_PAGE_DOWN, KEY_ENTER, KEY_CANCEL, OUT_CTRL_TITLE) from exceptions import AbortInteraction @@ -16,21 +17,24 @@ DEFAULT_IDLE_TIMEOUT = const(4*3600) # (seconds) 4 hours # See ux_mk or ux_q1 for some display functions now if version.has_qwerty: from lcd_display import CHARS_W, CHARS_H - CH_PER_W = CHARS_W + # stories look nicer if we do not use the whole width + CH_PER_W = (CHARS_W - 1) STORY_H = CHARS_H - from ux_q1 import PressRelease, ux_enter_number, ux_input_numbers, ux_input_text, ux_show_pin - from ux_q1 import ux_login_countdown, ux_confirm, ux_dice_rolling, ux_render_words + from ux_q1 import PressRelease, ux_enter_number, ux_input_text, ux_show_pin + from ux_q1 import ux_login_countdown, ux_dice_rolling, ux_render_words from ux_q1 import ux_show_phish_words OK = "ENTER" X = "CANCEL" else: # How many characters can we fit on each line? How many lines? - # (using FontSmall) + # (using FontSmall) .. except it's an approximation since variable-width font. + # - 18 can work but rightmost spot is half-width. We allow . and , in that spot. + # - really should look at rendered-width of text CH_PER_W = 17 STORY_H = 5 - from ux_mk4 import PressRelease, ux_enter_number, ux_input_numbers, ux_input_text, ux_show_pin - from ux_mk4 import ux_login_countdown, ux_confirm, ux_dice_rolling, ux_render_words + from ux_mk4 import PressRelease, ux_enter_number, ux_input_text, ux_show_pin + from ux_mk4 import ux_login_countdown, ux_dice_rolling, ux_render_words from ux_mk4 import ux_show_phish_words OK = "OK" X = "X" @@ -170,7 +174,6 @@ def ux_poll_key(): return ch - async def ux_show_story(msg, title=None, escape=None, sensitive=False, strict_escape=False, hint_icons=None): # show a big long string, and wait for XY to continue @@ -246,7 +249,21 @@ async def ux_show_story(msg, title=None, escape=None, sensitive=False, if ch in { KEY_NFC, KEY_QR }: return ch - +async def ux_confirm(msg, title="Are you SURE ?!?", confirm_key=None): + # confirmation screen, with stock title and Y=of course. + if not version.has_qwerty and len(title) > 12: + msg = title + "\n\n" + msg + title = None + + suffix = "" + if confirm_key: + suffix = ("\n\nPress (%s) to prove you read to the end of this message" + " and accept all consequences.") % confirm_key + + msg += suffix + r = await ux_show_story(msg, title=title, escape=confirm_key) + + return r == (confirm_key or 'y') async def idle_logout(): import glob @@ -341,7 +358,6 @@ async def ux_enter_bip32_index(prompt, can_cancel=False, unlimited=False): return await ux_enter_number(prompt=prompt, max_value=max_value, can_cancel=can_cancel) def _import_prompt_builder(title, no_qr, no_nfc, slot_b_only=False): - from version import has_qwerty, num_sd_slots, has_qr from glob import NFC, VD prompt, escape = None, KEY_CANCEL+"x" @@ -377,16 +393,15 @@ def _import_prompt_builder(title, no_qr, no_nfc, slot_b_only=False): return prompt, escape -def export_prompt_builder(what_it_is, no_qr=False, no_nfc=False, key0=None, - force_prompt=False): +def export_prompt_builder(what_it_is, no_qr=False, no_nfc=False, key0=None, offer_kt=False, + force_prompt=False, txid=None): # Build the prompt for export # - key0 can be for special stuff - from version import has_qwerty, num_sd_slots, has_qr from glob import NFC, VD prompt, escape = None, KEY_CANCEL+"x" - if (NFC or VD) or (num_sd_slots>1) or key0 or force_prompt: + if (NFC or VD) or (num_sd_slots>1) or key0 or force_prompt or offer_kt or txid or (not no_qr): # no need to spam with another prompt, only option is SD card prompt = "Press (1) to save %s to SD Card" % what_it_is @@ -416,6 +431,14 @@ def export_prompt_builder(what_it_is, no_qr=False, no_nfc=False, key0=None, prompt += ", (4) to show QR code" escape += '4' + if txid: + prompt += ", (6) for QR Code of TXID" + escape += "6" + + if offer_kt: + prompt += ", (T) to " + offer_kt + escape += 't' + if key0: prompt += ', (0) ' + key0 escape += '0' @@ -457,18 +480,22 @@ def import_export_prompt_decode(ch): async def import_export_prompt(what_it_is, is_import=False, no_qr=False, no_nfc=False, title=None, intro='', footnotes='', - slot_b_only=False, force_prompt=False): + offer_kt=False, slot_b_only=False, force_prompt=False, + txid=None): + # Show story allowing user to select source for importing/exporting # - return either str(mode) OR dict(file_args) # - KEY_NFC or KEY_QR for those sources # - KEY_CANCEL for abort by user # - dict() => do file system thing, using file_args to control vdisk vs. SD vs slot_b + # - 't' => key teleport, but only offered with offer_kt is set (contetxt, and Q only) + from glob import NFC if is_import: prompt, escape = _import_prompt_builder(what_it_is, no_qr, no_nfc, slot_b_only) else: - prompt, escape = export_prompt_builder(what_it_is, no_qr, no_nfc, - force_prompt=force_prompt) + prompt, escape = export_prompt_builder(what_it_is, no_qr, no_nfc, txid=txid, + force_prompt=force_prompt, offer_kt=offer_kt) # TODO: detect if we're only asking A or B, when just one card is inserted # - assume that's what they want to do @@ -478,8 +505,10 @@ async def import_export_prompt(what_it_is, is_import=False, no_qr=False, # they don't have NFC nor VD enabled, and no second slots... so will be file. return dict(force_vdisk=False, slot_b=None) else: - ch = await ux_show_story(intro+prompt+footnotes, escape=escape, title=title, - strict_escape=True) + hints = ("" if no_qr else KEY_QR) + (KEY_NFC if not no_nfc and NFC else "") + msg_lst = [i for i in (intro, prompt, footnotes) if i] + ch = await ux_show_story("\n\n".join(msg_lst), escape=escape, title=title, + strict_escape=True, hint_icons=hints) return import_export_prompt_decode(ch) diff --git a/shared/ux_mk4.py b/shared/ux_mk4.py index 5ebcd2ea..feb37ad2 100644 --- a/shared/ux_mk4.py +++ b/shared/ux_mk4.py @@ -58,17 +58,9 @@ class PressRelease: else: self.last_key = ch return ch - - -async def ux_confirm(msg): - # confirmation screen, with stock title and Y=of course. - from ux import ux_show_story - resp = await ux_show_story("Are you SURE ?!?\n\n" + msg) - return resp == 'y' - -async def ux_enter_number(prompt, max_value, can_cancel=False): +async def ux_enter_number(prompt, max_value, can_cancel=False, value=''): # return the decimal number which the user has entered # - default/blank value assumed to be zero # - clamps large values to the max @@ -80,7 +72,7 @@ async def ux_enter_number(prompt, max_value, can_cancel=False): press = PressRelease('1234567890y') y = 26 - value = '' + value = str(value) max_w = int(log(max_value, 10) + 1) dis.clear() @@ -122,8 +114,8 @@ async def ux_enter_number(prompt, max_value, can_cancel=False): # cleanup leading zeros and such value = str(min(int(value), max_value)) -async def ux_input_numbers(val): - # collect a series of digits +async def ux_input_digits(val, prompt=None, maxlen=32): + # collect a series of digits. from glob import dis from display import FontTiny @@ -137,6 +129,11 @@ async def ux_input_numbers(val): dis.clear() dis.text(None, -1, footer, FontTiny) + + if prompt: + dis.text(0, 0, prompt) + y += 8 + dis.save() while 1: @@ -169,7 +166,7 @@ async def ux_input_numbers(val): # quit if they press X on empty screen return else: - if len(here) < 32: + if len(here) < maxlen: here += ch async def ux_input_text(pw, confirm_exit=True, hex_only=False, max_len=100, min_len=0, **_kws): @@ -286,7 +283,7 @@ async def ux_input_text(pw, confirm_exit=True, hex_only=False, max_len=100, min_ ch = await press.wait() if ch == 'y': if len(pw) < min_len: - ch = await ux_show_story('Need %d characters at least. Press OK ' + ch = await ux_show_story('Need %d character(s) at least. Press OK ' 'to continue X to exit.' % min_len, escape="xy", strict_escape=True) if ch == "x": return diff --git a/shared/ux_q1.py b/shared/ux_q1.py index eaac2011..1d98a841 100644 --- a/shared/ux_q1.py +++ b/shared/ux_q1.py @@ -2,16 +2,14 @@ # # ux_q1.py - UX/UI interactions that are Q1 specific and use big screen, keyboard. # -import utime, gc, ngu, sys, chains +import utime, gc, ngu, sys, bip39 import uasyncio as asyncio from uasyncio import sleep_ms from charcodes import * from lcd_display import CHARS_W, CHARS_H, CursorSpec, CURSOR_SOLID, CURSOR_OUTLINE from exceptions import AbortInteraction, QRDecodeExplained -import bip39 from decoders import decode_qr_result from ubinascii import hexlify as b2a_hex -from ubinascii import unhexlify as a2b_hex from ubinascii import b2a_base64 from utils import problem_file_line, show_single_address @@ -77,16 +75,8 @@ class PressRelease: else: self.last_key = ch return ch - -async def ux_confirm(msg): - # confirmation screen, with stock title and Y=of course. - from ux import ux_show_story - resp = await ux_show_story(msg, title="Are you SURE ?!?") - - return resp == 'y' - -async def ux_enter_number(prompt, max_value, can_cancel=False): +async def ux_enter_number(prompt, max_value, can_cancel=False, value=''): # return the decimal number which the user has entered # - default/blank value assumed to be zero # - clamps large values to the max @@ -96,7 +86,7 @@ async def ux_enter_number(prompt, max_value, can_cancel=False): # allow key repeat on X only? press = PressRelease() - value = '' + value = str(value) max_w = int(log(max_value, 10) + 1) dis.clear() @@ -125,6 +115,7 @@ async def ux_enter_number(prompt, max_value, can_cancel=False): elif ch == KEY_DELETE: if value: value = value[0:-1] + dis.text(0, 4, ' '*CHARS_W) elif ch == KEY_CLEAR: value = '' dis.text(0, 4, ' '*CHARS_W) @@ -141,11 +132,6 @@ async def ux_enter_number(prompt, max_value, can_cancel=False): # cleanup leading zeros and such value = str(min(int(value), max_value)) -async def ux_input_numbers(val): - # collect a series of digits - # - not wanted on Q1; just get the digits mixed in w/ the text. - pass - async def ux_input_text(value, confirm_exit=False, hex_only=False, max_len=100, prompt='Enter value', min_len=0, b39_complete=False, scan_ok=False, placeholder=None, funct_keys=None, force_xy=None): @@ -543,23 +529,22 @@ async def ux_login_countdown(sec): dis.busy_bar(0) -def ux_render_words(words, leading_blanks=1): +def ux_render_words(words, leading_blanks=0): # re-use word-list rendering code to show as a string in a story. # - because I want them all on-screen at once, and not simple to do that - buf = [bytearray(CHARS_W) for y in range(CHARS_H)] - rv = [''] * leading_blanks num_words = len(words) if num_words == 12: for y in range(6): + # no need to use NOWRAP here, will always fit (2 word columns) rv.append('%2d: %-8s %2d: %s' % (y+1, words[y], y+7, words[y+6])) else: lines = 6 if num_words == 18 else 8 for y in range(lines): - rv.append('%d:%-8s %2d:%-8s %2d:%s' % (y+1, words[y], - y+lines+1, words[y+lines], - y+(lines*2)+1, words[y+(lines*2)])) + rv.append(OUT_CTRL_NOWRAP+'%d:%-8s %2d:%-8s %2d:%s' % ( + y+1, words[y], y+lines+1, words[y+lines], + y+(lines*2)+1, words[y+(lines*2)])) return '\n'.join(rv) @@ -568,10 +553,21 @@ def ux_draw_words(y, num_words, words): # Draw seed words on single screen (hard) and return x/y position of start of each from glob import dis + if num_words == 2: + # simple version for first & last words, used only during login to spending policy + X = 14 + Y = y+1 + dis.text(X-7, Y, 'FIRST: %s' % words[0]) + dis.text(X-4, Y+1, '⋯') + dis.text(X-6, Y+2, 'LAST: %s' % words[-1]) + + return [ (X, Y), (X, Y+2) ] + if num_words == 12: cols = 2 xpos = [2, 18] else: + assert num_words in (18, 24) cols = 3 xpos = [0, 11, 23] @@ -598,14 +594,17 @@ def ux_draw_words(y, num_words, words): return rv -async def seed_word_entry(prompt, num_words, has_checksum=True, done_cb=None): +async def seed_word_entry(prompt, num_words, has_checksum=True, done_cb=None, line2=None): # Accept a seed phrase, only # - replaces WordNestMenu on Q1 # - max word length is 8, min is 3 # - useful: simulator.py --q1 --eff --seq 'aa ee 4i ' from glob import dis + from ux import ux_confirm - assert num_words and prompt and done_cb + assert num_words and prompt + + not24 = (num_words != 24) def redraw_words(wrds=None): if not wrds: @@ -613,7 +612,15 @@ async def seed_word_entry(prompt, num_words, has_checksum=True, done_cb=None): dis.clear() dis.text(None, 0, prompt, invert=1) - p = ux_draw_words(2 if num_words != 24 else 1, num_words, wrds) + + Y = 2 if not24 else 1 + if line2 and not24: + # add second line, if provided, but only if words length < 24 + # currently only used to show backup filename during backup pwd entry + dis.text(None, 1, line2, invert=1) + Y += 1 + + p = ux_draw_words(Y, num_words, wrds) return wrds, p words, pos = redraw_words() @@ -695,8 +702,7 @@ async def seed_word_entry(prompt, num_words, has_checksum=True, done_cb=None): elif ch == KEY_CANCEL: if word_num >= 2: tmp = dis.save_state() - ok = await ux_confirm("Everything you've entered will be lost.") - if not ok: + if not await ux_confirm("Everything you've entered will be lost."): dis.restore_state(tmp) continue return None @@ -717,7 +723,7 @@ async def seed_word_entry(prompt, num_words, has_checksum=True, done_cb=None): maybe = [i for i in last_words if i.startswith(value)] if len(maybe) == 1: value = maybe[0] - elif len(maybe) == 0: + elif not maybe: if len(last_words) == 8: # 24 words case ll = ''.join(sorted(set([w[0] for w in last_words]))) err_msg = 'Final word starts with: ' + ll @@ -764,7 +770,10 @@ async def seed_word_entry(prompt, num_words, has_checksum=True, done_cb=None): else: err_msg = 'Next key: ' + nextchars - await done_cb(words) + if done_cb: + await done_cb(words) + + return words def ux_dice_rolling(): from glob import dis @@ -791,7 +800,7 @@ class QRScannerInteraction: pass @staticmethod - async def scan(prompt, line2=None): + async def scan(prompt, line2=None, enter_quits=False): # draw animation, while waiting for them to scan something # - CANCEL to abort # - returns a string, BBQr object or None. @@ -810,6 +819,8 @@ class QRScannerInteraction: task = asyncio.create_task(SCAN.scan_once()) + escape = KEY_CANCEL + (KEY_ENTER if enter_quits else '') + ph = 0 while 1: if task.done(): @@ -821,9 +832,9 @@ class QRScannerInteraction: ph = (ph + 1) % len(frames) # wait for key or 250ms animation delay - ch = await ux_wait_keydown(KEY_CANCEL, 250) + ch = await ux_wait_keydown(escape, 250) - if ch == KEY_CANCEL: + if ch and (ch in escape): data = None break @@ -835,14 +846,14 @@ class QRScannerInteraction: return data - async def scan_general(self, prompt, convertor): + async def scan_general(self, prompt, convertor, line2=None, enter_quits=False): # Scan stuff, and parse it .. raise QRDecodeExplained if you don't like it # continues until something is accepted - problem = None + problem = line2 while 1: try: - got = await self.scan(prompt, line2=problem) + got = await self.scan(prompt, line2=problem, enter_quits=enter_quits) if got is None: return None @@ -852,7 +863,7 @@ class QRScannerInteraction: problem = str(exc) continue except Exception as exc: - #import sys; sys.print_exception(exc) + # import sys; sys.print_exception(exc) problem = "Unable to decode QR" continue @@ -882,9 +893,37 @@ class QRScannerInteraction: return await self.scan_general(prompt, convertor) + async def scan_for_addresses(self, prompt, line2=None): + # accept only payment addresses; strips BIP-21 junk that might be there + # - always a list result, might be size one + from utils import decode_bip21_text - async def scan_anything(self, expect_secret=False, tmp=False): + def addr_taster(got): + # could be muliple-line text file via BBQR or single line + got = decode_qr_result(got, expect_text=True) + + try: + rv = [] + for ln in got.split(): + what, args = decode_bip21_text(ln) + if what == 'addr': + rv.append(args[1]) + if rv: + return rv + except QRDecodeExplained: + raise + except: + pass + raise QRDecodeExplained("Not a payment address?") + + return await self.scan_general(prompt, addr_taster, line2=line2, enter_quits=True) + + + async def scan_anything(self, expect_secret=False, tmp=False, miniscript_wallet=None): # start a QR scan, and act on what we find, whatever it may be. + from ux import ux_show_story + from pincodes import pa + problem = None while 1: prompt = 'Scan any QR code, or CANCEL' if not expect_secret else \ @@ -897,104 +936,113 @@ class QRScannerInteraction: # Figure out what we got. what, vals = decode_qr_result(got, expect_secret=expect_secret) + break except QRDecodeExplained as exc: problem = str(exc) continue - except Exception as exc: - import sys; sys.print_exception(exc) + except Exception: + # import sys; sys.print_exception(exc) problem = "Unable to decode QR" continue - if what == 'xprv': - from actions import import_extended_key_as_secret - text_xprv, = vals - await import_extended_key_as_secret(text_xprv, tmp) + if pa.hobbled_mode: + # block most imports in hobbled mode. + # - specific checks in place for teleport (PSBT is okay) + from ccc import sssp_spending_policy + whitelist = {'psbt', 'addr', 'vmsg', 'text', 'xpub', 'teleport' } + + sv_ok = sssp_spending_policy('okeys') + if sv_ok: + # seed vault, and tmp seeds are okay with user, even in hobble mode + whitelist.update({'xprv', 'words'}) + + if what not in whitelist: + await ux_show_story("Blocked when Spending Policy is in force.", title='Sorry') return - if what == 'words': - from seed import commit_new_words, set_ephemeral_seed_words # dirty API - words, = vals - if tmp: - await set_ephemeral_seed_words(words, 'From QR') - else: - await commit_new_words(words) + if what == 'xprv': + from actions import import_extended_key_as_secret + text_xprv, = vals + await import_extended_key_as_secret(text_xprv, tmp) + return - return + if what == 'words': + from seed import commit_new_words, set_ephemeral_seed_words # dirty API + words, = vals + if tmp: + await set_ephemeral_seed_words(words, 'From QR') + else: + await commit_new_words(words) - if what == 'psbt': - decoder, psbt_len, got = vals - await qr_psbt_sign(decoder, psbt_len, got) - return + return - if what == 'txn': - bin_txn, = vals - await ux_visualize_txn(bin_txn) - return + if what == 'psbt': + decoder, psbt_len, got = vals + await qr_psbt_sign(decoder, psbt_len, got, miniscript_wallet) - if what == 'addr': - proto, addr, args = vals - await ux_visualize_bip21(proto, addr, args) - return + elif what == 'txn': + bin_txn, = vals + await ux_visualize_txn(bin_txn) - if what in ("multi", "minisc"): - from auth import maybe_enroll_xpub - from ux import ux_show_story - ms_config, = vals - try: - maybe_enroll_xpub(config=ms_config, - miniscript=False if what == "multi" else None) - except Exception as e: - await ux_show_story( - 'Failed to import.\n\n%s\n%s' % (e, problem_file_line(e))) - return + elif what == 'addr': + proto, addr, args = vals + await ux_visualize_bip21(proto, addr, args) - if what == "wif": - data, = vals - wif_str, key_pair, compressed, testnet = data - await ux_visualize_wif(wif_str, key_pair, compressed, testnet) - return + elif what == "minisc": + from auth import maybe_enroll_xpub + ms_config, = vals + try: + maybe_enroll_xpub(config=ms_config) + except Exception as e: + await ux_show_story( + 'Failed to import.\n\n%s\n%s' % (e, problem_file_line(e))) + return - if what == "vmsg": - data, = vals - from auth import verify_armored_signed_msg - await verify_armored_signed_msg(data) - return + elif what == "wif": + data, = vals + wif_str, key_pair, compressed, testnet = data + await ux_visualize_wif(wif_str, key_pair, compressed, testnet) - if what == "smsg": - data, = vals - from auth import approve_msg_sign, msg_signing_done - await approve_msg_sign(None, None, None, - msg_sign_request=data, kill_menu=True, - approved_cb=msg_signing_done) - return + elif what == "vmsg": + data, = vals + from msgsign import verify_armored_signed_msg + await verify_armored_signed_msg(data) - if what == 'text' or what == 'xpub': - # we couldn't really decode it. - txt, = vals - await ux_visualize_textqr(txt) - return + elif what == "smsg": + data, = vals + from auth import approve_msg_sign + from msgsign import msg_signing_done + await approve_msg_sign(None, None, None, + msg_sign_request=data, kill_menu=True, + approved_cb=msg_signing_done) - # not reached? - problem = 'Unhandled: ' + what - + elif what == 'text' or what == 'xpub': + # we couldn't really decode it. + txt, = vals + await ux_visualize_textqr(txt) -async def qr_psbt_sign(decoder, psbt_len, raw): + elif what == 'teleport': + from teleport import kt_incoming + await kt_incoming(*vals) + + else: + await ux_show_story(what, title='Unhandled') + + +async def qr_psbt_sign(decoder, psbt_len, raw, miniscript_wallet=None): # Got a PSBT coming in from QR scanner. Sign it. # - similar to auth.sign_psbt_file() - from auth import UserAuthorizedAction, ApproveTransaction, try_push_tx - from utils import CapsHexWriter - from glob import dis, PSRAM - from ux import show_qr_code, the_ux, ux_show_story - from ux_q1 import show_bbqr_codes + from auth import UserAuthorizedAction, ApproveTransaction + from ux import the_ux from sffile import SFFile - from auth import MAX_TXN_LEN, TXN_INPUT_OFFSET, TXN_OUTPUT_OFFSET + from auth import TXN_INPUT_OFFSET, psbt_encoding_taster if raw != 'PSRAM': # might already be in place - + # copy to PSRAM, and convert encoding at same time if isinstance(raw, str): raw = raw.encode() - # copy to PSRAM, and convert encoding at same time + _, output_encoder, _ = psbt_encoding_taster(raw[:10], psbt_len) total = 0 with SFFile(TXN_INPUT_OFFSET, max_size=psbt_len) as out: if not decoder: @@ -1008,39 +1056,16 @@ async def qr_psbt_sign(decoder, psbt_len, raw): assert total <= psbt_len psbt_len = total - async def done(psbt): - dis.fullscreen("Wait...") - txid = None - - with SFFile(TXN_OUTPUT_OFFSET, max_size=MAX_TXN_LEN, message="Saving...") as psram: - - # save transaction, as hex into PSRAM - with CapsHexWriter(psram) as fd: - if psbt.is_complete(): - txid = psbt.finalize(fd) - else: - psbt.serialize(fd) - - data_len, sha = psram.tell(), fd.checksum.digest() - - UserAuthorizedAction.cleanup() - - # Show the result as a QR, perhaps many BBQr's - # - note: already HEX here! - here = PSRAM.read_at(TXN_OUTPUT_OFFSET, data_len) - if txid and await try_push_tx(a2b_hex(here), txid, sha): - return # success, exit - - try: - await show_qr_code(here.decode(), is_alnum=True, - msg=(txid or 'Partly Signed PSBT')) - except (ValueError, RuntimeError): - await show_bbqr_codes('T' if txid else 'P', here, - (txid or 'Partly Signed PSBT'), - already_hex=True) + else: + with SFFile(TXN_INPUT_OFFSET, max_size=psbt_len) as out: + taste = out.read(10) + _, output_encoder, _ = psbt_encoding_taster(taste, psbt_len) UserAuthorizedAction.cleanup() - UserAuthorizedAction.active_request = ApproveTransaction(psbt_len, approved_cb=done) + UserAuthorizedAction.active_request = ApproveTransaction( + psbt_len, input_method="qr", output_encoder=output_encoder, + miniscript_wallet=miniscript_wallet, + ) the_ux.push(UserAuthorizedAction.active_request) async def ux_visualize_txn(bin_txn): @@ -1073,7 +1098,7 @@ async def ux_visualize_txn(bin_txn): msg += '\n\nTxid:\n' + b2a_hex(txid).decode() except Exception as exc: - sys.print_exception(exc) + # sys.print_exception(exc) msg = "Unable to deserialize" await ux_show_story(msg, title="Signed Transaction") @@ -1114,9 +1139,10 @@ async def ux_visualize_bip21(proto, addr, args): if ch == '1': from ownership import OWNERSHIP - await OWNERSHIP.search_ux(addr) + await OWNERSHIP.search_ux(addr, args) async def ux_visualize_wif(wif_str, kp, compressed, testnet): + # TODO: remove until we support signing w/ WIF keys IMHO from ux import ux_show_story msg = wif_str + "\n\n" msg += "chain: %s\n\n" % ("XTN" if testnet else "BTC") @@ -1126,7 +1152,7 @@ async def ux_visualize_wif(wif_str, kp, compressed, testnet): async def qr_msg_sign_done(signature, address, text): from ux import ux_show_story - from auth import rfc_signature_template_gen + from msgsign import rfc_signature_template from export import export_by_qr sig = b2a_base64(signature).decode('ascii').strip() @@ -1138,12 +1164,13 @@ async def qr_msg_sign_done(signature, address, text): if ch == "y": await export_by_qr(sig, "Signature", "U") if ch == "0": - armored_str = "".join(rfc_signature_template_gen(addr=address, msg=text, + armored_str = "".join(rfc_signature_template(addr=address, msg=text, sig=sig)) await show_bbqr_codes("U", armored_str, "Armored MSG") async def qr_sign_msg(txt): - from auth import ux_sign_msg + from msgsign import ux_sign_msg + await ux_sign_msg(txt, approved_cb=qr_msg_sign_done, kill_menu=True) async def ux_visualize_textqr(txt, maxlen=MSG_SIGNING_MAX_LENGTH): @@ -1160,8 +1187,6 @@ async def ux_visualize_textqr(txt, maxlen=MSG_SIGNING_MAX_LENGTH): msg = "%s\n\nAbove is text that was scanned. " % txt if escape: msg += " Press (0) to sign the text. " - else: - msg += "We can't do any more with it." ch = await ux_show_story(title="Simple Text", msg=msg, escape=escape) if escape and (ch == "0"): @@ -1179,10 +1204,13 @@ async def show_bbqr_codes(type_code, data, msg, already_hex=False): # - BUT: need zlib compress (not present) .. delayed for now from bbqr import TYPE_LABELS, int2base36, b32encode, num_qr_needed from glob import PSRAM, dis - from ux import ux_wait_keyup, ux_wait_keydown + from ux import ux_wait_keydown import uqr - assert not PSRAM.is_at(data, 0) # input data would be overwritten with our work + # put QR shenanigans at offset 1MB after TXN_OUTPUT_OFFSET + TMP_OFFSET = const(3 * 1024 * 1024) + + assert not PSRAM.is_at(data, TMP_OFFSET) # output data would be overwritten with our work assert type_code in TYPE_LABELS dis.fullscreen('Generating BBQr...', .1) @@ -1207,20 +1235,25 @@ async def show_bbqr_codes(type_code, data, msg, already_hex=False): # BBQr header hdr = 'B$' + encoding + type_code + int2base36(num_parts) + int2base36(pkt) - # encode the bytes assert pos < data_len, (pkt, pos, data_len) if already_hex: - # not encoding, just chars->bytes + # not encoding, just hex string hp = pos*2 - body = data[hp:hp+(part_size*2)].decode() + body = data[hp:hp+(part_size*2)] else: - # base32 encoding + # encode bytes to base32 encoding body = b32encode(data[pos:pos+part_size]) pos += part_size + # first packet, want to discover a working small value for QR version + if pkt == 0: + mnv = 10 if num_parts > 1 else 1 + else: + mnv = force_version + # do the hard work - qr_data = uqr.make(hdr+body, min_version=(10 if pkt == 0 else force_version), + qr_data = uqr.make(hdr+body, min_version=mnv, max_version=force_version, encoding=uqr.Mode_ALPHANUMERIC) # save the rendered QR @@ -1234,11 +1267,11 @@ async def show_bbqr_codes(type_code, data, msg, already_hex=False): else: _, _, raw = qr_data.packed() - PSRAM.write_at(qr_size * pkt, qr_size)[0:raw_qr_size] = raw + PSRAM.write_at(TMP_OFFSET + (qr_size * pkt), qr_size)[0:raw_qr_size] = raw del qr_data - dis.progress_bar_show((pkt+1) / num_parts) + dis.progress_sofar((pkt+1), num_parts) # display rate (plus time to send to display, etc) ms_per_each = 200 @@ -1250,7 +1283,7 @@ async def show_bbqr_codes(type_code, data, msg, already_hex=False): ch = None while not ch: for pkt in range(num_parts): - buf = PSRAM.read_at(qr_size * pkt, raw_qr_size) + buf = PSRAM.read_at(TMP_OFFSET + (qr_size * pkt), raw_qr_size) dis.draw_qr_display( (scan_w, w, buf), msg, True, None, None, False, partial_bar=((pkt, num_parts) if num_parts else None)) diff --git a/shared/vdisk.py b/shared/vdisk.py index 8b4fcab4..1ac66f98 100644 --- a/shared/vdisk.py +++ b/shared/vdisk.py @@ -79,7 +79,7 @@ class VirtDisk: # corrupt or unformated? # XXX incomplete error handling here; needs work VBLKDEV.set_inserted(True) - sys.print_exception(exc) + # sys.print_exception(exc) return None @@ -93,7 +93,7 @@ class VirtDisk: return list(sorted(('/vdisk/'+fn, sz) for (fn,ty,_,sz) in os.ilistdir('/vdisk') if ty == 0x8000)) except BaseException as exc: - sys.print_exception(exc) + # sys.print_exception(exc) return [] finally: @@ -111,10 +111,10 @@ class VirtDisk: return actual - def new_psbt(self, filename, sz): + def new_psbt(self, filename): # New incoming PSBT has been detected, start to sign it. from auth import sign_psbt_file - uasyncio.create_task(sign_psbt_file(filename, force_vdisk=True)) + uasyncio.create_task(sign_psbt_file(filename, force_vdisk=True, ux_abort=True)) def new_firmware(self, filename, sz): # potential new firmware file detected @@ -157,9 +157,9 @@ class VirtDisk: lfn = fn.lower() - if lfn.endswith('.psbt') and sz > 100: + if lfn.endswith('.psbt') and sz > 100 and ("-signed" not in lfn): self.ignore.add(fn) - self.new_psbt(fn, sz) + self.new_psbt(fn) break if lfn.endswith('.dfu') and sz > FW_MIN_LENGTH: diff --git a/shared/version.py b/shared/version.py index 60f5f9f0..015c3846 100644 --- a/shared/version.py +++ b/shared/version.py @@ -4,7 +4,8 @@ # # REMINDER: update simulator version of this file if API changes are made. # -from public_constants import MAX_TXN_LEN, MAX_UPLOAD_LEN +from public_constants import MAX_TXN_LEN_MK4 as MAX_TXN_LEN +from public_constants import MAX_UPLOAD_LEN_MK4 as MAX_UPLOAD_LEN def decode_firmware_header(hdr): from sigheader import FWH_PY_FORMAT @@ -76,7 +77,6 @@ def probe_system(): # run-once code to determine what hardware we are running on global hw_label, has_608, is_factory_mode, is_devmode, has_psram, is_edge global has_se2, mk_num, has_nfc, has_qr, num_sd_slots, has_qwerty, has_battery, supports_hsm - global MAX_UPLOAD_LEN, MAX_TXN_LEN from sigheader import RAM_BOOT_FLAGS, RBF_FACTORY_MODE import ckcc, callgate, machine @@ -124,11 +124,6 @@ def probe_system(): # newer, edge code in effect? is_edge = (get_mpy_version()[1][-1] == 'X') - # increase size limits for mk4 - from public_constants import MAX_TXN_LEN_MK4, MAX_UPLOAD_LEN_MK4 - MAX_UPLOAD_LEN = MAX_UPLOAD_LEN_MK4 - MAX_TXN_LEN = MAX_TXN_LEN_MK4 - probe_system() # EOF diff --git a/shared/wallet.py b/shared/wallet.py index 626dc9ad..1b002f83 100644 --- a/shared/wallet.py +++ b/shared/wallet.py @@ -2,12 +2,29 @@ # # wallet.py - A place you find UTXO, addresses and descriptors. # -import chains -from glob import settings -from stash import SensitiveValues +import ngu, ujson, uio, chains, ure, version, stash +from binascii import hexlify as b2a_hex +from serializations import ser_string +from desc_utils import bip388_wallet_policy_to_descriptor, append_checksum, bip388_validate_policy, Key +from public_constants import AF_P2TR, AF_P2WSH, AF_CLASSIC, AF_P2SH, AF_P2WSH_P2SH +from menu import MenuSystem, MenuItem, start_chooser +from ux import ux_show_story, ux_confirm, ux_dramatic_pause, OK, X, ux_enter_bip32_index +from files import CardSlot, CardMissingError, needs_microsd +from utils import problem_file_line, xfp2str, to_ascii_printable, swab32, show_single_address +from charcodes import KEY_QR, KEY_CANCEL, KEY_NFC, KEY_ENTER +from glob import settings + +# Arbitrary value, not 0 or 1, used to derive a pubkey from preshared xpub in Key Teleport +KT_RXPUBKEY_DERIV = const(20250317) + +# PSBT Xpub trust policies +TRUST_VERIFY = const(0) +TRUST_OFFER = const(1) +TRUST_PSBT = const(2) MAX_BIP32_IDX = (2 ** 31) - 1 +MAX_NAME_LEN = 30 # use (almost) full potential of Q screen class WalletOutOfSpace(RuntimeError): pass @@ -22,13 +39,13 @@ class WalletABC: # chain def yield_addresses(self, start_idx, count, change_idx=0): - # TODO: returns various tuples, with at least (idx, address, ...) + # returns various tuples, with at least (idx, address, ...) pass def render_address(self, change_idx, idx): # make one single address as text. - tmp = list(self.yield_addresses(idx, 1, change_idx=change_idx)) + tmp = list(self.yield_addresses(idx, 1, change_idx)) assert len(tmp) == 1 assert tmp[0][0] == idx @@ -46,6 +63,13 @@ class MasterSingleSigWallet(WalletABC): # - path can be overriden when we come here via address explorer n = chains.addr_fmt_label(addr_fmt) + if not version.has_qwerty: + # Mk4 tiny display + # Classic P2PKH -> P2PKH + # Segwit P2WPKH -> P2WPKH + # P2SH-Segwit -> no change (should not be used that much) + n = n.split(" ")[-1] + purpose = chains.af_to_bip44_purpose(addr_fmt) prefix = path or 'm/%dh/{coin_type}h/{account}h' % purpose @@ -55,12 +79,13 @@ class MasterSingleSigWallet(WalletABC): self.chain = chains.current_chain() if account_idx != 0: - n += ' Account#%d' % account_idx + rv = " Account#%d" if version.has_qwerty else " Acct#%d" + n += rv % account_idx if self.chain.ctype == 'XTN': - n += ' (Testnet)' + n += ' (Testnet)' if version.has_qwerty else " XTN" if self.chain.ctype == 'XRT': - n += ' (Regtest)' + n += ' (Regtest)' if version.has_qwerty else " XRT" self.name = n self.addr_fmt = addr_fmt @@ -85,7 +110,7 @@ class MasterSingleSigWallet(WalletABC): assert 0 <= change_idx <= 1 path += '/%d' % change_idx - with SensitiveValues() as sv: + with stash.SensitiveValues() as sv: node = sv.derive_path(path) if count is None: # special case - showing single, ignoring start_idx @@ -110,7 +135,7 @@ class MasterSingleSigWallet(WalletABC): def render_address(self, change_idx, idx): # Optimized for a single address. path = self._path + '/%d/%d' % (change_idx, idx) - with SensitiveValues() as sv: + with stash.SensitiveValues() as sv: node = sv.derive_path(path) return self.chain.address(node, self.addr_fmt) @@ -119,95 +144,116 @@ class MasterSingleSigWallet(WalletABC): return self._path + '/%d/%d' % (change_idx, idx) def to_descriptor(self): - from glob import settings from descriptor import Descriptor, Key xfp = settings.get('xfp') xpub = settings.get('xpub') - d = Descriptor(key=Key.from_cc_data(xfp, self._path, xpub)) - d.set_from_addr_fmt(self.addr_fmt) + d = Descriptor(key=Key.from_cc_data(xfp, self._path, xpub), addr_fmt=self.addr_fmt) return d -class BaseStorageWallet(WalletABC): - key_name = None +class MiniScriptWallet(WalletABC): + skey = "miniscript" + # optional: user can short-circuit many checks (system wide, one power-cycle only) + disable_checks = False + + def __init__(self, name, desc_tmplt, keys_info, af, ik_u=None, + desc=None, m_n=None, bip67=None, chain_type=None): + + assert 1 <= len(name) <= MAX_NAME_LEN, "name len" - def __init__(self, chain_type=None): self.storage_idx = -1 - self.chain_type = chain_type or 'BTC' + self.name = name + self.desc_tmplt = desc_tmplt + self.keys_info = keys_info + self.desc = desc + self.addr_fmt = af + # internal key unspendable (taproot only) + self.ik_u = ik_u + # below are basic multisig meta + # if m_n is not None, we are dealing with basic multisig + self.m_n = m_n + self.bip67 = bip67 + # at this point all the keys are already validated + self.chain_type = chain_type or chains.current_chain().ctype + + def serialize(self): + opts = {"af": self.addr_fmt} + if self.ik_u is not None: + opts['ik_u'] = self.ik_u + if self.chain_type != "BTC": + opts['ct'] = self.chain_type + if self.m_n: + opts['m_n'] = self.m_n + opts['b67'] = self.bip67 + + return self.name, self.desc_tmplt, self.keys_info, opts + + @classmethod + def deserialize(cls, c, idx=-1): + # after deserialization - we lack loaded descriptor object + # we do not need it for everything + needs_migration = False + if len(c) == 4: + name, desc_tmplt, keys_info, opts = c + else: + # needs migration + name, desc_tmplt, keys_info, opts = miniscript_640_migrate(c) + needs_migration = True + + af = opts.get("af") + ct = opts.get("ct", "BTC") + ik_u = opts.get("ik_u", False) + m_n = opts.get("m_n", None) + b67 = opts.get("b67", None) + + rv = cls(name, desc_tmplt, keys_info, af, ik_u, m_n=m_n, + bip67=b67, chain_type=ct) + rv.storage_idx = idx + return rv, needs_migration @property def chain(self): return chains.get_chain(self.chain_type) - @classmethod - def none_setup_yet(cls, other_chain=False): - return '(none setup yet)' + ("*" if other_chain else "") - - @classmethod - def is_correct_chain(cls, o, curr_chain): - if o[1] is None: - # mainnet - ch = "BTC" - else: - ch = o[1] - - if ch == curr_chain.ctype: - return True - return False + @property + def key_chain(self): + return chains.get_chain("XTN" if self.chain_type == "XRT" else self.chain_type) @classmethod def exists(cls): # are there any wallets defined? - exists = False - exists_other_chain = False - c = chains.current_key_chain() - for o in settings.get(cls.key_name, []): - if cls.is_correct_chain(o, c): - exists = True - else: - exists_other_chain = True - - return exists, exists_other_chain + return bool(settings.get(cls.skey, [])) @classmethod - def get_all(cls): - # return them all, as a generator - return cls.iter_wallets() - - @classmethod - def iter_wallets(cls): + def iter_wallets(cls, name=None, addr_fmts=None): # - this is only place we should be searching this list, please!! - lst = settings.get(cls.key_name, []) - c = chains.current_key_chain() + lst = settings.get(cls.skey, []) + for idx in range(len(lst)): + w, migrate = cls.deserialize(lst[idx], idx) + if migrate: + if idx == 0: + from glob import dis + dis.fullscreen("Migrating...") - for idx, rec in enumerate(lst): - if cls.is_correct_chain(rec, c): - yield cls.deserialize(rec, idx) + lst[idx] = w.serialize() + settings.set("miniscript", lst) + settings.save() - def serialize(self): - raise NotImplemented + if w.key_chain.ctype != chains.current_key_chain().ctype: + continue + if name and name != w.name: + continue + if addr_fmts and w.addr_fmt not in addr_fmts: + continue - @classmethod - def deserialize(cls, c, idx=-1): - raise NotImplemented - - @classmethod - def get_by_idx(cls, nth): - # instance from index number (used in menu) - lst = settings.get(cls.key_name, []) - try: - obj = lst[nth] - except IndexError: - return None - - return cls.deserialize(obj, nth) + yield w def commit(self): # data to save # - important that this fails immediately when nvram overflows obj = self.serialize() - v = settings.get(self.key_name, []) + v = settings.get(self.skey, []) orig = v.copy() if not v or self.storage_idx == -1: # create @@ -217,7 +263,7 @@ class BaseStorageWallet(WalletABC): # update in place v[self.storage_idx] = obj - settings.set(self.key_name, v) + settings.set(self.skey, v) # save now, rather than in background, so we can recover # from out-of-space situation @@ -226,7 +272,7 @@ class BaseStorageWallet(WalletABC): except: # back out change; no longer sure of NVRAM state try: - settings.set(self.key_name, orig) + settings.set(self.skey, orig) settings.save() except: pass # give up on recovery @@ -236,16 +282,1149 @@ class BaseStorageWallet(WalletABC): # remove saved entry # - important: not expecting more than one instance of this class in memory assert self.storage_idx >= 0 - lst = settings.get(self.key_name, []) + lst = settings.get(self.skey, []) try: del lst[self.storage_idx] if lst: - settings.set(self.key_name, lst) + settings.set(self.skey, lst) else: - settings.remove_key(self.key_name) + settings.remove_key(self.skey) settings.save() # actual write except IndexError: pass self.storage_idx = -1 + @classmethod + def get_trust_policy(cls): + which = settings.get('pms', None) + if which is None: + which = TRUST_VERIFY if cls.exists() else TRUST_OFFER + + return which + + @classmethod + def find_match(cls, xfp_paths, addr_fmt=None, M=None, N=None): + for rv in cls.iter_wallets(): + if addr_fmt is not None: + if rv.addr_fmt != addr_fmt: + continue + + if M and N: + if not rv.m_n: + continue + + m, n = rv.m_n + if m != M or n != N: + continue + + if rv.matching_subpaths(xfp_paths): + return rv + + return None + + def xfp_paths(self, skip_unspend_ik=False): + if not self.desc: + res = [] + for i, k_str in enumerate(self.keys_info): + if not i and self.ik_u and skip_unspend_ik: + continue + k = Key.from_string(k_str) + res.append(k.origin.psbt_derivation()) + return res + + return self.desc.xfp_paths(skip_unspend_ik=skip_unspend_ik) + + def matching_subpaths(self, xfp_paths): + my_xfp_paths = self.to_descriptor().xfp_paths() + + if len(xfp_paths) != len(my_xfp_paths): + return False + + for x in my_xfp_paths: + prefix_len = len(x) + for y in xfp_paths: + if x == y[:prefix_len]: + break + else: + return False + return True + + def subderivation_indexes(self, xfp_paths): + # we already know that they do match + my_xfp_paths = self.to_descriptor().xfp_paths() + res = set() + for x in my_xfp_paths: + prefix_len = len(x) + for y in xfp_paths: + if x == y[:prefix_len]: + to_derive = tuple(y[prefix_len:]) + res.add(to_derive) + + err = "derivation indexes" + assert res, err + if len(res) == 1: + branch, idx = list(res)[0] + else: + branch = [i[0] for i in res] + indexes = set([i[1] for i in res]) + assert len(indexes) == 1, err + idx = list(indexes)[0] + + return branch, idx + + def get_my_deriv(self): + # returns derivation path of the first "our" key in keys info vector + # used for signed exports only + str_xfp = xfp2str(settings.get('xfp')) + for ek in self.keys_info: + orig_end = ek.find("]") + if orig_end == -1: + continue # key without origin + + orig = ek[1:orig_end] + fp_end = orig.find("/") + if fp_end == -1: + master_fp = orig + fp_end = len(orig) + else: + master_fp = orig[:fp_end] + + if master_fp.upper() == str_xfp: + return "m" + orig[fp_end:] + + # didn't find any origin info + # BUT we know that our key is included (verified on import) + # therefore our key root key + return "m" + + def derive_desc(self, xfp_paths): + branch, idx = self.subderivation_indexes(xfp_paths) + derived_desc = self.desc.derive(branch).derive(idx) + return derived_desc + + def validate_script_pubkey(self, script_pubkey, xfp_paths, merkle_root=None): + derived_desc = self.derive_desc(xfp_paths) + derived_spk = derived_desc.script_pubkey() + assert derived_spk == script_pubkey, "spk mismatch\n\ncalc:\n%s\n\npsbt:\n%s" % ( + b2a_hex(derived_spk).decode(), b2a_hex(script_pubkey).decode() + ) + if merkle_root: + calc = derived_desc.tapscript.merkle_root + assert calc == merkle_root, "merkle root mismatch\n\ncalc:\n%s\n\npsbt:\n%s" % ( + b2a_hex(calc).decode(), b2a_hex(merkle_root).decode() + ) + return derived_desc + + def detail(self): + s = "Wallet Name:\n %s\n\n" % self.name + if self.m_n: + # basic multisig + M, N = self.m_n + s += "Policy: %d of %d\n\n" % (M, N) + + s += chains.addr_fmt_label(self.addr_fmt) + s += "\n\n" + self.desc_tmplt + return s + + async def show_detail(self, story="", allow_import=False): + story += self.detail() + story += "\n\nPress (1) to see extended public keys" + + if allow_import: + story += ", OK to approve, X to cancel." + + while True: + ch = await ux_show_story(story, escape="1") + if ch == "1": + await self.show_keys() + + elif ch != "y": + return None + else: + return True + + async def show_keys(self): + msg = "" + for idx, k_str in enumerate(self.keys_info): + if idx: + msg += '\n---===---\n\n' + elif self.addr_fmt == AF_P2TR: + # index 0, taproot internal key + msg += "Taproot internal key:\n\n" + if self.ik_u: + msg += "(provably unspendable)\n\n" + + msg += '@%s:\n %s\n\n' % (idx, k_str) + + await ux_show_story(msg) + + def to_descriptor(self): + if self.desc is None: + # actual descriptor is not loaded, but was asked for + # fill policy - aka storage format - to actual descriptor + import glob + + if self.name in glob.DESC_CACHE: + # loaded descriptor from cache + self.desc = glob.DESC_CACHE[self.name] + else: + print("loading... policy --> descriptor !!!") + # no need to validate already saved descriptor - was validated upon enroll + self.desc = self._from_bip388_wallet_policy(self.desc_tmplt, self.keys_info, + validate=False) + # cache len always 1 + glob.DESC_CACHE = {} + glob.DESC_CACHE[self.name] = self.desc + + return self.desc + + @staticmethod + def _from_bip388_wallet_policy(desc_template, keys_info, validate=True): + desc_str = bip388_wallet_policy_to_descriptor( + desc_template.replace("/<0;1>/*", "/**"), + keys_info + ) + from descriptor import Descriptor + desc_obj = Descriptor.from_string(desc_str) + if validate: + desc_obj.validate(MiniScriptWallet.disable_checks) + return desc_obj + + @classmethod + def from_bip388_wallet_policy(cls, name, desc_template, keys_info): + bip388_validate_policy(desc_template, keys_info) + desc_obj = cls._from_bip388_wallet_policy(desc_template, keys_info) + msc = cls.from_descriptor_obj(name, desc_obj, desc_template, keys_info) + return msc + + @classmethod + def from_descriptor_obj(cls, name, desc_obj, desc_tmplt=None, keys_info=None): + if not desc_tmplt or not keys_info: + # BIP388 wasn't generated yet - generating from descriptor upon import/enroll + desc_tmplt, keys_info = desc_obj.bip388_wallet_policy() + # self-validation + bip388_validate_policy(desc_tmplt, keys_info) + + ik_u = desc_obj.key and desc_obj.key.is_provably_unspendable + af = desc_obj.addr_fmt + m_n = None + bip67 = None + if desc_obj.is_basic_multisig: + m_n = desc_obj.miniscript.m_n() + bip67 = desc_obj.is_sortedmulti + + return cls(name, desc_tmplt, keys_info, af, ik_u, desc_obj, m_n, bip67) + + @classmethod + def from_file(cls, config, name=None, bip388=False): + from descriptor import Descriptor + + if bip388: + # config is JSON wallet policy + wal = cls.from_bip388_wallet_policy(config["name"], config["desc_template"], + config["keys_info"]) + else: + if name is None: + desc_obj, cs = Descriptor.from_string(config.strip(), checksum=True) + name = cs + else: + name = to_ascii_printable(name) + desc_obj = Descriptor.from_string(config.strip()) + + desc_obj.validate(cls.disable_checks) + + wal = cls.from_descriptor_obj(name, desc_obj) + + return wal + + @classmethod + def import_from_psbt(cls, addr_fmt, M, N, xpubs_list): + # given the raw data from PSBT global header, offer the user + # the details, and/or bypass that all and just trust the data. + # - xpubs_list is a list of (xfp+path, binary BIP-32 xpub) + # - already know not in our records. + from descriptor import Descriptor + from miniscript import Sortedmulti, Number + + # build up an in-memory version of the wallet. + # - capture address format based on path used for my leg (if standards compliant) + + assert N == len(xpubs_list) + assert 1 <= M <= N <= 20, 'M/N range' + my_xfp = settings.get('xfp') + + has_mine = 0 + + keys = [] + for ek, xfp_pth in xpubs_list: + k = Key.from_psbt_xpub(ek, xfp_pth) + has_mine += k.validate(my_xfp, cls.disable_checks) + keys.append(k) + + assert has_mine == 1 # 'my key not included' + + name = 'PSBT-%d-of-%d' % (M, N) + # this will always create sortedmulti multisig (BIP-67) + # because BIP-174 came years after wide-spread acceptance of BIP-67 policy + desc_obj = Descriptor(miniscript=Sortedmulti(Number(M), *keys), + addr_fmt=addr_fmt) + return cls.from_descriptor_obj(name, desc_obj) + + def validate_psbt_xpubs(self, psbt_xpubs): + keys = set() + for ek, xfp_pth in psbt_xpubs: + key = Key.from_psbt_xpub(ek, xfp_pth) + key.validate(settings.get('xfp', 0), self.disable_checks) + keys.add(key) + + if not self.disable_checks: + assert set(self.to_descriptor().keys) == keys + + def ux_unique_name_msg(self, name=None): + return ("Miniscript wallet with name '%s'" + " already exists. All wallets MUST" + " have unique names.\n\n" % (name or self.name)) + + def find_duplicates(self): + for rv in self.iter_wallets(): + assert self.name != rv.name, self.ux_unique_name_msg() + + # optimization miniscript vs. multisig & different M/N multisigs + if self.m_n != rv.m_n: + # different M/N + continue + + err = "Duplicate wallet. Wallet '%s' is the same." % rv.name + if self.m_n: + # enrolling basic multisig wallet + if self.addr_fmt == rv.addr_fmt and sorted(self.keys_info) == sorted(rv.keys_info): + if self.bip67 != rv.bip67: + err += " BIP-67 clash." + err += "\n\n" + assert False, err + + else: + if self.desc_tmplt == rv.desc_tmplt and self.keys_info == rv.keys_info: + assert False, err + "\n\n" + + async def confirm_import(self): + nope, yes = (KEY_CANCEL, KEY_ENTER) if version.has_qwerty else ("x", "y") + try: + self.find_duplicates() + story, allow_import = "Create new miniscript wallet?\n\n", True + if self.m_n and not self.bip67: + story += ("WARNING: BIP-67 disabled! Unsorted multisig - " + "order of keys in descriptor/backup is crucial\n\n") + except AssertionError as e: + story, allow_import = str(e), False + + to_save = await self.show_detail(story, allow_import=allow_import) + + ch = yes if to_save else nope + if to_save and allow_import: + assert self.storage_idx == -1 + self.commit() + import glob + # new wallet was imported - cache descriptor + glob.DESC_CACHE = {} + assert self.desc + glob.DESC_CACHE[self.name] = self.desc + await ux_dramatic_pause("Saved.", 2) + + return ch + + def yield_addresses(self, start_idx, count, change_idx=0, scripts=False): + ch = chains.current_chain() + # change_idx work as boolean here - you cannot specify random change_idx + # as it is defined by descriptor + dd = self.to_descriptor().derive(None, change=bool(change_idx)) + idx = start_idx + while count: + if idx > MAX_BIP32_IDX: + break + # make the redeem script, convert into address + d = dd.derive(idx) + scr = d.miniscript.compile() if d.miniscript else None + addr = ch.render_address(d.script_pubkey(compiled_scr=scr)) + ders = script = None + if scripts: + ders = "" + for k in d.keys: + ders += "[%s]; " % str(k.origin) + + if d.tapscript: + # DFS ordered list of scripts + script = "" + for leaf_ver, scr, _ in d.tapscript._processed_tree: + script += b2a_hex(chains.tapscript_serialize(scr, leaf_ver)).decode() + "; " + else: + script = b2a_hex(ser_string(scr)).decode() + + yield idx, addr, ders, script + + idx += 1 + count -= 1 + + def make_addresses_msg(self, msg, start, n, change=0): + from glob import dis + + addrs = [] + + for idx, addr, *_ in self.yield_addresses(start, n, change): + msg += '.../%d =>\n' % idx # just idx, if derivations or scripts needed - export csv + addrs.append(addr) + msg += show_single_address(addr) + '\n\n' + dis.progress_sofar(idx - start + 1, n) + + return msg, addrs + + def generate_address_csv(self, start, n, change, saver=None): + scripts = settings.get("aemscsv", False) + header = ['Index', 'Payment Address'] + if scripts: + header += ['Script', 'Derivations'] + + yield '"' + '","'.join(header) + '"\n' + for idx, addr, ders, script in self.yield_addresses(start, n, change, scripts=scripts): + if saver: + saver(addr, idx) + + ln = '%d,"%s"' % (idx, addr) + if scripts: + ln += ',"%s"' % script + ln += ',"%s"' % ders + ln += '\n' + yield ln + + def to_string(self, checksum=True): + # policy filling - not possible to specify internal/external always multipath export + # only supported from bitcoin-core 29.0 + if self.desc_tmplt and self.keys_info: + desc = bip388_wallet_policy_to_descriptor(self.desc_tmplt, self.keys_info) + if checksum: + desc = append_checksum(desc) + return desc + + return self.desc.to_string() + + def bitcoin_core_serialize(self): + return [{ + "desc": self.to_string(), # policy fill + "active": True, + "timestamp": "now", + "range": [0, 100], + }] + + async def export_wallet_file(self, core=False, bip388=False, sign=True): + # do not load descriptor - just fill policy + # only with multipath format <0;1> + from glob import NFC, dis + from ux import import_export_prompt + + dis.fullscreen('Wait...') + + if core: + name = "Bitcoin Core miniscript" + fname_pattern = 'bitcoin-core-%s.txt' % self.name + msg = "importdescriptors cmd" + core_obj = self.bitcoin_core_serialize() + core_str = ujson.dumps(core_obj) + res = "importdescriptors '%s'\n" % core_str + elif bip388: + # policy as JSON + msg = self.name + name = "BIP-388 Wallet Policy" + fname_pattern = 'b388-%s.json' % self.name + res = ujson.dumps({"name": self.name, + "desc_template": self.desc_tmplt, + "keys_info": self.keys_info}) + else: + name = "Miniscript" + fname_pattern = 'minsc-%s.txt' % self.name + msg = self.name + res = self.to_string() + + ch = await import_export_prompt("%s file" % name) + if isinstance(ch, str): + if ch in "3"+KEY_NFC: + if bip388: + await NFC.share_json(res) + else: + await NFC.share_text(res) + elif ch == KEY_QR: + try: + from ux import show_qr_code + await show_qr_code(res, msg=msg) + except: + if version.has_qwerty: + from ux_q1 import show_bbqr_codes + await show_bbqr_codes('U', res, msg) + return + + try: + with CardSlot(**ch) as card: + fname, nice = card.pick_filename(fname_pattern) + + # do actual write + with open(fname, 'w+') as fp: + fp.write(res) + + if sign: + # sign with my key at the same path as first address of export + derive = self.get_my_deriv() + "/0/0" + from msgsign import write_sig_file + h = ngu.hash.sha256s(res.encode()) + sig_nice = write_sig_file([(h, fname)], derive, AF_CLASSIC) + + msg = '%s file written:\n\n%s' % (name, nice) + if sign: + msg += '\n\n%s signature file written:\n\n%s' % (name, sig_nice) + await ux_show_story(msg) + + except CardMissingError: + await needs_microsd() + return + except Exception as e: + await ux_show_story('Failed to write!\n\n%s\n%s' % (e, problem_file_line(e))) + return + + def xpubs_from_xfp(self, xfp): + # return list of XPUB's which match xfp + res = [] + desc = self.to_descriptor() + for k in desc.keys: + if k.origin and k.origin.cc_fp == xfp: + res.append(k) + elif swab32(k.node.my_fp()) == xfp: + res.append(k) + + assert res, "missing xfp %s" % xfp2str(xfp) + # returned is list of keys with corresponding master xfp + # key in list are lexicographically sorted based on their public keys + # lowest public key first + return sorted(res, key=lambda o: o.serialize()) + + def kt_make_rxkey(self, xfp): + # Derive the receiver's pubkey from preshared xpub and a special derivation + # - also provide the keypair we're using from our side of connection + # - returns 4 byte nonce which is sent un-encrypted, his_pubkey and my_keypair + ri = ngu.random.uniform(1<<28) + + # sorted lexicographically, always use the lowest pubkey from the list at index 0 + keys = self.xpubs_from_xfp(xfp) + k = keys[0] + k = k.derive(KT_RXPUBKEY_DERIV).derive(ri) + pubkey = k.node.pubkey() + + kp = self.kt_my_keypair(ri) + return ri.to_bytes(4, 'big'), pubkey, kp + + def kt_my_keypair(self, ri): + # Calc my keypair for sending PSBT files. + # + # sorted lexicographically, always use the lowest pubkey from the list at index 0 + keys = self.xpubs_from_xfp(settings.get('xfp')) + + subpath = "/%d/%d" % (KT_RXPUBKEY_DERIV, ri) + path = keys[0].origin.str_derivation() + subpath + with stash.SensitiveValues() as sv: + node = sv.derive_path(path) + kp = ngu.secp256k1.keypair(node.privkey()) + return kp + + @classmethod + def kt_search_rxkey(cls, payload): + # Construct the keypair for to be decryption + # - has to try pubkey each all the unique XFP for all co-signers in all wallets + # - checks checksum of ECDH unwrapped data to see if it's the right one + # - returns session key, decrypted first layer, and XFP of sender + from teleport import decode_step1 + + # this nonce is part of the derivation path so each txn gets new keys + ri = int.from_bytes(payload[0:4], 'big') + + my_xfp = settings.get('xfp') + + for msc in cls.iter_wallets(): + kp = msc.kt_my_keypair(ri) + for k in msc.to_descriptor().keys: + if k.origin.cc_fp == my_xfp: + continue + kk = k.derive(KT_RXPUBKEY_DERIV).derive(ri) + his_pubkey = kk.node.pubkey() + # if implied session key decodes the checksum, it is right + ses_key, body = decode_step1(kp, his_pubkey, payload[4:]) + if ses_key: + return ses_key, body, kk.origin.cc_fp + + return None, None, None + + async def export_electrum(self): + # Generate and save an Electrum JSON file. + from export import export_contents + + assert self.m_n, "not multisig" + M, N = self.m_n + + def doit(): + rv = dict(seed_version=17, use_encryption=False, + wallet_type='%dof%d' % (M, N)) + + ch = self.chain + + # the important stuff. + for idx, key in enumerate(self.to_descriptor().keys): + # CHALLENGE: we must do slip-132 format [yz]pubs here when not p2sh mode. + xp = ch.serialize_public(key.node, self.addr_fmt) + + rv['x%d/' % (idx + 1)] = {"hw_type":"coldcard", "type":"hardware", + "ckcc_xfp": key.origin.cc_fp, "xpub":xp, + "label":"Coldcard %s" % xfp2str(key.origin.cc_fp), + "derivation":key.origin.str_derivation()} + + # sign export with first p2pkh key + return ujson.dumps(rv), self.get_my_deriv() + "/0/0", AF_CLASSIC + + fname = '%s-%s.%s' % ("el", self.name.replace(" ", "_"), "json") + await export_contents('Electrum multisig wallet', doit, + fname, is_json=True) + +async def miniscript_delete(msc): + if not await ux_confirm("Delete miniscript wallet '%s'?\n\nFunds may be impacted." % msc.name): + await ux_dramatic_pause('Aborted.', 3) + return + + msc.delete() + await ux_dramatic_pause('Deleted.', 3) + +async def miniscript_wallet_delete(menu, label, item): + msc = item.arg + + await miniscript_delete(msc) + + from ux import the_ux + # pop stack + the_ux.pop() + + m = the_ux.top_of_stack() + m.update_contents() + +async def miniscript_wallet_rename(menu, label, item): + from glob import dis + from ux import ux_input_text, the_ux + + idx, msc = item.arg + new_name = await ux_input_text(msc.name, confirm_exit=False, + min_len=1, max_len=MAX_NAME_LEN) + + if not new_name: + return + + wallets = settings.get("miniscript", []) + names = [i[0] for i in wallets] + if new_name in names: + await ux_show_story(msc.ux_unique_name_msg(new_name), title="FAILED") + return + + dis.fullscreen("Saving...") + + # save it + wal = list(wallets[idx]) + wal[0] = new_name + # it will become list after JSON encode/decode anyways + wallets[idx] = wal + msc.name = new_name + settings.set("miniscript", wallets) + + # update label in sub-menu + menu.items[0].label = new_name + # and name in parent menu too + parent = the_ux.parent_of(menu) + if parent: + parent.update_contents() + +async def miniscript_wallet_detail(menu, label, item): + # show details of single multisig wallet + msc = item.arg + return await msc.show_detail() + +async def import_miniscript(*a): + # pick text file from SD card, import as multisig setup file + from actions import file_picker + from ux import import_export_prompt + + ch = await import_export_prompt("miniscript wallet file", is_import=True) + if isinstance(ch, str): + if ch == KEY_QR: + await import_miniscript_qr() + elif ch == KEY_NFC: + await import_miniscript_nfc() + return + + def possible(filename): + with open(filename, 'rt') as fd: + for ln in fd: + if "sh(" in ln or "wsh(" in ln or "tr(" in ln: + # descriptor import + return True + + fn = await file_picker(suffix=['.txt', '.json'], min_size=100, + taster=possible, **ch) + if not fn: return + + try: + with CardSlot(**ch) as card: + with open(fn, 'rt') as fp: + data = fp.read() + except CardMissingError: + await needs_microsd() + return + + from auth import maybe_enroll_xpub + try: + possible_name = (fn.split('/')[-1].split('.'))[0] if fn else None + maybe_enroll_xpub(config=data, name=possible_name) + except BaseException as e: + await ux_show_story('Failed to import miniscript.\n\n%s\n%s' % (e, problem_file_line(e))) + +async def import_miniscript_nfc(*a): + from glob import NFC + try: + return await NFC.import_miniscript_nfc() + except Exception as e: + await ux_show_story('Failed to import miniscript.\n\n%s\n%s' % (e, problem_file_line(e))) + +async def import_miniscript_qr(*a): + from auth import maybe_enroll_xpub + from ux_q1 import QRScannerInteraction + data = await QRScannerInteraction().scan_text('Scan Miniscript from a QR code') + if not data: + # press pressed CANCEL + return + try: + maybe_enroll_xpub(config=data) + except Exception as e: + await ux_show_story('Failed to import miniscript.\n\n%s\n%s' % (e, problem_file_line(e))) + +async def miniscript_wallet_export(menu, label, item): + # create a text file with the details; ready for import to next Coldcard + msc = item.arg[0] + kwargs = item.arg[1] + await msc.export_wallet_file(**kwargs) + +async def miniscript_wallet_descriptors(menu, label, item): + # descriptor menu + msc = item.arg + if not msc: + return + + rv = [ + MenuItem('Export', f=miniscript_wallet_export, arg=(msc, {"core": False})), + MenuItem('Bitcoin Core', f=miniscript_wallet_export, arg=(msc, {"core": True})), + MenuItem('BIP-388 Policy', f=miniscript_wallet_export, arg=(msc, {"bip388":True})), + ] + return rv + +async def miniscript_sign_psbt(a, b, item): + from actions import _ready2sign + await _ready2sign(probe=False, miniscript_wallet=item.arg) + +async def make_miniscript_wallet_menu(menu, label, item): + # details, actions on single multisig wallet + idx, msc = item.arg + + rv = [ + MenuItem('"%s"' % msc.name, f=miniscript_wallet_detail, arg=msc), + MenuItem('View Details', f=miniscript_wallet_detail, arg=msc), + MenuItem('Descriptors', menu=miniscript_wallet_descriptors, arg=msc), + MenuItem('Sign PSBT', f=miniscript_sign_psbt, arg=msc), + MenuItem('Rename', f=miniscript_wallet_rename, arg=(idx, msc)), + MenuItem('Delete', f=miniscript_wallet_delete, arg=msc), + ] + if msc.m_n and msc.bip67: + # basic multisig but only sortedmulti + rv.append(MenuItem('Electrum Wallet', f=multisig_electrum_export, arg=msc)) + + return rv + + +class MiniscriptMenu(MenuSystem): + @classmethod + def construct(cls): + import version + from menu import ShortcutItem + from bsms import make_ms_wallet_bsms_menu + from multisig import create_ms_step1 + + rv = [] + for i, msc in enumerate(MiniScriptWallet.iter_wallets()): + rv.append(MenuItem('%s' % msc.name, menu=make_miniscript_wallet_menu, arg=(i,msc))) + + rv = rv or [MenuItem("(none setup yet)")] + + from glob import NFC + rv.append(MenuItem('Import', f=import_miniscript)) + rv.append(MenuItem('Export XPUB', f=export_miniscript_xpubs)) + rv.append(MenuItem('BSMS (BIP-129)', menu=make_ms_wallet_bsms_menu)) + rv.append(MenuItem('Create Airgapped', f=create_ms_step1)) + rv.append(MenuItem('Trust PSBT?', f=trust_psbt_menu)) + rv.append(MenuItem('Skip Checks?', f=disable_checks_menu)) + rv.append(ShortcutItem(KEY_NFC, predicate=lambda: NFC is not None, + f=import_miniscript_nfc)) + rv.append(ShortcutItem(KEY_QR, predicate=lambda: version.has_qwerty, + f=import_miniscript_qr)) + return rv + + def update_contents(self): + # Reconstruct the list of wallets on this dynamic menu, because + # we added or changed them and are showing that same menu again. + tmp = self.construct() + self.replace_items(tmp) + +async def make_miniscript_menu(*a): + # list of all multisig wallets, and high-level settings/actions + from pincodes import pa + + if pa.is_secret_blank(): + await ux_show_story("You must have wallet seed before creating miniscript wallets.") + return + + ms = settings.get("multisig") + if ms: + # in version 6.4.0 EDGE + # MultisigWallet was removed & multisigs are now part of miniscript + # upon entry to Miniscript menu - multisig migration if performed + migrated = await multisig_640_migration(ms) + msc = settings.get("miniscript", []) + settings.set("miniscript", msc + migrated) + settings.remove_key("multisig") + settings.save() + + + rv = MiniscriptMenu.construct() + return MiniscriptMenu(rv) + + +def disable_checks_chooser(): + ch = ['Normal', 'Skip Checks'] + + def xset(idx, text): + MiniScriptWallet.disable_checks = bool(idx) + + return int(MiniScriptWallet.disable_checks), ch, xset + +async def disable_checks_menu(*a): + + if not MiniScriptWallet.disable_checks: + ch = await ux_show_story('''\ +With many different wallet vendors and implementors involved, it can \ +be hard to create a PSBT consistent with the many keys involved. \ +With this setting, you can \ +disable the more stringent verification checks your Coldcard normally provides. + +USE AT YOUR OWN RISK. These checks exist for good reason! Signed txn may \ +not be accepted by network. + +This settings lasts only until power down. + +Press (4) to confirm entering this DANGEROUS mode. +''', escape='4') + + if ch != '4': return + + start_chooser(disable_checks_chooser) + + +def psbt_xpubs_policy_chooser(): + # Chooser for trust policy + ch = ['Verify Only', 'Offer Import', 'Trust PSBT'] + + def xset(idx, text): + settings.set('pms', idx) + + return MiniScriptWallet.get_trust_policy(), ch, xset + +async def trust_psbt_menu(*a): + # show a story then go into chooser + + ch = await ux_show_story('''\ +This setting controls what the Coldcard does \ +with the co-signer public keys (XPUB) that may \ +be provided inside a PSBT file. Three choices: + +- Verify Only. Do not import the xpubs found, but do \ +verify the correct wallet already exists on the Coldcard. + +- Offer Import. If it's a new multisig wallet, offer to import \ +the details and store them as a new wallet in the Coldcard. + +- Trust PSBT. Use the wallet data in the PSBT as a temporary, +multisig wallet, and do not import it. This permits some \ +deniability and additional privacy. + +When the XPUB data is not provided in the PSBT, regardless of the above, \ +we require the appropriate multisig wallet to already exist \ +on the Coldcard. Default is to 'Offer' unless a multisig wallet already \ +exists, otherwise 'Verify'.''') + + if ch == 'x': return + start_chooser(psbt_xpubs_policy_chooser) + + +async def multisig_electrum_export(menu, label, item): + # create a JSON file that Electrum can use. Challenges: + # - file contains derivation paths for each co-signer to use + # - electrum is using BIP-43 with purpose=48 (purpose48_derivation) to make paths like: + # m/48h/1h/0h/2h + # - above is now called BIP-48 + # - other signers might not be coldcards (we don't know) + # solution: + # - when building air-gap, pick address type at that point, and matching path to suit + # - could check path prefix and addr_fmt make sense together, but meh. + msc = item.arg + await msc.export_electrum() + + +async def export_miniscript_xpubs(*a, xfp=None, alt_secret=None, skip_prompt=False): + # WAS: Create a single text file with lots of docs, and all possible useful xpub values. + # THEN: Just create the one-liner xpub export value they need/want to support BIP-45 + # NOW: Export JSON with one xpub per useful address type and semi-standard derivation path + # + # - consumer for this file is supposed to be ourselves, when we build on-device multisig. + # - however some 3rd parties are making use of it as well. + # - used for CCC feature now as well, but result looks just like normal export + # + xfp = xfp2str(xfp or settings.get('xfp', 0)) + chain = chains.current_chain() + + fname_pattern = 'ccxp-%s.json' % xfp + label = "Multisig XPUB" + + if not skip_prompt: + msg = '''\ +This feature creates a small file containing \ +the extended public keys (XPUB) you would need to join \ +a multisig wallet. + +Public keys for BIP-48 conformant paths are used: + +P2SH-P2WSH: + m/48h/{coin}h/{{acct}}h/1h +P2WSH: + m/48h/{coin}h/{{acct}}h/2h +P2TR: + m/48h/{coin}h/{{acct}}h/3h + +{ok} to continue. {x} to abort.'''.format(coin=chain.b44_cointype, ok=OK, x=X) + + ch = await ux_show_story(msg) + if ch != "y": + return + + acct = await ux_enter_bip32_index('Account Number:') or 0 + + def render(acct_num): + sign_der = None + with uio.StringIO() as fp: + fp.write('{\n') + with stash.SensitiveValues(secret=alt_secret) as sv: + for name, deriv, fmt in chains.MS_STD_DERIVATIONS: + if fmt == AF_P2SH and acct_num: + continue + dd = deriv.format(coin=chain.b44_cointype, acct_num=acct_num) + if fmt == AF_P2WSH: + sign_der = dd + "/0/0" + node = sv.derive_path(dd) + xp = chain.serialize_public(node, fmt) + fp.write(' "%s_deriv": "%s",\n' % (name, dd)) + fp.write(' "%s": "%s",\n' % (name, xp)) + xpub = chain.serialize_public(node) + fp.write(' "%s_key_exp": "%s",\n' % (name, "[%s/%s]%s" % (xfp, dd.replace("m/", ""), xpub))) + + fp.write(' "account": "%d",\n' % acct_num) + fp.write(' "xfp": "%s"\n}\n' % xfp) + return fp.getvalue(), sign_der, AF_CLASSIC + + from export import export_contents + await export_contents(label, lambda: render(acct), fname_pattern, + force_bbqr=True, is_json=True) + +## MIGRATION === + +def miniscript_640_migrate(old_serialization): + from ubinascii import unhexlify as a2b_hex + from ucollections import OrderedDict + from desc_utils import PROVABLY_UNSPENDABLE + + def remove_subderivation(str_key): + # find the end of origin derivation + orig_der_end = str_key.find(']') + if orig_der_end != -1: + orig_der = str_key[:orig_der_end + 1] + rest = str_key[orig_der_end + 1:] + else: + orig_der = "" + rest = str_key + + rest_split = rest.split("/") + subder = "/%s" % "/".join(rest_split[1:]) + return orig_der + rest_split[0], subder + + # last 4 members are irrelevant + name, ct, af, key, keys, policy, _, _, _, _ = old_serialization + + # standardize policy according to BIP-388 + policy = policy.replace("/<0;1>/*", "/**") + + # P2TR problem - policy here does not contain internal key (key) + # therefore numbering is wrong - needs to be x+1 to make place for internal key + # problem - keys can be duplicates with just subderivation different + + # deduplicate keys to become origin keys + keys = list(OrderedDict([(remove_subderivation(k)[0], None) for k in keys]).keys()) + + if key: + # taproot internal key + # will always be @0 + # need to check if this key is not already in policy somewhere + if "unspend(" in key: + # this is no longer supported - need to convert to xpub + end = key.find(")") + chain_code_str = key[8:end] + ik_u = True + ik_subder = key[end+1:] + n = ngu.hdnode.HDNode() + n.from_chaincode_pubkey(a2b_hex(chain_code_str), PROVABLY_UNSPENDABLE) + ik_key = chains.current_chain().serialize_public(n) + else: + ik_key, ik_subder = remove_subderivation(key) + ik_u = Key.from_string(ik_key).is_provably_unspendable + + if ik_subder == "/<0;1>/*": + ik_subder = "/**" + + # internal key can be used in script tree & can already be at its correct position + # i.e. first in the keys vector + ik_pos_incorrect = int(ik_key != keys[0]) + + keys_info = [] + for i in range(len(keys) - 1, -1, -1): + ph = "@%d" % i + assert policy.find(ph) != -1 + + res_key = keys[i] + + if af == AF_P2TR: + # to make space for internal key in policy we need to bump placeholder + if res_key == ik_key: + # this origin key is the same as internal key + # so it is @0 + policy = policy.replace(ph, "@0") + continue # no need to insert - will do later + else: + policy = policy.replace(ph, "@%d" % (i + ik_pos_incorrect)) + + keys_info.insert(0, res_key) + + new_opts = {"af": af} + # policy in old version lacks script type + if af == AF_P2TR: + # handle internal key + keys_info.insert(0, ik_key) + desc_tmplt = "tr(@0%s,%s)" % (ik_subder, policy) + new_opts["ik_u"] = ik_u + + elif af == AF_P2WSH: + desc_tmplt = "wsh(" + policy + ")" + elif af == AF_P2WSH_P2SH: + desc_tmplt = "sh(wsh(" + policy + "))" + else: + desc_tmplt = "sh(" + policy + ")" + + if ct != "BTC": + new_opts['ct'] = ct + + # previous version had unbounded names, cut it + return name[:MAX_NAME_LEN], desc_tmplt, keys_info, new_opts + + +async def multisig_640_migration(multisig_wallets): + # all MultisigWallet needs to be converted to MiniscriptWallet + # this function just returns new list of migrated multisig wallets without + # changing any persisted settings data + from glob import dis + dis.fullscreen("Migrating...") + total = len(multisig_wallets) + + migrated_multi = [] + # first element is always name, whether migrated or not + # shorten to MAX_NAME_LEN that will be done to miniscript names upon migration + taken_names = [tup[0][:MAX_NAME_LEN] for tup in settings.get("miniscript", [])] + for i, ms in enumerate(multisig_wallets): + bip67 = 1 # default enabled, requires 5-element serialization to disable + if len(ms) == 5: + bip67 = ms[-1] + ms = ms[:-1] + + name, m_of_n, xpubs, opts = ms + ct = opts.get('ch', 'BTC') + af = opts.get('ft', AF_P2SH) + + if len(xpubs[0]) == 2: + common_prefix = opts.get('pp', None) + if not common_prefix: + common_prefix = 'm' + common_prefix = common_prefix.replace("'", "h") + xpubs = [(a, common_prefix, b) for a, b in xpubs] + else: + # new format decompression + if 'd' in opts: + derivs = [p.replace("'", "h") for p in opts.get('d')] + xpubs = [(a, derivs[b], c) for a, b, c in xpubs] + + keys_info = [] + for mfp, der, ek in xpubs: + xfp = xfp2str(mfp).lower() + if der == "m": + keys_info.append("[%s]%s" % (xfp, ek)) + else: + keys_info.append("[%s/%s]%s" % (xfp, der.replace("m/", ""), ek)) + + ms_type = "sortedmulti" if bip67 else "multi" + if af == AF_P2WSH: + desc_tmplt = "wsh(" + ms_type + "(%s))" + elif af == AF_P2WSH_P2SH: + desc_tmplt = "sh(wsh(" + ms_type + "(%s)))" + else: + desc_tmplt = "sh(" + ms_type + "(%s))" + + M, N = m_of_n + inner = "%d,%s" % (M, ",".join(["@%d/**" % i for i in range(M)])) + desc_tmplt = desc_tmplt % inner + + new_opts = { + "af": af, + "m_n": (M, N), + "b67": bip67 + } + if ct != "BTC": + new_opts['ct'] = ct + + # this should not happen as multisg names were limited to 20 chars max + name = name[:MAX_NAME_LEN] + if name in taken_names: + # name collision with miniscript + while name in taken_names: + suffix = str(ngu.random.uniform(100)) + if (len(name) + len(suffix)) > MAX_NAME_LEN: + # issue + name = name[:MAX_NAME_LEN-len(suffix)] + + name = name + suffix + + migrated_multi.append((name, desc_tmplt, keys_info, new_opts)) + dis.progress_sofar(i+1, total) + + return migrated_multi + # EOF diff --git a/shared/web2fa.py b/shared/web2fa.py new file mode 100644 index 00000000..b78fc1dd --- /dev/null +++ b/shared/web2fa.py @@ -0,0 +1,176 @@ +# (c) Copyright 2021 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# +# web2fa.py -- Bounce a shared secret off a Coinkite server to allow mobile app 2FA. +# +# +import ngu, ndef, aes256ctr +from utils import b2a_base64url, url_quote, B2A +from version import has_qr +from ux import show_qr_code, ux_show_story, X + +# Only Coldcard.com server knows private key for this pubkey. It protects +# the privacy of the values we send to the server. +# +# = 0231301ec4acec08c1c7d0181f4ffb8be70d693acccc86cccb8f00bf2e00fcabfd +SERVER_PUBKEY = b'\x02\x31\x30\x1e\xc4\xac\xec\x08\xc1\xc7\xd0\x18\x1f\x4f\xfb\x8b\xe7\x0d\x69\x3a\xcc\xcc\x86\xcc\xcb\x8f\x00\xbf\x2e\x00\xfc\xab\xfd' + +def encrypt_details(qs): + # encryption and base64 here + # - pick single-use ephemeral secp256k1 keypair + # - do ECDH to generate a shared secret based on known pubkey of server + # - AES-256-CTR encryption based on that + # - base64url encode result + + # pick a random key pair, just for this session + pair = ngu.secp256k1.keypair() + my_pubkey = pair.pubkey().to_bytes(False) # compressed format + + session_key = pair.ecdh_multiply(SERVER_PUBKEY) + del pair + + enc = aes256ctr.new(session_key).cipher + + return b2a_base64url(my_pubkey + enc(qs.encode('ascii'))) + +async def perform_web2fa(label, shared_secret): + + # send them to web, prompt for valid response. Return True if it all worked. + expect = await nfc_share_2fa_link(label, shared_secret) + if not expect: + # aborted at NFC step + return False + + if has_qr: + # Make them scan the result, for example: + # + # CCC-AUTH:E902B3DAF2D98040F3A5F556D7CCC7C22BF3D455C146C4D4C0F7CF8B7937C530 + # + from ux_q1 import QRScannerInteraction + from exceptions import QRDecodeExplained + + prefix = 'CCC-AUTH:' + scanner = QRScannerInteraction() + + def validate(got): + if not got.startswith(prefix): + raise QRDecodeExplained("QR isn't from our site") + if got != prefix+expect: + # probably attempted replay + raise QRDecodeExplained("Incorrect code?") + return got + + data = await scanner.scan_general('Scan QR shown from Web', validate) + if not data: + return False # pressed cancel + + # only one legal response possible, and already validated above + return data == (prefix+expect) + + else: + # + # Mk4 and other devices w/o QR scanner, require user to enter 8 digits + # + from ux_mk4 import ux_input_digits + + while 1: + got = await ux_input_digits('', maxlen=8, + prompt="8-digits From Web") + + if not got: + # abort if empty entry + return False + + if got == expect: + # good match + return True + + ch = await ux_show_story("You entered an incorrect code. You must" + " enter the digits shown after the correct" + " 2FA code is provided to the website." + " Try again or %s to stop." % X) + if ch == 'x': + return False + + # not reached + return False + + +async def web2fa_enroll(ss=None): + # + # Enroll: Pick a secret and test they have loaded it into their phone. + # + + # must have NFC tho + from flow import feature_requires_nfc + if not await feature_requires_nfc(): + # they don't want to proceed + return None + + # Pick a shared secret; 10 bytes, so encodes to 16 base32 chars + ss = ss or ngu.codecs.b32_encode(ngu.random.bytes(10)) + + # show a QR that app know how to use + # - problem: on Mk4, not really enough space: + # - can only show up to 42 chars, and secret is 16, required overhead is 23 => 39 min + # - can't fit any metadata, like username or our serial # in there + # - better on Q1 where no limitations for this size of QR + + nm = 'COLDCARD' if has_qr else 'CC' # must be url-safe + qr = 'otpauth://totp/{nm}?secret={ss}'.format(ss=ss, nm=nm) + + while 1: + # show QR for enroll + await show_qr_code(qr, is_alnum=False, msg="Import into 2FA Mobile App", + force_msg=True) + + # important: force them to prove they stored it correctly + ok = await perform_web2fa('Enroll: COLDCARD', ss) + if ok: break + + ch = await ux_show_story("That isn't correct. Please re-import and/or " + "try again or %s to give up." % X) + if ch == 'x': + return None + + return ss + +def make_web2fa_url(wallet_name, shared_secret): + # Build complex URL into our server w/ encrypted data + # - picking a nonce in the process + prefix = 'coldcard.com/2fa?' + + # random nonce: if we get this back, then server approves of TOTP answer + if has_qr: + # data for a QR + nonce = B2A(ngu.random.bytes(32)).upper() + else: + # 8 digits for human entry + nonce = '%08d' % ngu.random.uniform(1_0000_0000) + + # compose URL + qs = 'g=%s&ss=%s&nm=%s&q=%d' % (nonce, shared_secret, url_quote(wallet_name), has_qr) + + # encrypt that + qs = encrypt_details(qs) + + return nonce, prefix + qs + +async def nfc_share_2fa_link(wallet_name, shared_secret): + # + # Share complex NFC deeplink into 2fa backend; returns expected response-code. + # Next step is to prompt for that 8-digit code (mk4) or scan QR (Q) + # + from glob import NFC + assert NFC + + nonce, url = make_web2fa_url(wallet_name, shared_secret) + + n = ndef.ndefMaker() + n.add_url(url, https=True) + + aborted = await NFC.share_start(n, prompt="Tap for 2FA Authentication", + line2="Wallet: " + wallet_name) + + return None if aborted else nonce + +# EOF diff --git a/shared/xor_seed.py b/shared/xor_seed.py index 1a4a9842..a89bde11 100644 --- a/shared/xor_seed.py +++ b/shared/xor_seed.py @@ -5,29 +5,16 @@ # - for secret spliting on paper # - all combination of partial XOR seed phrases are working wallets # -import stash, ngu, bip39, version +import ngu, bip39, version from ux import ux_show_story, the_ux, ux_confirm, ux_dramatic_pause from ux import show_qr_code, ux_render_words, OK -from seed import word_quiz, WordNestMenu, set_seed_value, set_ephemeral_seed +from seed import word_quiz, WordNestMenu, set_seed_value, set_ephemeral_seed, seed_vault_iter from glob import settings from menu import MenuSystem, MenuItem from actions import goto_top_menu -from utils import encode_seed_qr, pad_raw_secret +from utils import encode_seed_qr, deserialize_secret, xor from charcodes import KEY_QR - - -def xor(*args): - # bit-wise xor between all args - vlen = len(args[0]) - # all have to be same length - assert all(len(e) == vlen for e in args) - rv = bytearray(vlen) - - for i in range(vlen): - for a in args: - rv[i] ^= a[i] - - return rv +from stash import SecretStash, blank_object, SensitiveValues, numwords_to_len, len_to_numwords async def xor_split_start(*a): @@ -69,12 +56,7 @@ Otherwise, press {ok} to continue.'''.format(n=num_parts, ok=OK), escape='2') raw_secret = bytes(32) try: - with stash.SensitiveValues() as sv: - if sv.deltamode: - # die rather than give up our secrets - import callgate - callgate.fast_wipe() - + with SensitiveValues(enforce_delta=True) as sv: words = None if sv.mode == 'words': words = bip39.b2a_words(sv.raw).split(' ') @@ -82,7 +64,7 @@ Otherwise, press {ok} to continue.'''.format(n=num_parts, ok=OK), escape='2') # checksum of target result is useful chk_word = words[-1] - vlen = stash.numwords_to_len(len(words)) + vlen = numwords_to_len(len(words)) del words @@ -106,7 +88,7 @@ Otherwise, press {ok} to continue.'''.format(n=num_parts, ok=OK), escape='2') assert xor(*parts) == raw_secret # selftest finally: - stash.blank_object(raw_secret) + blank_object(raw_secret) word_parts = [bip39.b2a_words(p).split(' ') for p in parts] @@ -138,20 +120,22 @@ Quiz Passed!\n You have confirmed the details of the new split.''') # list of seed phrases -# stores encoded secret bytes (not word lists) +# - stores encoded secret bytes (not word lists) import_xor_parts = [] async def xor_all_done(data): # So we have another part, might be done or not. global import_xor_parts + chk_words = None + if data is None: # special case, needs something already in import_xor_parts - target_words = stash.len_to_numwords(len(import_xor_parts[0])) + target_words = len_to_numwords(len(import_xor_parts[0])) else: new_encoded = bip39.a2b_words(data) if isinstance(data, list) else data import_xor_parts.append(new_encoded) - target_words = stash.len_to_numwords(len(new_encoded)) + target_words = len_to_numwords(len(new_encoded)) XORWordNestMenu.pop_all() @@ -162,7 +146,7 @@ async def xor_all_done(data): if num_parts >= 2: chk_words = bip39.b2a_words(seed).split(' ') chk_word = chk_words[-1] - msg += "If you stop now, the %dth word of the XOR-combined seed phrase\nwill be:\n\n" % target_words + msg += "If you stop now, the %dth word of the XOR-combined seed phrase will be:\n\n" % target_words msg += "%d: %s\n\n" % (target_words, chk_word) if all((not x) for x in seed): @@ -186,7 +170,7 @@ async def xor_all_done(data): import_xor_parts.clear() # concern: we are contaminated w/ secrets elif chk_words and ch == KEY_QR: rv = encode_seed_qr(chk_words) - await show_qr_code(rv, True, msg="SeedQR") + await show_qr_code(rv, True, msg="SeedQR", is_secret=True) continue elif ch == '1': # do another list of words @@ -203,7 +187,7 @@ async def xor_all_done(data): from pincodes import pa from glob import dis - enc = stash.SecretStash.encode(seed_phrase=seed) + enc = SecretStash.encode(seed_phrase=seed) if pa.is_secret_blank(): # save it since they have no other secret @@ -217,17 +201,15 @@ async def xor_all_done(data): # only need XFPs for UI # xfps = [ # xfp2str(swab32( - # stash.SecretStash.decode(stash.SecretStash.encode(seed_phrase=i))[2].my_fp() + # SecretStash.decode(SecretStash.encode(seed_phrase=i))[2].my_fp() # )) # for i in enc_parts # ] - await set_ephemeral_seed( - enc, - meta='SeedXOR(%d parts, check: "%s")' % ( - num_parts, chk_word - ) - ) + await set_ephemeral_seed(enc, + origin='SeedXOR(%d parts, check: "%s")' % (num_parts, chk_word)) + goto_top_menu() + break class XORWordNestMenu(WordNestMenu): @@ -243,7 +225,7 @@ async def show_n_parts(parts, chk_word): for n,words in enumerate(parts): msg += '\n\nPart %s:\n' % chr(65+n) - msg += ux_render_words(words, leading_blanks=0) + msg += ux_render_words(words) msg += ('\n\nThe correctly reconstructed seed phrase will have this final word,' ' which we recommend recording:\n\n%d: %s\n\n' % (seed_len, chk_word)) @@ -256,12 +238,12 @@ async def xor_restore_start(*a): # shown on import menu when no seed of any kind yet # - or operational system ch = await ux_show_story('''\ -To import a seed split using XOR, you must import all the parts. -It does not matter the order (A/B/C or C/A/B) and the Coldcard -cannot determine when you have all the parts. You may stop at -any time and you will have a valid wallet. Combined seed parts -have to be equal length. No way to combine seed parts of different -length. Press %s for 24 words XOR, press (1) for 12 words XOR, +To import a seed split using XOR, you must import all the parts. \ +It does not matter the order (A/B/C or C/A/B) and the Coldcard \ +cannot determine when you have all the parts. You may stop at \ +any time and you will have a valid wallet. Combined seed parts \ +have to be equal length.\n +Press %s for 24 words XOR, press (1) for 12 words XOR, \ or press (2) for 18 words XOR.''' % OK, escape="12") if ch == 'x': return @@ -271,8 +253,6 @@ or press (2) for 18 words XOR.''' % OK, escape="12") elif ch == "2": desired_num_words = 18 - curr_num_words = settings.get('words', desired_num_words) - global import_xor_parts import_xor_parts.clear() @@ -284,22 +264,22 @@ or press (2) for 18 words XOR.''' % OK, escape="12") msg = ("Since you have a seed already on this Coldcard, the reconstructed XOR seed will be " "temporary and not saved. Wipe the seed first if you want to commit the new value " "into the secure element.") - if curr_num_words == desired_num_words: + + curr_num_words = settings.get('words', desired_num_words) + if (curr_num_words == desired_num_words) and not pa.hobbled_mode: escape += "1" - msg += ("\nPress (1) to include this Coldcard's seed words into the XOR seed set, " + msg += ("\n\nPress (1) to include this Coldcard's seed words into the XOR seed set, " "or %s to continue without." % OK) ch = await ux_show_story(msg, escape=escape) - if ch == 'x': return - if ch == '1': - dis.fullscreen("Wait...") - with stash.SensitiveValues() as sv: - if sv.deltamode: - # die rather than give up our secrets - import callgate - callgate.fast_wipe() + if ch == 'x': + return + if ch == '1': + assert not pa.hobbled_mode + dis.fullscreen("Wait...") + with SensitiveValues(enforce_delta=True) as sv: if sv.mode == 'words': # needs copy here [:] otherwise rewritten with zeros in __exit__ import_xor_parts.append(sv.raw[:]) @@ -307,15 +287,17 @@ or press (2) for 18 words XOR.''' % OK, escape="12") # Add from Seed Vault? # filter only those that are correct length and type from seed vault opt = [] - seeds = [] if pa.is_deltamode() else settings.master_get("seeds", []) - for i, (xfp_str, hex_str, _, _) in enumerate(seeds): - raw = pad_raw_secret(hex_str) - if raw[0] & 0x80: - # seed phrase - sk = raw[1:1 + stash.len_from_marker(raw[0])] - if stash.len_to_numwords(len(sk)) == desired_num_words: - opt.append((i, xfp_str, sk)) - del seeds + for i, rec in enumerate(seed_vault_iter()): + raw = deserialize_secret(rec.encoded) + + nw = SecretStash.is_words(raw) + if nw and nw == desired_num_words: + # it is words, and right length + sk = SecretStash.decode_words(raw, bin_mode=True) + opt.append((i, rec.xfp, sk)) + + blank_object(raw) + if opt: escape = "2" msg = ("Seed Vault is enabled. %d stored seeds have suitable type and length." diff --git a/stm32/.gitignore b/stm32/.gitignore index d1542d38..c7b33a6a 100644 --- a/stm32/.gitignore +++ b/stm32/.gitignore @@ -9,7 +9,7 @@ firmware.lss firmware-signed.* firmware.elf file_time.c -*-RC1-coldcard.dfu +*-RC1-*.dfu RC2-*.dfu # somewhat useful binary snapshots diff --git a/stm32/MK4-Makefile b/stm32/MK4-Makefile index 72c3cf55..609f3497 100644 --- a/stm32/MK4-Makefile +++ b/stm32/MK4-Makefile @@ -12,14 +12,14 @@ HW_MODEL = mk4 PARENT_MKFILE = MK4-Makefile # This is release of the bootloader that will be built into the factory.dfu -BOOTLOADER_VERSION = 3.2.0 +BOOTLOADER_VERSION = 3.2.1 BOOTLOADER_DIR = mk4-bootloader LATEST_RELEASE = $(shell ls -t1 ../releases/*-mk4-*.dfu | head -1) # Our version for this release. # - caution, the bootrom will not accept version < 3.0.0 -VERSION_STRING = 6.3.5X +VERSION_STRING = 6.4.0X # keep near top, because defined default target (all) include shared.mk diff --git a/stm32/Q1-Makefile b/stm32/Q1-Makefile index 0e669dac..23dd0785 100644 --- a/stm32/Q1-Makefile +++ b/stm32/Q1-Makefile @@ -10,13 +10,13 @@ HW_MODEL = q1 PARENT_MKFILE = Q1-Makefile # This is release of the bootloader that will be built into the factory.dfu -BOOTLOADER_VERSION = 1.0.4 +BOOTLOADER_VERSION = 1.1.0 BOOTLOADER_DIR = q1-bootloader LATEST_RELEASE = $(shell ls -t1 ../releases/*-q1-*.dfu | head -1) # Our version for this release. -VERSION_STRING = 6.3.5QX +VERSION_STRING = 6.4.0QX # Remove this closer to shipping. #$(warning "Forcing debug build") diff --git a/stm32/bootloader/README.md b/stm32/bootloader/README.md index 1b629de4..13cbb426 100644 --- a/stm32/bootloader/README.md +++ b/stm32/bootloader/README.md @@ -19,7 +19,7 @@ your key storage per-system unique. - the most helpful file here is `bootloader.lss` which is generated in build process -- using OpenOCD is prefered for lower level code like this (not GDB) +- using OpenOCD is preferred for lower level code like this (not GDB) - `stm32l4x.cpu arm disassemble 0x000008 10 thumb` is very helpful @@ -140,7 +140,7 @@ Mk4: ## Re-do Bag Number -- cannot writes ones, and then change flash cells; have to remain unprogrammed +- cannot write ones, and then change flash cells; have to remain unprogrammed dfu-util -d 0483:df11 -a 0 -s 0x0801c000:8192 -U pairing.bin diff --git a/stm32/mk4-bootloader/ae.c b/stm32/mk4-bootloader/ae.c index a55e34cc..df632ed1 100644 --- a/stm32/mk4-bootloader/ae.c +++ b/stm32/mk4-bootloader/ae.c @@ -1726,6 +1726,7 @@ ae_read_config_byte(int offset) uint8_t tmp[4]; ae_read_config_word(offset, tmp); + // BUG: didnt check for failure, in which case we will return un-inited values return tmp[offset % 4]; } diff --git a/stm32/mk4-bootloader/pins.c b/stm32/mk4-bootloader/pins.c index bba8272d..25ae4238 100644 --- a/stm32/mk4-bootloader/pins.c +++ b/stm32/mk4-bootloader/pins.c @@ -718,7 +718,8 @@ pin_login_attempt(pinAttempt_t *args) args->num_fails = 0; args->attempts_left = MAX_TARGET_ATTEMPTS; - if(check_all_zeros(slot.xdata, 32) || (slot.tc_flags & TC_WIPE)) { + bool wipe = (slot.tc_flags & TC_WIPE) && !(slot.tc_flags & (TC_WORD_WALLET|TC_XPRV_WALLET)); + if(check_all_zeros(slot.xdata, 32) || wipe) { args->state_flags |= PA_ZERO_SECRET; } diff --git a/stm32/mk4-bootloader/releases/3.2.1.txt b/stm32/mk4-bootloader/releases/3.2.1.txt new file mode 100644 index 00000000..8f3fdd6b --- /dev/null +++ b/stm32/mk4-bootloader/releases/3.2.1.txt @@ -0,0 +1,4 @@ +0904b790af34c8acd8e3156cd5b4e818ae09e93611e90c673a7953fec67802d0 bootloader.dfu +7c7acbb849d17721f9a53b613d631f8bb8ed3b49c2bf5e1a413511c7d9105775 bootloader.bin +e71a730d2025bfcc0bf334614c60022e8df3d847c7c6a53f172aace004d69553 bootloader.lss +3.2.1 time=20250415.090935 git=master@adcf2c8e diff --git a/stm32/mk4-bootloader/releases/3.2.1/bootloader.bin b/stm32/mk4-bootloader/releases/3.2.1/bootloader.bin new file mode 100644 index 00000000..964e8174 Binary files /dev/null and b/stm32/mk4-bootloader/releases/3.2.1/bootloader.bin differ diff --git a/stm32/mk4-bootloader/releases/3.2.1/bootloader.dfu b/stm32/mk4-bootloader/releases/3.2.1/bootloader.dfu new file mode 100644 index 00000000..13784b58 Binary files /dev/null and b/stm32/mk4-bootloader/releases/3.2.1/bootloader.dfu differ diff --git a/stm32/mk4-bootloader/releases/3.2.1/bootloader.lss b/stm32/mk4-bootloader/releases/3.2.1/bootloader.lss new file mode 100644 index 00000000..a67725ce --- /dev/null +++ b/stm32/mk4-bootloader/releases/3.2.1/bootloader.lss @@ -0,0 +1,34612 @@ + +bootloader.elf: file format elf32-littlearm + +Sections: +Idx Name Size VMA LMA File off Algn + 0 .text 0000ea48 08000000 08000000 00010000 2**8 + CONTENTS, ALLOC, LOAD, READONLY, CODE + 1 .relocate 00000150 2009e000 0800ea48 0002e000 2**2 + CONTENTS, ALLOC, LOAD, READONLY, CODE + 2 .bss 000002e8 2009e150 0800eb98 0002e150 2**2 + ALLOC + 3 .stack 00000800 2009e438 0800ee80 0002e150 2**0 + ALLOC + 4 .debug_info 0002bc2d 00000000 00000000 0002e150 2**0 + CONTENTS, READONLY, DEBUGGING, OCTETS + 5 .debug_abbrev 00005f7a 00000000 00000000 00059d7d 2**0 + CONTENTS, READONLY, DEBUGGING, OCTETS + 6 .debug_loc 00014618 00000000 00000000 0005fcf7 2**0 + CONTENTS, READONLY, DEBUGGING, OCTETS + 7 .debug_aranges 000010c8 00000000 00000000 0007430f 2**0 + CONTENTS, READONLY, DEBUGGING, OCTETS + 8 .debug_ranges 00002148 00000000 00000000 000753d7 2**0 + CONTENTS, READONLY, DEBUGGING, OCTETS + 9 .debug_macro 00032533 00000000 00000000 0007751f 2**0 + CONTENTS, READONLY, DEBUGGING, OCTETS + 10 .debug_line 0001de5f 00000000 00000000 000a9a52 2**0 + CONTENTS, READONLY, DEBUGGING, OCTETS + 11 .debug_str 0011cbb0 00000000 00000000 000c78b1 2**0 + CONTENTS, READONLY, DEBUGGING, OCTETS + 12 .comment 00000049 00000000 00000000 001e4461 2**0 + CONTENTS, READONLY + 13 .ARM.attributes 00000032 00000000 00000000 001e44aa 2**0 + CONTENTS, READONLY + 14 .debug_frame 000036f4 00000000 00000000 001e44dc 2**2 + CONTENTS, READONLY, DEBUGGING, OCTETS + +Disassembly of section .text: + +08000000 <_sfixed>: + 8000000: 200a0000 .word 0x200a0000 + 8000004: 080000b5 .word 0x080000b5 + 8000008: 0800001d .word 0x0800001d + 800000c: 0800001f .word 0x0800001f + 8000010: 08000021 .word 0x08000021 + 8000014: 08000023 .word 0x08000023 + 8000018: 08000025 .word 0x08000025 + +0800001c : + 800001c: be01 bkpt 0x0001 + +0800001e : + 800001e: be02 bkpt 0x0002 + +08000020 : + 8000020: be03 bkpt 0x0003 + +08000022 : + 8000022: be04 bkpt 0x0004 + +08000024 : + 8000024: be05 bkpt 0x0005 + 8000026: e7fe b.n 8000026 + +08000028 : + ... + 8000040: 08000305 .word 0x08000305 + +08000044 : + 8000044: 00000200 .word 0x00000200 + ... + 8000060: 20296328 .word 0x20296328 + 8000064: 79706f43 .word 0x79706f43 + 8000068: 68676972 .word 0x68676972 + 800006c: 30322074 .word 0x30322074 + 8000070: 322d3831 .word 0x322d3831 + 8000074: 20323230 .word 0x20323230 + 8000078: 43207962 .word 0x43207962 + 800007c: 6b6e696f .word 0x6b6e696f + 8000080: 20657469 .word 0x20657469 + 8000084: 2e636e49 .word 0x2e636e49 + 8000088: 0a200a20 .word 0x0a200a20 + 800008c: 73696854 .word 0x73696854 + 8000090: 61707320 .word 0x61707320 + 8000094: 66206563 .word 0x66206563 + 8000098: 7220726f .word 0x7220726f + 800009c: 21746e65 .word 0x21746e65 + 80000a0: 73754a20 .word 0x73754a20 + 80000a4: 42312074 .word 0x42312074 + 80000a8: 792f4354 .word 0x792f4354 + 80000ac: 2e726165 .word 0x2e726165 + 80000b0: 0a200a20 .word 0x0a200a20 + +080000b4 : + 80000b4: f000 f816 bl 80000e4 + 80000b8: f04f 30ff mov.w r0, #4294967295 ; 0xffffffff + 80000bc: f04f 0100 mov.w r1, #0 + 80000c0: f04f 0200 mov.w r2, #0 + 80000c4: f04f 0300 mov.w r3, #0 + 80000c8: f000 f91c bl 8000304 + 80000cc: f248 0120 movw r1, #32800 ; 0x8020 + 80000d0: ea4f 3101 mov.w r1, r1, lsl #12 + 80000d4: 6808 ldr r0, [r1, #0] + 80000d6: 4685 mov sp, r0 + 80000d8: f04f 0001 mov.w r0, #1 + 80000dc: f8d1 e004 ldr.w lr, [r1, #4] + 80000e0: 4770 bx lr + ... + +080000e4 : + void +firewall_setup(void) +{ + // This is critical: without the clock enabled to "SYSCFG" we + // can't tell the FW is enabled or not! Enabling it would also not work + __HAL_RCC_SYSCFG_CLK_ENABLE(); + 80000e4: 4b1b ldr r3, [pc, #108] ; (8000154 ) +{ + 80000e6: b500 push {lr} + __HAL_RCC_SYSCFG_CLK_ENABLE(); + 80000e8: 6e1a ldr r2, [r3, #96] ; 0x60 + 80000ea: f042 0201 orr.w r2, r2, #1 + 80000ee: 661a str r2, [r3, #96] ; 0x60 + 80000f0: 6e1b ldr r3, [r3, #96] ; 0x60 +{ + 80000f2: b08b sub sp, #44 ; 0x2c + __HAL_RCC_SYSCFG_CLK_ENABLE(); + 80000f4: f003 0301 and.w r3, r3, #1 + 80000f8: 9300 str r3, [sp, #0] + 80000fa: 9b00 ldr r3, [sp, #0] + + if(__HAL_FIREWALL_IS_ENABLED()) { + 80000fc: 4b16 ldr r3, [pc, #88] ; (8000158 ) + 80000fe: 685b ldr r3, [r3, #4] + 8000100: 07db lsls r3, r3, #31 + 8000102: d524 bpl.n 800014e + // REMINDERS: + // - cannot debug anything in boot loader w/ firewall enabled (no readback, no bkpt) + // - when RDP=2, this protection still important or else python can read pairing secret + // - in factory mode (RDP!=2), it's nice to have this disabled so we can debug still + // - could look at RDP level here, but it would be harder to completely reset the bag number! + if(check_all_ones_raw(rom_secrets->bag_number, sizeof(rom_secrets->bag_number))) { + 8000104: 4815 ldr r0, [pc, #84] ; (800015c ) + 8000106: 2120 movs r1, #32 + 8000108: f002 faae bl 8002668 + 800010c: b9f8 cbnz r0, 800014e + // for debug builds, never enable firewall + return; +#endif + + extern int firewall_starts; // see startup.S ... aligned@256 (0x08000300) + uint32_t start = (uint32_t)&firewall_starts; + 800010e: 4b14 ldr r3, [pc, #80] ; (8000160 ) + uint32_t len = BL_FLASH_SIZE - (start - BL_FLASH_BASE); + 8000110: 4a14 ldr r2, [pc, #80] ; (8000164 ) + // but sensitive stuff is still there (which would allow bypass) + // - so it's important to enable option bytes to set write-protect flash of entire bootloader + // - to disable debug and complete protection, must enable write-protect "level 2" (RDP=2) + // + + FIREWALL_InitTypeDef init = { + 8000112: 9302 str r3, [sp, #8] + uint32_t len = BL_FLASH_SIZE - (start - BL_FLASH_BASE); + 8000114: 1ad3 subs r3, r2, r3 + FIREWALL_InitTypeDef init = { + 8000116: e9cd 3203 strd r3, r2, [sp, #12] + 800011a: f44f 4380 mov.w r3, #16384 ; 0x4000 + 800011e: e9cd 3005 strd r3, r0, [sp, #20] + 8000122: e9cd 0007 strd r0, r0, [sp, #28] + 8000126: 9009 str r0, [sp, #36] ; 0x24 + .VDataSegmentLength = 0, + .VolatileDataExecution = 0, + .VolatileDataShared = 0, + }; + + int rv = HAL_FIREWALL_Config((FIREWALL_InitTypeDef *)&init); + 8000128: a802 add r0, sp, #8 + 800012a: f000 f821 bl 8000170 + if(rv) { + 800012e: b110 cbz r0, 8000136 + INCONSISTENT("fw"); + 8000130: 480d ldr r0, [pc, #52] ; (8000168 ) + 8000132: f000 fc89 bl 8000a48 + } + + __HAL_FIREWALL_PREARM_DISABLE(); + 8000136: 4b0d ldr r3, [pc, #52] ; (800016c ) + 8000138: 6a1a ldr r2, [r3, #32] + 800013a: f022 0201 bic.w r2, r2, #1 + 800013e: 621a str r2, [r3, #32] + 8000140: 6a1b ldr r3, [r3, #32] + 8000142: f003 0301 and.w r3, r3, #1 + 8000146: 9301 str r3, [sp, #4] + 8000148: 9b01 ldr r3, [sp, #4] + HAL_FIREWALL_EnableFirewall(); + 800014a: f000 f88b bl 8000264 +} + 800014e: b00b add sp, #44 ; 0x2c + 8000150: f85d fb04 ldr.w pc, [sp], #4 + 8000154: 40021000 .word 0x40021000 + 8000158: 40010000 .word 0x40010000 + 800015c: 0801c050 .word 0x0801c050 + 8000160: 08000300 .word 0x08000300 + 8000164: 0801c000 .word 0x0801c000 + 8000168: 0800d700 .word 0x0800d700 + 800016c: 40011c00 .word 0x40011c00 + +08000170 : + * @param fw_init: Firewall initialization structure + * @note The API returns HAL_ERROR if the Firewall is already enabled. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_FIREWALL_Config(FIREWALL_InitTypeDef * fw_init) +{ + 8000170: b573 push {r0, r1, r4, r5, r6, lr} + /* Check the Firewall initialization structure allocation */ + if(fw_init == NULL) + 8000172: b910 cbnz r0, 800017a + { + return HAL_ERROR; + 8000174: 2001 movs r0, #1 + /* Set Firewall Configuration Register VDE and VDS bits + (volatile data execution and shared configuration) */ + MODIFY_REG(FIREWALL->CR, FW_CR_VDS|FW_CR_VDE, fw_init->VolatileDataExecution|fw_init->VolatileDataShared); + + return HAL_OK; +} + 8000176: b002 add sp, #8 + 8000178: bd70 pop {r4, r5, r6, pc} + __HAL_RCC_FIREWALL_CLK_ENABLE(); + 800017a: 4b19 ldr r3, [pc, #100] ; (80001e0 ) + 800017c: 6e1a ldr r2, [r3, #96] ; 0x60 + 800017e: f042 0280 orr.w r2, r2, #128 ; 0x80 + 8000182: 661a str r2, [r3, #96] ; 0x60 + 8000184: 6e1b ldr r3, [r3, #96] ; 0x60 + 8000186: f003 0380 and.w r3, r3, #128 ; 0x80 + 800018a: 9301 str r3, [sp, #4] + 800018c: 9b01 ldr r3, [sp, #4] + if (__HAL_FIREWALL_IS_ENABLED() != RESET) + 800018e: 4b15 ldr r3, [pc, #84] ; (80001e4 ) + 8000190: 685b ldr r3, [r3, #4] + 8000192: 07db lsls r3, r3, #31 + 8000194: d5ee bpl.n 8000174 + if (fw_init->CodeSegmentLength != 0U) + 8000196: 6841 ldr r1, [r0, #4] + if (fw_init->NonVDataSegmentLength < 0x100U) + 8000198: 68c2 ldr r2, [r0, #12] + if (fw_init->CodeSegmentLength != 0U) + 800019a: b109 cbz r1, 80001a0 + if (fw_init->NonVDataSegmentLength < 0x100U) + 800019c: 2aff cmp r2, #255 ; 0xff + 800019e: d9e9 bls.n 8000174 + WRITE_REG(FIREWALL->CSSA, (FW_CSSA_ADD & fw_init->CodeSegmentStartAddress)); + 80001a0: 6803 ldr r3, [r0, #0] + 80001a2: 4e11 ldr r6, [pc, #68] ; (80001e8 ) + if (fw_init->VDataSegmentLength != 0U) + 80001a4: 6944 ldr r4, [r0, #20] + WRITE_REG(FIREWALL->CSSA, (FW_CSSA_ADD & fw_init->CodeSegmentStartAddress)); + 80001a6: ea03 0506 and.w r5, r3, r6 + 80001aa: 4b10 ldr r3, [pc, #64] ; (80001ec ) + 80001ac: 601d str r5, [r3, #0] + WRITE_REG(FIREWALL->CSL, (FW_CSL_LENG & fw_init->CodeSegmentLength)); + 80001ae: 4d10 ldr r5, [pc, #64] ; (80001f0 ) + 80001b0: 4029 ands r1, r5 + 80001b2: 6059 str r1, [r3, #4] + WRITE_REG(FIREWALL->NVDSSA, (FW_NVDSSA_ADD & fw_init->NonVDataSegmentStartAddress)); + 80001b4: 6881 ldr r1, [r0, #8] + WRITE_REG(FIREWALL->NVDSL, (FW_NVDSL_LENG & fw_init->NonVDataSegmentLength)); + 80001b6: 402a ands r2, r5 + WRITE_REG(FIREWALL->NVDSSA, (FW_NVDSSA_ADD & fw_init->NonVDataSegmentStartAddress)); + 80001b8: 4031 ands r1, r6 + 80001ba: 6099 str r1, [r3, #8] + WRITE_REG(FIREWALL->NVDSL, (FW_NVDSL_LENG & fw_init->NonVDataSegmentLength)); + 80001bc: 60da str r2, [r3, #12] + WRITE_REG(FIREWALL->VDSSA, (FW_VDSSA_ADD & fw_init->VDataSegmentStartAddress)); + 80001be: 6901 ldr r1, [r0, #16] + 80001c0: 4a0c ldr r2, [pc, #48] ; (80001f4 ) + 80001c2: 4011 ands r1, r2 + WRITE_REG(FIREWALL->VDSL, (FW_VDSL_LENG & fw_init->VDataSegmentLength)); + 80001c4: 4022 ands r2, r4 + WRITE_REG(FIREWALL->VDSSA, (FW_VDSSA_ADD & fw_init->VDataSegmentStartAddress)); + 80001c6: 6119 str r1, [r3, #16] + WRITE_REG(FIREWALL->VDSL, (FW_VDSL_LENG & fw_init->VDataSegmentLength)); + 80001c8: 615a str r2, [r3, #20] + MODIFY_REG(FIREWALL->CR, FW_CR_VDS|FW_CR_VDE, fw_init->VolatileDataExecution|fw_init->VolatileDataShared); + 80001ca: e9d0 2006 ldrd r2, r0, [r0, #24] + 80001ce: 6a19 ldr r1, [r3, #32] + 80001d0: 4302 orrs r2, r0 + 80001d2: f021 0106 bic.w r1, r1, #6 + 80001d6: 430a orrs r2, r1 + 80001d8: 621a str r2, [r3, #32] + return HAL_OK; + 80001da: 2000 movs r0, #0 + 80001dc: e7cb b.n 8000176 + 80001de: bf00 nop + 80001e0: 40021000 .word 0x40021000 + 80001e4: 40010000 .word 0x40010000 + 80001e8: 00ffff00 .word 0x00ffff00 + 80001ec: 40011c00 .word 0x40011c00 + 80001f0: 003fff00 .word 0x003fff00 + 80001f4: 0003ffc0 .word 0x0003ffc0 + +080001f8 : +void HAL_FIREWALL_GetConfig(FIREWALL_InitTypeDef * fw_config) +{ + + /* Enable Firewall clock, in case no Firewall configuration has been carried + out up to this point */ + __HAL_RCC_FIREWALL_CLK_ENABLE(); + 80001f8: 4b15 ldr r3, [pc, #84] ; (8000250 ) + 80001fa: 6e1a ldr r2, [r3, #96] ; 0x60 +{ + 80001fc: b573 push {r0, r1, r4, r5, r6, lr} + __HAL_RCC_FIREWALL_CLK_ENABLE(); + 80001fe: f042 0280 orr.w r2, r2, #128 ; 0x80 + 8000202: 661a str r2, [r3, #96] ; 0x60 + 8000204: 6e1b ldr r3, [r3, #96] ; 0x60 + + /* Retrieve code segment protection setting */ + fw_config->CodeSegmentStartAddress = (READ_REG(FIREWALL->CSSA) & FW_CSSA_ADD); + 8000206: 4e13 ldr r6, [pc, #76] ; (8000254 ) + fw_config->CodeSegmentLength = (READ_REG(FIREWALL->CSL) & FW_CSL_LENG); + 8000208: 4d13 ldr r5, [pc, #76] ; (8000258 ) + __HAL_RCC_FIREWALL_CLK_ENABLE(); + 800020a: f003 0380 and.w r3, r3, #128 ; 0x80 + 800020e: 9301 str r3, [sp, #4] + 8000210: 9b01 ldr r3, [sp, #4] + fw_config->CodeSegmentStartAddress = (READ_REG(FIREWALL->CSSA) & FW_CSSA_ADD); + 8000212: 4b12 ldr r3, [pc, #72] ; (800025c ) + 8000214: 681a ldr r2, [r3, #0] + 8000216: 4032 ands r2, r6 + 8000218: 6002 str r2, [r0, #0] + fw_config->CodeSegmentLength = (READ_REG(FIREWALL->CSL) & FW_CSL_LENG); + 800021a: 685c ldr r4, [r3, #4] + 800021c: 402c ands r4, r5 + 800021e: 6044 str r4, [r0, #4] + + /* Retrieve non volatile data segment protection setting */ + fw_config->NonVDataSegmentStartAddress = (READ_REG(FIREWALL->NVDSSA) & FW_NVDSSA_ADD); + 8000220: 6899 ldr r1, [r3, #8] + fw_config->NonVDataSegmentLength = (READ_REG(FIREWALL->NVDSL) & FW_NVDSL_LENG); + + /* Retrieve volatile data segment protection setting */ + fw_config->VDataSegmentStartAddress = (READ_REG(FIREWALL->VDSSA) & FW_VDSSA_ADD); + 8000222: 4c0f ldr r4, [pc, #60] ; (8000260 ) + fw_config->NonVDataSegmentStartAddress = (READ_REG(FIREWALL->NVDSSA) & FW_NVDSSA_ADD); + 8000224: 4031 ands r1, r6 + 8000226: 6081 str r1, [r0, #8] + fw_config->NonVDataSegmentLength = (READ_REG(FIREWALL->NVDSL) & FW_NVDSL_LENG); + 8000228: 68da ldr r2, [r3, #12] + 800022a: 402a ands r2, r5 + 800022c: 60c2 str r2, [r0, #12] + fw_config->VDataSegmentStartAddress = (READ_REG(FIREWALL->VDSSA) & FW_VDSSA_ADD); + 800022e: 6919 ldr r1, [r3, #16] + 8000230: 4021 ands r1, r4 + 8000232: 6101 str r1, [r0, #16] + fw_config->VDataSegmentLength = (READ_REG(FIREWALL->VDSL) & FW_VDSL_LENG); + 8000234: 695a ldr r2, [r3, #20] + 8000236: 4022 ands r2, r4 + 8000238: 6142 str r2, [r0, #20] + + /* Retrieve volatile data execution setting */ + fw_config->VolatileDataExecution = (READ_REG(FIREWALL->CR) & FW_CR_VDE); + 800023a: 6a1a ldr r2, [r3, #32] + 800023c: f002 0204 and.w r2, r2, #4 + 8000240: 6182 str r2, [r0, #24] + + /* Retrieve volatile data shared setting */ + fw_config->VolatileDataShared = (READ_REG(FIREWALL->CR) & FW_CR_VDS); + 8000242: 6a1b ldr r3, [r3, #32] + 8000244: f003 0302 and.w r3, r3, #2 + 8000248: 61c3 str r3, [r0, #28] + + return; +} + 800024a: b002 add sp, #8 + 800024c: bd70 pop {r4, r5, r6, pc} + 800024e: bf00 nop + 8000250: 40021000 .word 0x40021000 + 8000254: 00ffff00 .word 0x00ffff00 + 8000258: 003fff00 .word 0x003fff00 + 800025c: 40011c00 .word 0x40011c00 + 8000260: 0003ffc0 .word 0x0003ffc0 + +08000264 : + * @retval None + */ +void HAL_FIREWALL_EnableFirewall(void) +{ + /* Clears FWDIS bit of SYSCFG CFGR1 register */ + CLEAR_BIT(SYSCFG->CFGR1, SYSCFG_CFGR1_FWDIS); + 8000264: 4a02 ldr r2, [pc, #8] ; (8000270 ) + 8000266: 6853 ldr r3, [r2, #4] + 8000268: f023 0301 bic.w r3, r3, #1 + 800026c: 6053 str r3, [r2, #4] + +} + 800026e: 4770 bx lr + 8000270: 40010000 .word 0x40010000 + +08000274 : + * @retval None + */ +void HAL_FIREWALL_EnablePreArmFlag(void) +{ + /* Set FPA bit */ + SET_BIT(FIREWALL->CR, FW_CR_FPA); + 8000274: 4a02 ldr r2, [pc, #8] ; (8000280 ) + 8000276: 6a13 ldr r3, [r2, #32] + 8000278: f043 0301 orr.w r3, r3, #1 + 800027c: 6213 str r3, [r2, #32] +} + 800027e: 4770 bx lr + 8000280: 40011c00 .word 0x40011c00 + +08000284 : + * @retval None + */ +void HAL_FIREWALL_DisablePreArmFlag(void) +{ + /* Clear FPA bit */ + CLEAR_BIT(FIREWALL->CR, FW_CR_FPA); + 8000284: 4a02 ldr r2, [pc, #8] ; (8000290 ) + 8000286: 6a13 ldr r3, [r2, #32] + 8000288: f023 0301 bic.w r3, r3, #1 + 800028c: 6213 str r3, [r2, #32] +} + 800028e: 4770 bx lr + 8000290: 40011c00 .word 0x40011c00 + ... + +08000300 <_firewall_start>: + 8000300: 0f193a11 .word 0x0f193a11 + +08000304 : + 8000304: f24e 0900 movw r9, #57344 ; 0xe000 + 8000308: f2c2 0909 movt r9, #8201 ; 0x2009 + 800030c: f44f 5a00 mov.w sl, #8192 ; 0x2000 + 8000310: 44ca add sl, r9 + +08000312 : + 8000312: f849 ab04 str.w sl, [r9], #4 + 8000316: 45d1 cmp r9, sl + 8000318: d1fb bne.n 8000312 + 800031a: 46ea mov sl, sp + 800031c: 46cd mov sp, r9 + 800031e: e92d 4400 stmdb sp!, {sl, lr} + +08000322 : + 8000322: f000 f841 bl 80003a8 + 8000326: e8bd 4400 ldmia.w sp!, {sl, lr} + 800032a: 46d5 mov sp, sl + 800032c: f24e 0900 movw r9, #57344 ; 0xe000 + 8000330: f2c2 0909 movt r9, #8201 ; 0x2009 + 8000334: f44f 5a00 mov.w sl, #8192 ; 0x2000 + 8000338: 44ca add sl, r9 + +0800033a : + 800033a: f849 0b04 str.w r0, [r9], #4 + 800033e: 45d1 cmp r9, sl + 8000340: d1fb bne.n 800033a + 8000342: 4770 bx lr + +08000344 <__NVIC_SystemReset>: + \details Acts as a special kind of Data Memory Barrier. + It completes when all explicit memory accesses before this instruction complete. + */ +__STATIC_FORCEINLINE void __DSB(void) +{ + __ASM volatile ("dsb 0xF":::"memory"); + 8000344: f3bf 8f4f dsb sy +__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void) +{ + __DSB(); /* Ensure all outstanding memory accesses included + buffered write are completed before reset */ + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 8000348: 4905 ldr r1, [pc, #20] ; (8000360 <__NVIC_SystemReset+0x1c>) + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 800034a: 4b06 ldr r3, [pc, #24] ; (8000364 <__NVIC_SystemReset+0x20>) + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 800034c: 68ca ldr r2, [r1, #12] + 800034e: f402 62e0 and.w r2, r2, #1792 ; 0x700 + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 8000352: 4313 orrs r3, r2 + 8000354: 60cb str r3, [r1, #12] + 8000356: f3bf 8f4f dsb sy + SCB_AIRCR_SYSRESETREQ_Msk ); /* Keep priority group unchanged */ + __DSB(); /* Ensure completion of memory access */ + + for(;;) /* wait until reset */ + { + __NOP(); + 800035a: bf00 nop + for(;;) /* wait until reset */ + 800035c: e7fd b.n 800035a <__NVIC_SystemReset+0x16> + 800035e: bf00 nop + 8000360: e000ed00 .word 0xe000ed00 + 8000364: 05fa0004 .word 0x05fa0004 + +08000368 : +good_addr(const uint8_t *b, int minlen, int len, bool readonly) +{ + uint32_t x = (uint32_t)b; + + if(minlen) { + if(!b) return EFAULT; // gave no buffer + 8000368: b198 cbz r0, 8000392 + if(len < minlen) return ERANGE; // too small + 800036a: 4291 cmp r1, r2 + 800036c: dc13 bgt.n 8000396 + } + + if((x >= SRAM1_BASE) && ((x+len) <= BL_SRAM_BASE)) { + 800036e: f1b0 5f00 cmp.w r0, #536870912 ; 0x20000000 + 8000372: d303 bcc.n 800037c + 8000374: 490b ldr r1, [pc, #44] ; (80003a4 ) + 8000376: 4402 add r2, r0 + 8000378: 428a cmp r2, r1 + 800037a: d90e bls.n 800039a + // ok: it's inside the SRAM areas, up to where we start + return 0; + } + + if(!readonly) { + 800037c: b17b cbz r3, 800039e + return EPERM; + } + + if((x >= FIRMWARE_START) && (x - FIRMWARE_START) < FW_MAX_LENGTH_MK4) { + 800037e: f100 4077 add.w r0, r0, #4143972352 ; 0xf7000000 + 8000382: f500 007e add.w r0, r0, #16646144 ; 0xfe0000 + // inside flash of main firmware (happens for QSTR's) + return 0; + } + + return EACCES; + 8000386: f5b0 1ff0 cmp.w r0, #1966080 ; 0x1e0000 + 800038a: bf34 ite cc + 800038c: 2000 movcc r0, #0 + 800038e: 200d movcs r0, #13 + 8000390: 4770 bx lr + if(!b) return EFAULT; // gave no buffer + 8000392: 200e movs r0, #14 + 8000394: 4770 bx lr + if(len < minlen) return ERANGE; // too small + 8000396: 2022 movs r0, #34 ; 0x22 + 8000398: 4770 bx lr + return 0; + 800039a: 2000 movs r0, #0 + 800039c: 4770 bx lr + return EPERM; + 800039e: 2001 movs r0, #1 +} + 80003a0: 4770 bx lr + 80003a2: bf00 nop + 80003a4: 2009e000 .word 0x2009e000 + +080003a8 : +// + __attribute__ ((used)) + int +firewall_dispatch(int method_num, uint8_t *buf_io, int len_in, + uint32_t arg2, uint32_t incoming_sp, uint32_t incoming_lr) +{ + 80003a8: b570 push {r4, r5, r6, lr} + 80003aa: b09e sub sp, #120 ; 0x78 + 80003ac: 460d mov r5, r1 + 80003ae: 9c23 ldr r4, [sp, #140] ; 0x8c + 80003b0: 9301 str r3, [sp, #4] + __ASM volatile ("cpsid i" : : : "memory"); + 80003b2: b672 cpsid i + // in case the caller didn't already, but would just lead to a crash anyway + __disable_irq(); + + // "1=any code executed outside the protected segment will close the Firewall" + // "0=.. will reset the processor" + __HAL_FIREWALL_PREARM_DISABLE(); + 80003b4: 4ba5 ldr r3, [pc, #660] ; (800064c ) + 80003b6: 6a19 ldr r1, [r3, #32] + 80003b8: f021 0101 bic.w r1, r1, #1 + 80003bc: 6219 str r1, [r3, #32] + 80003be: 6a1b ldr r3, [r3, #32] + 80003c0: f003 0301 and.w r3, r3, #1 + 80003c4: 9302 str r3, [sp, #8] + // using read/write in place. + // - use arg2 use when a simple number is needed; never a pointer! + // - mpy may provide a pointer to flash if we give it a qstr or small value, and if + // we're reading only, that's fine. + + if(len_in > 1024) { // arbitrary max, increase as needed + 80003c6: f5b2 6f80 cmp.w r2, #1024 ; 0x400 + __HAL_FIREWALL_PREARM_DISABLE(); + 80003ca: 9b02 ldr r3, [sp, #8] + if(len_in > 1024) { // arbitrary max, increase as needed + 80003cc: f300 82e3 bgt.w 8000996 + + // Use these macros +#define REQUIRE_IN_ONLY(x) if((rv = good_addr(buf_io, (x), len_in, true))) { goto fail; } +#define REQUIRE_OUT(x) if((rv = good_addr(buf_io, (x), len_in, false))) { goto fail; } + + switch(method_num) { + 80003d0: 3001 adds r0, #1 + 80003d2: 281c cmp r0, #28 + 80003d4: f200 81b6 bhi.w 8000744 + 80003d8: e8df f010 tbh [pc, r0, lsl #1] + 80003dc: 001d02f9 .word 0x001d02f9 + 80003e0: 00800034 .word 0x00800034 + 80003e4: 00d100bd .word 0x00d100bd + 80003e8: 01f300f2 .word 0x01f300f2 + 80003ec: 01b401b4 .word 0x01b401b4 + 80003f0: 01b401b4 .word 0x01b401b4 + 80003f4: 00fa01b4 .word 0x00fa01b4 + 80003f8: 01b401b4 .word 0x01b401b4 + 80003fc: 01240105 .word 0x01240105 + 8000400: 01670154 .word 0x01670154 + 8000404: 01f701ab .word 0x01f701ab + 8000408: 025f0206 .word 0x025f0206 + 800040c: 02b702a2 .word 0x02b702a2 + 8000410: 02cf02bf .word 0x02cf02bf + 8000414: 02eb .short 0x02eb + case 0: { + REQUIRE_OUT(64); + 8000416: 2300 movs r3, #0 + 8000418: 2140 movs r1, #64 ; 0x40 + 800041a: 4628 mov r0, r5 + 800041c: 9200 str r2, [sp, #0] + 800041e: f7ff ffa3 bl 8000368 + 8000422: 4604 mov r4, r0 + 8000424: bb48 cbnz r0, 800047a + + // Return my version string + memset(buf_io, 0, len_in); + 8000426: 4601 mov r1, r0 + 8000428: 9a00 ldr r2, [sp, #0] + 800042a: 4628 mov r0, r5 + 800042c: f00d f922 bl 800d674 + strlcpy((char *)buf_io, version_string, len_in); + 8000430: 9a00 ldr r2, [sp, #0] + 8000432: 4987 ldr r1, [pc, #540] ; (8000650 ) + 8000434: 4628 mov r0, r5 + 8000436: f00d f93b bl 800d6b0 + + rv = strlen(version_string); + 800043a: 4885 ldr r0, [pc, #532] ; (8000650 ) + 800043c: f00d f94d bl 800d6da + ae_setup(); + ae_keep_alive(); + switch(arg2) { + default: + case 0: // read state + rv = ae_get_gpio(); + 8000440: 4604 mov r4, r0 + break; + 8000442: e01a b.n 800047a + REQUIRE_OUT(32); + 8000444: 2300 movs r3, #0 + 8000446: 2120 movs r1, #32 + 8000448: 4628 mov r0, r5 + 800044a: f7ff ff8d bl 8000368 + 800044e: 4604 mov r4, r0 + 8000450: b998 cbnz r0, 800047a + sha256_init(&ctx); + 8000452: a80b add r0, sp, #44 ; 0x2c + 8000454: f005 f81a bl 800548c + sha256_update(&ctx, (void *)&arg2, 4); + 8000458: 2204 movs r2, #4 + 800045a: eb0d 0102 add.w r1, sp, r2 + 800045e: a80b add r0, sp, #44 ; 0x2c + 8000460: f005 f822 bl 80054a8 + sha256_update(&ctx, (void *)BL_FLASH_BASE, BL_FLASH_SIZE); + 8000464: f04f 6100 mov.w r1, #134217728 ; 0x8000000 + 8000468: a80b add r0, sp, #44 ; 0x2c + 800046a: f44f 32e0 mov.w r2, #114688 ; 0x1c000 + 800046e: f005 f81b bl 80054a8 + sha256_final(&ctx, buf_io); + 8000472: 4629 mov r1, r5 + 8000474: a80b add r0, sp, #44 ; 0x2c + 8000476: f005 f85d bl 8005534 + +fail: + + // Precaution: we don't want to leave SE1 authorized for any specific keys, + // perhaps due to an error path we didn't see. Always reset the chip. + ae_reset_chip(); + 800047a: f002 fa95 bl 80029a8 + + // Unlikely it matters, but clear flash memory cache. + __HAL_FLASH_DATA_CACHE_DISABLE(); + 800047e: 4b75 ldr r3, [pc, #468] ; (8000654 ) + 8000480: 681a ldr r2, [r3, #0] + 8000482: f422 6280 bic.w r2, r2, #1024 ; 0x400 + 8000486: 601a str r2, [r3, #0] + __HAL_FLASH_DATA_CACHE_RESET(); + 8000488: 681a ldr r2, [r3, #0] + 800048a: f442 5280 orr.w r2, r2, #4096 ; 0x1000 + 800048e: 601a str r2, [r3, #0] + 8000490: 681a ldr r2, [r3, #0] + 8000492: f422 5280 bic.w r2, r2, #4096 ; 0x1000 + 8000496: 601a str r2, [r3, #0] + __HAL_FLASH_DATA_CACHE_ENABLE(); + 8000498: 681a ldr r2, [r3, #0] + 800049a: f442 6280 orr.w r2, r2, #1024 ; 0x400 + 800049e: 601a str r2, [r3, #0] + + // .. and instruction memory (flash cache too?) + __HAL_FLASH_INSTRUCTION_CACHE_DISABLE(); + 80004a0: 681a ldr r2, [r3, #0] + 80004a2: f422 7200 bic.w r2, r2, #512 ; 0x200 + 80004a6: 601a str r2, [r3, #0] + __HAL_FLASH_INSTRUCTION_CACHE_RESET(); + 80004a8: 681a ldr r2, [r3, #0] + 80004aa: f442 6200 orr.w r2, r2, #2048 ; 0x800 + 80004ae: 601a str r2, [r3, #0] + 80004b0: 681a ldr r2, [r3, #0] + 80004b2: f422 6200 bic.w r2, r2, #2048 ; 0x800 + 80004b6: 601a str r2, [r3, #0] + __HAL_FLASH_INSTRUCTION_CACHE_ENABLE(); + 80004b8: 681a ldr r2, [r3, #0] + 80004ba: f442 7200 orr.w r2, r2, #512 ; 0x200 + 80004be: 601a str r2, [r3, #0] + + // authorize return from firewall into user's code + __HAL_FIREWALL_PREARM_ENABLE(); + 80004c0: f5a3 3382 sub.w r3, r3, #66560 ; 0x10400 + + return rv; +} + 80004c4: 4620 mov r0, r4 + __HAL_FIREWALL_PREARM_ENABLE(); + 80004c6: 6a1a ldr r2, [r3, #32] + 80004c8: f042 0201 orr.w r2, r2, #1 + 80004cc: 621a str r2, [r3, #32] + 80004ce: 6a1b ldr r3, [r3, #32] + 80004d0: f003 0301 and.w r3, r3, #1 + 80004d4: 930b str r3, [sp, #44] ; 0x2c + 80004d6: 9b0b ldr r3, [sp, #44] ; 0x2c +} + 80004d8: b01e add sp, #120 ; 0x78 + 80004da: bd70 pop {r4, r5, r6, pc} +// Write bag number (probably a string) +void flash_save_bag_number(const uint8_t new_number[32]); + +// Are we operating in level2? +static inline bool flash_is_security_level2(void) { + rng_delay(); + 80004dc: f002 f94e bl 800277c + return ((FLASH->OPTR & FLASH_OPTR_RDP_Msk) == 0xCC); + 80004e0: 4b5c ldr r3, [pc, #368] ; (8000654 ) + 80004e2: 6a1b ldr r3, [r3, #32] + 80004e4: b2db uxtb r3, r3 + 80004e6: f1a3 02cc sub.w r2, r3, #204 ; 0xcc + 80004ea: 4255 negs r5, r2 + 80004ec: 4155 adcs r5, r2 + switch(arg2) { + 80004ee: 9a01 ldr r2, [sp, #4] + 80004f0: 2a02 cmp r2, #2 + 80004f2: d01c beq.n 800052e + 80004f4: 2a03 cmp r2, #3 + 80004f6: d01f beq.n 8000538 + 80004f8: 2a01 cmp r2, #1 + 80004fa: d013 beq.n 8000524 + if(secure) { + 80004fc: 2bcc cmp r3, #204 ; 0xcc + 80004fe: f000 8216 beq.w 800092e + puts("Die: DFU"); + 8000502: 4855 ldr r0, [pc, #340] ; (8000658 ) + scr = screen_upgrading; // was screen_dfu, but limited audience + 8000504: 4c55 ldr r4, [pc, #340] ; (800065c ) + puts("Die: DFU"); + 8000506: f004 fc51 bl 8004dac + bool secure = flash_is_security_level2(); + 800050a: 2500 movs r5, #0 + oled_setup(); + 800050c: f000 fc0a bl 8000d24 + oled_show(scr); + 8000510: 4620 mov r0, r4 + 8000512: f000 fc97 bl 8000e44 + wipe_all_sram(); + 8000516: f000 fa77 bl 8000a08 + psram_wipe(); + 800051a: f004 fd6f bl 8004ffc + if(secure) { + 800051e: b18d cbz r5, 8000544 + LOCKUP_FOREVER(); + 8000520: bf30 wfi + 8000522: e7fd b.n 8000520 + puts("Die: Downgrade"); + 8000524: 484e ldr r0, [pc, #312] ; (8000660 ) + scr = screen_downgrade; + 8000526: 4c4f ldr r4, [pc, #316] ; (8000664 ) + puts("Die: Downgrade"); + 8000528: f004 fc40 bl 8004dac + break; + 800052c: e7ee b.n 800050c + puts("Die: Blankish"); + 800052e: 484e ldr r0, [pc, #312] ; (8000668 ) + scr = screen_blankish; + 8000530: 4c4e ldr r4, [pc, #312] ; (800066c ) + puts("Die: Blankish"); + 8000532: f004 fc3b bl 8004dac + break; + 8000536: e7e9 b.n 800050c + puts("Die: Brick"); + 8000538: 484d ldr r0, [pc, #308] ; (8000670 ) + scr = screen_brick; + 800053a: 4c4e ldr r4, [pc, #312] ; (8000674 ) + puts("Die: Brick"); + 800053c: f004 fc36 bl 8004dac + secure = true; // no point going into DFU, if even possible + 8000540: 2501 movs r5, #1 + break; + 8000542: e7e3 b.n 800050c + memcpy(dfu_flag->magic, REBOOT_TO_DFU, sizeof(dfu_flag->magic)); + 8000544: 494c ldr r1, [pc, #304] ; (8000678 ) + 8000546: 4a4d ldr r2, [pc, #308] ; (800067c ) + 8000548: 6808 ldr r0, [r1, #0] + 800054a: 6849 ldr r1, [r1, #4] + 800054c: 4613 mov r3, r2 + 800054e: c303 stmia r3!, {r0, r1} + dfu_flag->screen = scr; + 8000550: 6094 str r4, [r2, #8] + NVIC_SystemReset(); + 8000552: f7ff fef7 bl 8000344 <__NVIC_SystemReset> + switch(arg2) { + 8000556: 9b01 ldr r3, [sp, #4] + 8000558: f033 0302 bics.w r3, r3, #2 + 800055c: d102 bne.n 8000564 + oled_show(screen_logout); + 800055e: 4848 ldr r0, [pc, #288] ; (8000680 ) + 8000560: f000 fc70 bl 8000e44 + wipe_all_sram(); + 8000564: f000 fa50 bl 8000a08 + psram_wipe(); + 8000568: f004 fd48 bl 8004ffc + if(arg2 == 2) { + 800056c: 9b01 ldr r3, [sp, #4] + 800056e: 2b02 cmp r3, #2 + 8000570: d103 bne.n 800057a + delay_ms(100); + 8000572: 2064 movs r0, #100 ; 0x64 + 8000574: f003 f9c0 bl 80038f8 + 8000578: e7eb b.n 8000552 + LOCKUP_FOREVER(); + 800057a: bf30 wfi + 800057c: e7fd b.n 800057a + ae_setup(); + 800057e: f002 fa21 bl 80029c4 + ae_keep_alive(); + 8000582: f002 fa51 bl 8002a28 + switch(arg2) { + 8000586: 9b01 ldr r3, [sp, #4] + 8000588: 2b02 cmp r3, #2 + 800058a: d00a beq.n 80005a2 + 800058c: 2b03 cmp r3, #3 + 800058e: d00a beq.n 80005a6 + 8000590: 2b01 cmp r3, #1 + 8000592: d002 beq.n 800059a + rv = ae_get_gpio(); + 8000594: f002 ffc6 bl 8003524 + 8000598: e752 b.n 8000440 + rv = ae_set_gpio(0); + 800059a: 2000 movs r0, #0 + rv = ae_set_gpio(1); + 800059c: f002 ff94 bl 80034c8 + 80005a0: e74e b.n 8000440 + 80005a2: 2001 movs r0, #1 + 80005a4: e7fa b.n 800059c + checksum_flash(fw_digest, world_digest, 0); + 80005a6: 2200 movs r2, #0 + 80005a8: a90b add r1, sp, #44 ; 0x2c + 80005aa: a803 add r0, sp, #12 + 80005ac: f001 fa44 bl 8001a38 + rv = ae_set_gpio_secure(world_digest); + 80005b0: a80b add r0, sp, #44 ; 0x2c + 80005b2: f002 ff9f bl 80034f4 + 80005b6: 4604 mov r4, r0 + oled_show(screen_blankish); + 80005b8: 482c ldr r0, [pc, #176] ; (800066c ) + 80005ba: f000 fc43 bl 8000e44 + break; + 80005be: e75c b.n 800047a + ae_setup(); + 80005c0: f002 fa00 bl 80029c4 + rv = (ae_pair_unlock() != 0); + 80005c4: f002 fbf4 bl 8002db0 + 80005c8: 1e04 subs r4, r0, #0 + 80005ca: bf18 it ne + 80005cc: 2401 movne r4, #1 + break; + 80005ce: e754 b.n 800047a + REQUIRE_OUT(1); + 80005d0: 2300 movs r3, #0 + 80005d2: 2101 movs r1, #1 + 80005d4: 4628 mov r0, r5 + 80005d6: f7ff fec7 bl 8000368 + 80005da: 4604 mov r4, r0 + 80005dc: 2800 cmp r0, #0 + 80005de: f47f af4c bne.w 800047a + buf_io[0] = 0; // NOT SUPPORTED on Mk4 + 80005e2: 7028 strb r0, [r5, #0] + break; + 80005e4: e749 b.n 800047a + if(len_in != 4 && len_in != 32 && len_in != 72) { + 80005e6: 2a04 cmp r2, #4 + 80005e8: d004 beq.n 80005f4 + 80005ea: 2a20 cmp r2, #32 + 80005ec: d002 beq.n 80005f4 + 80005ee: 2a48 cmp r2, #72 ; 0x48 + 80005f0: f040 81d1 bne.w 8000996 + REQUIRE_OUT(4); + 80005f4: 2300 movs r3, #0 + 80005f6: 2104 movs r1, #4 + 80005f8: 4628 mov r0, r5 + 80005fa: 9200 str r2, [sp, #0] + 80005fc: f7ff feb4 bl 8000368 + 8000600: 4604 mov r4, r0 + 8000602: 2800 cmp r0, #0 + 8000604: f47f af39 bne.w 800047a + ae_setup(); + 8000608: f002 f9dc bl 80029c4 + if(ae_read_data_slot(arg2 & 0xf, buf_io, len_in)) { + 800060c: 9801 ldr r0, [sp, #4] + 800060e: 9a00 ldr r2, [sp, #0] + 8000610: 4629 mov r1, r5 + 8000612: f000 000f and.w r0, r0, #15 + 8000616: f002 ff11 bl 800343c + if(rv) { + 800061a: 2800 cmp r0, #0 + 800061c: f000 80d1 beq.w 80007c2 + rv = EIO; + 8000620: 2405 movs r4, #5 + 8000622: e72a b.n 800047a + REQUIRE_OUT(MAX_PIN_LEN); + 8000624: 2300 movs r3, #0 + 8000626: 2120 movs r1, #32 + 8000628: 4628 mov r0, r5 + 800062a: f7ff fe9d bl 8000368 + 800062e: 4604 mov r4, r0 + 8000630: 2800 cmp r0, #0 + 8000632: f47f af22 bne.w 800047a + if((arg2 < 1) || (arg2 > MAX_PIN_LEN)) { + 8000636: 9901 ldr r1, [sp, #4] + 8000638: 1e4b subs r3, r1, #1 + 800063a: 2b1f cmp r3, #31 + 800063c: f200 81ab bhi.w 8000996 + if(pin_prefix_words((char *)buf_io, arg2, (uint32_t *)buf_io)) { + 8000640: 462a mov r2, r5 + 8000642: 4628 mov r0, r5 + 8000644: f003 fc5c bl 8003f00 + 8000648: e7e7 b.n 800061a + 800064a: bf00 nop + 800064c: 40011c00 .word 0x40011c00 + 8000650: 0800e720 .word 0x0800e720 + 8000654: 40022000 .word 0x40022000 + 8000658: 0800d706 .word 0x0800d706 + 800065c: 0800e18b .word 0x0800e18b + 8000660: 0800d70f .word 0x0800d70f + 8000664: 0800da7a .word 0x0800da7a + 8000668: 0800d71e .word 0x0800d71e + 800066c: 0800d7de .word 0x0800d7de + 8000670: 0800d72c .word 0x0800d72c + 8000674: 0800d80b .word 0x0800d80b + 8000678: 0800d737 .word 0x0800d737 + 800067c: 20008000 .word 0x20008000 + 8000680: 0800db96 .word 0x0800db96 + REQUIRE_OUT(32); + 8000684: 2300 movs r3, #0 + 8000686: 2120 movs r1, #32 + 8000688: 4628 mov r0, r5 + 800068a: f7ff fe6d bl 8000368 + 800068e: 4604 mov r4, r0 + 8000690: 2800 cmp r0, #0 + 8000692: f47f aef2 bne.w 800047a + memset(buf_io, 0x55, 32); // to help show errors + 8000696: 2220 movs r2, #32 + 8000698: 2155 movs r1, #85 ; 0x55 + 800069a: 4628 mov r0, r5 + 800069c: f00c ffea bl 800d674 + rng_buffer(buf_io, 32); + 80006a0: 2120 movs r1, #32 + 80006a2: 4628 mov r0, r5 + 80006a4: f002 f854 bl 8002750 + break; + 80006a8: e6e7 b.n 800047a + REQUIRE_OUT(PIN_ATTEMPT_SIZE_V2); + 80006aa: 2300 movs r3, #0 + 80006ac: f44f 718c mov.w r1, #280 ; 0x118 + 80006b0: 4628 mov r0, r5 + 80006b2: 9200 str r2, [sp, #0] + 80006b4: f7ff fe58 bl 8000368 + 80006b8: 4604 mov r4, r0 + 80006ba: 2800 cmp r0, #0 + 80006bc: f47f aedd bne.w 800047a + switch(arg2) { + 80006c0: e9dd 2300 ldrd r2, r3, [sp] + 80006c4: 2b08 cmp r3, #8 + 80006c6: d83d bhi.n 8000744 + 80006c8: e8df f003 tbb [pc, r3] + 80006cc: 110d0905 .word 0x110d0905 + 80006d0: 221d1915 .word 0x221d1915 + 80006d4: 26 .byte 0x26 + 80006d5: 00 .byte 0x00 + rv = pin_setup_attempt(args); + 80006d6: 4628 mov r0, r5 + 80006d8: f003 fc30 bl 8003f3c + 80006dc: e6b0 b.n 8000440 + rv = pin_delay(args); + 80006de: 4628 mov r0, r5 + 80006e0: f003 fc9a bl 8004018 + 80006e4: e6ac b.n 8000440 + rv = pin_login_attempt(args); + 80006e6: 4628 mov r0, r5 + 80006e8: f003 fc98 bl 800401c + 80006ec: e6a8 b.n 8000440 + rv = pin_change(args); + 80006ee: 4628 mov r0, r5 + 80006f0: f003 fda2 bl 8004238 + 80006f4: e6a4 b.n 8000440 + rv = pin_fetch_secret(args); + 80006f6: 4628 mov r0, r5 + 80006f8: f003 fe56 bl 80043a8 + 80006fc: e6a0 b.n 8000440 + rv = pin_firmware_greenlight(args); + 80006fe: 4628 mov r0, r5 + 8000700: f004 f812 bl 8004728 + 8000704: e69c b.n 8000440 + rv = pin_long_secret(args, NULL); + 8000706: 2100 movs r1, #0 + rv = pin_long_secret(args, &buf_io[PIN_ATTEMPT_SIZE_V2]); + 8000708: 4628 mov r0, r5 + 800070a: f003 ff4f bl 80045ac + 800070e: e697 b.n 8000440 + rv = pin_firmware_upgrade(args); + 8000710: 4628 mov r0, r5 + 8000712: f004 f849 bl 80047a8 + 8000716: e693 b.n 8000440 + REQUIRE_OUT(PIN_ATTEMPT_SIZE_V2 + AE_LONG_SECRET_LEN); + 8000718: 2300 movs r3, #0 + 800071a: f44f 712e mov.w r1, #696 ; 0x2b8 + 800071e: 4628 mov r0, r5 + 8000720: f7ff fe22 bl 8000368 + 8000724: 4604 mov r4, r0 + 8000726: 2800 cmp r0, #0 + 8000728: f47f aea7 bne.w 800047a + rv = pin_long_secret(args, &buf_io[PIN_ATTEMPT_SIZE_V2]); + 800072c: f505 718c add.w r1, r5, #280 ; 0x118 + 8000730: e7ea b.n 8000708 + switch(arg2) { + 8000732: 9b01 ldr r3, [sp, #4] + 8000734: 2b64 cmp r3, #100 ; 0x64 + 8000736: d041 beq.n 80007bc + 8000738: d806 bhi.n 8000748 + 800073a: 2b01 cmp r3, #1 + 800073c: d01e beq.n 800077c + 800073e: 2b02 cmp r3, #2 + 8000740: d028 beq.n 8000794 + 8000742: b13b cbz r3, 8000754 + 8000744: 2402 movs r4, #2 + 8000746: e698 b.n 800047a + 8000748: 2b65 cmp r3, #101 ; 0x65 + 800074a: d03c beq.n 80007c6 + 800074c: 2b66 cmp r3, #102 ; 0x66 + 800074e: d1f9 bne.n 8000744 + flash_lockdown_hard(OB_RDP_LEVEL_2); // No change possible after this. + 8000750: 20cc movs r0, #204 ; 0xcc + 8000752: e034 b.n 80007be + REQUIRE_OUT(32); + 8000754: 2120 movs r1, #32 + 8000756: 4628 mov r0, r5 + 8000758: f7ff fe06 bl 8000368 + 800075c: 4604 mov r4, r0 + 800075e: 2800 cmp r0, #0 + 8000760: f47f ae8b bne.w 800047a + memcpy(buf_io, rom_secrets->bag_number, 32); + 8000764: 4aa1 ldr r2, [pc, #644] ; (80009ec ) + 8000766: 4ea2 ldr r6, [pc, #648] ; (80009f0 ) + 8000768: 4613 mov r3, r2 + 800076a: cb03 ldmia r3!, {r0, r1} + 800076c: 42b3 cmp r3, r6 + 800076e: 6028 str r0, [r5, #0] + 8000770: 6069 str r1, [r5, #4] + 8000772: 461a mov r2, r3 + 8000774: f105 0508 add.w r5, r5, #8 + 8000778: d1f6 bne.n 8000768 + 800077a: e67e b.n 800047a + REQUIRE_IN_ONLY(32); + 800077c: 2120 movs r1, #32 + 800077e: 4628 mov r0, r5 + 8000780: f7ff fdf2 bl 8000368 + 8000784: 4604 mov r4, r0 + 8000786: 2800 cmp r0, #0 + 8000788: f47f ae77 bne.w 800047a + flash_save_bag_number(buf_io); + 800078c: 4628 mov r0, r5 + 800078e: f001 fcf9 bl 8002184 + break; + 8000792: e672 b.n 800047a + REQUIRE_OUT(1); + 8000794: 2300 movs r3, #0 + 8000796: 2101 movs r1, #1 + 8000798: 4628 mov r0, r5 + 800079a: f7ff fde5 bl 8000368 + 800079e: 4604 mov r4, r0 + 80007a0: 2800 cmp r0, #0 + 80007a2: f47f ae6a bne.w 800047a + rng_delay(); + 80007a6: f001 ffe9 bl 800277c + return ((FLASH->OPTR & FLASH_OPTR_RDP_Msk) == 0xCC); + 80007aa: 4b92 ldr r3, [pc, #584] ; (80009f4 ) + 80007ac: 6a1b ldr r3, [r3, #32] + 80007ae: b2db uxtb r3, r3 + buf_io[0] = (flash_is_security_level2() ? 2 : 0xff); + 80007b0: 2bcc cmp r3, #204 ; 0xcc + 80007b2: bf0c ite eq + 80007b4: 2302 moveq r3, #2 + 80007b6: 23ff movne r3, #255 ; 0xff + buf_io[0] = 32; + 80007b8: 702b strb r3, [r5, #0] + break; + 80007ba: e65e b.n 800047a + flash_lockdown_hard(OB_RDP_LEVEL_0); // wipes contents of flash (1->0) + 80007bc: 20aa movs r0, #170 ; 0xaa + flash_lockdown_hard(OB_RDP_LEVEL_2); // No change possible after this. + 80007be: f001 fde3 bl 8002388 + int rv = 0; + 80007c2: 2400 movs r4, #0 + break; + 80007c4: e659 b.n 800047a + flash_lockdown_hard(OB_RDP_LEVEL_1); // Can only do 0->1 (experiments) + 80007c6: 20bb movs r0, #187 ; 0xbb + 80007c8: e7f9 b.n 80007be + REQUIRE_OUT(128); + 80007ca: 2300 movs r3, #0 + 80007cc: 2180 movs r1, #128 ; 0x80 + 80007ce: 4628 mov r0, r5 + 80007d0: f7ff fdca bl 8000368 + 80007d4: 4604 mov r4, r0 + 80007d6: 2800 cmp r0, #0 + 80007d8: f47f ae4f bne.w 800047a + ae_setup(); + 80007dc: f002 f8f2 bl 80029c4 + rv = ae_config_read(buf_io); + 80007e0: 4628 mov r0, r5 + 80007e2: f002 fef0 bl 80035c6 + 80007e6: e718 b.n 800061a + switch(arg2) { + 80007e8: 9b01 ldr r3, [sp, #4] + 80007ea: 2b03 cmp r3, #3 + 80007ec: d8aa bhi.n 8000744 + 80007ee: e8df f003 tbb [pc, r3] + 80007f2: 0f02 .short 0x0f02 + 80007f4: 441d .short 0x441d + REQUIRE_OUT(8); + 80007f6: 2300 movs r3, #0 + 80007f8: 2108 movs r1, #8 + 80007fa: 4628 mov r0, r5 + 80007fc: f7ff fdb4 bl 8000368 + 8000800: 4604 mov r4, r0 + 8000802: 2800 cmp r0, #0 + 8000804: f47f ae39 bne.w 800047a + get_min_version(buf_io); + 8000808: 4628 mov r0, r5 + 800080a: f001 f9a5 bl 8001b58 + break; + 800080e: e634 b.n 800047a + REQUIRE_IN_ONLY(8); + 8000810: 2301 movs r3, #1 + 8000812: 2108 movs r1, #8 + 8000814: 4628 mov r0, r5 + 8000816: f7ff fda7 bl 8000368 + 800081a: 4604 mov r4, r0 + 800081c: 2800 cmp r0, #0 + 800081e: f47f ae2c bne.w 800047a + rv = check_is_downgrade(buf_io, NULL); + 8000822: 4601 mov r1, r0 + 8000824: 4628 mov r0, r5 + 8000826: f001 f9b7 bl 8001b98 + 800082a: e609 b.n 8000440 + REQUIRE_IN_ONLY(8); + 800082c: 2301 movs r3, #1 + 800082e: 2108 movs r1, #8 + 8000830: 4628 mov r0, r5 + 8000832: f7ff fd99 bl 8000368 + 8000836: 4604 mov r4, r0 + 8000838: 2800 cmp r0, #0 + 800083a: f47f ae1e bne.w 800047a + if(buf_io[0] < 0x10 || buf_io[0] >= 0x40) { + 800083e: 782b ldrb r3, [r5, #0] + 8000840: 3b10 subs r3, #16 + rv = ERANGE; + 8000842: 2b2f cmp r3, #47 ; 0x2f + } if(check_is_downgrade(buf_io, NULL)) { + 8000844: 4601 mov r1, r0 + 8000846: 4628 mov r0, r5 + rv = ERANGE; + 8000848: bf88 it hi + 800084a: 2422 movhi r4, #34 ; 0x22 + } if(check_is_downgrade(buf_io, NULL)) { + 800084c: f001 f9a4 bl 8001b98 + 8000850: 2800 cmp r0, #0 + 8000852: f040 80c8 bne.w 80009e6 + get_min_version(min); + 8000856: a80b add r0, sp, #44 ; 0x2c + 8000858: f001 f97e bl 8001b58 + if(memcmp(min, buf_io, 8) == 0) { + 800085c: 2208 movs r2, #8 + 800085e: 4629 mov r1, r5 + 8000860: a80b add r0, sp, #44 ; 0x2c + 8000862: f00c fecf bl 800d604 + 8000866: 2800 cmp r0, #0 + 8000868: f000 80bd beq.w 80009e6 + if(record_highwater_version(buf_io)) { + 800086c: 4628 mov r0, r5 + 800086e: f001 fda5 bl 80023bc + rv = ENOMEM; + 8000872: 2800 cmp r0, #0 + 8000874: bf18 it ne + 8000876: 240c movne r4, #12 + 8000878: e5ff b.n 800047a + REQUIRE_OUT(4); + 800087a: 2300 movs r3, #0 + 800087c: 2104 movs r1, #4 + 800087e: 4628 mov r0, r5 + 8000880: f7ff fd72 bl 8000368 + 8000884: 4604 mov r4, r0 + 8000886: 2800 cmp r0, #0 + 8000888: f47f adf7 bne.w 800047a + ae_setup(); + 800088c: f002 f89a bl 80029c4 + rv = ae_get_counter((uint32_t *)buf_io, 0) ? EIO: 0; + 8000890: 4621 mov r1, r4 + 8000892: 4628 mov r0, r5 + 8000894: f002 fc87 bl 80031a6 + 8000898: e6bf b.n 800061a + REQUIRE_OUT(PIN_ATTEMPT_SIZE_V2 + sizeof(trick_slot_t)); + 800089a: 2300 movs r3, #0 + 800089c: f44f 71cc mov.w r1, #408 ; 0x198 + 80008a0: 4628 mov r0, r5 + 80008a2: f7ff fd61 bl 8000368 + 80008a6: 4604 mov r4, r0 + 80008a8: 2800 cmp r0, #0 + 80008aa: f47f ade6 bne.w 800047a + rv = pin_check_logged_in(args, &trick_mode); + 80008ae: a90b add r1, sp, #44 ; 0x2c + 80008b0: 4628 mov r0, r5 + 80008b2: f003 fc8f bl 80041d4 + if(rv) goto fail; + 80008b6: 4604 mov r4, r0 + 80008b8: 2800 cmp r0, #0 + 80008ba: f47f adde bne.w 800047a + if(trick_mode) { + 80008be: f89d 302c ldrb.w r3, [sp, #44] ; 0x2c + 80008c2: b10b cbz r3, 80008c8 + mcu_key_clear(NULL); + 80008c4: f001 fdc8 bl 8002458 + switch(arg2) { + 80008c8: 9b01 ldr r3, [sp, #4] + 80008ca: 2b01 cmp r3, #1 + trick_slot_t *slot = (trick_slot_t *)(&buf_io[PIN_ATTEMPT_SIZE_V2]); + 80008cc: f505 728c add.w r2, r5, #280 ; 0x118 + switch(arg2) { + 80008d0: d00c beq.n 80008ec + 80008d2: 2b02 cmp r3, #2 + 80008d4: d01b beq.n 800090e + 80008d6: 2b00 cmp r3, #0 + 80008d8: f47f af34 bne.w 8000744 + if(!trick_mode) { + 80008dc: f89d 302c ldrb.w r3, [sp, #44] ; 0x2c + 80008e0: 2b00 cmp r3, #0 + 80008e2: f47f adca bne.w 800047a + se2_clear_tricks(); + 80008e6: f007 fa31 bl 8007d4c + 80008ea: e5c6 b.n 800047a + if(trick_mode) { + 80008ec: f89d 102c ldrb.w r1, [sp, #44] ; 0x2c + 80008f0: 2900 cmp r1, #0 + 80008f2: f47f af27 bne.w 8000744 + if(slot->pin_len > 16) { + 80008f6: f8d5 1170 ldr.w r1, [r5, #368] ; 0x170 + 80008fa: 2910 cmp r1, #16 + 80008fc: dc4b bgt.n 8000996 + if(se2_test_trick_pin(slot->pin, slot->pin_len, slot, true)) { + 80008fe: f505 70b0 add.w r0, r5, #352 ; 0x160 + 8000902: f007 fa89 bl 8007e18 + 8000906: 2800 cmp r0, #0 + 8000908: f47f adb7 bne.w 800047a + 800090c: e71a b.n 8000744 + if(!trick_mode) { + 800090e: f89d 302c ldrb.w r3, [sp, #44] ; 0x2c + 8000912: 2b00 cmp r3, #0 + 8000914: f47f adb1 bne.w 800047a + rv = se2_save_trick(slot); + 8000918: 4610 mov r0, r2 + 800091a: f007 fb9d bl 8008058 + 800091e: e58f b.n 8000440 + if(arg2 == 0xBeef) { + 8000920: 9b01 ldr r3, [sp, #4] + 8000922: f64b 62ef movw r2, #48879 ; 0xbeef + 8000926: 4293 cmp r3, r2 + 8000928: d103 bne.n 8000932 + fast_wipe(); + 800092a: f001 fe87 bl 800263c + rv = EPERM; + 800092e: 2401 movs r4, #1 + 8000930: e5a3 b.n 800047a + } else if(arg2 == 0xDead) { + 8000932: f64d 62ad movw r2, #57005 ; 0xdead + 8000936: 4293 cmp r3, r2 + 8000938: d1f9 bne.n 800092e + mcu_key_clear(NULL); + 800093a: 2000 movs r0, #0 + 800093c: f001 fd8c bl 8002458 + oled_show(screen_wiped); + 8000940: 482d ldr r0, [pc, #180] ; (80009f8 ) + 8000942: f000 fa7f bl 8000e44 + LOCKUP_FOREVER(); + 8000946: bf30 wfi + 8000948: e7fd b.n 8000946 + if(arg2 == 0xDead) fast_brick(); + 800094a: 9a01 ldr r2, [sp, #4] + 800094c: f64d 63ad movw r3, #57005 ; 0xdead + 8000950: 429a cmp r2, r3 + 8000952: d1ec bne.n 800092e + 8000954: f001 fe44 bl 80025e0 + 8000958: e7e9 b.n 800092e + REQUIRE_OUT(8); + 800095a: 2300 movs r3, #0 + 800095c: 2108 movs r1, #8 + 800095e: 4628 mov r0, r5 + 8000960: f7ff fd02 bl 8000368 + 8000964: 4604 mov r4, r0 + 8000966: 2800 cmp r0, #0 + 8000968: f47f ad87 bne.w 800047a + mcu_key_usage(avail, consumed, total); + 800096c: f105 0208 add.w r2, r5, #8 + 8000970: 1d29 adds r1, r5, #4 + 8000972: 4628 mov r0, r5 + 8000974: f001 fd9e bl 80024b4 + break; + 8000978: e57f b.n 800047a + REQUIRE_OUT(33); + 800097a: 2300 movs r3, #0 + 800097c: 2121 movs r1, #33 ; 0x21 + 800097e: 4628 mov r0, r5 + 8000980: f7ff fcf2 bl 8000368 + 8000984: 4604 mov r4, r0 + 8000986: 2800 cmp r0, #0 + 8000988: f47f ad77 bne.w 800047a + switch(arg2) { + 800098c: 9b01 ldr r3, [sp, #4] + 800098e: 2b01 cmp r3, #1 + 8000990: d003 beq.n 800099a + 8000992: 2b02 cmp r3, #2 + 8000994: d008 beq.n 80009a8 + rv = ERANGE; + 8000996: 2422 movs r4, #34 ; 0x22 + 8000998: e56f b.n 800047a + ae_setup(); + 800099a: f002 f813 bl 80029c4 + ae_secure_random(&buf_io[1]); + 800099e: 1c68 adds r0, r5, #1 + 80009a0: f002 fb78 bl 8003094 + buf_io[0] = 32; + 80009a4: 2320 movs r3, #32 + 80009a6: e707 b.n 80007b8 + se2_read_rng(&buf_io[1]); + 80009a8: 1c68 adds r0, r5, #1 + 80009aa: f007 fd39 bl 8008420 + buf_io[0] = 8; + 80009ae: 2308 movs r3, #8 + 80009b0: e702 b.n 80007b8 + REQUIRE_OUT(80); + 80009b2: 2300 movs r3, #0 + 80009b4: 2150 movs r1, #80 ; 0x50 + 80009b6: 4628 mov r0, r5 + 80009b8: f7ff fcd6 bl 8000368 + 80009bc: 4604 mov r4, r0 + 80009be: 2800 cmp r0, #0 + 80009c0: f47f ad5b bne.w 800047a + strcpy((char *)buf_io, "ATECC608B\nDS28C36B"); + 80009c4: 490d ldr r1, [pc, #52] ; (80009fc ) + 80009c6: 4628 mov r0, r5 + 80009c8: f00c fe6a bl 800d6a0 + break; + 80009cc: e555 b.n 800047a + if(incoming_lr <= BL_FLASH_BASE || incoming_lr >= (uint32_t)&firewall_starts) { + 80009ce: f1b4 6f00 cmp.w r4, #134217728 ; 0x8000000 + 80009d2: d902 bls.n 80009da + 80009d4: 4b0a ldr r3, [pc, #40] ; (8000a00 ) + 80009d6: 429c cmp r4, r3 + 80009d8: d302 bcc.n 80009e0 + fatal_error("LR"); + 80009da: 480a ldr r0, [pc, #40] ; (8000a04 ) + 80009dc: f000 f834 bl 8000a48 + system_startup(); + 80009e0: f000 f890 bl 8000b04 + break; + 80009e4: e6ed b.n 80007c2 + rv = EAGAIN; + 80009e6: 240b movs r4, #11 + 80009e8: e547 b.n 800047a + 80009ea: bf00 nop + 80009ec: 0801c050 .word 0x0801c050 + 80009f0: 0801c070 .word 0x0801c070 + 80009f4: 40022000 .word 0x40022000 + 80009f8: 0800e310 .word 0x0800e310 + 80009fc: 0800d740 .word 0x0800d740 + 8000a00: 08000300 .word 0x08000300 + 8000a04: 0800d753 .word 0x0800d753 + +08000a08 : +// + static inline void +memset4(uint32_t *dest, uint32_t value, uint32_t byte_len) +{ + for(; byte_len; byte_len-=4, dest++) { + *dest = value; + 8000a08: 4a0a ldr r2, [pc, #40] ; (8000a34 ) + for(; byte_len; byte_len-=4, dest++) { + 8000a0a: 490b ldr r1, [pc, #44] ; (8000a38 ) + +// wipe_all_sram() +// + void +wipe_all_sram(void) +{ + 8000a0c: f04f 5300 mov.w r3, #536870912 ; 0x20000000 + *dest = value; + 8000a10: f843 2b04 str.w r2, [r3], #4 + for(; byte_len; byte_len-=4, dest++) { + 8000a14: 428b cmp r3, r1 + 8000a16: d1fb bne.n 8000a10 + 8000a18: 4908 ldr r1, [pc, #32] ; (8000a3c ) + 8000a1a: f04f 5380 mov.w r3, #268435456 ; 0x10000000 + *dest = value; + 8000a1e: f843 2b04 str.w r2, [r3], #4 + for(; byte_len; byte_len-=4, dest++) { + 8000a22: 428b cmp r3, r1 + 8000a24: d1fb bne.n 8000a1e + 8000a26: 4b06 ldr r3, [pc, #24] ; (8000a40 ) + 8000a28: 4906 ldr r1, [pc, #24] ; (8000a44 ) + *dest = value; + 8000a2a: f843 2b04 str.w r2, [r3], #4 + for(; byte_len; byte_len-=4, dest++) { + 8000a2e: 428b cmp r3, r1 + 8000a30: d1fb bne.n 8000a2a + STATIC_ASSERT((SRAM3_BASE + SRAM3_SIZE) - BL_SRAM_BASE == 8192); + + memset4((void *)SRAM1_BASE, noise, SRAM1_SIZE_MAX); + memset4((void *)SRAM2_BASE, noise, SRAM2_SIZE); + memset4((void *)SRAM3_BASE, noise, SRAM3_SIZE - (BL_SRAM_BASE - SRAM3_BASE)); +} + 8000a32: 4770 bx lr + 8000a34: deadbeef .word 0xdeadbeef + 8000a38: 20030000 .word 0x20030000 + 8000a3c: 10010000 .word 0x10010000 + 8000a40: 20040000 .word 0x20040000 + 8000a44: 20042000 .word 0x20042000 + +08000a48 : + +// fatal_error(const char *msg) +// + void __attribute__((noreturn)) +fatal_error(const char *msgvoid) +{ + 8000a48: b508 push {r3, lr} + oled_setup(); + 8000a4a: f000 f96b bl 8000d24 + oled_show(screen_fatal); + 8000a4e: 4802 ldr r0, [pc, #8] ; (8000a58 ) + 8000a50: f000 f9f8 bl 8000e44 + BREAKPOINT; +#endif + + // Maybe should do a reset after a delay, like with + // the watchdog timer or something. + LOCKUP_FOREVER(); + 8000a54: bf30 wfi + 8000a56: e7fd b.n 8000a54 + 8000a58: 0800db52 .word 0x0800db52 + +08000a5c : + +// fatal_mitm() +// + void __attribute__((noreturn)) +fatal_mitm(void) +{ + 8000a5c: b508 push {r3, lr} + oled_setup(); + 8000a5e: f000 f961 bl 8000d24 + oled_show(screen_mitm); + 8000a62: 4803 ldr r0, [pc, #12] ; (8000a70 ) + 8000a64: f000 f9ee bl 8000e44 + +#ifdef RELEASE + wipe_all_sram(); + 8000a68: f7ff ffce bl 8000a08 +#endif + + LOCKUP_FOREVER(); + 8000a6c: bf30 wfi + 8000a6e: e7fd b.n 8000a6c + 8000a70: 0800dc56 .word 0x0800dc56 + +08000a74 : + +// enter_dfu() +// + void __attribute__((noreturn)) +enter_dfu(void) +{ + 8000a74: b507 push {r0, r1, r2, lr} + puts("enter_dfu()"); + 8000a76: 481f ldr r0, [pc, #124] ; (8000af4 ) + 8000a78: f004 f998 bl 8004dac + + // clear the green light, if set + ae_setup(); + 8000a7c: f001 ffa2 bl 80029c4 + ae_set_gpio(0); + 8000a80: 2000 movs r0, #0 + 8000a82: f002 fd21 bl 80034c8 + + // Reset huge parts of the chip + __HAL_RCC_APB1_FORCE_RESET(); + 8000a86: 4b1c ldr r3, [pc, #112] ; (8000af8 ) + 8000a88: f04f 31ff mov.w r1, #4294967295 ; 0xffffffff + __HAL_RCC_APB1_RELEASE_RESET(); + 8000a8c: 2200 movs r2, #0 + __HAL_RCC_APB1_FORCE_RESET(); + 8000a8e: 6399 str r1, [r3, #56] ; 0x38 + 8000a90: 63d9 str r1, [r3, #60] ; 0x3c + __HAL_RCC_APB1_RELEASE_RESET(); + 8000a92: 639a str r2, [r3, #56] ; 0x38 + 8000a94: 63da str r2, [r3, #60] ; 0x3c + + __HAL_RCC_APB2_FORCE_RESET(); + 8000a96: 6419 str r1, [r3, #64] ; 0x40 + __HAL_RCC_APB2_RELEASE_RESET(); + 8000a98: 641a str r2, [r3, #64] ; 0x40 + + __HAL_RCC_AHB1_FORCE_RESET(); + 8000a9a: 6299 str r1, [r3, #40] ; 0x28 + __HAL_RCC_AHB1_RELEASE_RESET(); + 8000a9c: 629a str r2, [r3, #40] ; 0x28 + // But not this; it borks things. + __HAL_RCC_AHB2_FORCE_RESET(); + __HAL_RCC_AHB2_RELEASE_RESET(); +#endif + + __HAL_RCC_AHB3_FORCE_RESET(); + 8000a9e: 6319 str r1, [r3, #48] ; 0x30 + __HAL_RCC_AHB3_RELEASE_RESET(); + 8000aa0: 631a str r2, [r3, #48] ; 0x30 + + __HAL_FIREWALL_PREARM_ENABLE(); + 8000aa2: f5a3 4374 sub.w r3, r3, #62464 ; 0xf400 + 8000aa6: 6a1a ldr r2, [r3, #32] + 8000aa8: f042 0201 orr.w r2, r2, #1 + 8000aac: 621a str r2, [r3, #32] + 8000aae: 6a1b ldr r3, [r3, #32] + 8000ab0: f003 0301 and.w r3, r3, #1 + 8000ab4: 9301 str r3, [sp, #4] + 8000ab6: 9b01 ldr r3, [sp, #4] + + // Wipe all of memory SRAM, just in case + // there is some way to trick us into DFU + // after sensitive content in place. + wipe_all_sram(); + 8000ab8: f7ff ffa6 bl 8000a08 + rng_delay(); + 8000abc: f001 fe5e bl 800277c + return ((FLASH->OPTR & FLASH_OPTR_RDP_Msk) == 0xCC); + 8000ac0: 4b0e ldr r3, [pc, #56] ; (8000afc ) + 8000ac2: 6a1b ldr r3, [r3, #32] + 8000ac4: b2db uxtb r3, r3 + + if(flash_is_security_level2()) { + 8000ac6: 2bcc cmp r3, #204 ; 0xcc + 8000ac8: d101 bne.n 8000ace + // cannot do DFU in RDP=2, so just die. Helps to preserve screen + LOCKUP_FOREVER(); + 8000aca: bf30 wfi + 8000acc: e7fd b.n 8000aca + } + + // Reset clocks. + HAL_RCC_DeInit(); + 8000ace: f007 fde5 bl 800869c + + // move system ROM into 0x0 + __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); + 8000ad2: 4a0b ldr r2, [pc, #44] ; (8000b00 ) + 8000ad4: 6813 ldr r3, [r2, #0] + 8000ad6: f023 0307 bic.w r3, r3, #7 + 8000ada: f043 0301 orr.w r3, r3, #1 + 8000ade: 6013 str r3, [r2, #0] + + // need this here?! + asm("nop; nop; nop; nop;"); + 8000ae0: bf00 nop + 8000ae2: bf00 nop + 8000ae4: bf00 nop + 8000ae6: bf00 nop + + // simulate a reset vector + __ASM volatile ("movs r0, #0\n" + 8000ae8: 2000 movs r0, #0 + 8000aea: 6803 ldr r3, [r0, #0] + 8000aec: f383 8808 msr MSP, r3 + 8000af0: 6843 ldr r3, [r0, #4] + 8000af2: 4798 blx r3 + "ldr r3, [r0, #4]\n" + "blx r3" + : : : "r0", "r3"); // also SP + + // NOT-REACHED. + __builtin_unreachable(); + 8000af4: 0800d756 .word 0x0800d756 + 8000af8: 40021000 .word 0x40021000 + 8000afc: 40022000 .word 0x40022000 + 8000b00: 40010000 .word 0x40010000 + +08000b04 : +{ + 8000b04: b510 push {r4, lr} + system_init0(); + 8000b06: f001 f985 bl 8001e14 + clocks_setup(); + 8000b0a: f001 f9a5 bl 8001e58 + rng_setup(); // needs to be super early + 8000b0e: f001 fdf3 bl 80026f8 + rng_delay(); + 8000b12: f001 fe33 bl 800277c + if(!check_all_ones(rom_secrets->bag_number, sizeof(rom_secrets->bag_number)) + 8000b16: 4838 ldr r0, [pc, #224] ; (8000bf8 ) + 8000b18: 2120 movs r1, #32 + 8000b1a: f001 fdb1 bl 8002680 + 8000b1e: b948 cbnz r0, 8000b34 + rng_delay(); + 8000b20: f001 fe2c bl 800277c + return ((FLASH->OPTR & FLASH_OPTR_RDP_Msk) == 0xCC); + 8000b24: 4b35 ldr r3, [pc, #212] ; (8000bfc ) + 8000b26: 6a1b ldr r3, [r3, #32] + 8000b28: b2db uxtb r3, r3 + && !flash_is_security_level2() + 8000b2a: 2bcc cmp r3, #204 ; 0xcc + 8000b2c: d002 beq.n 8000b34 + flash_lockdown_hard(OB_RDP_LEVEL_2); + 8000b2e: 20cc movs r0, #204 ; 0xcc + 8000b30: f001 fc2a bl 8002388 + gpio_setup(); + 8000b34: f002 fef0 bl 8003918 + uint32_t reset_reason = RCC->CSR; + 8000b38: 4c31 ldr r4, [pc, #196] ; (8000c00 ) + console_setup(); + 8000b3a: f004 f85d bl 8004bf8 + puts2(BOOT_BANNER); + 8000b3e: 4831 ldr r0, [pc, #196] ; (8000c04 ) + 8000b40: f004 f8a6 bl 8004c90 + puts(version_string); + 8000b44: 4830 ldr r0, [pc, #192] ; (8000c08 ) + 8000b46: f004 f931 bl 8004dac + uint32_t reset_reason = RCC->CSR; + 8000b4a: f8d4 3094 ldr.w r3, [r4, #148] ; 0x94 + if(reset_reason & RCC_CSR_FWRSTF) { + 8000b4e: 01db lsls r3, r3, #7 + 8000b50: d502 bpl.n 8000b58 + puts(">FIREWALLED<"); + 8000b52: 482e ldr r0, [pc, #184] ; (8000c0c ) + 8000b54: f004 f92a bl 8004dac + SET_BIT(RCC->CSR, RCC_CSR_RMVF); + 8000b58: f8d4 3094 ldr.w r3, [r4, #148] ; 0x94 + 8000b5c: f443 0300 orr.w r3, r3, #8388608 ; 0x800000 + 8000b60: f8c4 3094 str.w r3, [r4, #148] ; 0x94 + if(memcmp(dfu_flag->magic, REBOOT_TO_DFU, sizeof(dfu_flag->magic)) == 0) { + 8000b64: 4c2a ldr r4, [pc, #168] ; (8000c10 ) + pin_setup0(); + 8000b66: f003 f935 bl 8003dd4 + rng_delay(); + 8000b6a: f001 fe07 bl 800277c + oled_setup(); + 8000b6e: f000 f8d9 bl 8000d24 + if(memcmp(dfu_flag->magic, REBOOT_TO_DFU, sizeof(dfu_flag->magic)) == 0) { + 8000b72: 4928 ldr r1, [pc, #160] ; (8000c14 ) + 8000b74: 2208 movs r2, #8 + 8000b76: 4620 mov r0, r4 + 8000b78: f00c fd44 bl 800d604 + 8000b7c: b928 cbnz r0, 8000b8a + dfu_flag->magic[0] = 0; + 8000b7e: 7020 strb r0, [r4, #0] + oled_show(dfu_flag->screen); + 8000b80: 68a0 ldr r0, [r4, #8] + 8000b82: f000 f95f bl 8000e44 + enter_dfu(); + 8000b86: f7ff ff75 bl 8000a74 + rng_delay(); + 8000b8a: f001 fdf7 bl 800277c + oled_show_progress(screen_verify, 0); + 8000b8e: 2100 movs r1, #0 + 8000b90: 4821 ldr r0, [pc, #132] ; (8000c18 ) + 8000b92: f000 f999 bl 8000ec8 + wipe_all_sram(); + 8000b96: f7ff ff37 bl 8000a08 + ae_setup(); + 8000b9a: f001 ff13 bl 80029c4 + ae_set_gpio(0); // turn light red + 8000b9e: 2000 movs r0, #0 + 8000ba0: f002 fc92 bl 80034c8 + se2_setup(); + 8000ba4: f007 f88c bl 8007cc0 + se2_probe(); + 8000ba8: f006 fe10 bl 80077cc + flash_setup(); + 8000bac: f001 fb56 bl 800225c + psram_setup(); + 8000bb0: f004 f934 bl 8004e1c + if(ae_pair_unlock() != 0) { + 8000bb4: f002 f8fc bl 8002db0 + 8000bb8: b138 cbz r0, 8000bca + oled_show(screen_brick); + 8000bba: 4818 ldr r0, [pc, #96] ; (8000c1c ) + 8000bbc: f000 f942 bl 8000e44 + puts("pair-bricked"); + 8000bc0: 4817 ldr r0, [pc, #92] ; (8000c20 ) + 8000bc2: f004 f8f3 bl 8004dac + LOCKUP_FOREVER(); + 8000bc6: bf30 wfi + 8000bc8: e7fd b.n 8000bc6 + puts2("Verify: "); + 8000bca: 4816 ldr r0, [pc, #88] ; (8000c24 ) + 8000bcc: f004 f860 bl 8004c90 + bool main_ok = verify_firmware(); + 8000bd0: f001 f8a4 bl 8001d1c + if(main_ok) { + 8000bd4: b120 cbz r0, 8000be0 +} + 8000bd6: e8bd 4010 ldmia.w sp!, {r4, lr} + oled_show(screen_blankish); + 8000bda: 4813 ldr r0, [pc, #76] ; (8000c28 ) + 8000bdc: f000 b932 b.w 8000e44 + psram_recover_firmware(); + 8000be0: f004 fa6a bl 80050b8 + rng_delay(); + 8000be4: f001 fdca bl 800277c + return ((FLASH->OPTR & FLASH_OPTR_RDP_Msk) == 0xCC); + 8000be8: 4b04 ldr r3, [pc, #16] ; (8000bfc ) + 8000bea: 6a1b ldr r3, [r3, #32] + 8000bec: b2db uxtb r3, r3 + if(!flash_is_security_level2()) { + 8000bee: 2bcc cmp r3, #204 ; 0xcc + 8000bf0: d1c9 bne.n 8000b86 + while(1) sdcard_recovery(); + 8000bf2: f004 fc11 bl 8005418 + 8000bf6: e7fc b.n 8000bf2 + 8000bf8: 0801c050 .word 0x0801c050 + 8000bfc: 40022000 .word 0x40022000 + 8000c00: 40021000 .word 0x40021000 + 8000c04: 0800d762 .word 0x0800d762 + 8000c08: 0800e720 .word 0x0800e720 + 8000c0c: 0800d776 .word 0x0800d776 + 8000c10: 20008000 .word 0x20008000 + 8000c14: 0800d737 .word 0x0800d737 + 8000c18: 0800e242 .word 0x0800e242 + 8000c1c: 0800d80b .word 0x0800d80b + 8000c20: 0800d783 .word 0x0800d783 + 8000c24: 0800d790 .word 0x0800d790 + 8000c28: 0800d7de .word 0x0800d7de + +08000c2c : + static inline void +write_bytes(int len, const uint8_t *buf) +{ +#ifndef DISABLE_OLED + // send via SPI(1) + HAL_SPI_Transmit(&spi_port, (uint8_t *)buf, len, HAL_MAX_DELAY); + 8000c2c: b282 uxth r2, r0 + 8000c2e: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 8000c32: 4801 ldr r0, [pc, #4] ; (8000c38 ) + 8000c34: f000 bc06 b.w 8001444 + 8000c38: 2009e154 .word 0x2009e154 + +08000c3c : + +// oled_write_cmd() +// + void +oled_write_cmd(uint8_t cmd) +{ + 8000c3c: b507 push {r0, r1, r2, lr} + HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); + 8000c3e: 2201 movs r2, #1 +{ + 8000c40: f88d 0007 strb.w r0, [sp, #7] + HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); + 8000c44: 2110 movs r1, #16 + 8000c46: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000c4a: f000 fb5b bl 8001304 + HAL_GPIO_WritePin(GPIOA, DC_PIN, 0); + 8000c4e: 2200 movs r2, #0 + 8000c50: f44f 7180 mov.w r1, #256 ; 0x100 + 8000c54: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000c58: f000 fb54 bl 8001304 + HAL_GPIO_WritePin(GPIOA, CS_PIN, 0); + 8000c5c: 2200 movs r2, #0 + 8000c5e: 2110 movs r1, #16 + 8000c60: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000c64: f000 fb4e bl 8001304 + + write_bytes(1, &cmd); + 8000c68: f10d 0107 add.w r1, sp, #7 + 8000c6c: 2001 movs r0, #1 + 8000c6e: f7ff ffdd bl 8000c2c + + HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); + 8000c72: 2201 movs r2, #1 + 8000c74: 2110 movs r1, #16 + 8000c76: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000c7a: f000 fb43 bl 8001304 +} + 8000c7e: b003 add sp, #12 + 8000c80: f85d fb04 ldr.w pc, [sp], #4 + +08000c84 : + +// oled_write_cmd_sequence() +// + void +oled_write_cmd_sequence(int len, const uint8_t *cmds) +{ + 8000c84: b570 push {r4, r5, r6, lr} + 8000c86: 4605 mov r5, r0 + 8000c88: 460e mov r6, r1 + for(int i=0; i + oled_write_cmd(cmds[i]); + } +} + 8000c90: bd70 pop {r4, r5, r6, pc} + oled_write_cmd(cmds[i]); + 8000c92: 5d30 ldrb r0, [r6, r4] + 8000c94: f7ff ffd2 bl 8000c3c + for(int i=0; i + +08000c9c : + +// oled_write_data() +// + void +oled_write_data(int len, const uint8_t *pixels) +{ + 8000c9c: b538 push {r3, r4, r5, lr} + HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); + 8000c9e: 2201 movs r2, #1 +{ + 8000ca0: 4604 mov r4, r0 + 8000ca2: 460d mov r5, r1 + HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); + 8000ca4: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000ca8: 2110 movs r1, #16 + 8000caa: f000 fb2b bl 8001304 + HAL_GPIO_WritePin(GPIOA, DC_PIN, 1); + 8000cae: 2201 movs r2, #1 + 8000cb0: f44f 7180 mov.w r1, #256 ; 0x100 + 8000cb4: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000cb8: f000 fb24 bl 8001304 + HAL_GPIO_WritePin(GPIOA, CS_PIN, 0); + 8000cbc: 2200 movs r2, #0 + 8000cbe: 2110 movs r1, #16 + 8000cc0: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000cc4: f000 fb1e bl 8001304 + + write_bytes(len, pixels); + 8000cc8: 4629 mov r1, r5 + 8000cca: 4620 mov r0, r4 + 8000ccc: f7ff ffae bl 8000c2c + + HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); +} + 8000cd0: e8bd 4038 ldmia.w sp!, {r3, r4, r5, lr} + HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); + 8000cd4: 2201 movs r2, #1 + 8000cd6: 2110 movs r1, #16 + 8000cd8: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000cdc: f000 bb12 b.w 8001304 + +08000ce0 : +// +// Just setup SPI, do not reset display, etc. +// + void +oled_spi_setup(void) +{ + 8000ce0: b538 push {r3, r4, r5, lr} +#ifndef DISABLE_OLED + // might already be setup + if(spi_port.Instance == SPI1) return; + 8000ce2: 4c0e ldr r4, [pc, #56] ; (8000d1c ) + 8000ce4: 4d0e ldr r5, [pc, #56] ; (8000d20 ) + 8000ce6: 6823 ldr r3, [r4, #0] + 8000ce8: 42ab cmp r3, r5 + 8000cea: d016 beq.n 8000d1a + + memset(&spi_port, 0, sizeof(spi_port)); + 8000cec: f104 0008 add.w r0, r4, #8 + 8000cf0: 225c movs r2, #92 ; 0x5c + 8000cf2: 2100 movs r1, #0 + 8000cf4: f00c fcbe bl 800d674 + + spi_port.Instance = SPI1; + + // see SPI_InitTypeDef + spi_port.Init.Mode = SPI_MODE_MASTER; + 8000cf8: f44f 7382 mov.w r3, #260 ; 0x104 + 8000cfc: 6063 str r3, [r4, #4] + spi_port.Init.Direction = SPI_DIRECTION_2LINES; + spi_port.Init.DataSize = SPI_DATASIZE_8BIT; + 8000cfe: f44f 63e0 mov.w r3, #1792 ; 0x700 + 8000d02: 60e3 str r3, [r4, #12] + spi_port.Init.CLKPolarity = SPI_POLARITY_LOW; + spi_port.Init.CLKPhase = SPI_PHASE_1EDGE; + spi_port.Init.NSS = SPI_NSS_SOFT; + spi_port.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16; // conservative + 8000d04: f44f 7000 mov.w r0, #512 ; 0x200 + 8000d08: 2318 movs r3, #24 + 8000d0a: e9c4 0306 strd r0, r3, [r4, #24] + spi_port.Instance = SPI1; + 8000d0e: 6025 str r5, [r4, #0] + spi_port.Init.FirstBit = SPI_FIRSTBIT_MSB; + spi_port.Init.TIMode = SPI_TIMODE_DISABLED; + spi_port.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED; + + HAL_SPI_Init(&spi_port); + 8000d10: 4620 mov r0, r4 +#endif +} + 8000d12: e8bd 4038 ldmia.w sp!, {r3, r4, r5, lr} + HAL_SPI_Init(&spi_port); + 8000d16: f000 bb37 b.w 8001388 +} + 8000d1a: bd38 pop {r3, r4, r5, pc} + 8000d1c: 2009e154 .word 0x2009e154 + 8000d20: 40013000 .word 0x40013000 + +08000d24 : +// +// Ok to call this lots. +// + void +oled_setup(void) +{ + 8000d24: b530 push {r4, r5, lr} + puts("oled disabled");return; // disable so I can use MCO +#endif + + static uint32_t inited; + + if(inited == 0x238a572F) { + 8000d26: 4b2c ldr r3, [pc, #176] ; (8000dd8 ) + 8000d28: 4a2c ldr r2, [pc, #176] ; (8000ddc ) + 8000d2a: 6819 ldr r1, [r3, #0] + 8000d2c: 4291 cmp r1, r2 +{ + 8000d2e: b089 sub sp, #36 ; 0x24 + if(inited == 0x238a572F) { + 8000d30: d050 beq.n 8000dd4 + return; + } + inited = 0x238a572F; + 8000d32: 601a str r2, [r3, #0] + + // enable some internal clocks + __HAL_RCC_GPIOA_CLK_ENABLE(); + 8000d34: 4b2a ldr r3, [pc, #168] ; (8000de0 ) + __HAL_RCC_SPI1_CLK_ENABLE(); + + // simple pins + GPIO_InitTypeDef setup = { + 8000d36: 4d2b ldr r5, [pc, #172] ; (8000de4 ) + __HAL_RCC_GPIOA_CLK_ENABLE(); + 8000d38: 6cda ldr r2, [r3, #76] ; 0x4c + 8000d3a: f042 0201 orr.w r2, r2, #1 + 8000d3e: 64da str r2, [r3, #76] ; 0x4c + 8000d40: 6cda ldr r2, [r3, #76] ; 0x4c + 8000d42: f002 0201 and.w r2, r2, #1 + 8000d46: 9201 str r2, [sp, #4] + 8000d48: 9a01 ldr r2, [sp, #4] + __HAL_RCC_SPI1_CLK_ENABLE(); + 8000d4a: 6e1a ldr r2, [r3, #96] ; 0x60 + 8000d4c: f442 5280 orr.w r2, r2, #4096 ; 0x1000 + 8000d50: 661a str r2, [r3, #96] ; 0x60 + 8000d52: 6e1b ldr r3, [r3, #96] ; 0x60 + 8000d54: f403 5380 and.w r3, r3, #4096 ; 0x1000 + 8000d58: 9302 str r3, [sp, #8] + 8000d5a: 9b02 ldr r3, [sp, #8] + GPIO_InitTypeDef setup = { + 8000d5c: cd0f ldmia r5!, {r0, r1, r2, r3} + 8000d5e: ac03 add r4, sp, #12 + 8000d60: c40f stmia r4!, {r0, r1, r2, r3} + 8000d62: 682b ldr r3, [r5, #0] + 8000d64: 6023 str r3, [r4, #0] + .Mode = GPIO_MODE_OUTPUT_PP, + .Pull = GPIO_NOPULL, + .Speed = GPIO_SPEED_FREQ_MEDIUM, + .Alternate = 0, + }; + HAL_GPIO_Init(GPIOA, &setup); + 8000d66: a903 add r1, sp, #12 + 8000d68: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000d6c: f000 f950 bl 8001010 + + // starting values + HAL_GPIO_WritePin(GPIOA, RESET_PIN | CS_PIN | DC_PIN, 1); + 8000d70: 2201 movs r2, #1 + 8000d72: f44f 71a8 mov.w r1, #336 ; 0x150 + 8000d76: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000d7a: f000 fac3 bl 8001304 + + // SPI pins + setup.Pin = SPI_SCK | SPI_MOSI; + setup.Mode = GPIO_MODE_AF_PP; + 8000d7e: 22a0 movs r2, #160 ; 0xa0 + 8000d80: 2302 movs r3, #2 + 8000d82: e9cd 2303 strd r2, r3, [sp, #12] + setup.Alternate = GPIO_AF5_SPI1; + HAL_GPIO_Init(GPIOA, &setup); + 8000d86: a903 add r1, sp, #12 + setup.Alternate = GPIO_AF5_SPI1; + 8000d88: 2305 movs r3, #5 + HAL_GPIO_Init(GPIOA, &setup); + 8000d8a: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + setup.Alternate = GPIO_AF5_SPI1; + 8000d8e: 9307 str r3, [sp, #28] + HAL_GPIO_Init(GPIOA, &setup); + 8000d90: f000 f93e bl 8001010 + + // lock the RESET pin so that St's DFU code doesn't clear screen + // it might be trying to use it a MISO signal for SPI loading + HAL_GPIO_LockPin(GPIOA, RESET_PIN | CS_PIN | DC_PIN); + 8000d94: f44f 71a8 mov.w r1, #336 ; 0x150 + 8000d98: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000d9c: f000 fabb bl 8001316 + + // 10ms low-going pulse on reset pin + delay_ms(1); + 8000da0: 2001 movs r0, #1 + 8000da2: f002 fda9 bl 80038f8 + HAL_GPIO_WritePin(GPIOA, RESET_PIN, 0); + 8000da6: 2200 movs r2, #0 + 8000da8: 2140 movs r1, #64 ; 0x40 + 8000daa: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000dae: f000 faa9 bl 8001304 + delay_ms(10); + 8000db2: 200a movs r0, #10 + 8000db4: f002 fda0 bl 80038f8 + HAL_GPIO_WritePin(GPIOA, RESET_PIN, 1); + 8000db8: 2201 movs r2, #1 + 8000dba: 2140 movs r1, #64 ; 0x40 + 8000dbc: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000dc0: f000 faa0 bl 8001304 + + oled_spi_setup(); + 8000dc4: f7ff ff8c bl 8000ce0 + // this code: + // '0x37c', '0x1700', '0x603' + //SPI1->CR1 = 0x354; + + // write a sequence to reset things + oled_write_cmd_sequence(sizeof(reset_commands), reset_commands); + 8000dc8: 4907 ldr r1, [pc, #28] ; (8000de8 ) + 8000dca: 2019 movs r0, #25 + 8000dcc: f7ff ff5a bl 8000c84 + + rng_delay(); + 8000dd0: f001 fcd4 bl 800277c +} + 8000dd4: b009 add sp, #36 ; 0x24 + 8000dd6: bd30 pop {r4, r5, pc} + 8000dd8: 2009e150 .word 0x2009e150 + 8000ddc: 238a572f .word 0x238a572f + 8000de0: 40021000 .word 0x40021000 + 8000de4: 0800d79c .word 0x0800d79c + 8000de8: 0800d7bf .word 0x0800d7bf + +08000dec : +// +// No decompression. +// + void +oled_show_raw(uint32_t len, const uint8_t *pixels) +{ + 8000dec: b538 push {r3, r4, r5, lr} + 8000dee: 4604 mov r4, r0 + 8000df0: 460d mov r5, r1 + oled_setup(); + 8000df2: f7ff ff97 bl 8000d24 + + oled_write_cmd_sequence(sizeof(before_show), before_show); + 8000df6: 4912 ldr r1, [pc, #72] ; (8000e40 ) + 8000df8: 2006 movs r0, #6 + 8000dfa: f7ff ff43 bl 8000c84 + + HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); + 8000dfe: 2201 movs r2, #1 + 8000e00: 2110 movs r1, #16 + 8000e02: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000e06: f000 fa7d bl 8001304 + HAL_GPIO_WritePin(GPIOA, DC_PIN, 1); + 8000e0a: 2201 movs r2, #1 + 8000e0c: f44f 7180 mov.w r1, #256 ; 0x100 + 8000e10: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000e14: f000 fa76 bl 8001304 + HAL_GPIO_WritePin(GPIOA, CS_PIN, 0); + 8000e18: 2200 movs r2, #0 + 8000e1a: 2110 movs r1, #16 + 8000e1c: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000e20: f000 fa70 bl 8001304 + + write_bytes(len, pixels); + 8000e24: 4629 mov r1, r5 + 8000e26: 4620 mov r0, r4 + 8000e28: f7ff ff00 bl 8000c2c + + HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); + 8000e2c: 2201 movs r2, #1 + 8000e2e: 2110 movs r1, #16 + 8000e30: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000e34: f000 fa66 bl 8001304 + rng_delay(); +} + 8000e38: e8bd 4038 ldmia.w sp!, {r3, r4, r5, lr} + rng_delay(); + 8000e3c: f001 bc9e b.w 800277c + 8000e40: 0800d7b9 .word 0x0800d7b9 + +08000e44 : +// +// Perform simple RLE decompression. +// + void +oled_show(const uint8_t *pixels) +{ + 8000e44: b530 push {r4, r5, lr} + 8000e46: b0a1 sub sp, #132 ; 0x84 + 8000e48: 4604 mov r4, r0 + oled_setup(); + 8000e4a: f7ff ff6b bl 8000d24 + + oled_write_cmd_sequence(sizeof(before_show), before_show); + 8000e4e: 491d ldr r1, [pc, #116] ; (8000ec4 ) + 8000e50: 2006 movs r0, #6 + 8000e52: f7ff ff17 bl 8000c84 + + HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); + 8000e56: 2201 movs r2, #1 + 8000e58: 2110 movs r1, #16 + 8000e5a: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000e5e: f000 fa51 bl 8001304 + HAL_GPIO_WritePin(GPIOA, DC_PIN, 1); + 8000e62: 2201 movs r2, #1 + 8000e64: f44f 7180 mov.w r1, #256 ; 0x100 + 8000e68: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000e6c: f000 fa4a bl 8001304 + HAL_GPIO_WritePin(GPIOA, CS_PIN, 0); + 8000e70: 2200 movs r2, #0 + 8000e72: 2110 movs r1, #16 + 8000e74: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000e78: f000 fa44 bl 8001304 + uint8_t buf[127]; + const uint8_t *p = pixels; + + // NOTE: must also update code in oled_show_progress, which dups this heavily. + while(1) { + uint8_t hdr = *(p++); + 8000e7c: 7823 ldrb r3, [r4, #0] + if(!hdr) break; + 8000e7e: b1b3 cbz r3, 8000eae + + uint8_t len = hdr & 0x7f; + 8000e80: f003 057f and.w r5, r3, #127 ; 0x7f + if(hdr & 0x80) { + 8000e84: 061b lsls r3, r3, #24 + 8000e86: d50b bpl.n 8000ea0 + uint8_t hdr = *(p++); + 8000e88: 3401 adds r4, #1 + // random bytes follow + memcpy(buf, p, len); + 8000e8a: 4621 mov r1, r4 + 8000e8c: 462a mov r2, r5 + 8000e8e: 4668 mov r0, sp + 8000e90: f00c fbc8 bl 800d624 + p += len; + 8000e94: 442c add r4, r5 + // repeat same byte + memset(buf, *p, len); + p++; + } + + write_bytes(len, buf); + 8000e96: 4669 mov r1, sp + 8000e98: 4628 mov r0, r5 + 8000e9a: f7ff fec7 bl 8000c2c + while(1) { + 8000e9e: e7ed b.n 8000e7c + memset(buf, *p, len); + 8000ea0: 7861 ldrb r1, [r4, #1] + 8000ea2: 462a mov r2, r5 + 8000ea4: 4668 mov r0, sp + 8000ea6: f00c fbe5 bl 800d674 + p++; + 8000eaa: 3402 adds r4, #2 + 8000eac: e7f3 b.n 8000e96 + } + + HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); + 8000eae: 2201 movs r2, #1 + 8000eb0: 2110 movs r1, #16 + 8000eb2: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000eb6: f000 fa25 bl 8001304 + rng_delay(); + 8000eba: f001 fc5f bl 800277c +} + 8000ebe: b021 add sp, #132 ; 0x84 + 8000ec0: bd30 pop {r4, r5, pc} + 8000ec2: bf00 nop + 8000ec4: 0800d7b9 .word 0x0800d7b9 + +08000ec8 : +// +// Perform simple RLE decompression, and add a bar on final screen line. +// + void +oled_show_progress(const uint8_t *pixels, int progress) +{ + 8000ec8: e92d 43f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, lr} + 8000ecc: b0a1 sub sp, #132 ; 0x84 + 8000ece: 460d mov r5, r1 + 8000ed0: 4606 mov r6, r0 + oled_setup(); + 8000ed2: f7ff ff27 bl 8000d24 + + oled_write_cmd_sequence(sizeof(before_show), before_show); + 8000ed6: 493b ldr r1, [pc, #236] ; (8000fc4 ) + 8000ed8: 2006 movs r0, #6 + 8000eda: f7ff fed3 bl 8000c84 + + HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); + 8000ede: 2201 movs r2, #1 + 8000ee0: 2110 movs r1, #16 + 8000ee2: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000ee6: f000 fa0d bl 8001304 + HAL_GPIO_WritePin(GPIOA, DC_PIN, 1); + 8000eea: 2201 movs r2, #1 + 8000eec: f44f 7180 mov.w r1, #256 ; 0x100 + 8000ef0: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000ef4: f000 fa06 bl 8001304 + HAL_GPIO_WritePin(GPIOA, CS_PIN, 0); + 8000ef8: 2110 movs r1, #16 + 8000efa: 2200 movs r2, #0 + 8000efc: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000f00: f000 fa00 bl 8001304 + + uint8_t buf[127]; + const uint8_t *p = pixels; + + const uint16_t p_start = 896; + uint32_t p_count = 1280 * progress / 1000; + 8000f04: f44f 61a0 mov.w r1, #1280 ; 0x500 + 8000f08: 434d muls r5, r1 + 8000f0a: 2400 movs r4, #0 + 8000f0c: f44f 717a mov.w r1, #1000 ; 0x3e8 + 8000f10: fb95 f5f1 sdiv r5, r5, r1 + + if(p_count > 128) p_count = 128; + 8000f14: 2d80 cmp r5, #128 ; 0x80 + 8000f16: bf28 it cs + 8000f18: 2580 movcs r5, #128 ; 0x80 + uint32_t p_count = 1280 * progress / 1000; + 8000f1a: 46a0 mov r8, r4 + + bool last_line = false; + + uint16_t offset = 0; + while(1) { + uint8_t hdr = *(p++); + 8000f1c: 7833 ldrb r3, [r6, #0] + if(hdr == 0) break; + 8000f1e: 2b00 cmp r3, #0 + 8000f20: d045 beq.n 8000fae + + uint8_t len = hdr & 0x7f; + 8000f22: f003 097f and.w r9, r3, #127 ; 0x7f + if(hdr & 0x80) { + 8000f26: 061b lsls r3, r3, #24 + 8000f28: d524 bpl.n 8000f74 + uint8_t hdr = *(p++); + 8000f2a: 3601 adds r6, #1 + // random bytes follow + memcpy(buf, p, len); + 8000f2c: 4631 mov r1, r6 + 8000f2e: 464a mov r2, r9 + 8000f30: 4668 mov r0, sp + 8000f32: f00c fb77 bl 800d624 + p += len; + 8000f36: 444e add r6, r9 + // repeat same byte + memset(buf, *p, len); + p++; + } + + if(!last_line && (offset+len) >= p_start) { + 8000f38: f1b8 0f00 cmp.w r8, #0 + 8000f3c: d117 bne.n 8000f6e + 8000f3e: eb04 0309 add.w r3, r4, r9 + 8000f42: f5b3 7f60 cmp.w r3, #896 ; 0x380 + 8000f46: db29 blt.n 8000f9c + last_line = true; + + // adjust so we're aligned w/ last line + int h = p_start - offset; + if(h) { + 8000f48: f5d4 7460 rsbs r4, r4, #896 ; 0x380 + 8000f4c: d00d beq.n 8000f6a + write_bytes(h, buf); + 8000f4e: 4669 mov r1, sp + 8000f50: 4620 mov r0, r4 + memmove(buf, buf+h, len-h); + 8000f52: eba9 0904 sub.w r9, r9, r4 + write_bytes(h, buf); + 8000f56: f7ff fe69 bl 8000c2c + memmove(buf, buf+h, len-h); + 8000f5a: 464a mov r2, r9 + 8000f5c: eb0d 0104 add.w r1, sp, r4 + 8000f60: 4668 mov r0, sp + 8000f62: f00c fb6d bl 800d640 + len -= h; + 8000f66: fa5f f989 uxtb.w r9, r9 + offset += h; + 8000f6a: f44f 7460 mov.w r4, #896 ; 0x380 + } + } + + if(last_line) { + 8000f6e: 466b mov r3, sp + while(1) { + 8000f70: 462f mov r7, r5 + 8000f72: e00c b.n 8000f8e + memset(buf, *p, len); + 8000f74: 7871 ldrb r1, [r6, #1] + 8000f76: 464a mov r2, r9 + 8000f78: 4668 mov r0, sp + 8000f7a: f00c fb7b bl 800d674 + p++; + 8000f7e: 3602 adds r6, #2 + 8000f80: e7da b.n 8000f38 + for(int j=0; (p_count > 0) && (j 0) && (j + 8000f90: 1bea subs r2, r5, r7 + 8000f92: 454a cmp r2, r9 + 8000f94: dbf5 blt.n 8000f82 + 8000f96: f04f 0801 mov.w r8, #1 + 8000f9a: e000 b.n 8000f9e + 8000f9c: 462f mov r7, r5 + } + } + + write_bytes(len, buf); + 8000f9e: 4669 mov r1, sp + 8000fa0: 4648 mov r0, r9 + offset += len; + 8000fa2: 444c add r4, r9 + write_bytes(len, buf); + 8000fa4: f7ff fe42 bl 8000c2c + offset += len; + 8000fa8: b2a4 uxth r4, r4 + while(1) { + 8000faa: 463d mov r5, r7 + 8000fac: e7b6 b.n 8000f1c + } + + HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); + 8000fae: 2201 movs r2, #1 + 8000fb0: 2110 movs r1, #16 + 8000fb2: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000fb6: f000 f9a5 bl 8001304 + rng_delay(); + 8000fba: f001 fbdf bl 800277c +} + 8000fbe: b021 add sp, #132 ; 0x84 + 8000fc0: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + 8000fc4: 0800d7b9 .word 0x0800d7b9 + +08000fc8 : + +// oled_factory_busy() +// + void +oled_factory_busy(void) +{ + 8000fc8: b510 push {r4, lr} + 8000fca: b0a0 sub sp, #128 ; 0x80 + 8000fcc: 466a mov r2, sp + 8000fce: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 8000fd2: 4614 mov r4, r2 + }; + uint8_t data[128]; + + for(int x=0; x<128; x++) { + // each byte here is a vertical column, 8 pixels tall, MSB at bottom + data[x] = (1<<(7 - (x%8))); + 8000fd4: 2001 movs r0, #1 + 8000fd6: f003 0107 and.w r1, r3, #7 + for(int x=0; x<128; x++) { + 8000fda: 3b01 subs r3, #1 + data[x] = (1<<(7 - (x%8))); + 8000fdc: fa00 f101 lsl.w r1, r0, r1 + for(int x=0; x<128; x++) { + 8000fe0: f113 0f81 cmn.w r3, #129 ; 0x81 + data[x] = (1<<(7 - (x%8))); + 8000fe4: f802 1b01 strb.w r1, [r2], #1 + for(int x=0; x<128; x++) { + 8000fe8: d1f5 bne.n 8000fd6 + } + + oled_write_cmd_sequence(sizeof(setup), setup); + 8000fea: 4907 ldr r1, [pc, #28] ; (8001008 ) + 8000fec: 2006 movs r0, #6 + 8000fee: f7ff fe49 bl 8000c84 + oled_write_data(sizeof(data), data); + 8000ff2: 4621 mov r1, r4 + 8000ff4: 2080 movs r0, #128 ; 0x80 + 8000ff6: f7ff fe51 bl 8000c9c + oled_write_cmd_sequence(sizeof(animate), animate); + 8000ffa: 4904 ldr r1, [pc, #16] ; (800100c ) + 8000ffc: 2009 movs r0, #9 + 8000ffe: f7ff fe41 bl 8000c84 +} + 8001002: b020 add sp, #128 ; 0x80 + 8001004: bd10 pop {r4, pc} + 8001006: bf00 nop + 8001008: 0800d7d8 .word 0x0800d7d8 + 800100c: 0800d7b0 .word 0x0800d7b0 + +08001010 : + * @param GPIO_Init: pointer to a GPIO_InitTypeDef structure that contains + * the configuration information for the specified GPIO peripheral. + * @retval None + */ +void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init) +{ + 8001010: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + /*--------------------- EXTI Mode Configuration ------------------------*/ + /* Configure the External Interrupt or event for the current IO */ + if((GPIO_Init->Mode & EXTI_MODE) == EXTI_MODE) + { + /* Enable SYSCFG Clock */ + __HAL_RCC_SYSCFG_CLK_ENABLE(); + 8001014: f8df 81b4 ldr.w r8, [pc, #436] ; 80011cc + temp &= ~(((uint32_t)0x0F) << (4 * (position & 0x03))); + temp |= (GPIO_GET_INDEX(GPIOx) << (4 * (position & 0x03))); + SYSCFG->EXTICR[position >> 2] = temp; + + /* Clear EXTI line configuration */ + temp = EXTI->IMR1; + 8001018: 4c6a ldr r4, [pc, #424] ; (80011c4 ) + temp |= (GPIO_GET_INDEX(GPIOx) << (4 * (position & 0x03))); + 800101a: f8df 91b4 ldr.w r9, [pc, #436] ; 80011d0 +{ + 800101e: b085 sub sp, #20 + uint32_t position = 0x00; + 8001020: 2300 movs r3, #0 + while (((GPIO_Init->Pin) >> position) != RESET) + 8001022: 680a ldr r2, [r1, #0] + 8001024: fa32 f503 lsrs.w r5, r2, r3 + 8001028: d102 bne.n 8001030 + } + } + + position++; + } +} + 800102a: b005 add sp, #20 + 800102c: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + iocurrent = (GPIO_Init->Pin) & (1U << position); + 8001030: 2701 movs r7, #1 + 8001032: 409f lsls r7, r3 + if(iocurrent) + 8001034: 403a ands r2, r7 + 8001036: f000 80b4 beq.w 80011a2 + if((GPIO_Init->Mode == GPIO_MODE_AF_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_OD)) + 800103a: 684d ldr r5, [r1, #4] + 800103c: f025 0a10 bic.w sl, r5, #16 + 8001040: f1ba 0f02 cmp.w sl, #2 + 8001044: d116 bne.n 8001074 + temp = GPIOx->AFR[position >> 3]; + 8001046: ea4f 0ed3 mov.w lr, r3, lsr #3 + 800104a: eb00 0e8e add.w lr, r0, lr, lsl #2 + temp &= ~((uint32_t)0xF << ((uint32_t)(position & (uint32_t)0x07) * 4)) ; + 800104e: f003 0b07 and.w fp, r3, #7 + temp = GPIOx->AFR[position >> 3]; + 8001052: f8de 6020 ldr.w r6, [lr, #32] + temp &= ~((uint32_t)0xF << ((uint32_t)(position & (uint32_t)0x07) * 4)) ; + 8001056: ea4f 0b8b mov.w fp, fp, lsl #2 + 800105a: f04f 0c0f mov.w ip, #15 + 800105e: fa0c fc0b lsl.w ip, ip, fp + 8001062: ea26 0c0c bic.w ip, r6, ip + temp |= ((uint32_t)(GPIO_Init->Alternate) << (((uint32_t)position & (uint32_t)0x07) * 4)); + 8001066: 690e ldr r6, [r1, #16] + 8001068: fa06 f60b lsl.w r6, r6, fp + 800106c: ea46 060c orr.w r6, r6, ip + GPIOx->AFR[position >> 3] = temp; + 8001070: f8ce 6020 str.w r6, [lr, #32] + temp = GPIOx->MODER; + 8001074: f8d0 b000 ldr.w fp, [r0] + temp &= ~(GPIO_MODER_MODE0 << (position * 2)); + 8001078: ea4f 0e43 mov.w lr, r3, lsl #1 + 800107c: f04f 0c03 mov.w ip, #3 + 8001080: fa0c fc0e lsl.w ip, ip, lr + 8001084: ea6f 060c mvn.w r6, ip + 8001088: ea2b 0b0c bic.w fp, fp, ip + temp |= ((GPIO_Init->Mode & GPIO_MODE) << (position * 2)); + 800108c: f005 0c03 and.w ip, r5, #3 + 8001090: fa0c fc0e lsl.w ip, ip, lr + if((GPIO_Init->Mode == GPIO_MODE_OUTPUT_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_PP) || + 8001094: f10a 3aff add.w sl, sl, #4294967295 ; 0xffffffff + temp |= ((GPIO_Init->Mode & GPIO_MODE) << (position * 2)); + 8001098: ea4c 0c0b orr.w ip, ip, fp + if((GPIO_Init->Mode == GPIO_MODE_OUTPUT_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_PP) || + 800109c: f1ba 0f01 cmp.w sl, #1 + temp &= ~(GPIO_MODER_MODE0 << (position * 2)); + 80010a0: 9601 str r6, [sp, #4] + GPIOx->MODER = temp; + 80010a2: f8c0 c000 str.w ip, [r0] + if((GPIO_Init->Mode == GPIO_MODE_OUTPUT_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_PP) || + 80010a6: d815 bhi.n 80010d4 + temp = GPIOx->OSPEEDR; + 80010a8: f8d0 c008 ldr.w ip, [r0, #8] + temp &= ~(GPIO_OSPEEDR_OSPEED0 << (position * 2)); + 80010ac: ea06 0c0c and.w ip, r6, ip + temp |= (GPIO_Init->Speed << (position * 2)); + 80010b0: 68ce ldr r6, [r1, #12] + 80010b2: fa06 fa0e lsl.w sl, r6, lr + 80010b6: ea4a 0c0c orr.w ip, sl, ip + GPIOx->OSPEEDR = temp; + 80010ba: f8c0 c008 str.w ip, [r0, #8] + temp = GPIOx->OTYPER; + 80010be: f8d0 c004 ldr.w ip, [r0, #4] + temp &= ~(GPIO_OTYPER_OT0 << position) ; + 80010c2: ea2c 0707 bic.w r7, ip, r7 + temp |= (((GPIO_Init->Mode & GPIO_OUTPUT_TYPE) >> 4) << position); + 80010c6: f3c5 1c00 ubfx ip, r5, #4, #1 + 80010ca: fa0c fc03 lsl.w ip, ip, r3 + 80010ce: ea4c 0707 orr.w r7, ip, r7 + GPIOx->OTYPER = temp; + 80010d2: 6047 str r7, [r0, #4] + temp = GPIOx->PUPDR; + 80010d4: 68c7 ldr r7, [r0, #12] + temp &= ~(GPIO_PUPDR_PUPD0 << (position * 2)); + 80010d6: 9e01 ldr r6, [sp, #4] + 80010d8: 4037 ands r7, r6 + temp |= ((GPIO_Init->Pull) << (position * 2)); + 80010da: 688e ldr r6, [r1, #8] + 80010dc: fa06 f60e lsl.w r6, r6, lr + 80010e0: 433e orrs r6, r7 + GPIOx->PUPDR = temp; + 80010e2: 60c6 str r6, [r0, #12] + if((GPIO_Init->Mode & EXTI_MODE) == EXTI_MODE) + 80010e4: 00ee lsls r6, r5, #3 + 80010e6: d55c bpl.n 80011a2 + __HAL_RCC_SYSCFG_CLK_ENABLE(); + 80010e8: f8d8 6060 ldr.w r6, [r8, #96] ; 0x60 + 80010ec: f046 0601 orr.w r6, r6, #1 + 80010f0: f8c8 6060 str.w r6, [r8, #96] ; 0x60 + 80010f4: f8d8 6060 ldr.w r6, [r8, #96] ; 0x60 + 80010f8: f023 0703 bic.w r7, r3, #3 + 80010fc: f107 4780 add.w r7, r7, #1073741824 ; 0x40000000 + 8001100: f006 0601 and.w r6, r6, #1 + 8001104: f507 3780 add.w r7, r7, #65536 ; 0x10000 + 8001108: 9603 str r6, [sp, #12] + temp &= ~(((uint32_t)0x0F) << (4 * (position & 0x03))); + 800110a: f003 0c03 and.w ip, r3, #3 + __HAL_RCC_SYSCFG_CLK_ENABLE(); + 800110e: 9e03 ldr r6, [sp, #12] + temp = SYSCFG->EXTICR[position >> 2]; + 8001110: f8d7 a008 ldr.w sl, [r7, #8] + temp &= ~(((uint32_t)0x0F) << (4 * (position & 0x03))); + 8001114: f04f 0e0f mov.w lr, #15 + 8001118: ea4f 0c8c mov.w ip, ip, lsl #2 + 800111c: fa0e f60c lsl.w r6, lr, ip + temp |= (GPIO_GET_INDEX(GPIOx) << (4 * (position & 0x03))); + 8001120: f1b0 4f90 cmp.w r0, #1207959552 ; 0x48000000 + temp &= ~(((uint32_t)0x0F) << (4 * (position & 0x03))); + 8001124: ea2a 0e06 bic.w lr, sl, r6 + temp |= (GPIO_GET_INDEX(GPIOx) << (4 * (position & 0x03))); + 8001128: d03d beq.n 80011a6 + 800112a: 4e27 ldr r6, [pc, #156] ; (80011c8 ) + 800112c: 42b0 cmp r0, r6 + 800112e: d03c beq.n 80011aa + 8001130: f506 6680 add.w r6, r6, #1024 ; 0x400 + 8001134: 42b0 cmp r0, r6 + 8001136: d03a beq.n 80011ae + 8001138: f506 6680 add.w r6, r6, #1024 ; 0x400 + 800113c: 42b0 cmp r0, r6 + 800113e: d038 beq.n 80011b2 + 8001140: f506 6680 add.w r6, r6, #1024 ; 0x400 + 8001144: 42b0 cmp r0, r6 + 8001146: d036 beq.n 80011b6 + 8001148: f506 6680 add.w r6, r6, #1024 ; 0x400 + 800114c: 42b0 cmp r0, r6 + 800114e: d034 beq.n 80011ba + 8001150: 4548 cmp r0, r9 + 8001152: d034 beq.n 80011be + 8001154: f506 6600 add.w r6, r6, #2048 ; 0x800 + 8001158: 42b0 cmp r0, r6 + 800115a: bf0c ite eq + 800115c: 2607 moveq r6, #7 + 800115e: 2608 movne r6, #8 + 8001160: fa06 f60c lsl.w r6, r6, ip + 8001164: ea46 060e orr.w r6, r6, lr + SYSCFG->EXTICR[position >> 2] = temp; + 8001168: 60be str r6, [r7, #8] + temp = EXTI->IMR1; + 800116a: 6826 ldr r6, [r4, #0] + temp &= ~((uint32_t)iocurrent); + 800116c: 43d7 mvns r7, r2 + if((GPIO_Init->Mode & GPIO_MODE_IT) == GPIO_MODE_IT) + 800116e: f415 3f80 tst.w r5, #65536 ; 0x10000 + temp &= ~((uint32_t)iocurrent); + 8001172: bf0c ite eq + 8001174: 403e andeq r6, r7 + temp |= iocurrent; + 8001176: 4316 orrne r6, r2 + EXTI->IMR1 = temp; + 8001178: 6026 str r6, [r4, #0] + temp = EXTI->EMR1; + 800117a: 6866 ldr r6, [r4, #4] + if((GPIO_Init->Mode & GPIO_MODE_EVT) == GPIO_MODE_EVT) + 800117c: f415 3f00 tst.w r5, #131072 ; 0x20000 + temp &= ~((uint32_t)iocurrent); + 8001180: bf0c ite eq + 8001182: 403e andeq r6, r7 + temp |= iocurrent; + 8001184: 4316 orrne r6, r2 + EXTI->EMR1 = temp; + 8001186: 6066 str r6, [r4, #4] + temp = EXTI->RTSR1; + 8001188: 68a6 ldr r6, [r4, #8] + if((GPIO_Init->Mode & RISING_EDGE) == RISING_EDGE) + 800118a: f415 1f80 tst.w r5, #1048576 ; 0x100000 + temp &= ~((uint32_t)iocurrent); + 800118e: bf0c ite eq + 8001190: 403e andeq r6, r7 + temp |= iocurrent; + 8001192: 4316 orrne r6, r2 + EXTI->RTSR1 = temp; + 8001194: 60a6 str r6, [r4, #8] + temp = EXTI->FTSR1; + 8001196: 68e6 ldr r6, [r4, #12] + if((GPIO_Init->Mode & FALLING_EDGE) == FALLING_EDGE) + 8001198: 02ad lsls r5, r5, #10 + temp &= ~((uint32_t)iocurrent); + 800119a: bf54 ite pl + 800119c: 403e andpl r6, r7 + temp |= iocurrent; + 800119e: 4316 orrmi r6, r2 + EXTI->FTSR1 = temp; + 80011a0: 60e6 str r6, [r4, #12] + position++; + 80011a2: 3301 adds r3, #1 + 80011a4: e73d b.n 8001022 + temp |= (GPIO_GET_INDEX(GPIOx) << (4 * (position & 0x03))); + 80011a6: 2600 movs r6, #0 + 80011a8: e7da b.n 8001160 + 80011aa: 2601 movs r6, #1 + 80011ac: e7d8 b.n 8001160 + 80011ae: 2602 movs r6, #2 + 80011b0: e7d6 b.n 8001160 + 80011b2: 2603 movs r6, #3 + 80011b4: e7d4 b.n 8001160 + 80011b6: 2604 movs r6, #4 + 80011b8: e7d2 b.n 8001160 + 80011ba: 2605 movs r6, #5 + 80011bc: e7d0 b.n 8001160 + 80011be: 2606 movs r6, #6 + 80011c0: e7ce b.n 8001160 + 80011c2: bf00 nop + 80011c4: 40010400 .word 0x40010400 + 80011c8: 48000400 .word 0x48000400 + 80011cc: 40021000 .word 0x40021000 + 80011d0: 48001800 .word 0x48001800 + +080011d4 : + * @param GPIO_Pin: specifies the port bit to be written. + * This parameter can be one of GPIO_PIN_x where x can be (0..15). + * @retval None + */ +void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin) +{ + 80011d4: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + { + tmp = ((uint32_t)0x0F) << (4 * (position & 0x03)); + SYSCFG->EXTICR[position >> 2] &= ~tmp; + + /* Clear EXTI line configuration */ + EXTI->IMR1 &= ~((uint32_t)iocurrent); + 80011d8: 4c43 ldr r4, [pc, #268] ; (80012e8 ) + if(tmp == (GPIO_GET_INDEX(GPIOx) << (4 * (position & 0x03)))) + 80011da: f8df a114 ldr.w sl, [pc, #276] ; 80012f0 + 80011de: f8df b114 ldr.w fp, [pc, #276] ; 80012f4 + uint32_t position = 0x00; + 80011e2: 2200 movs r2, #0 + iocurrent = (GPIO_Pin) & (1U << position); + 80011e4: f04f 0901 mov.w r9, #1 + while ((GPIO_Pin >> position) != RESET) + 80011e8: fa31 f302 lsrs.w r3, r1, r2 + 80011ec: d101 bne.n 80011f2 + } + } + + position++; + } +} + 80011ee: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + iocurrent = (GPIO_Pin) & (1U << position); + 80011f2: fa09 f802 lsl.w r8, r9, r2 + if (iocurrent) + 80011f6: ea18 0c01 ands.w ip, r8, r1 + 80011fa: d064 beq.n 80012c6 + GPIOx->MODER |= (GPIO_MODER_MODE0 << (position * 2)); + 80011fc: 6805 ldr r5, [r0, #0] + 80011fe: 2303 movs r3, #3 + 8001200: 0056 lsls r6, r2, #1 + 8001202: fa03 f606 lsl.w r6, r3, r6 + GPIOx->AFR[position >> 3] &= ~((uint32_t)0xF << ((uint32_t)(position & (uint32_t)0x07) * 4)) ; + 8001206: fa22 fe03 lsr.w lr, r2, r3 + GPIOx->MODER |= (GPIO_MODER_MODE0 << (position * 2)); + 800120a: 4335 orrs r5, r6 + 800120c: eb00 0e8e add.w lr, r0, lr, lsl #2 + 8001210: 6005 str r5, [r0, #0] + GPIOx->AFR[position >> 3] &= ~((uint32_t)0xF << ((uint32_t)(position & (uint32_t)0x07) * 4)) ; + 8001212: f8de 5020 ldr.w r5, [lr, #32] + 8001216: f002 0707 and.w r7, r2, #7 + 800121a: 462b mov r3, r5 + 800121c: 00bf lsls r7, r7, #2 + 800121e: 250f movs r5, #15 + 8001220: fa05 f707 lsl.w r7, r5, r7 + 8001224: ea23 0707 bic.w r7, r3, r7 + 8001228: f8ce 7020 str.w r7, [lr, #32] + GPIOx->OSPEEDR &= ~(GPIO_OSPEEDR_OSPEED0 << (position * 2)); + 800122c: 6887 ldr r7, [r0, #8] + 800122e: ea27 0706 bic.w r7, r7, r6 + 8001232: 6087 str r7, [r0, #8] + GPIOx->OTYPER &= ~(GPIO_OTYPER_OT0 << position) ; + 8001234: 6847 ldr r7, [r0, #4] + 8001236: ea27 0708 bic.w r7, r7, r8 + 800123a: 6047 str r7, [r0, #4] + GPIOx->PUPDR &= ~(GPIO_PUPDR_PUPD0 << (position * 2)); + 800123c: 68c7 ldr r7, [r0, #12] + 800123e: ea27 0606 bic.w r6, r7, r6 + 8001242: 60c6 str r6, [r0, #12] + tmp = SYSCFG->EXTICR[position >> 2]; + 8001244: f022 0603 bic.w r6, r2, #3 + 8001248: f106 4680 add.w r6, r6, #1073741824 ; 0x40000000 + 800124c: f506 3680 add.w r6, r6, #65536 ; 0x10000 + tmp &= (((uint32_t)0x0F) << (4 * (position & 0x03))); + 8001250: f002 0703 and.w r7, r2, #3 + tmp = SYSCFG->EXTICR[position >> 2]; + 8001254: f8d6 e008 ldr.w lr, [r6, #8] + tmp &= (((uint32_t)0x0F) << (4 * (position & 0x03))); + 8001258: 00bf lsls r7, r7, #2 + 800125a: 40bd lsls r5, r7 + if(tmp == (GPIO_GET_INDEX(GPIOx) << (4 * (position & 0x03)))) + 800125c: f1b0 4f90 cmp.w r0, #1207959552 ; 0x48000000 + tmp &= (((uint32_t)0x0F) << (4 * (position & 0x03))); + 8001260: ea05 0e0e and.w lr, r5, lr + if(tmp == (GPIO_GET_INDEX(GPIOx) << (4 * (position & 0x03)))) + 8001264: d031 beq.n 80012ca + 8001266: 4b21 ldr r3, [pc, #132] ; (80012ec ) + 8001268: 4298 cmp r0, r3 + 800126a: d030 beq.n 80012ce + 800126c: f503 6380 add.w r3, r3, #1024 ; 0x400 + 8001270: 4298 cmp r0, r3 + 8001272: d02e beq.n 80012d2 + 8001274: f503 6380 add.w r3, r3, #1024 ; 0x400 + 8001278: 4298 cmp r0, r3 + 800127a: d02c beq.n 80012d6 + 800127c: f503 6380 add.w r3, r3, #1024 ; 0x400 + 8001280: 4298 cmp r0, r3 + 8001282: d02a beq.n 80012da + 8001284: f503 6380 add.w r3, r3, #1024 ; 0x400 + 8001288: 4298 cmp r0, r3 + 800128a: d028 beq.n 80012de + 800128c: 4550 cmp r0, sl + 800128e: d028 beq.n 80012e2 + 8001290: 4558 cmp r0, fp + 8001292: bf0c ite eq + 8001294: 2307 moveq r3, #7 + 8001296: 2308 movne r3, #8 + 8001298: 40bb lsls r3, r7 + 800129a: 4573 cmp r3, lr + 800129c: d113 bne.n 80012c6 + SYSCFG->EXTICR[position >> 2] &= ~tmp; + 800129e: 68b3 ldr r3, [r6, #8] + 80012a0: ea23 0505 bic.w r5, r3, r5 + 80012a4: 60b5 str r5, [r6, #8] + EXTI->IMR1 &= ~((uint32_t)iocurrent); + 80012a6: 6823 ldr r3, [r4, #0] + 80012a8: ea23 030c bic.w r3, r3, ip + 80012ac: 6023 str r3, [r4, #0] + EXTI->EMR1 &= ~((uint32_t)iocurrent); + 80012ae: 6863 ldr r3, [r4, #4] + 80012b0: ea23 030c bic.w r3, r3, ip + 80012b4: 6063 str r3, [r4, #4] + EXTI->RTSR1 &= ~((uint32_t)iocurrent); + 80012b6: 68a3 ldr r3, [r4, #8] + 80012b8: ea23 030c bic.w r3, r3, ip + 80012bc: 60a3 str r3, [r4, #8] + EXTI->FTSR1 &= ~((uint32_t)iocurrent); + 80012be: 68e3 ldr r3, [r4, #12] + 80012c0: ea23 030c bic.w r3, r3, ip + 80012c4: 60e3 str r3, [r4, #12] + position++; + 80012c6: 3201 adds r2, #1 + 80012c8: e78e b.n 80011e8 + if(tmp == (GPIO_GET_INDEX(GPIOx) << (4 * (position & 0x03)))) + 80012ca: 2300 movs r3, #0 + 80012cc: e7e4 b.n 8001298 + 80012ce: 2301 movs r3, #1 + 80012d0: e7e2 b.n 8001298 + 80012d2: 2302 movs r3, #2 + 80012d4: e7e0 b.n 8001298 + 80012d6: 2303 movs r3, #3 + 80012d8: e7de b.n 8001298 + 80012da: 2304 movs r3, #4 + 80012dc: e7dc b.n 8001298 + 80012de: 2305 movs r3, #5 + 80012e0: e7da b.n 8001298 + 80012e2: 2306 movs r3, #6 + 80012e4: e7d8 b.n 8001298 + 80012e6: bf00 nop + 80012e8: 40010400 .word 0x40010400 + 80012ec: 48000400 .word 0x48000400 + 80012f0: 48001800 .word 0x48001800 + 80012f4: 48001c00 .word 0x48001c00 + +080012f8 : + GPIO_PinState bitstatus; + + /* Check the parameters */ + assert_param(IS_GPIO_PIN(GPIO_Pin)); + + if((GPIOx->IDR & GPIO_Pin) != (uint32_t)GPIO_PIN_RESET) + 80012f8: 6903 ldr r3, [r0, #16] + 80012fa: 4219 tst r1, r3 + else + { + bitstatus = GPIO_PIN_RESET; + } + return bitstatus; +} + 80012fc: bf14 ite ne + 80012fe: 2001 movne r0, #1 + 8001300: 2000 moveq r0, #0 + 8001302: 4770 bx lr + +08001304 : +{ + /* Check the parameters */ + assert_param(IS_GPIO_PIN(GPIO_Pin)); + assert_param(IS_GPIO_PIN_ACTION(PinState)); + + if(PinState != GPIO_PIN_RESET) + 8001304: b10a cbz r2, 800130a + { + GPIOx->BSRR = (uint32_t)GPIO_Pin; + 8001306: 6181 str r1, [r0, #24] + 8001308: 4770 bx lr + } + else + { + GPIOx->BRR = (uint32_t)GPIO_Pin; + 800130a: 6281 str r1, [r0, #40] ; 0x28 + } +} + 800130c: 4770 bx lr + +0800130e : +void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) +{ + /* Check the parameters */ + assert_param(IS_GPIO_PIN(GPIO_Pin)); + + GPIOx->ODR ^= GPIO_Pin; + 800130e: 6943 ldr r3, [r0, #20] + 8001310: 4059 eors r1, r3 + 8001312: 6141 str r1, [r0, #20] +} + 8001314: 4770 bx lr + +08001316 : + * @param GPIO_Pin: specifies the port bits to be locked. + * This parameter can be any combination of GPIO_Pin_x where x can be (0..15). + * @retval None + */ +HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) +{ + 8001316: b082 sub sp, #8 + __IO uint32_t tmp = GPIO_LCKR_LCKK; + 8001318: f44f 3380 mov.w r3, #65536 ; 0x10000 + 800131c: 9301 str r3, [sp, #4] + /* Check the parameters */ + assert_param(IS_GPIO_LOCK_INSTANCE(GPIOx)); + assert_param(IS_GPIO_PIN(GPIO_Pin)); + + /* Apply lock key write sequence */ + tmp |= GPIO_Pin; + 800131e: 9b01 ldr r3, [sp, #4] + 8001320: 430b orrs r3, r1 + 8001322: 9301 str r3, [sp, #4] + /* Set LCKx bit(s): LCKK='1' + LCK[15-0] */ + GPIOx->LCKR = tmp; + 8001324: 9b01 ldr r3, [sp, #4] + 8001326: 61c3 str r3, [r0, #28] + /* Reset LCKx bit(s): LCKK='0' + LCK[15-0] */ + GPIOx->LCKR = GPIO_Pin; + 8001328: 61c1 str r1, [r0, #28] + /* Set LCKx bit(s): LCKK='1' + LCK[15-0] */ + GPIOx->LCKR = tmp; + 800132a: 9b01 ldr r3, [sp, #4] + 800132c: 61c3 str r3, [r0, #28] + /* Read LCKK bit*/ + tmp = GPIOx->LCKR; + 800132e: 69c3 ldr r3, [r0, #28] + 8001330: 9301 str r3, [sp, #4] + + if((GPIOx->LCKR & GPIO_LCKR_LCKK) != RESET) + 8001332: 69c0 ldr r0, [r0, #28] + 8001334: f480 3080 eor.w r0, r0, #65536 ; 0x10000 + } + else + { + return HAL_ERROR; + } +} + 8001338: f3c0 4000 ubfx r0, r0, #16, #1 + 800133c: b002 add sp, #8 + 800133e: 4770 bx lr + +08001340 : + UNUSED(GPIO_Pin); + + /* NOTE: This function should not be modified, when the callback is needed, + the HAL_GPIO_EXTI_Callback could be implemented in the user file + */ +} + 8001340: 4770 bx lr + ... + +08001344 : + if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET) + 8001344: 4a04 ldr r2, [pc, #16] ; (8001358 ) + 8001346: 6951 ldr r1, [r2, #20] + 8001348: 4201 tst r1, r0 +{ + 800134a: b508 push {r3, lr} + if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET) + 800134c: d002 beq.n 8001354 + __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin); + 800134e: 6150 str r0, [r2, #20] + HAL_GPIO_EXTI_Callback(GPIO_Pin); + 8001350: f7ff fff6 bl 8001340 +} + 8001354: bd08 pop {r3, pc} + 8001356: bf00 nop + 8001358: 40010400 .word 0x40010400 + +0800135c : +static HAL_StatusTypeDef SPI_WaitFifoStateUntilTimeout(SPI_HandleTypeDef *hspi, uint32_t Fifo, uint32_t State, + uint32_t Timeout, uint32_t Tickstart) +{ + __IO uint8_t tmpreg; + + while ((hspi->Instance->SR & Fifo) != State) + 800135c: 6803 ldr r3, [r0, #0] +static HAL_StatusTypeDef SPI_EndRxTxTransaction(SPI_HandleTypeDef *hspi, uint32_t Timeout, uint32_t Tickstart) + 800135e: b082 sub sp, #8 + while ((hspi->Instance->SR & Fifo) != State) + 8001360: 689a ldr r2, [r3, #8] + 8001362: f412 5fc0 tst.w r2, #6144 ; 0x1800 + 8001366: d1fb bne.n 8001360 + * @retval HAL status + */ +static HAL_StatusTypeDef SPI_WaitFlagStateUntilTimeout(SPI_HandleTypeDef *hspi, uint32_t Flag, uint32_t State, + uint32_t Timeout, uint32_t Tickstart) +{ + while ((__HAL_SPI_GET_FLAG(hspi, Flag) ? SET : RESET) != State) + 8001368: 689a ldr r2, [r3, #8] + 800136a: 0612 lsls r2, r2, #24 + 800136c: d4fc bmi.n 8001368 + while ((hspi->Instance->SR & Fifo) != State) + 800136e: 6898 ldr r0, [r3, #8] + 8001370: f410 60c0 ands.w r0, r0, #1536 ; 0x600 + 8001374: d101 bne.n 800137a +} + 8001376: b002 add sp, #8 + 8001378: 4770 bx lr + tmpreg = *((__IO uint8_t *)&hspi->Instance->DR); + 800137a: 7b1a ldrb r2, [r3, #12] + 800137c: b2d2 uxtb r2, r2 + 800137e: f88d 2007 strb.w r2, [sp, #7] + UNUSED(tmpreg); + 8001382: f89d 2007 ldrb.w r2, [sp, #7] + 8001386: e7f2 b.n 800136e + +08001388 : +{ + 8001388: b5f0 push {r4, r5, r6, r7, lr} + if (hspi == NULL) + 800138a: 2800 cmp r0, #0 + 800138c: d054 beq.n 8001438 + if (hspi->State == HAL_SPI_STATE_RESET) + 800138e: f890 305d ldrb.w r3, [r0, #93] ; 0x5d + if (hspi->Init.TIMode == SPI_TIMODE_DISABLE) + 8001392: f8d0 c024 ldr.w ip, [r0, #36] ; 0x24 + if (hspi->State == HAL_SPI_STATE_RESET) + 8001396: f003 02ff and.w r2, r3, #255 ; 0xff + 800139a: b90b cbnz r3, 80013a0 + hspi->Lock = HAL_UNLOCKED; + 800139c: f880 205c strb.w r2, [r0, #92] ; 0x5c + __HAL_SPI_DISABLE(hspi); + 80013a0: 6801 ldr r1, [r0, #0] + if (hspi->Init.DataSize > SPI_DATASIZE_8BIT) + 80013a2: 68c2 ldr r2, [r0, #12] + hspi->State = HAL_SPI_STATE_BUSY; + 80013a4: 2302 movs r3, #2 + 80013a6: f880 305d strb.w r3, [r0, #93] ; 0x5d + __HAL_SPI_DISABLE(hspi); + 80013aa: 680b ldr r3, [r1, #0] + if (hspi->Init.DataSize > SPI_DATASIZE_8BIT) + 80013ac: f5b2 6fe0 cmp.w r2, #1792 ; 0x700 + __HAL_SPI_DISABLE(hspi); + 80013b0: f023 0340 bic.w r3, r3, #64 ; 0x40 + 80013b4: 600b str r3, [r1, #0] + if (hspi->Init.DataSize > SPI_DATASIZE_8BIT) + 80013b6: f04f 0300 mov.w r3, #0 + 80013ba: d83f bhi.n 800143c + frxth = SPI_RXFIFO_THRESHOLD_QF; + 80013bc: f44f 5580 mov.w r5, #4096 ; 0x1000 + if ((hspi->Init.DataSize != SPI_DATASIZE_16BIT) && (hspi->Init.DataSize != SPI_DATASIZE_8BIT)) + 80013c0: d000 beq.n 80013c4 + hspi->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; + 80013c2: 6283 str r3, [r0, #40] ; 0x28 + if (hspi->Init.CRCLength == SPI_CRC_LENGTH_DATASIZE) + 80013c4: 6b03 ldr r3, [r0, #48] ; 0x30 + 80013c6: b92b cbnz r3, 80013d4 + if (hspi->Init.DataSize > SPI_DATASIZE_8BIT) + 80013c8: f5b2 6fe0 cmp.w r2, #1792 ; 0x700 + hspi->Init.CRCLength = SPI_CRC_LENGTH_16BIT; + 80013cc: bf8c ite hi + 80013ce: 2302 movhi r3, #2 + hspi->Init.CRCLength = SPI_CRC_LENGTH_8BIT; + 80013d0: 2301 movls r3, #1 + 80013d2: 6303 str r3, [r0, #48] ; 0x30 + WRITE_REG(hspi->Instance->CR1, (hspi->Init.Mode | hspi->Init.Direction | + 80013d4: e9d0 3701 ldrd r3, r7, [r0, #4] + 80013d8: 433b orrs r3, r7 + 80013da: 6907 ldr r7, [r0, #16] + 80013dc: 6984 ldr r4, [r0, #24] + 80013de: 6a86 ldr r6, [r0, #40] ; 0x28 + 80013e0: 433b orrs r3, r7 + 80013e2: 6947 ldr r7, [r0, #20] + 80013e4: 433b orrs r3, r7 + 80013e6: 69c7 ldr r7, [r0, #28] + 80013e8: 433b orrs r3, r7 + 80013ea: 6a07 ldr r7, [r0, #32] + 80013ec: 433b orrs r3, r7 + 80013ee: 4333 orrs r3, r6 + 80013f0: f404 7700 and.w r7, r4, #512 ; 0x200 + 80013f4: 433b orrs r3, r7 + 80013f6: 600b str r3, [r1, #0] + if (hspi->Init.CRCLength == SPI_CRC_LENGTH_16BIT) + 80013f8: 6b03 ldr r3, [r0, #48] ; 0x30 + 80013fa: 2b02 cmp r3, #2 + hspi->Instance->CR1 |= SPI_CR1_CRCL; + 80013fc: bf02 ittt eq + 80013fe: 680b ldreq r3, [r1, #0] + 8001400: f443 6300 orreq.w r3, r3, #2048 ; 0x800 + 8001404: 600b streq r3, [r1, #0] + WRITE_REG(hspi->Instance->CR2, (((hspi->Init.NSS >> 16U) & SPI_CR2_SSOE) | hspi->Init.TIMode | + 8001406: 6b43 ldr r3, [r0, #52] ; 0x34 + 8001408: ea4c 0202 orr.w r2, ip, r2 + 800140c: 0c24 lsrs r4, r4, #16 + 800140e: 431a orrs r2, r3 + 8001410: f004 0404 and.w r4, r4, #4 + 8001414: 4322 orrs r2, r4 + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 8001416: f5b6 5f00 cmp.w r6, #8192 ; 0x2000 + WRITE_REG(hspi->Instance->CRCPR, hspi->Init.CRCPolynomial); + 800141a: bf08 it eq + 800141c: 6ac3 ldreq r3, [r0, #44] ; 0x2c + WRITE_REG(hspi->Instance->CR2, (((hspi->Init.NSS >> 16U) & SPI_CR2_SSOE) | hspi->Init.TIMode | + 800141e: ea45 0502 orr.w r5, r5, r2 + 8001422: 604d str r5, [r1, #4] + hspi->State = HAL_SPI_STATE_READY; + 8001424: f04f 0201 mov.w r2, #1 + WRITE_REG(hspi->Instance->CRCPR, hspi->Init.CRCPolynomial); + 8001428: bf08 it eq + 800142a: 610b streq r3, [r1, #16] + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + 800142c: 2300 movs r3, #0 + 800142e: 6603 str r3, [r0, #96] ; 0x60 + hspi->State = HAL_SPI_STATE_READY; + 8001430: f880 205d strb.w r2, [r0, #93] ; 0x5d + return HAL_OK; + 8001434: 4618 mov r0, r3 +} + 8001436: bdf0 pop {r4, r5, r6, r7, pc} + return HAL_ERROR; + 8001438: 2001 movs r0, #1 + 800143a: e7fc b.n 8001436 + frxth = SPI_RXFIFO_THRESHOLD_HF; + 800143c: 461d mov r5, r3 + if ((hspi->Init.DataSize != SPI_DATASIZE_16BIT) && (hspi->Init.DataSize != SPI_DATASIZE_8BIT)) + 800143e: f5b2 6f70 cmp.w r2, #3840 ; 0xf00 + 8001442: e7bd b.n 80013c0 + +08001444 : +{ + 8001444: e92d 41f3 stmdb sp!, {r0, r1, r4, r5, r6, r7, r8, lr} + 8001448: 461e mov r6, r3 + __HAL_LOCK(hspi); + 800144a: f890 305c ldrb.w r3, [r0, #92] ; 0x5c + 800144e: 2b01 cmp r3, #1 +{ + 8001450: 4604 mov r4, r0 + 8001452: 460d mov r5, r1 + 8001454: 4690 mov r8, r2 + __HAL_LOCK(hspi); + 8001456: f000 809c beq.w 8001592 + 800145a: 2301 movs r3, #1 + 800145c: f880 305c strb.w r3, [r0, #92] ; 0x5c + tickstart = HAL_GetTick(); + 8001460: f005 fe44 bl 80070ec + if (hspi->State != HAL_SPI_STATE_READY) + 8001464: f894 305d ldrb.w r3, [r4, #93] ; 0x5d + 8001468: 2b01 cmp r3, #1 + tickstart = HAL_GetTick(); + 800146a: 4607 mov r7, r0 + if (hspi->State != HAL_SPI_STATE_READY) + 800146c: b2d8 uxtb r0, r3 + 800146e: f040 808e bne.w 800158e + if ((pData == NULL) || (Size == 0U)) + 8001472: 2d00 cmp r5, #0 + 8001474: d07a beq.n 800156c + 8001476: f1b8 0f00 cmp.w r8, #0 + 800147a: d077 beq.n 800156c + hspi->State = HAL_SPI_STATE_BUSY_TX; + 800147c: 2303 movs r3, #3 + 800147e: f884 305d strb.w r3, [r4, #93] ; 0x5d + if (hspi->Init.Direction == SPI_DIRECTION_1LINE) + 8001482: 68a3 ldr r3, [r4, #8] + SPI_1LINE_TX(hspi); + 8001484: 6822 ldr r2, [r4, #0] + hspi->pTxBuffPtr = (uint8_t *)pData; + 8001486: 63a5 str r5, [r4, #56] ; 0x38 + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + 8001488: 2100 movs r1, #0 + if (hspi->Init.Direction == SPI_DIRECTION_1LINE) + 800148a: f5b3 4f00 cmp.w r3, #32768 ; 0x8000 + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + 800148e: 6621 str r1, [r4, #96] ; 0x60 + hspi->TxXferCount = Size; + 8001490: f8a4 803e strh.w r8, [r4, #62] ; 0x3e + hspi->RxXferCount = 0U; + 8001494: f8a4 1046 strh.w r1, [r4, #70] ; 0x46 + SPI_1LINE_TX(hspi); + 8001498: bf08 it eq + 800149a: 6813 ldreq r3, [r2, #0] + hspi->TxXferSize = Size; + 800149c: f8a4 803c strh.w r8, [r4, #60] ; 0x3c + SPI_1LINE_TX(hspi); + 80014a0: bf08 it eq + 80014a2: f443 4380 orreq.w r3, r3, #16384 ; 0x4000 + hspi->RxISR = NULL; + 80014a6: e9c4 1113 strd r1, r1, [r4, #76] ; 0x4c + hspi->pRxBuffPtr = (uint8_t *)NULL; + 80014aa: 6421 str r1, [r4, #64] ; 0x40 + hspi->RxXferSize = 0U; + 80014ac: f8a4 1044 strh.w r1, [r4, #68] ; 0x44 + SPI_1LINE_TX(hspi); + 80014b0: bf08 it eq + 80014b2: 6013 streq r3, [r2, #0] + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 80014b4: 6aa3 ldr r3, [r4, #40] ; 0x28 + 80014b6: f5b3 5f00 cmp.w r3, #8192 ; 0x2000 + 80014ba: d107 bne.n 80014cc + SPI_RESET_CRC(hspi); + 80014bc: 6813 ldr r3, [r2, #0] + 80014be: f423 5300 bic.w r3, r3, #8192 ; 0x2000 + 80014c2: 6013 str r3, [r2, #0] + 80014c4: 6813 ldr r3, [r2, #0] + 80014c6: f443 5300 orr.w r3, r3, #8192 ; 0x2000 + 80014ca: 6013 str r3, [r2, #0] + if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE) + 80014cc: 6813 ldr r3, [r2, #0] + 80014ce: 0659 lsls r1, r3, #25 + __HAL_SPI_ENABLE(hspi); + 80014d0: bf5e ittt pl + 80014d2: 6813 ldrpl r3, [r2, #0] + 80014d4: f043 0340 orrpl.w r3, r3, #64 ; 0x40 + 80014d8: 6013 strpl r3, [r2, #0] + if ((hspi->Init.Mode == SPI_MODE_SLAVE) || (hspi->TxXferCount == 0x01U)) + 80014da: 6863 ldr r3, [r4, #4] + 80014dc: b11b cbz r3, 80014e6 + 80014de: 8fe3 ldrh r3, [r4, #62] ; 0x3e + 80014e0: b29b uxth r3, r3 + 80014e2: 2b01 cmp r3, #1 + 80014e4: d110 bne.n 8001508 + if (hspi->TxXferCount > 1U) + 80014e6: 8fe3 ldrh r3, [r4, #62] ; 0x3e + 80014e8: b29b uxth r3, r3 + 80014ea: 2b01 cmp r3, #1 + 80014ec: d905 bls.n 80014fa + hspi->Instance->DR = *((uint16_t *)pData); + 80014ee: f835 3b02 ldrh.w r3, [r5], #2 + 80014f2: 60d3 str r3, [r2, #12] + hspi->TxXferCount -= 2U; + 80014f4: 8fe3 ldrh r3, [r4, #62] ; 0x3e + 80014f6: 3b02 subs r3, #2 + 80014f8: e004 b.n 8001504 + *((__IO uint8_t *)&hspi->Instance->DR) = (*pData++); + 80014fa: f815 3b01 ldrb.w r3, [r5], #1 + 80014fe: 7313 strb r3, [r2, #12] + hspi->TxXferCount--; + 8001500: 8fe3 ldrh r3, [r4, #62] ; 0x3e + 8001502: 3b01 subs r3, #1 + 8001504: b29b uxth r3, r3 + 8001506: 87e3 strh r3, [r4, #62] ; 0x3e + while (hspi->TxXferCount > 0U) + 8001508: 8fe3 ldrh r3, [r4, #62] ; 0x3e + 800150a: b29b uxth r3, r3 + 800150c: b9e3 cbnz r3, 8001548 + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 800150e: 6aa3 ldr r3, [r4, #40] ; 0x28 + 8001510: f5b3 5f00 cmp.w r3, #8192 ; 0x2000 + SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT); + 8001514: bf01 itttt eq + 8001516: 6822 ldreq r2, [r4, #0] + 8001518: 6813 ldreq r3, [r2, #0] + 800151a: f443 5380 orreq.w r3, r3, #4096 ; 0x1000 + 800151e: 6013 streq r3, [r2, #0] + if (SPI_EndRxTxTransaction(hspi, Timeout, tickstart) != HAL_OK) + 8001520: 4620 mov r0, r4 + 8001522: f7ff ff1b bl 800135c + 8001526: b108 cbz r0, 800152c + hspi->ErrorCode = HAL_SPI_ERROR_FLAG; + 8001528: 2320 movs r3, #32 + 800152a: 6623 str r3, [r4, #96] ; 0x60 + if (hspi->Init.Direction == SPI_DIRECTION_2LINES) + 800152c: 68a3 ldr r3, [r4, #8] + 800152e: b933 cbnz r3, 800153e + __HAL_SPI_CLEAR_OVRFLAG(hspi); + 8001530: 9301 str r3, [sp, #4] + 8001532: 6823 ldr r3, [r4, #0] + 8001534: 68da ldr r2, [r3, #12] + 8001536: 9201 str r2, [sp, #4] + 8001538: 689b ldr r3, [r3, #8] + 800153a: 9301 str r3, [sp, #4] + 800153c: 9b01 ldr r3, [sp, #4] + if (hspi->ErrorCode != HAL_SPI_ERROR_NONE) + 800153e: 6e20 ldr r0, [r4, #96] ; 0x60 + errorcode = HAL_BUSY; + 8001540: 3800 subs r0, #0 + 8001542: bf18 it ne + 8001544: 2001 movne r0, #1 +error: + 8001546: e011 b.n 800156c + if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE)) + 8001548: 6823 ldr r3, [r4, #0] + 800154a: 689a ldr r2, [r3, #8] + 800154c: 0792 lsls r2, r2, #30 + 800154e: d50b bpl.n 8001568 + if (hspi->TxXferCount > 1U) + 8001550: 8fe2 ldrh r2, [r4, #62] ; 0x3e + 8001552: b292 uxth r2, r2 + 8001554: 2a01 cmp r2, #1 + 8001556: d903 bls.n 8001560 + hspi->Instance->DR = *((uint16_t *)pData); + 8001558: f835 2b02 ldrh.w r2, [r5], #2 + 800155c: 60da str r2, [r3, #12] + 800155e: e7c9 b.n 80014f4 + *((__IO uint8_t *)&hspi->Instance->DR) = (*pData++); + 8001560: f815 2b01 ldrb.w r2, [r5], #1 + 8001564: 731a strb r2, [r3, #12] + hspi->TxXferCount--; + 8001566: e7cb b.n 8001500 + if ((Timeout == 0U) || ((Timeout != HAL_MAX_DELAY) && ((HAL_GetTick() - tickstart) >= Timeout))) + 8001568: b94e cbnz r6, 800157e + errorcode = HAL_TIMEOUT; + 800156a: 2003 movs r0, #3 + hspi->State = HAL_SPI_STATE_READY; + 800156c: 2301 movs r3, #1 + 800156e: f884 305d strb.w r3, [r4, #93] ; 0x5d + __HAL_UNLOCK(hspi); + 8001572: 2300 movs r3, #0 + 8001574: f884 305c strb.w r3, [r4, #92] ; 0x5c +} + 8001578: b002 add sp, #8 + 800157a: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + if ((Timeout == 0U) || ((Timeout != HAL_MAX_DELAY) && ((HAL_GetTick() - tickstart) >= Timeout))) + 800157e: 1c73 adds r3, r6, #1 + 8001580: d0c2 beq.n 8001508 + 8001582: f005 fdb3 bl 80070ec + 8001586: 1bc0 subs r0, r0, r7 + 8001588: 42b0 cmp r0, r6 + 800158a: d3bd bcc.n 8001508 + 800158c: e7ed b.n 800156a + errorcode = HAL_BUSY; + 800158e: 2002 movs r0, #2 + 8001590: e7ec b.n 800156c + __HAL_LOCK(hspi); + 8001592: 2002 movs r0, #2 + 8001594: e7f0 b.n 8001578 + +08001596 : + * @param Timeout: Timeout duration + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, + uint32_t Timeout) +{ + 8001596: e92d 43f7 stmdb sp!, {r0, r1, r2, r4, r5, r6, r7, r8, r9, lr} + 800159a: 461e mov r6, r3 + uint32_t tmp = 0U, tmp1 = 0U; +#if (USE_SPI_CRC != 0U) + __IO uint16_t tmpreg = 0U; + 800159c: 2300 movs r3, #0 + 800159e: f8ad 3006 strh.w r3, [sp, #6] + + /* Check Direction parameter */ + assert_param(IS_SPI_DIRECTION_2LINES(hspi->Init.Direction)); + + /* Process Locked */ + __HAL_LOCK(hspi); + 80015a2: f890 305c ldrb.w r3, [r0, #92] ; 0x5c +{ + 80015a6: f8dd 8028 ldr.w r8, [sp, #40] ; 0x28 + __HAL_LOCK(hspi); + 80015aa: 2b01 cmp r3, #1 +{ + 80015ac: 4604 mov r4, r0 + 80015ae: 460d mov r5, r1 + 80015b0: 4617 mov r7, r2 + __HAL_LOCK(hspi); + 80015b2: f000 8124 beq.w 80017fe + 80015b6: 2301 movs r3, #1 + 80015b8: f880 305c strb.w r3, [r0, #92] ; 0x5c + + /* Init tickstart for timeout management*/ + tickstart = HAL_GetTick(); + 80015bc: f005 fd96 bl 80070ec + + tmp = hspi->State; + 80015c0: f894 305d ldrb.w r3, [r4, #93] ; 0x5d + tmp1 = hspi->Init.Mode; + 80015c4: 6861 ldr r1, [r4, #4] + + if (!((tmp == HAL_SPI_STATE_READY) || \ + 80015c6: 2b01 cmp r3, #1 + tickstart = HAL_GetTick(); + 80015c8: 4681 mov r9, r0 + tmp = hspi->State; + 80015ca: b2da uxtb r2, r3 + if (!((tmp == HAL_SPI_STATE_READY) || \ + 80015cc: d00a beq.n 80015e4 + 80015ce: f5b1 7f82 cmp.w r1, #260 ; 0x104 + 80015d2: f040 8112 bne.w 80017fa + ((tmp1 == SPI_MODE_MASTER) && (hspi->Init.Direction == SPI_DIRECTION_2LINES) && (tmp == HAL_SPI_STATE_BUSY_RX)))) + 80015d6: 68a3 ldr r3, [r4, #8] + 80015d8: 2b00 cmp r3, #0 + 80015da: f040 810e bne.w 80017fa + 80015de: 2a04 cmp r2, #4 + 80015e0: f040 810b bne.w 80017fa + { + errorcode = HAL_BUSY; + goto error; + } + + if ((pTxData == NULL) || (pRxData == NULL) || (Size == 0U)) + 80015e4: b955 cbnz r5, 80015fc + { + errorcode = HAL_ERROR; + 80015e6: 2101 movs r1, #1 + { + errorcode = HAL_ERROR; + } + +error : + hspi->State = HAL_SPI_STATE_READY; + 80015e8: 2301 movs r3, #1 + 80015ea: f884 305d strb.w r3, [r4, #93] ; 0x5d + __HAL_UNLOCK(hspi); + 80015ee: 2300 movs r3, #0 + 80015f0: f884 305c strb.w r3, [r4, #92] ; 0x5c + return errorcode; +} + 80015f4: 4608 mov r0, r1 + 80015f6: b003 add sp, #12 + 80015f8: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + if ((pTxData == NULL) || (pRxData == NULL) || (Size == 0U)) + 80015fc: 2f00 cmp r7, #0 + 80015fe: d0f2 beq.n 80015e6 + 8001600: 2e00 cmp r6, #0 + 8001602: d0f0 beq.n 80015e6 + if (hspi->State != HAL_SPI_STATE_BUSY_RX) + 8001604: f894 305d ldrb.w r3, [r4, #93] ; 0x5d + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 8001608: 6aa2 ldr r2, [r4, #40] ; 0x28 + hspi->pRxBuffPtr = (uint8_t *)pRxData; + 800160a: 6427 str r7, [r4, #64] ; 0x40 + if (hspi->State != HAL_SPI_STATE_BUSY_RX) + 800160c: 2b04 cmp r3, #4 + hspi->State = HAL_SPI_STATE_BUSY_TX_RX; + 800160e: bf1c itt ne + 8001610: 2305 movne r3, #5 + 8001612: f884 305d strbne.w r3, [r4, #93] ; 0x5d + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + 8001616: 2300 movs r3, #0 + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 8001618: f5b2 5f00 cmp.w r2, #8192 ; 0x2000 + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + 800161c: 6623 str r3, [r4, #96] ; 0x60 + hspi->TxISR = NULL; + 800161e: e9c4 3313 strd r3, r3, [r4, #76] ; 0x4c + hspi->RxXferCount = Size; + 8001622: f8a4 6046 strh.w r6, [r4, #70] ; 0x46 + SPI_RESET_CRC(hspi); + 8001626: 6823 ldr r3, [r4, #0] + hspi->RxXferSize = Size; + 8001628: f8a4 6044 strh.w r6, [r4, #68] ; 0x44 + hspi->pTxBuffPtr = (uint8_t *)pTxData; + 800162c: 63a5 str r5, [r4, #56] ; 0x38 + hspi->TxXferCount = Size; + 800162e: 87e6 strh r6, [r4, #62] ; 0x3e + hspi->TxXferSize = Size; + 8001630: 87a6 strh r6, [r4, #60] ; 0x3c + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 8001632: d107 bne.n 8001644 + SPI_RESET_CRC(hspi); + 8001634: 681a ldr r2, [r3, #0] + 8001636: f422 5200 bic.w r2, r2, #8192 ; 0x2000 + 800163a: 601a str r2, [r3, #0] + 800163c: 681a ldr r2, [r3, #0] + 800163e: f442 5200 orr.w r2, r2, #8192 ; 0x2000 + 8001642: 601a str r2, [r3, #0] + if ((hspi->Init.DataSize > SPI_DATASIZE_8BIT) || (hspi->RxXferCount > 1U)) + 8001644: 68e2 ldr r2, [r4, #12] + 8001646: f5b2 6fe0 cmp.w r2, #1792 ; 0x700 + 800164a: d804 bhi.n 8001656 + 800164c: f8b4 2046 ldrh.w r2, [r4, #70] ; 0x46 + 8001650: b292 uxth r2, r2 + 8001652: 2a01 cmp r2, #1 + 8001654: d94e bls.n 80016f4 + CLEAR_BIT(hspi->Instance->CR2, SPI_RXFIFO_THRESHOLD); + 8001656: 685a ldr r2, [r3, #4] + 8001658: f422 5280 bic.w r2, r2, #4096 ; 0x1000 + SET_BIT(hspi->Instance->CR2, SPI_RXFIFO_THRESHOLD); + 800165c: 605a str r2, [r3, #4] + if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE) + 800165e: 681a ldr r2, [r3, #0] + 8001660: 0650 lsls r0, r2, #25 + __HAL_SPI_ENABLE(hspi); + 8001662: bf5e ittt pl + 8001664: 681a ldrpl r2, [r3, #0] + 8001666: f042 0240 orrpl.w r2, r2, #64 ; 0x40 + 800166a: 601a strpl r2, [r3, #0] + if ((hspi->Init.Mode == SPI_MODE_SLAVE) || (hspi->TxXferCount == 0x01U)) + 800166c: b119 cbz r1, 8001676 + 800166e: 8fe2 ldrh r2, [r4, #62] ; 0x3e + 8001670: b292 uxth r2, r2 + 8001672: 2a01 cmp r2, #1 + 8001674: d10a bne.n 800168c + if (hspi->TxXferCount > 1U) + 8001676: 8fe2 ldrh r2, [r4, #62] ; 0x3e + 8001678: b292 uxth r2, r2 + 800167a: 2a01 cmp r2, #1 + 800167c: d93e bls.n 80016fc + hspi->Instance->DR = *((uint16_t *)pTxData); + 800167e: f835 2b02 ldrh.w r2, [r5], #2 + 8001682: 60da str r2, [r3, #12] + hspi->TxXferCount -= 2U; + 8001684: 8fe3 ldrh r3, [r4, #62] ; 0x3e + 8001686: 3b02 subs r3, #2 + 8001688: b29b uxth r3, r3 + 800168a: 87e3 strh r3, [r4, #62] ; 0x3e + txallowed = 1U; + 800168c: 2601 movs r6, #1 + while ((hspi->TxXferCount > 0U) || (hspi->RxXferCount > 0U)) + 800168e: 8fe3 ldrh r3, [r4, #62] ; 0x3e + 8001690: b29b uxth r3, r3 + 8001692: 2b00 cmp r3, #0 + 8001694: d138 bne.n 8001708 + 8001696: f8b4 3046 ldrh.w r3, [r4, #70] ; 0x46 + 800169a: b29b uxth r3, r3 + 800169c: 2b00 cmp r3, #0 + 800169e: d133 bne.n 8001708 + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 80016a0: 6aa2 ldr r2, [r4, #40] ; 0x28 + if (txallowed && (hspi->TxXferCount > 0U) && (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE))) + 80016a2: 6823 ldr r3, [r4, #0] + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 80016a4: f5b2 5f00 cmp.w r2, #8192 ; 0x2000 + 80016a8: d10d bne.n 80016c6 + while ((__HAL_SPI_GET_FLAG(hspi, Flag) ? SET : RESET) != State) + 80016aa: 689a ldr r2, [r3, #8] + 80016ac: 07d1 lsls r1, r2, #31 + 80016ae: d5fc bpl.n 80016aa + if (hspi->Init.DataSize == SPI_DATASIZE_16BIT) + 80016b0: 68e2 ldr r2, [r4, #12] + 80016b2: f5b2 6f70 cmp.w r2, #3840 ; 0xf00 + 80016b6: f040 8092 bne.w 80017de + tmpreg = hspi->Instance->DR; + 80016ba: 68da ldr r2, [r3, #12] + 80016bc: b292 uxth r2, r2 + tmpreg = *(__IO uint8_t *)&hspi->Instance->DR; + 80016be: f8ad 2006 strh.w r2, [sp, #6] + UNUSED(tmpreg); + 80016c2: f8bd 2006 ldrh.w r2, [sp, #6] + if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_CRCERR)) + 80016c6: 6899 ldr r1, [r3, #8] + 80016c8: f011 0110 ands.w r1, r1, #16 + 80016cc: d007 beq.n 80016de + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC); + 80016ce: 6e22 ldr r2, [r4, #96] ; 0x60 + 80016d0: f042 0202 orr.w r2, r2, #2 + 80016d4: 6622 str r2, [r4, #96] ; 0x60 + __HAL_SPI_CLEAR_CRCERRFLAG(hspi); + 80016d6: f64f 72ef movw r2, #65519 ; 0xffef + 80016da: 609a str r2, [r3, #8] + errorcode = HAL_ERROR; + 80016dc: 2101 movs r1, #1 + if (SPI_EndRxTxTransaction(hspi, Timeout, tickstart) != HAL_OK) + 80016de: 4620 mov r0, r4 + 80016e0: f7ff fe3c bl 800135c + 80016e4: b108 cbz r0, 80016ea + hspi->ErrorCode = HAL_SPI_ERROR_FLAG; + 80016e6: 2320 movs r3, #32 + 80016e8: 6623 str r3, [r4, #96] ; 0x60 + if (hspi->ErrorCode != HAL_SPI_ERROR_NONE) + 80016ea: 6e23 ldr r3, [r4, #96] ; 0x60 + 80016ec: 2b00 cmp r3, #0 + 80016ee: f47f af7a bne.w 80015e6 + 80016f2: e779 b.n 80015e8 + SET_BIT(hspi->Instance->CR2, SPI_RXFIFO_THRESHOLD); + 80016f4: 685a ldr r2, [r3, #4] + 80016f6: f442 5280 orr.w r2, r2, #4096 ; 0x1000 + 80016fa: e7af b.n 800165c + *(__IO uint8_t *)&hspi->Instance->DR = (*pTxData++); + 80016fc: f815 2b01 ldrb.w r2, [r5], #1 + 8001700: 731a strb r2, [r3, #12] + hspi->TxXferCount--; + 8001702: 8fe3 ldrh r3, [r4, #62] ; 0x3e + 8001704: 3b01 subs r3, #1 + 8001706: e7bf b.n 8001688 + if (txallowed && (hspi->TxXferCount > 0U) && (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE))) + 8001708: 2e00 cmp r6, #0 + 800170a: d030 beq.n 800176e + 800170c: 8fe3 ldrh r3, [r4, #62] ; 0x3e + 800170e: b29b uxth r3, r3 + 8001710: 2b00 cmp r3, #0 + 8001712: d02c beq.n 800176e + 8001714: 6823 ldr r3, [r4, #0] + 8001716: 689a ldr r2, [r3, #8] + 8001718: 0792 lsls r2, r2, #30 + 800171a: d528 bpl.n 800176e + if (hspi->TxXferCount > 1U) + 800171c: 8fe2 ldrh r2, [r4, #62] ; 0x3e + 800171e: b292 uxth r2, r2 + 8001720: 2a01 cmp r2, #1 + hspi->Instance->DR = *((uint16_t *)pTxData); + 8001722: bf8b itete hi + 8001724: f835 2b02 ldrhhi.w r2, [r5], #2 + *(__IO uint8_t *)&hspi->Instance->DR = (*pTxData++); + 8001728: f815 2b01 ldrbls.w r2, [r5], #1 + hspi->Instance->DR = *((uint16_t *)pTxData); + 800172c: 60da strhi r2, [r3, #12] + *(__IO uint8_t *)&hspi->Instance->DR = (*pTxData++); + 800172e: 731a strbls r2, [r3, #12] + hspi->TxXferCount -= 2U; + 8001730: bf8b itete hi + 8001732: 8fe3 ldrhhi r3, [r4, #62] ; 0x3e + hspi->TxXferCount--; + 8001734: 8fe3 ldrhls r3, [r4, #62] ; 0x3e + hspi->TxXferCount -= 2U; + 8001736: 3b02 subhi r3, #2 + hspi->TxXferCount--; + 8001738: f103 33ff addls.w r3, r3, #4294967295 ; 0xffffffff + 800173c: b29b uxth r3, r3 + 800173e: 87e3 strh r3, [r4, #62] ; 0x3e + if ((hspi->TxXferCount == 0U) && (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)) + 8001740: 8fe6 ldrh r6, [r4, #62] ; 0x3e + 8001742: b2b6 uxth r6, r6 + 8001744: b996 cbnz r6, 800176c + 8001746: 6aa3 ldr r3, [r4, #40] ; 0x28 + 8001748: f5b3 5f00 cmp.w r3, #8192 ; 0x2000 + 800174c: d10f bne.n 800176e + if (((hspi->Instance->CR1 & SPI_CR1_MSTR) == 0U) && ((hspi->Instance->CR2 & SPI_CR2_NSSP) == SPI_CR2_NSSP)) + 800174e: 6823 ldr r3, [r4, #0] + 8001750: 681a ldr r2, [r3, #0] + 8001752: 0756 lsls r6, r2, #29 + 8001754: d406 bmi.n 8001764 + 8001756: 685a ldr r2, [r3, #4] + 8001758: 0710 lsls r0, r2, #28 + SET_BIT(hspi->Instance->CR1, SPI_CR1_SSM); + 800175a: bf42 ittt mi + 800175c: 681a ldrmi r2, [r3, #0] + 800175e: f442 7200 orrmi.w r2, r2, #512 ; 0x200 + 8001762: 601a strmi r2, [r3, #0] + SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT); + 8001764: 681a ldr r2, [r3, #0] + 8001766: f442 5280 orr.w r2, r2, #4096 ; 0x1000 + 800176a: 601a str r2, [r3, #0] + txallowed = 0U; + 800176c: 2600 movs r6, #0 + if ((hspi->RxXferCount > 0U) && (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_RXNE))) + 800176e: f8b4 3046 ldrh.w r3, [r4, #70] ; 0x46 + 8001772: b29b uxth r3, r3 + 8001774: b1e3 cbz r3, 80017b0 + 8001776: 6821 ldr r1, [r4, #0] + 8001778: 688b ldr r3, [r1, #8] + 800177a: f013 0301 ands.w r3, r3, #1 + 800177e: d017 beq.n 80017b0 + if (hspi->RxXferCount > 1U) + 8001780: f8b4 2046 ldrh.w r2, [r4, #70] ; 0x46 + 8001784: b292 uxth r2, r2 + 8001786: 2a01 cmp r2, #1 + 8001788: d91f bls.n 80017ca + *((uint16_t *)pRxData) = hspi->Instance->DR; + 800178a: 68ca ldr r2, [r1, #12] + 800178c: f827 2b02 strh.w r2, [r7], #2 + hspi->RxXferCount -= 2U; + 8001790: f8b4 2046 ldrh.w r2, [r4, #70] ; 0x46 + 8001794: 3a02 subs r2, #2 + 8001796: b292 uxth r2, r2 + 8001798: f8a4 2046 strh.w r2, [r4, #70] ; 0x46 + if (hspi->RxXferCount <= 1U) + 800179c: f8b4 2046 ldrh.w r2, [r4, #70] ; 0x46 + 80017a0: b292 uxth r2, r2 + 80017a2: 2a01 cmp r2, #1 + 80017a4: d803 bhi.n 80017ae + SET_BIT(hspi->Instance->CR2, SPI_RXFIFO_THRESHOLD); + 80017a6: 684a ldr r2, [r1, #4] + 80017a8: f442 5280 orr.w r2, r2, #4096 ; 0x1000 + 80017ac: 604a str r2, [r1, #4] + txallowed = 1U; + 80017ae: 461e mov r6, r3 + if ((Timeout != HAL_MAX_DELAY) && ((HAL_GetTick() - tickstart) >= Timeout)) + 80017b0: f1b8 3fff cmp.w r8, #4294967295 ; 0xffffffff + 80017b4: f43f af6b beq.w 800168e + 80017b8: f005 fc98 bl 80070ec + 80017bc: eba0 0009 sub.w r0, r0, r9 + 80017c0: 4540 cmp r0, r8 + 80017c2: f4ff af64 bcc.w 800168e + errorcode = HAL_TIMEOUT; + 80017c6: 2103 movs r1, #3 + 80017c8: e70e b.n 80015e8 + (*(uint8_t *)pRxData++) = *(__IO uint8_t *)&hspi->Instance->DR; + 80017ca: 7b0a ldrb r2, [r1, #12] + 80017cc: f807 2b01 strb.w r2, [r7], #1 + hspi->RxXferCount--; + 80017d0: f8b4 1046 ldrh.w r1, [r4, #70] ; 0x46 + 80017d4: 3901 subs r1, #1 + 80017d6: b289 uxth r1, r1 + 80017d8: f8a4 1046 strh.w r1, [r4, #70] ; 0x46 + 80017dc: e7e7 b.n 80017ae + tmpreg = *(__IO uint8_t *)&hspi->Instance->DR; + 80017de: 7b1a ldrb r2, [r3, #12] + 80017e0: f8ad 2006 strh.w r2, [sp, #6] + UNUSED(tmpreg); + 80017e4: f8bd 2006 ldrh.w r2, [sp, #6] + if (hspi->Init.CRCLength == SPI_CRC_LENGTH_16BIT) + 80017e8: 6b22 ldr r2, [r4, #48] ; 0x30 + 80017ea: 2a02 cmp r2, #2 + 80017ec: f47f af6b bne.w 80016c6 + while ((__HAL_SPI_GET_FLAG(hspi, Flag) ? SET : RESET) != State) + 80017f0: 689a ldr r2, [r3, #8] + 80017f2: 07d2 lsls r2, r2, #31 + 80017f4: d5fc bpl.n 80017f0 + tmpreg = *(__IO uint8_t *)&hspi->Instance->DR; + 80017f6: 7b1a ldrb r2, [r3, #12] + 80017f8: e761 b.n 80016be + errorcode = HAL_BUSY; + 80017fa: 2102 movs r1, #2 + 80017fc: e6f4 b.n 80015e8 + __HAL_LOCK(hspi); + 80017fe: 2102 movs r1, #2 + 8001800: e6f8 b.n 80015f4 + +08001802 : +{ + 8001802: e92d 41ff stmdb sp!, {r0, r1, r2, r3, r4, r5, r6, r7, r8, lr} + 8001806: 461f mov r7, r3 + __IO uint16_t tmpreg = 0U; + 8001808: 2300 movs r3, #0 + 800180a: f8ad 300e strh.w r3, [sp, #14] + if ((hspi->Init.Mode == SPI_MODE_MASTER) && (hspi->Init.Direction == SPI_DIRECTION_2LINES)) + 800180e: 6843 ldr r3, [r0, #4] + 8001810: f5b3 7f82 cmp.w r3, #260 ; 0x104 +{ + 8001814: 4604 mov r4, r0 + 8001816: 460e mov r6, r1 + 8001818: 4615 mov r5, r2 + if ((hspi->Init.Mode == SPI_MODE_MASTER) && (hspi->Init.Direction == SPI_DIRECTION_2LINES)) + 800181a: d10c bne.n 8001836 + 800181c: 6883 ldr r3, [r0, #8] + 800181e: b953 cbnz r3, 8001836 + hspi->State = HAL_SPI_STATE_BUSY_RX; + 8001820: 2304 movs r3, #4 + 8001822: f880 305d strb.w r3, [r0, #93] ; 0x5d + return HAL_SPI_TransmitReceive(hspi, pData, pData, Size, Timeout); + 8001826: 4613 mov r3, r2 + 8001828: 9700 str r7, [sp, #0] + 800182a: 460a mov r2, r1 + 800182c: f7ff feb3 bl 8001596 +} + 8001830: b004 add sp, #16 + 8001832: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + __HAL_LOCK(hspi); + 8001836: f894 305c ldrb.w r3, [r4, #92] ; 0x5c + 800183a: 2b01 cmp r3, #1 + 800183c: f000 80dd beq.w 80019fa + 8001840: 2301 movs r3, #1 + 8001842: f884 305c strb.w r3, [r4, #92] ; 0x5c + tickstart = HAL_GetTick(); + 8001846: f005 fc51 bl 80070ec + if (hspi->State != HAL_SPI_STATE_READY) + 800184a: f894 305d ldrb.w r3, [r4, #93] ; 0x5d + 800184e: 2b01 cmp r3, #1 + tickstart = HAL_GetTick(); + 8001850: 4680 mov r8, r0 + if (hspi->State != HAL_SPI_STATE_READY) + 8001852: b2d8 uxtb r0, r3 + 8001854: f040 80cf bne.w 80019f6 + if ((pData == NULL) || (Size == 0U)) + 8001858: 2e00 cmp r6, #0 + 800185a: f000 8092 beq.w 8001982 + 800185e: 2d00 cmp r5, #0 + 8001860: f000 808f beq.w 8001982 + hspi->State = HAL_SPI_STATE_BUSY_RX; + 8001864: 2304 movs r3, #4 + 8001866: f884 305d strb.w r3, [r4, #93] ; 0x5d + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 800186a: 6aa3 ldr r3, [r4, #40] ; 0x28 + hspi->RxXferSize = Size; + 800186c: f8a4 5044 strh.w r5, [r4, #68] ; 0x44 + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + 8001870: 2100 movs r1, #0 + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 8001872: f5b3 5f00 cmp.w r3, #8192 ; 0x2000 + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + 8001876: 6621 str r1, [r4, #96] ; 0x60 + hspi->TxISR = NULL; + 8001878: e9c4 1113 strd r1, r1, [r4, #76] ; 0x4c + hspi->RxXferCount = Size; + 800187c: f8a4 5046 strh.w r5, [r4, #70] ; 0x46 + hspi->pRxBuffPtr = (uint8_t *)pData; + 8001880: 6426 str r6, [r4, #64] ; 0x40 + SPI_RESET_CRC(hspi); + 8001882: 6825 ldr r5, [r4, #0] + hspi->pTxBuffPtr = (uint8_t *)NULL; + 8001884: 63a1 str r1, [r4, #56] ; 0x38 + hspi->TxXferSize = 0U; + 8001886: 87a1 strh r1, [r4, #60] ; 0x3c + hspi->TxXferCount = 0U; + 8001888: 87e1 strh r1, [r4, #62] ; 0x3e + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 800188a: d10d bne.n 80018a8 + SPI_RESET_CRC(hspi); + 800188c: 682b ldr r3, [r5, #0] + 800188e: f423 5300 bic.w r3, r3, #8192 ; 0x2000 + 8001892: 602b str r3, [r5, #0] + 8001894: 682b ldr r3, [r5, #0] + 8001896: f443 5300 orr.w r3, r3, #8192 ; 0x2000 + 800189a: 602b str r3, [r5, #0] + hspi->RxXferCount--; + 800189c: f8b4 3046 ldrh.w r3, [r4, #70] ; 0x46 + 80018a0: 3b01 subs r3, #1 + 80018a2: b29b uxth r3, r3 + 80018a4: f8a4 3046 strh.w r3, [r4, #70] ; 0x46 + if (hspi->Init.DataSize > SPI_DATASIZE_8BIT) + 80018a8: 68e3 ldr r3, [r4, #12] + 80018aa: f5b3 6fe0 cmp.w r3, #1792 ; 0x700 + CLEAR_BIT(hspi->Instance->CR2, SPI_RXFIFO_THRESHOLD); + 80018ae: 686b ldr r3, [r5, #4] + 80018b0: bf8c ite hi + 80018b2: f423 5380 bichi.w r3, r3, #4096 ; 0x1000 + SET_BIT(hspi->Instance->CR2, SPI_RXFIFO_THRESHOLD); + 80018b6: f443 5380 orrls.w r3, r3, #4096 ; 0x1000 + 80018ba: 606b str r3, [r5, #4] + if (hspi->Init.Direction == SPI_DIRECTION_1LINE) + 80018bc: 68a3 ldr r3, [r4, #8] + 80018be: f5b3 4f00 cmp.w r3, #32768 ; 0x8000 + SPI_1LINE_RX(hspi); + 80018c2: bf02 ittt eq + 80018c4: 682b ldreq r3, [r5, #0] + 80018c6: f423 4380 biceq.w r3, r3, #16384 ; 0x4000 + 80018ca: 602b streq r3, [r5, #0] + if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE) + 80018cc: 682b ldr r3, [r5, #0] + 80018ce: 0658 lsls r0, r3, #25 + 80018d0: d403 bmi.n 80018da + __HAL_SPI_ENABLE(hspi); + 80018d2: 682b ldr r3, [r5, #0] + 80018d4: f043 0340 orr.w r3, r3, #64 ; 0x40 + 80018d8: 602b str r3, [r5, #0] + while (hspi->RxXferCount > 0U) + 80018da: f8b4 3046 ldrh.w r3, [r4, #70] ; 0x46 + if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_RXNE)) + 80018de: 6822 ldr r2, [r4, #0] + while (hspi->RxXferCount > 0U) + 80018e0: b29b uxth r3, r3 + 80018e2: 2b00 cmp r3, #0 + 80018e4: d13e bne.n 8001964 + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 80018e6: 6aa3 ldr r3, [r4, #40] ; 0x28 + 80018e8: f5b3 5f00 cmp.w r3, #8192 ; 0x2000 + 80018ec: d11c bne.n 8001928 + SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT); + 80018ee: 6813 ldr r3, [r2, #0] + 80018f0: f443 5380 orr.w r3, r3, #4096 ; 0x1000 + 80018f4: 6013 str r3, [r2, #0] + while ((__HAL_SPI_GET_FLAG(hspi, Flag) ? SET : RESET) != State) + 80018f6: 6893 ldr r3, [r2, #8] + 80018f8: 07df lsls r7, r3, #31 + 80018fa: d5fc bpl.n 80018f6 + if (hspi->Init.DataSize > SPI_DATASIZE_8BIT) + 80018fc: 68e3 ldr r3, [r4, #12] + 80018fe: f5b3 6fe0 cmp.w r3, #1792 ; 0x700 + (*(uint8_t *)pData) = *(__IO uint8_t *)&hspi->Instance->DR; + 8001902: bf95 itete ls + 8001904: 7b13 ldrbls r3, [r2, #12] + *((uint16_t *)pData) = hspi->Instance->DR; + 8001906: 68d3 ldrhi r3, [r2, #12] + (*(uint8_t *)pData) = *(__IO uint8_t *)&hspi->Instance->DR; + 8001908: 7033 strbls r3, [r6, #0] + *((uint16_t *)pData) = hspi->Instance->DR; + 800190a: 8033 strhhi r3, [r6, #0] + while ((__HAL_SPI_GET_FLAG(hspi, Flag) ? SET : RESET) != State) + 800190c: 6823 ldr r3, [r4, #0] + 800190e: 689a ldr r2, [r3, #8] + 8001910: 07d6 lsls r6, r2, #31 + 8001912: d5fc bpl.n 800190e + if (hspi->Init.DataSize == SPI_DATASIZE_16BIT) + 8001914: 68e1 ldr r1, [r4, #12] + 8001916: f5b1 6f70 cmp.w r1, #3840 ; 0xf00 + 800191a: d142 bne.n 80019a2 + tmpreg = hspi->Instance->DR; + 800191c: 68db ldr r3, [r3, #12] + 800191e: b29b uxth r3, r3 + tmpreg = *(__IO uint8_t *)&hspi->Instance->DR; + 8001920: f8ad 300e strh.w r3, [sp, #14] + UNUSED(tmpreg); + 8001924: f8bd 300e ldrh.w r3, [sp, #14] + * @param Tickstart: tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef SPI_EndRxTransaction(SPI_HandleTypeDef *hspi, uint32_t Timeout, uint32_t Tickstart) +{ + if ((hspi->Init.Mode == SPI_MODE_MASTER) && ((hspi->Init.Direction == SPI_DIRECTION_1LINE) + 8001928: 6861 ldr r1, [r4, #4] + 800192a: 6823 ldr r3, [r4, #0] + 800192c: f5b1 7f82 cmp.w r1, #260 ; 0x104 + 8001930: d10a bne.n 8001948 + 8001932: 68a2 ldr r2, [r4, #8] + 8001934: f5b2 4f00 cmp.w r2, #32768 ; 0x8000 + 8001938: d002 beq.n 8001940 + || (hspi->Init.Direction == SPI_DIRECTION_2LINES_RXONLY))) + 800193a: f5b2 6f80 cmp.w r2, #1024 ; 0x400 + 800193e: d103 bne.n 8001948 + { + /* Disable SPI peripheral */ + __HAL_SPI_DISABLE(hspi); + 8001940: 681a ldr r2, [r3, #0] + 8001942: f022 0240 bic.w r2, r2, #64 ; 0x40 + 8001946: 601a str r2, [r3, #0] + while ((__HAL_SPI_GET_FLAG(hspi, Flag) ? SET : RESET) != State) + 8001948: 689a ldr r2, [r3, #8] + 800194a: 0610 lsls r0, r2, #24 + 800194c: d4fc bmi.n 8001948 + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FLAG); + return HAL_TIMEOUT; + } + + if ((hspi->Init.Mode == SPI_MODE_MASTER) && ((hspi->Init.Direction == SPI_DIRECTION_1LINE) + 800194e: f5b1 7f82 cmp.w r1, #260 ; 0x104 + 8001952: d036 beq.n 80019c2 + if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_CRCERR)) + 8001954: 689a ldr r2, [r3, #8] + 8001956: 06d2 lsls r2, r2, #27 + 8001958: d445 bmi.n 80019e6 + if (hspi->ErrorCode != HAL_SPI_ERROR_NONE) + 800195a: 6e20 ldr r0, [r4, #96] ; 0x60 + errorcode = HAL_BUSY; + 800195c: 3800 subs r0, #0 + 800195e: bf18 it ne + 8001960: 2001 movne r0, #1 +error : + 8001962: e00e b.n 8001982 + if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_RXNE)) + 8001964: 6893 ldr r3, [r2, #8] + 8001966: 07d9 lsls r1, r3, #31 + 8001968: d509 bpl.n 800197e + (* (uint8_t *)pData) = *(__IO uint8_t *)&hspi->Instance->DR; + 800196a: 7b13 ldrb r3, [r2, #12] + 800196c: f806 3b01 strb.w r3, [r6], #1 + hspi->RxXferCount--; + 8001970: f8b4 3046 ldrh.w r3, [r4, #70] ; 0x46 + 8001974: 3b01 subs r3, #1 + 8001976: b29b uxth r3, r3 + 8001978: f8a4 3046 strh.w r3, [r4, #70] ; 0x46 + 800197c: e7ad b.n 80018da + if ((Timeout == 0U) || ((Timeout != HAL_MAX_DELAY) && ((HAL_GetTick() - tickstart) >= Timeout))) + 800197e: b93f cbnz r7, 8001990 + errorcode = HAL_TIMEOUT; + 8001980: 2003 movs r0, #3 + hspi->State = HAL_SPI_STATE_READY; + 8001982: 2301 movs r3, #1 + 8001984: f884 305d strb.w r3, [r4, #93] ; 0x5d + __HAL_UNLOCK(hspi); + 8001988: 2300 movs r3, #0 + 800198a: f884 305c strb.w r3, [r4, #92] ; 0x5c + return errorcode; + 800198e: e74f b.n 8001830 + if ((Timeout == 0U) || ((Timeout != HAL_MAX_DELAY) && ((HAL_GetTick() - tickstart) >= Timeout))) + 8001990: 1c7b adds r3, r7, #1 + 8001992: d0a2 beq.n 80018da + 8001994: f005 fbaa bl 80070ec + 8001998: eba0 0008 sub.w r0, r0, r8 + 800199c: 42b8 cmp r0, r7 + 800199e: d39c bcc.n 80018da + 80019a0: e7ee b.n 8001980 + tmpreg = *(__IO uint8_t *)&hspi->Instance->DR; + 80019a2: 7b1a ldrb r2, [r3, #12] + 80019a4: f8ad 200e strh.w r2, [sp, #14] + if ((hspi->Init.DataSize == SPI_DATASIZE_8BIT) && (hspi->Init.CRCLength == SPI_CRC_LENGTH_16BIT)) + 80019a8: f5b1 6fe0 cmp.w r1, #1792 ; 0x700 + UNUSED(tmpreg); + 80019ac: f8bd 200e ldrh.w r2, [sp, #14] + if ((hspi->Init.DataSize == SPI_DATASIZE_8BIT) && (hspi->Init.CRCLength == SPI_CRC_LENGTH_16BIT)) + 80019b0: d1ba bne.n 8001928 + 80019b2: 6b22 ldr r2, [r4, #48] ; 0x30 + 80019b4: 2a02 cmp r2, #2 + 80019b6: d1b7 bne.n 8001928 + while ((__HAL_SPI_GET_FLAG(hspi, Flag) ? SET : RESET) != State) + 80019b8: 689a ldr r2, [r3, #8] + 80019ba: 07d5 lsls r5, r2, #31 + 80019bc: d5fc bpl.n 80019b8 + tmpreg = *(__IO uint8_t *)&hspi->Instance->DR; + 80019be: 7b1b ldrb r3, [r3, #12] + 80019c0: e7ae b.n 8001920 + if ((hspi->Init.Mode == SPI_MODE_MASTER) && ((hspi->Init.Direction == SPI_DIRECTION_1LINE) + 80019c2: 68a2 ldr r2, [r4, #8] + 80019c4: f5b2 4f00 cmp.w r2, #32768 ; 0x8000 + 80019c8: d002 beq.n 80019d0 + || (hspi->Init.Direction == SPI_DIRECTION_2LINES_RXONLY))) + 80019ca: f5b2 6f80 cmp.w r2, #1024 ; 0x400 + 80019ce: d1c1 bne.n 8001954 + while ((hspi->Instance->SR & Fifo) != State) + 80019d0: 689a ldr r2, [r3, #8] + 80019d2: f412 6fc0 tst.w r2, #1536 ; 0x600 + 80019d6: d0bd beq.n 8001954 + tmpreg = *((__IO uint8_t *)&hspi->Instance->DR); + 80019d8: 7b1a ldrb r2, [r3, #12] + 80019da: b2d2 uxtb r2, r2 + 80019dc: f88d 200d strb.w r2, [sp, #13] + UNUSED(tmpreg); + 80019e0: f89d 200d ldrb.w r2, [sp, #13] + 80019e4: e7f4 b.n 80019d0 + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC); + 80019e6: 6e22 ldr r2, [r4, #96] ; 0x60 + 80019e8: f042 0202 orr.w r2, r2, #2 + 80019ec: 6622 str r2, [r4, #96] ; 0x60 + __HAL_SPI_CLEAR_CRCERRFLAG(hspi); + 80019ee: f64f 72ef movw r2, #65519 ; 0xffef + 80019f2: 609a str r2, [r3, #8] + 80019f4: e7b1 b.n 800195a + errorcode = HAL_BUSY; + 80019f6: 2002 movs r0, #2 + 80019f8: e7c3 b.n 8001982 + __HAL_LOCK(hspi); + 80019fa: 2002 movs r0, #2 + 80019fc: e718 b.n 8001830 + ... + +08001a00 : + +// checksum_more() +// + static void +checksum_more(SHA256_CTX *ctx, uint32_t *total, const uint8_t *addr, int len) +{ + 8001a00: b5f8 push {r3, r4, r5, r6, r7, lr} + 8001a02: 460c mov r4, r1 + // mk4 has hardware hash engine, and no DFU button + int percent = ((*total) * 100) / TOTAL_CHECKSUM_LEN; + 8001a04: 6809 ldr r1, [r1, #0] +{ + 8001a06: 461d mov r5, r3 + int percent = ((*total) * 100) / TOTAL_CHECKSUM_LEN; + 8001a08: 2364 movs r3, #100 ; 0x64 +{ + 8001a0a: 4617 mov r7, r2 + 8001a0c: 4606 mov r6, r0 + int percent = ((*total) * 100) / TOTAL_CHECKSUM_LEN; + 8001a0e: 4359 muls r1, r3 + puts2("Verify %0x"); + puthex2(percent); + putchar('\n'); +#endif + + oled_show_progress(screen_verify, percent); + 8001a10: 4807 ldr r0, [pc, #28] ; (8001a30 ) + 8001a12: 4b08 ldr r3, [pc, #32] ; (8001a34 ) + 8001a14: fbb1 f1f3 udiv r1, r1, r3 + 8001a18: f7ff fa56 bl 8000ec8 + + sha256_update(ctx, addr, len); + 8001a1c: 462a mov r2, r5 + 8001a1e: 4639 mov r1, r7 + 8001a20: 4630 mov r0, r6 + 8001a22: f003 fd41 bl 80054a8 + *total += len; + 8001a26: 6823 ldr r3, [r4, #0] + 8001a28: 442b add r3, r5 + 8001a2a: 6023 str r3, [r4, #0] +} + 8001a2c: bdf8 pop {r3, r4, r5, r6, r7, pc} + 8001a2e: bf00 nop + 8001a30: 0800e242 .word 0x0800e242 + 8001a34: 0018541c .word 0x0018541c + +08001a38 : + +// checksum_flash() +// + void +checksum_flash(uint8_t fw_digest[32], uint8_t world_digest[32], uint32_t fw_length) +{ + 8001a38: b570 push {r4, r5, r6, lr} + 8001a3a: b09c sub sp, #112 ; 0x70 + 8001a3c: 4606 mov r6, r0 + 8001a3e: 460d mov r5, r1 + 8001a40: 4614 mov r4, r2 + const uint8_t *start = (const uint8_t *)FIRMWARE_START; + + rng_delay(); + 8001a42: f000 fe9b bl 800277c + + SHA256_CTX ctx; + uint32_t total_len = 0; + 8001a46: 2300 movs r3, #0 + 8001a48: 9300 str r3, [sp, #0] + + if(fw_length == 0) { + 8001a4a: 2c00 cmp r4, #0 + 8001a4c: d15f bne.n 8001b0e + uint8_t first[32]; + sha256_init(&ctx); + 8001a4e: a809 add r0, sp, #36 ; 0x24 + 8001a50: f003 fd1c bl 800548c + + // use length from header in flash + fw_length = FW_HDR->firmware_length; + 8001a54: 4b36 ldr r3, [pc, #216] ; (8001b30 ) + + // start of firmware (just after we end) to header + checksum_more(&ctx, &total_len, start, FW_HEADER_OFFSET + FW_HEADER_SIZE - 64); + 8001a56: 4a37 ldr r2, [pc, #220] ; (8001b34 ) + fw_length = FW_HDR->firmware_length; + 8001a58: f8d3 4098 ldr.w r4, [r3, #152] ; 0x98 + checksum_more(&ctx, &total_len, start, FW_HEADER_OFFSET + FW_HEADER_SIZE - 64); + 8001a5c: 4669 mov r1, sp + 8001a5e: f44f 537f mov.w r3, #16320 ; 0x3fc0 + 8001a62: a809 add r0, sp, #36 ; 0x24 + 8001a64: f7ff ffcc bl 8001a00 + + // from after header to end + checksum_more(&ctx, &total_len, start + FW_HEADER_OFFSET + FW_HEADER_SIZE, + 8001a68: 4a33 ldr r2, [pc, #204] ; (8001b38 ) + 8001a6a: f5a4 4380 sub.w r3, r4, #16384 ; 0x4000 + 8001a6e: 4669 mov r1, sp + 8001a70: a809 add r0, sp, #36 ; 0x24 + 8001a72: f7ff ffc5 bl 8001a00 + fw_length - (FW_HEADER_OFFSET + FW_HEADER_SIZE)); + + sha256_final(&ctx, first); + 8001a76: a901 add r1, sp, #4 + 8001a78: a809 add r0, sp, #36 ; 0x24 + 8001a7a: f003 fd5b bl 8005534 + + // double SHA256 + sha256_single(first, sizeof(first), fw_digest); + 8001a7e: 4632 mov r2, r6 + 8001a80: 2120 movs r1, #32 + 8001a82: a801 add r0, sp, #4 + 8001a84: f003 fd6a bl 800555c + // fw_digest should already be populated by caller + total_len = fw_length - 64; + } + + // start over, and get the rest of flash. All of it. + sha256_init(&ctx); + 8001a88: a809 add r0, sp, #36 ; 0x24 + 8001a8a: f003 fcff bl 800548c + + // .. and chain in what we have so far + sha256_update(&ctx, fw_digest, 32); + 8001a8e: 2220 movs r2, #32 + 8001a90: 4631 mov r1, r6 + 8001a92: a809 add r0, sp, #36 ; 0x24 + 8001a94: f003 fd08 bl 80054a8 + + // Bootloader, including pairing secret area, but excluding MCU keys. + const uint8_t *base = (const uint8_t *)BL_FLASH_BASE; + checksum_more(&ctx, &total_len, base, ((uint8_t *)MCU_KEYS)-base); + 8001a98: f44f 33f0 mov.w r3, #122880 ; 0x1e000 + 8001a9c: f04f 6200 mov.w r2, #134217728 ; 0x8000000 + 8001aa0: 4669 mov r1, sp + 8001aa2: a809 add r0, sp, #36 ; 0x24 + 8001aa4: f7ff ffac bl 8001a00 + + // Probably-blank area after firmware, and filesystem area. + // Important: firmware images (fw_length) must be aligned with flash erase unit size (4k). + const uint8_t *fs = start + fw_length; + const uint8_t *last = base + MAIN_FLASH_SIZE; + checksum_more(&ctx, &total_len, fs, last-fs); + 8001aa8: f104 6200 add.w r2, r4, #134217728 ; 0x8000000 + 8001aac: f5c4 13b0 rsb r3, r4, #1441792 ; 0x160000 + 8001ab0: f502 3200 add.w r2, r2, #131072 ; 0x20000 + 8001ab4: 4669 mov r1, sp + 8001ab6: a809 add r0, sp, #36 ; 0x24 + 8001ab8: f7ff ffa2 bl 8001a00 + + rng_delay(); + 8001abc: f000 fe5e bl 800277c + + // OTP area + checksum_more(&ctx, &total_len, (void *)0x1fff7000, 0x400); + 8001ac0: 4a1e ldr r2, [pc, #120] ; (8001b3c ) + 8001ac2: f44f 6380 mov.w r3, #1024 ; 0x400 + 8001ac6: 4669 mov r1, sp + 8001ac8: a809 add r0, sp, #36 ; 0x24 + 8001aca: f7ff ff99 bl 8001a00 + + // "just in case" ... the option bytes (2 banks) + checksum_more(&ctx, &total_len, (void *)0x1fff7800, 0x28); + 8001ace: 4a1c ldr r2, [pc, #112] ; (8001b40 ) + 8001ad0: 2328 movs r3, #40 ; 0x28 + 8001ad2: 4669 mov r1, sp + 8001ad4: a809 add r0, sp, #36 ; 0x24 + 8001ad6: f7ff ff93 bl 8001a00 + checksum_more(&ctx, &total_len, (void *)0x1ffff800, 0x28); + 8001ada: 4a1a ldr r2, [pc, #104] ; (8001b44 ) + 8001adc: 2328 movs r3, #40 ; 0x28 + 8001ade: 4669 mov r1, sp + 8001ae0: a809 add r0, sp, #36 ; 0x24 + 8001ae2: f7ff ff8d bl 8001a00 + + // System ROM (they say it can't change, but clearly + // implemented as flash cells) + checksum_more(&ctx, &total_len, (void *)0x1fff0000, 0x7000); + 8001ae6: 4a18 ldr r2, [pc, #96] ; (8001b48 ) + 8001ae8: f44f 43e0 mov.w r3, #28672 ; 0x7000 + 8001aec: 4669 mov r1, sp + 8001aee: a809 add r0, sp, #36 ; 0x24 + 8001af0: f7ff ff86 bl 8001a00 + + // device serial number, just for kicks + checksum_more(&ctx, &total_len, (void *)0x1fff7590, 12); + 8001af4: 4a15 ldr r2, [pc, #84] ; (8001b4c ) + 8001af6: 230c movs r3, #12 + 8001af8: 4669 mov r1, sp + 8001afa: a809 add r0, sp, #36 ; 0x24 + 8001afc: f7ff ff80 bl 8001a00 + + ASSERT(total_len == TOTAL_CHECKSUM_LEN); + 8001b00: 4b13 ldr r3, [pc, #76] ; (8001b50 ) + 8001b02: 9a00 ldr r2, [sp, #0] + 8001b04: 429a cmp r2, r3 + 8001b06: d006 beq.n 8001b16 + 8001b08: 4812 ldr r0, [pc, #72] ; (8001b54 ) + 8001b0a: f7fe ff9d bl 8000a48 + total_len = fw_length - 64; + 8001b0e: f1a4 0340 sub.w r3, r4, #64 ; 0x40 + 8001b12: 9300 str r3, [sp, #0] + 8001b14: e7b8 b.n 8001a88 + + sha256_final(&ctx, world_digest); + 8001b16: 4629 mov r1, r5 + 8001b18: a809 add r0, sp, #36 ; 0x24 + 8001b1a: f003 fd0b bl 8005534 + + // double SHA256 (a bitcoin fetish) + sha256_single(world_digest, 32, world_digest); + 8001b1e: 462a mov r2, r5 + 8001b20: 2120 movs r1, #32 + 8001b22: 4628 mov r0, r5 + 8001b24: f003 fd1a bl 800555c + + rng_delay(); + 8001b28: f000 fe28 bl 800277c +} + 8001b2c: b01c add sp, #112 ; 0x70 + 8001b2e: bd70 pop {r4, r5, r6, pc} + 8001b30: 08023f00 .word 0x08023f00 + 8001b34: 08020000 .word 0x08020000 + 8001b38: 08024000 .word 0x08024000 + 8001b3c: 1fff7000 .word 0x1fff7000 + 8001b40: 1fff7800 .word 0x1fff7800 + 8001b44: 1ffff800 .word 0x1ffff800 + 8001b48: 1fff0000 .word 0x1fff0000 + 8001b4c: 1fff7590 .word 0x1fff7590 + 8001b50: 0018541c .word 0x0018541c + 8001b54: 0800e3e0 .word 0x0800e3e0 + +08001b58 : +// Scan the OTP area and determine what the current min-version (timestamp) +// we can allow. All zeros if any if okay. +// + void +get_min_version(uint8_t min_version[8]) +{ + 8001b58: b570 push {r4, r5, r6, lr} + 8001b5a: 4604 mov r4, r0 + const uint8_t *otp = (const uint8_t *)OPT_FLASH_BASE; + 8001b5c: 4d0c ldr r5, [pc, #48] ; (8001b90 ) + + rng_delay(); + memset(min_version, 0, 8); + + for(int i=0; i) + rng_delay(); + 8001b60: f000 fe0c bl 800277c + memset(min_version, 0, 8); + 8001b64: 2300 movs r3, #0 + 8001b66: 6023 str r3, [r4, #0] + 8001b68: 6063 str r3, [r4, #4] + // is it programmed? + if(otp[0] == 0xff) continue; + + // is it a timestamp value? + if(otp[0] >= 0x40) continue; + if(otp[0] < 0x10) continue; + 8001b6a: 782b ldrb r3, [r5, #0] + 8001b6c: 3b10 subs r3, #16 + 8001b6e: 2b2f cmp r3, #47 ; 0x2f + 8001b70: d80a bhi.n 8001b88 + + if(memcmp(otp, min_version, 8) > 0) { + 8001b72: 4621 mov r1, r4 + 8001b74: 2208 movs r2, #8 + 8001b76: 4628 mov r0, r5 + 8001b78: f00b fd44 bl 800d604 + 8001b7c: 2800 cmp r0, #0 + memcpy(min_version, otp, 8); + 8001b7e: bfc1 itttt gt + 8001b80: 462b movgt r3, r5 + 8001b82: cb03 ldmiagt r3!, {r0, r1} + 8001b84: 6020 strgt r0, [r4, #0] + 8001b86: 6061 strgt r1, [r4, #4] + for(int i=0; i + } + } +} + 8001b8e: bd70 pop {r4, r5, r6, pc} + 8001b90: 1fff7000 .word 0x1fff7000 + 8001b94: 1fff7400 .word 0x1fff7400 + +08001b98 : + +// check_is_downgrade() +// + bool +check_is_downgrade(const uint8_t timestamp[8], const char *version) +{ + 8001b98: b513 push {r0, r1, r4, lr} + 8001b9a: 4604 mov r4, r0 +#ifndef FOR_Q1_ONLY + if(version) { + 8001b9c: b129 cbz r1, 8001baa + int major = (version[1] == '.') ? (version[0]-'0') : 10; + 8001b9e: 784b ldrb r3, [r1, #1] + 8001ba0: 2b2e cmp r3, #46 ; 0x2e + 8001ba2: d102 bne.n 8001baa + if(major < 3) { + 8001ba4: 780b ldrb r3, [r1, #0] + 8001ba6: 2b32 cmp r3, #50 ; 0x32 + 8001ba8: d90a bls.n 8001bc0 + } +#endif + + // look at FW_HDR->timestamp and compare to a growing list in main flash OTP + uint8_t min[8]; + get_min_version(min); + 8001baa: 4668 mov r0, sp + 8001bac: f7ff ffd4 bl 8001b58 + + return (memcmp(timestamp, min, 8) < 0); + 8001bb0: 2208 movs r2, #8 + 8001bb2: 4669 mov r1, sp + 8001bb4: 4620 mov r0, r4 + 8001bb6: f00b fd25 bl 800d604 + 8001bba: 0fc0 lsrs r0, r0, #31 +} + 8001bbc: b002 add sp, #8 + 8001bbe: bd10 pop {r4, pc} + return true; + 8001bc0: 2001 movs r0, #1 + 8001bc2: e7fb b.n 8001bbc + +08001bc4 : + +// warn_fishy_firmware() +// + void +warn_fishy_firmware(const uint8_t *pixels) +{ + 8001bc4: b538 push {r3, r4, r5, lr} + 8001bc6: 4605 mov r5, r0 + const int wait = 100; +#else + const int wait = 10; +#endif + + for(int i=0; i < wait; i++) { + 8001bc8: 2400 movs r4, #0 + oled_show_progress(pixels, (i*100)/wait); + 8001bca: 4621 mov r1, r4 + 8001bcc: 4628 mov r0, r5 + 8001bce: f7ff f97b bl 8000ec8 + for(int i=0; i < wait; i++) { + 8001bd2: 3401 adds r4, #1 + + delay_ms(250); + 8001bd4: 20fa movs r0, #250 ; 0xfa + 8001bd6: f001 fe8f bl 80038f8 + for(int i=0; i < wait; i++) { + 8001bda: 2c64 cmp r4, #100 ; 0x64 + 8001bdc: d1f5 bne.n 8001bca + } +} + 8001bde: bd38 pop {r3, r4, r5, pc} + +08001be0 : + +// verify_header() +// + bool +verify_header(const coldcardFirmwareHeader_t *hdr) +{ + 8001be0: b510 push {r4, lr} + 8001be2: 4604 mov r4, r0 + rng_delay(); + 8001be4: f000 fdca bl 800277c + + if(hdr->magic_value != FW_HEADER_MAGIC) goto fail; + 8001be8: 6822 ldr r2, [r4, #0] + 8001bea: 4b0b ldr r3, [pc, #44] ; (8001c18 ) + 8001bec: 429a cmp r2, r3 + 8001bee: d110 bne.n 8001c12 + if(hdr->version_string[0] == 0x0) goto fail; + 8001bf0: 7b20 ldrb r0, [r4, #12] + 8001bf2: b168 cbz r0, 8001c10 + if(hdr->timestamp[0] >= 0x40) goto fail; // 22 yr product lifetime + 8001bf4: 7923 ldrb r3, [r4, #4] + 8001bf6: 2b3f cmp r3, #63 ; 0x3f + 8001bf8: d80b bhi.n 8001c12 + if(hdr->firmware_length < FW_MIN_LENGTH) goto fail; + 8001bfa: 69a3 ldr r3, [r4, #24] + 8001bfc: f5a3 2380 sub.w r3, r3, #262144 ; 0x40000 + 8001c00: f5b3 1fd0 cmp.w r3, #1703936 ; 0x1a0000 + 8001c04: d205 bcs.n 8001c12 + if(hdr->firmware_length >= FW_MAX_LENGTH_MK4) goto fail; + if(hdr->pubkey_num >= NUM_KNOWN_PUBKEYS) goto fail; + 8001c06: 6960 ldr r0, [r4, #20] + 8001c08: 2805 cmp r0, #5 + 8001c0a: bf8c ite hi + 8001c0c: 2000 movhi r0, #0 + 8001c0e: 2001 movls r0, #1 + + return true; +fail: + return false; +} + 8001c10: bd10 pop {r4, pc} + return false; + 8001c12: 2000 movs r0, #0 + 8001c14: e7fc b.n 8001c10 + 8001c16: bf00 nop + 8001c18: cc001234 .word 0xcc001234 + +08001c1c : +// +// Given double-sha256 over the firmware bytes, check the signature. +// + bool +verify_signature(const coldcardFirmwareHeader_t *hdr, const uint8_t fw_check[32]) +{ + 8001c1c: b530 push {r4, r5, lr} + // this takes a few ms at least, not fast. + int ok = uECC_verify(approved_pubkeys[hdr->pubkey_num], fw_check, 32, + 8001c1e: 6943 ldr r3, [r0, #20] + 8001c20: 4d0b ldr r5, [pc, #44] ; (8001c50 ) +{ + 8001c22: b085 sub sp, #20 + int ok = uECC_verify(approved_pubkeys[hdr->pubkey_num], fw_check, 32, + 8001c24: eb05 1583 add.w r5, r5, r3, lsl #6 +{ + 8001c28: 4604 mov r4, r0 + 8001c2a: 9103 str r1, [sp, #12] + int ok = uECC_verify(approved_pubkeys[hdr->pubkey_num], fw_check, 32, + 8001c2c: f004 fe5a bl 80068e4 + 8001c30: f104 0340 add.w r3, r4, #64 ; 0x40 + 8001c34: 9903 ldr r1, [sp, #12] + 8001c36: 9000 str r0, [sp, #0] + 8001c38: 2220 movs r2, #32 + 8001c3a: 4628 mov r0, r5 + 8001c3c: f005 f8d9 bl 8006df2 + 8001c40: 4604 mov r4, r0 + hdr->signature, uECC_secp256k1()); + + //puts(ok ? "Sig ok" : "Sig fail"); + rng_delay(); + 8001c42: f000 fd9b bl 800277c + + return ok; +} + 8001c46: 1e20 subs r0, r4, #0 + 8001c48: bf18 it ne + 8001c4a: 2001 movne r0, #1 + 8001c4c: b005 add sp, #20 + 8001c4e: bd30 pop {r4, r5, pc} + 8001c50: 0800e45a .word 0x0800e45a + +08001c54 : +// Check hdr, and even signature of protential new firmware in PSRAM. +// Returns checksum needed for 608 +// + bool +verify_firmware_in_ram(const uint8_t *start, uint32_t len, uint8_t world_check[32]) +{ + 8001c54: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + const coldcardFirmwareHeader_t *hdr = (const coldcardFirmwareHeader_t *) + 8001c58: f500 567e add.w r6, r0, #16256 ; 0x3f80 +{ + 8001c5c: b09c sub sp, #112 ; 0x70 + 8001c5e: 4605 mov r5, r0 + (start + FW_HEADER_OFFSET); + uint8_t fw_digest[32]; + + // check basics like verison, hw compat, etc + if(!verify_header(hdr)) goto fail; + 8001c60: 4630 mov r0, r6 +{ + 8001c62: 4617 mov r7, r2 + if(!verify_header(hdr)) goto fail; + 8001c64: f7ff ffbc bl 8001be0 + 8001c68: 4604 mov r4, r0 + 8001c6a: b150 cbz r0, 8001c82 + + if(check_is_downgrade(hdr->timestamp, (const char *)hdr->version_string)) { + 8001c6c: f106 010c add.w r1, r6, #12 + 8001c70: 1d30 adds r0, r6, #4 + 8001c72: f7ff ff91 bl 8001b98 + 8001c76: 4604 mov r4, r0 + 8001c78: b138 cbz r0, 8001c8a + puts("downgrade"); + 8001c7a: 481e ldr r0, [pc, #120] ; (8001cf4 ) + 8001c7c: f003 f896 bl 8004dac + + checksum_flash(fw_digest, world_check, hdr->firmware_length); + + return true; +fail: + return false; + 8001c80: 2400 movs r4, #0 +} + 8001c82: 4620 mov r0, r4 + 8001c84: b01c add sp, #112 ; 0x70 + 8001c86: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + rng_delay(); + 8001c8a: f000 fd77 bl 800277c + hdr->firmware_length - (FW_HEADER_OFFSET + FW_HEADER_SIZE)); + 8001c8e: f505 5840 add.w r8, r5, #12288 ; 0x3000 + sha256_init(&ctx); + 8001c92: a809 add r0, sp, #36 ; 0x24 + uint32_t total_len = 0; + 8001c94: 9400 str r4, [sp, #0] + sha256_init(&ctx); + 8001c96: f003 fbf9 bl 800548c + checksum_more(&ctx, &total_len, start, FW_HEADER_OFFSET + FW_HEADER_SIZE - 64); + 8001c9a: f44f 537f mov.w r3, #16320 ; 0x3fc0 + 8001c9e: 462a mov r2, r5 + 8001ca0: 4669 mov r1, sp + 8001ca2: a809 add r0, sp, #36 ; 0x24 + 8001ca4: f7ff feac bl 8001a00 + hdr->firmware_length - (FW_HEADER_OFFSET + FW_HEADER_SIZE)); + 8001ca8: f8d8 3f98 ldr.w r3, [r8, #3992] ; 0xf98 + checksum_more(&ctx, &total_len, start + FW_HEADER_OFFSET + FW_HEADER_SIZE, + 8001cac: f505 4280 add.w r2, r5, #16384 ; 0x4000 + 8001cb0: f5a3 4380 sub.w r3, r3, #16384 ; 0x4000 + 8001cb4: 4669 mov r1, sp + 8001cb6: a809 add r0, sp, #36 ; 0x24 + 8001cb8: f7ff fea2 bl 8001a00 + sha256_final(&ctx, fw_digest); + 8001cbc: a901 add r1, sp, #4 + 8001cbe: a809 add r0, sp, #36 ; 0x24 + 8001cc0: f003 fc38 bl 8005534 + sha256_single(fw_digest, 32, fw_digest); + 8001cc4: aa01 add r2, sp, #4 + 8001cc6: 4610 mov r0, r2 + 8001cc8: 2120 movs r1, #32 + 8001cca: f003 fc47 bl 800555c + rng_delay(); + 8001cce: f000 fd55 bl 800277c + if(!verify_signature(hdr, fw_digest)) { + 8001cd2: a901 add r1, sp, #4 + 8001cd4: 4630 mov r0, r6 + 8001cd6: f7ff ffa1 bl 8001c1c + 8001cda: 4604 mov r4, r0 + 8001cdc: b918 cbnz r0, 8001ce6 + puts("sig fail"); + 8001cde: 4806 ldr r0, [pc, #24] ; (8001cf8 ) + 8001ce0: f003 f864 bl 8004dac + goto fail; + 8001ce4: e7cd b.n 8001c82 + checksum_flash(fw_digest, world_check, hdr->firmware_length); + 8001ce6: f8d8 2f98 ldr.w r2, [r8, #3992] ; 0xf98 + 8001cea: 4639 mov r1, r7 + 8001cec: a801 add r0, sp, #4 + 8001cee: f7ff fea3 bl 8001a38 + return true; + 8001cf2: e7c6 b.n 8001c82 + 8001cf4: 0800e3e7 .word 0x0800e3e7 + 8001cf8: 0800e3f1 .word 0x0800e3f1 + +08001cfc : +// - don't set the light at this point. +// - requires bootloader to have been unchanged since world_check recorded (debug issue) +// + bool +verify_world_checksum(const uint8_t world_check[32]) +{ + 8001cfc: b507 push {r0, r1, r2, lr} + 8001cfe: 9001 str r0, [sp, #4] + ae_setup(); + 8001d00: f000 fe60 bl 80029c4 + ae_pair_unlock(); + 8001d04: f001 f854 bl 8002db0 + + return (ae_checkmac_hard(KEYNUM_firmware, world_check) == 0); + 8001d08: 9901 ldr r1, [sp, #4] + 8001d0a: 200e movs r0, #14 + 8001d0c: f001 f9de bl 80030cc +} + 8001d10: fab0 f080 clz r0, r0 + 8001d14: 0940 lsrs r0, r0, #5 + 8001d16: b003 add sp, #12 + 8001d18: f85d fb04 ldr.w pc, [sp], #4 + +08001d1c : + +// verify_firmware() +// + bool +verify_firmware(void) +{ + 8001d1c: b570 push {r4, r5, r6, lr} + STATIC_ASSERT(sizeof(coldcardFirmwareHeader_t) == FW_HEADER_SIZE); + + rng_delay(); + + // watch for unprogrammed header. and some + if(FW_HDR->version_string[0] == 0xff) goto blank; + 8001d1e: 4e2a ldr r6, [pc, #168] ; (8001dc8 ) +{ + 8001d20: b090 sub sp, #64 ; 0x40 + rng_delay(); + 8001d22: f000 fd2b bl 800277c + if(FW_HDR->version_string[0] == 0xff) goto blank; + 8001d26: f896 308c ldrb.w r3, [r6, #140] ; 0x8c + 8001d2a: 2bff cmp r3, #255 ; 0xff + 8001d2c: d107 bne.n 8001d3e + puts("corrupt firmware"); + oled_show(screen_corrupt); + return false; + +blank: + puts("no firmware"); + 8001d2e: 4827 ldr r0, [pc, #156] ; (8001dcc ) + puts("corrupt firmware"); + 8001d30: f003 f83c bl 8004dac + oled_show(screen_corrupt); + 8001d34: 4826 ldr r0, [pc, #152] ; (8001dd0 ) + 8001d36: f7ff f885 bl 8000e44 + return false; + 8001d3a: 2400 movs r4, #0 + 8001d3c: e030 b.n 8001da0 + if(!verify_header(FW_HDR)) goto fail; + 8001d3e: 4825 ldr r0, [pc, #148] ; (8001dd4 ) + 8001d40: f7ff ff4e bl 8001be0 + 8001d44: 2800 cmp r0, #0 + 8001d46: d03c beq.n 8001dc2 + rng_delay(); + 8001d48: f000 fd18 bl 800277c + checksum_flash(fw_check, world_check, 0); + 8001d4c: 2200 movs r2, #0 + 8001d4e: a908 add r1, sp, #32 + 8001d50: 4668 mov r0, sp + 8001d52: f7ff fe71 bl 8001a38 + rng_delay(); + 8001d56: f000 fd11 bl 800277c + if(!verify_signature(FW_HDR, fw_check)) goto fail; + 8001d5a: 481e ldr r0, [pc, #120] ; (8001dd4 ) + 8001d5c: 4669 mov r1, sp + 8001d5e: f7ff ff5d bl 8001c1c + 8001d62: 4604 mov r4, r0 + 8001d64: b368 cbz r0, 8001dc2 + int not_green = ae_set_gpio_secure(world_check); + 8001d66: a808 add r0, sp, #32 + 8001d68: f001 fbc4 bl 80034f4 + 8001d6c: 4605 mov r5, r0 + rng_delay(); + 8001d6e: f000 fd05 bl 800277c + rng_delay(); + 8001d72: f000 fd03 bl 800277c + return ((FLASH->OPTR & FLASH_OPTR_RDP_Msk) == 0xCC); + 8001d76: 4b18 ldr r3, [pc, #96] ; (8001dd8 ) + 8001d78: 6a1b ldr r3, [r3, #32] + 8001d7a: b2db uxtb r3, r3 + if(!flash_is_security_level2() && not_green) { + 8001d7c: 2bcc cmp r3, #204 ; 0xcc + 8001d7e: d008 beq.n 8001d92 + 8001d80: b18d cbz r5, 8001da6 + oled_show_progress(screen_verify, 100); + 8001d82: 4816 ldr r0, [pc, #88] ; (8001ddc ) + 8001d84: 2164 movs r1, #100 ; 0x64 + 8001d86: f7ff f89f bl 8000ec8 + puts("Factory boot"); + 8001d8a: 4815 ldr r0, [pc, #84] ; (8001de0 ) + puts("Good firmware"); + 8001d8c: f003 f80e bl 8004dac + 8001d90: e006 b.n 8001da0 + } else if(not_green) { + 8001d92: b145 cbz r5, 8001da6 + puts("WARN: Red light"); + 8001d94: 4813 ldr r0, [pc, #76] ; (8001de4 ) + 8001d96: f003 f809 bl 8004dac + warn_fishy_firmware(screen_red_light); + 8001d9a: 4813 ldr r0, [pc, #76] ; (8001de8 ) + warn_fishy_firmware(screen_devmode); + 8001d9c: f7ff ff12 bl 8001bc4 + oled_show(screen_corrupt); + + return false; +} + 8001da0: 4620 mov r0, r4 + 8001da2: b010 add sp, #64 ; 0x40 + 8001da4: bd70 pop {r4, r5, r6, pc} + } else if(FW_HDR->pubkey_num == 0) { + 8001da6: f8d6 3094 ldr.w r3, [r6, #148] ; 0x94 + 8001daa: b923 cbnz r3, 8001db6 + puts("WARN: Unsigned firmware"); + 8001dac: 480f ldr r0, [pc, #60] ; (8001dec ) + 8001dae: f002 fffd bl 8004dac + warn_fishy_firmware(screen_devmode); + 8001db2: 480f ldr r0, [pc, #60] ; (8001df0 ) + 8001db4: e7f2 b.n 8001d9c + oled_show_progress(screen_verify, 100); + 8001db6: 4809 ldr r0, [pc, #36] ; (8001ddc ) + 8001db8: 2164 movs r1, #100 ; 0x64 + 8001dba: f7ff f885 bl 8000ec8 + puts("Good firmware"); + 8001dbe: 480d ldr r0, [pc, #52] ; (8001df4 ) + 8001dc0: e7e4 b.n 8001d8c + puts("corrupt firmware"); + 8001dc2: 480d ldr r0, [pc, #52] ; (8001df8 ) + 8001dc4: e7b4 b.n 8001d30 + 8001dc6: bf00 nop + 8001dc8: 08023f00 .word 0x08023f00 + 8001dcc: 0800e3fa .word 0x0800e3fa + 8001dd0: 0800d875 .word 0x0800d875 + 8001dd4: 08023f80 .word 0x08023f80 + 8001dd8: 40022000 .word 0x40022000 + 8001ddc: 0800e242 .word 0x0800e242 + 8001de0: 0800e406 .word 0x0800e406 + 8001de4: 0800e413 .word 0x0800e413 + 8001de8: 0800dd72 .word 0x0800dd72 + 8001dec: 0800e423 .word 0x0800e423 + 8001df0: 0800d932 .word 0x0800d932 + 8001df4: 0800e43b .word 0x0800e43b + 8001df8: 0800e449 .word 0x0800e449 + +08001dfc : + void +systick_setup(void) +{ + const uint32_t ticks = HCLK_FREQUENCY/1000; + + SysTick->LOAD = (ticks - 1); + 8001dfc: f04f 23e0 mov.w r3, #3758153728 ; 0xe000e000 + 8001e00: 4a03 ldr r2, [pc, #12] ; (8001e10 ) + 8001e02: 615a str r2, [r3, #20] + SysTick->VAL = 0; + 8001e04: 2200 movs r2, #0 + 8001e06: 619a str r2, [r3, #24] + SysTick->CTRL = SYSTICK_CLKSOURCE_HCLK | SysTick_CTRL_ENABLE_Msk; + 8001e08: 2205 movs r2, #5 + 8001e0a: 611a str r2, [r3, #16] +} + 8001e0c: 4770 bx lr + 8001e0e: bf00 nop + 8001e10: 0001d4bf .word 0x0001d4bf + +08001e14 : + SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; +#endif + + /* FPU settings ------------------------------------------------------------*/ +#if (__FPU_PRESENT == 1) && (__FPU_USED == 1) + SCB->CPACR |= ((3UL << 20U)|(3UL << 22U)); /* set CP10 and CP11 Full Access */ + 8001e14: 4a0e ldr r2, [pc, #56] ; (8001e50 ) + 8001e16: f8d2 3088 ldr.w r3, [r2, #136] ; 0x88 + 8001e1a: f443 0370 orr.w r3, r3, #15728640 ; 0xf00000 + 8001e1e: f8c2 3088 str.w r3, [r2, #136] ; 0x88 +#endif + + /* Reset the RCC clock configuration to the default reset state ------------*/ + /* Set MSION bit */ + RCC->CR |= RCC_CR_MSION; + 8001e22: 4b0c ldr r3, [pc, #48] ; (8001e54 ) + 8001e24: 681a ldr r2, [r3, #0] + + /* Reset CFGR register */ + RCC->CFGR = 0x00000000U; + 8001e26: 2100 movs r1, #0 + RCC->CR |= RCC_CR_MSION; + 8001e28: f042 0201 orr.w r2, r2, #1 + 8001e2c: 601a str r2, [r3, #0] + RCC->CFGR = 0x00000000U; + 8001e2e: 6099 str r1, [r3, #8] + + /* Reset HSEON, CSSON , HSION, and PLLON bits */ + RCC->CR &= 0xEAF6FFFFU; + 8001e30: 681a ldr r2, [r3, #0] + 8001e32: f022 52a8 bic.w r2, r2, #352321536 ; 0x15000000 + 8001e36: f422 2210 bic.w r2, r2, #589824 ; 0x90000 + 8001e3a: 601a str r2, [r3, #0] + + /* Reset PLLCFGR register */ + RCC->PLLCFGR = 0x00001000U; + 8001e3c: f44f 5280 mov.w r2, #4096 ; 0x1000 + 8001e40: 60da str r2, [r3, #12] + + /* Reset HSEBYP bit */ + RCC->CR &= 0xFFFBFFFFU; + 8001e42: 681a ldr r2, [r3, #0] + 8001e44: f422 2280 bic.w r2, r2, #262144 ; 0x40000 + 8001e48: 601a str r2, [r3, #0] + + /* Disable all interrupts */ + RCC->CIER = 0x00000000U; + 8001e4a: 6199 str r1, [r3, #24] +} + 8001e4c: 4770 bx lr + 8001e4e: bf00 nop + 8001e50: e000ed00 .word 0xe000ed00 + 8001e54: 40021000 .word 0x40021000 + +08001e58 : + +// clocks_setup() +// + void +clocks_setup(void) +{ + 8001e58: e92d 43f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, lr} + + // setup power supplies + HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST); + + // Configure LSE Drive Capability + __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW); + 8001e5c: 4c41 ldr r4, [pc, #260] ; (8001f64 ) +{ + 8001e5e: b0c1 sub sp, #260 ; 0x104 + HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST); + 8001e60: 2000 movs r0, #0 + 8001e62: f005 f959 bl 8007118 + __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW); + 8001e66: f8d4 3090 ldr.w r3, [r4, #144] ; 0x90 + 8001e6a: f023 0318 bic.w r3, r3, #24 + 8001e6e: f8c4 3090 str.w r3, [r4, #144] ; 0x90 + + // Enable HSE Oscillator and activate PLL with HSE as source + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; + + RCC_OscInitStruct.HSEState = RCC_HSE_ON; + 8001e72: 2201 movs r2, #1 + 8001e74: f44f 3380 mov.w r3, #65536 ; 0x10000 + 8001e78: e9cd 230a strd r2, r3, [sp, #40] ; 0x28 + RCC_OscInitStruct.LSEState = RCC_LSE_OFF; + RCC_OscInitStruct.MSIState = RCC_MSI_OFF; + + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + 8001e7c: 2703 movs r7, #3 + + // Select PLL as system clock source and configure + // the HCLK, PCLK1 and PCLK2 clocks dividers + RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK + 8001e7e: 230f movs r3, #15 + RCC_OscInitStruct.LSEState = RCC_LSE_OFF; + 8001e80: 2500 movs r5, #0 + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + 8001e82: 2602 movs r6, #2 + | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + 8001e84: e9cd 3705 strd r3, r7, [sp, #20] + + RCC_OscInitStruct.PLL.PLLM = CKCC_CLK_PLLM; + RCC_OscInitStruct.PLL.PLLN = CKCC_CLK_PLLN; + RCC_OscInitStruct.PLL.PLLP = CKCC_CLK_PLLP; + 8001e88: f04f 0807 mov.w r8, #7 + 8001e8c: 233c movs r3, #60 ; 0x3c + RCC_OscInitStruct.PLL.PLLQ = CKCC_CLK_PLLQ; + 8001e8e: f04f 0905 mov.w r9, #5 + + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; + + HAL_RCC_OscConfig(&RCC_OscInitStruct); + 8001e92: a80a add r0, sp, #40 ; 0x28 + RCC_OscInitStruct.PLL.PLLP = CKCC_CLK_PLLP; + 8001e94: e9cd 3817 strd r3, r8, [sp, #92] ; 0x5c + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + 8001e98: e9cd 6714 strd r6, r7, [sp, #80] ; 0x50 + RCC_OscInitStruct.PLL.PLLR = CKCC_CLK_PLLR; + 8001e9c: e9cd 9619 strd r9, r6, [sp, #100] ; 0x64 + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; + 8001ea0: e9cd 5507 strd r5, r5, [sp, #28] + RCC_OscInitStruct.LSEState = RCC_LSE_OFF; + 8001ea4: 950c str r5, [sp, #48] ; 0x30 + RCC_OscInitStruct.MSIState = RCC_MSI_OFF; + 8001ea6: 9510 str r5, [sp, #64] ; 0x40 + RCC_OscInitStruct.PLL.PLLM = CKCC_CLK_PLLM; + 8001ea8: 9616 str r6, [sp, #88] ; 0x58 + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; + 8001eaa: 9509 str r5, [sp, #36] ; 0x24 + HAL_RCC_OscConfig(&RCC_OscInitStruct); + 8001eac: f006 fcdc bl 8008868 + + HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5); + 8001eb0: 4649 mov r1, r9 + 8001eb2: a805 add r0, sp, #20 + 8001eb4: f006 ff86 bl 8008dc4 + + // DIS-able MSI-Hardware auto calibration mode with LSE + CLEAR_BIT(RCC->CR, RCC_CR_MSIPLLEN); + 8001eb8: 6823 ldr r3, [r4, #0] + 8001eba: f023 0304 bic.w r3, r3, #4 + 8001ebe: 6023 str r3, [r4, #0] + + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct; + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SAI1|RCC_PERIPHCLK_I2C2 + 8001ec0: 4b29 ldr r3, [pc, #164] ; (8001f68 ) + 8001ec2: 931b str r3, [sp, #108] ; 0x6c + + // PLLSAI is used to clock USB, ADC, I2C1 and RNG. The frequency is + // HSE(8MHz)/PLLM(2)*PLLSAI1N(24)/PLLSAIQ(2) = 48MHz. + // + PeriphClkInitStruct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI1; + PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLLSAI1; + 8001ec4: f04f 5380 mov.w r3, #268435456 ; 0x10000000 + 8001ec8: 933b str r3, [sp, #236] ; 0xec + PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLLSAI1; + 8001eca: f04f 6380 mov.w r3, #67108864 ; 0x4000000 + 8001ece: 9338 str r3, [sp, #224] ; 0xe0 + PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_HSE_DIV32; // but unused + PeriphClkInitStruct.RngClockSelection = RCC_RNGCLKSOURCE_PLLSAI1; + 8001ed0: 933a str r3, [sp, #232] ; 0xe8 + + PeriphClkInitStruct.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_HSE; + PeriphClkInitStruct.PLLSAI1.PLLSAI1M = 2; + PeriphClkInitStruct.PLLSAI1.PLLSAI1N = 24; + 8001ed2: 2318 movs r3, #24 + PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_HSE_DIV32; // but unused + 8001ed4: f44f 7240 mov.w r2, #768 ; 0x300 + PeriphClkInitStruct.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV7; + 8001ed8: e9cd 381e strd r3, r8, [sp, #120] ; 0x78 + PeriphClkInitStruct.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2; + PeriphClkInitStruct.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_SAI1CLK + |RCC_PLLSAI1_48M2CLK + |RCC_PLLSAI1_ADC1CLK; + + HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct); + 8001edc: a81b add r0, sp, #108 ; 0x6c + PeriphClkInitStruct.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_SAI1CLK + 8001ede: 4b23 ldr r3, [pc, #140] ; (8001f6c ) + PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_HSE_DIV32; // but unused + 8001ee0: 923f str r2, [sp, #252] ; 0xfc + PeriphClkInitStruct.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_SAI1CLK + 8001ee2: 9322 str r3, [sp, #136] ; 0x88 + PeriphClkInitStruct.PLLSAI1.PLLSAI1M = 2; + 8001ee4: e9cd 761c strd r7, r6, [sp, #112] ; 0x70 + PeriphClkInitStruct.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2; + 8001ee8: e9cd 6620 strd r6, r6, [sp, #128] ; 0x80 + PeriphClkInitStruct.I2c2ClockSelection = RCC_I2C2CLKSOURCE_PCLK1; + 8001eec: 9531 str r5, [sp, #196] ; 0xc4 + PeriphClkInitStruct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI1; + 8001eee: 9536 str r5, [sp, #216] ; 0xd8 + HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct); + 8001ef0: f007 fa8c bl 800940c + + __HAL_RCC_RTC_ENABLE(); + 8001ef4: f8d4 3090 ldr.w r3, [r4, #144] ; 0x90 + 8001ef8: f443 4300 orr.w r3, r3, #32768 ; 0x8000 + 8001efc: f8c4 3090 str.w r3, [r4, #144] ; 0x90 + __HAL_RCC_HASH_CLK_ENABLE(); // for SHA256 + 8001f00: 6ce3 ldr r3, [r4, #76] ; 0x4c + 8001f02: f443 3300 orr.w r3, r3, #131072 ; 0x20000 + 8001f06: 64e3 str r3, [r4, #76] ; 0x4c + 8001f08: 6ce3 ldr r3, [r4, #76] ; 0x4c + 8001f0a: f403 3300 and.w r3, r3, #131072 ; 0x20000 + 8001f0e: 9301 str r3, [sp, #4] + 8001f10: 9b01 ldr r3, [sp, #4] + __HAL_RCC_SPI1_CLK_ENABLE(); // for OLED + 8001f12: 6e23 ldr r3, [r4, #96] ; 0x60 + 8001f14: f443 5380 orr.w r3, r3, #4096 ; 0x1000 + 8001f18: 6623 str r3, [r4, #96] ; 0x60 + 8001f1a: 6e23 ldr r3, [r4, #96] ; 0x60 + 8001f1c: f403 5380 and.w r3, r3, #4096 ; 0x1000 + 8001f20: 9302 str r3, [sp, #8] + 8001f22: 9b02 ldr r3, [sp, #8] + //__HAL_RCC_SPI2_CLK_ENABLE(); // for SPI flash + __HAL_RCC_DMAMUX1_CLK_ENABLE(); // (need this) because code missing in mpy? + 8001f24: 6ca3 ldr r3, [r4, #72] ; 0x48 + 8001f26: f043 0304 orr.w r3, r3, #4 + 8001f2a: 64a3 str r3, [r4, #72] ; 0x48 + 8001f2c: 6ca3 ldr r3, [r4, #72] ; 0x48 + 8001f2e: f003 0304 and.w r3, r3, #4 + 8001f32: 9303 str r3, [sp, #12] + 8001f34: 9b03 ldr r3, [sp, #12] + + // for SE2 + __HAL_RCC_I2C2_CLK_ENABLE(); + 8001f36: 6da3 ldr r3, [r4, #88] ; 0x58 + 8001f38: f443 0380 orr.w r3, r3, #4194304 ; 0x400000 + 8001f3c: 65a3 str r3, [r4, #88] ; 0x58 + 8001f3e: 6da3 ldr r3, [r4, #88] ; 0x58 + 8001f40: f403 0380 and.w r3, r3, #4194304 ; 0x400000 + 8001f44: 9304 str r3, [sp, #16] + 8001f46: 9b04 ldr r3, [sp, #16] + __HAL_RCC_I2C2_FORCE_RESET(); + 8001f48: 6ba3 ldr r3, [r4, #56] ; 0x38 + 8001f4a: f443 0380 orr.w r3, r3, #4194304 ; 0x400000 + 8001f4e: 63a3 str r3, [r4, #56] ; 0x38 + __HAL_RCC_I2C2_RELEASE_RESET(); + 8001f50: 6ba3 ldr r3, [r4, #56] ; 0x38 + 8001f52: f423 0380 bic.w r3, r3, #4194304 ; 0x400000 + 8001f56: 63a3 str r3, [r4, #56] ; 0x38 + + // setup SYSTICK, but we don't have the irq hooked up and not using HAL + // but we use it in polling mode for delay_ms() + systick_setup(); + 8001f58: f7ff ff50 bl 8001dfc + +} + 8001f5c: b041 add sp, #260 ; 0x104 + 8001f5e: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + 8001f62: bf00 nop + 8001f64: 40021000 .word 0x40021000 + 8001f68: 00066880 .word 0x00066880 + 8001f6c: 01110000 .word 0x01110000 + +08001f70 : + } else { + + // write changes to OB flash bytes + + // Set OPTSTRT bit + SET_BIT(FLASH->CR, FLASH_CR_OPTSTRT); + 8001f70: 4b13 ldr r3, [pc, #76] ; (8001fc0 ) + 8001f72: 695a ldr r2, [r3, #20] + 8001f74: f442 3200 orr.w r2, r2, #131072 ; 0x20000 + 8001f78: 615a str r2, [r3, #20] + while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)) { + 8001f7a: 691a ldr r2, [r3, #16] + 8001f7c: 03d2 lsls r2, r2, #15 + 8001f7e: d4fc bmi.n 8001f7a + uint32_t error = (FLASH->SR & FLASH_FLAG_SR_ERRORS); + 8001f80: 6919 ldr r1, [r3, #16] + if(error) { + 8001f82: 4a10 ldr r2, [pc, #64] ; (8001fc4 ) + 8001f84: 4211 tst r1, r2 + 8001f86: d104 bne.n 8001f92 + if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP)) { + 8001f88: 691a ldr r2, [r3, #16] + 8001f8a: 07d0 lsls r0, r2, #31 + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP); + 8001f8c: bf44 itt mi + 8001f8e: 2201 movmi r2, #1 + 8001f90: 611a strmi r2, [r3, #16] + + /// Wait for update to complete + _flash_wait_done(); + + // lock OB again. + SET_BIT(FLASH->CR, FLASH_CR_OPTLOCK); + 8001f92: 4b0b ldr r3, [pc, #44] ; (8001fc0 ) + 8001f94: 695a ldr r2, [r3, #20] + 8001f96: f042 4280 orr.w r2, r2, #1073741824 ; 0x40000000 + 8001f9a: 615a str r2, [r3, #20] + + // include "launch" to make them take effect NOW + SET_BIT(FLASH->CR, FLASH_CR_OBL_LAUNCH); + 8001f9c: 695a ldr r2, [r3, #20] + 8001f9e: f042 6200 orr.w r2, r2, #134217728 ; 0x8000000 + 8001fa2: 615a str r2, [r3, #20] + while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)) { + 8001fa4: 691a ldr r2, [r3, #16] + 8001fa6: 03d1 lsls r1, r2, #15 + 8001fa8: d4fc bmi.n 8001fa4 + uint32_t error = (FLASH->SR & FLASH_FLAG_SR_ERRORS); + 8001faa: 6919 ldr r1, [r3, #16] + if(error) { + 8001fac: 4a05 ldr r2, [pc, #20] ; (8001fc4 ) + 8001fae: 4211 tst r1, r2 + 8001fb0: d104 bne.n 8001fbc + if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP)) { + 8001fb2: 691a ldr r2, [r3, #16] + 8001fb4: 07d2 lsls r2, r2, #31 + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP); + 8001fb6: bf44 itt mi + 8001fb8: 2201 movmi r2, #1 + 8001fba: 611a strmi r2, [r3, #16] + + _flash_wait_done(); + } +} + 8001fbc: 4770 bx lr + 8001fbe: bf00 nop + 8001fc0: 40022000 .word 0x40022000 + 8001fc4: 0002c3fa .word 0x0002c3fa + +08001fc8 : +{ + 8001fc8: b507 push {r0, r1, r2, lr} + memcpy(&_srelocate, &_etext, ((uint32_t)&_erelocate)-(uint32_t)&_srelocate); + 8001fca: 4809 ldr r0, [pc, #36] ; (8001ff0 ) + 8001fcc: 4a09 ldr r2, [pc, #36] ; (8001ff4 ) + 8001fce: 490a ldr r1, [pc, #40] ; (8001ff8 ) + 8001fd0: 1a12 subs r2, r2, r0 + 8001fd2: f00b fb27 bl 800d624 + __HAL_RCC_FLASH_CLK_ENABLE(); + 8001fd6: 4b09 ldr r3, [pc, #36] ; (8001ffc ) + 8001fd8: 6c9a ldr r2, [r3, #72] ; 0x48 + 8001fda: f442 7280 orr.w r2, r2, #256 ; 0x100 + 8001fde: 649a str r2, [r3, #72] ; 0x48 + 8001fe0: 6c9b ldr r3, [r3, #72] ; 0x48 + 8001fe2: f403 7380 and.w r3, r3, #256 ; 0x100 + 8001fe6: 9301 str r3, [sp, #4] + 8001fe8: 9b01 ldr r3, [sp, #4] +} + 8001fea: b003 add sp, #12 + 8001fec: f85d fb04 ldr.w pc, [sp], #4 + 8001ff0: 2009e000 .word 0x2009e000 + 8001ff4: 2009e150 .word 0x2009e150 + 8001ff8: 0800ea48 .word 0x0800ea48 + 8001ffc: 40021000 .word 0x40021000 + +08002000 : + SET_BIT(FLASH->CR, FLASH_CR_LOCK); + 8002000: 4a02 ldr r2, [pc, #8] ; (800200c ) + 8002002: 6953 ldr r3, [r2, #20] + 8002004: f043 4300 orr.w r3, r3, #2147483648 ; 0x80000000 + 8002008: 6153 str r3, [r2, #20] +} + 800200a: 4770 bx lr + 800200c: 40022000 .word 0x40022000 + +08002010 : +{ + 8002010: b508 push {r3, lr} + if(READ_BIT(FLASH->CR, FLASH_CR_LOCK)) { + 8002012: 4b08 ldr r3, [pc, #32] ; (8002034 ) + 8002014: 695a ldr r2, [r3, #20] + 8002016: 2a00 cmp r2, #0 + 8002018: da0a bge.n 8002030 + WRITE_REG(FLASH->KEYR, FLASH_KEY1); + 800201a: 4a07 ldr r2, [pc, #28] ; (8002038 ) + 800201c: 609a str r2, [r3, #8] + WRITE_REG(FLASH->KEYR, FLASH_KEY2); + 800201e: f102 3288 add.w r2, r2, #2290649224 ; 0x88888888 + 8002022: 609a str r2, [r3, #8] + if(READ_BIT(FLASH->CR, FLASH_CR_LOCK)) { + 8002024: 695b ldr r3, [r3, #20] + 8002026: 2b00 cmp r3, #0 + 8002028: da02 bge.n 8002030 + INCONSISTENT("failed to unlock"); + 800202a: 4804 ldr r0, [pc, #16] ; (800203c ) + 800202c: f7fe fd0c bl 8000a48 +} + 8002030: bd08 pop {r3, pc} + 8002032: bf00 nop + 8002034: 40022000 .word 0x40022000 + 8002038: 45670123 .word 0x45670123 + 800203c: 0800d700 .word 0x0800d700 + +08002040 : +{ + 8002040: b510 push {r4, lr} + if(!lock) { + 8002042: b980 cbnz r0, 8002066 + if(READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK)) { + 8002044: 4c0a ldr r4, [pc, #40] ; (8002070 ) + 8002046: 6963 ldr r3, [r4, #20] + 8002048: 005a lsls r2, r3, #1 + 800204a: d510 bpl.n 800206e + flash_unlock(); + 800204c: f7ff ffe0 bl 8002010 + WRITE_REG(FLASH->OPTKEYR, FLASH_OPTKEY1); + 8002050: 4b08 ldr r3, [pc, #32] ; (8002074 ) + 8002052: 60e3 str r3, [r4, #12] + WRITE_REG(FLASH->OPTKEYR, FLASH_OPTKEY2); + 8002054: f103 3344 add.w r3, r3, #1145324612 ; 0x44444444 + 8002058: 60e3 str r3, [r4, #12] + if(READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK)) { + 800205a: 6963 ldr r3, [r4, #20] + 800205c: 005b lsls r3, r3, #1 + 800205e: d506 bpl.n 800206e + INCONSISTENT("failed to OB unlock"); + 8002060: 4805 ldr r0, [pc, #20] ; (8002078 ) + 8002062: f7fe fcf1 bl 8000a48 +} + 8002066: e8bd 4010 ldmia.w sp!, {r4, lr} + 800206a: f7ff bf81 b.w 8001f70 + 800206e: bd10 pop {r4, pc} + 8002070: 40022000 .word 0x40022000 + 8002074: 08192a3b .word 0x08192a3b + 8002078: 0800d700 .word 0x0800d700 + +0800207c : + +// pick_pairing_secret() +// + static void +pick_pairing_secret(void) +{ + 800207c: b570 push {r4, r5, r6, lr} + 800207e: f5ad 6d85 sub.w sp, sp, #1064 ; 0x428 + // important the RNG works here. ok to call setup multiple times. + rng_setup(); + 8002082: f000 fb39 bl 80026f8 + 8002086: 24c8 movs r4, #200 ; 0xc8 +#else + // Demo to anyone watching that the RNG is working, but likely only + // to be seen by production team during initial powerup. + uint8_t tmp[1024]; + for(int i=0; i<200; i++) { + rng_buffer(tmp, sizeof(tmp)); + 8002088: f44f 6180 mov.w r1, #1024 ; 0x400 + 800208c: a80a add r0, sp, #40 ; 0x28 + 800208e: f000 fb5f bl 8002750 + + oled_show_raw(sizeof(tmp), (void *)tmp); + 8002092: a90a add r1, sp, #40 ; 0x28 + 8002094: f44f 6080 mov.w r0, #1024 ; 0x400 + 8002098: f7fe fea8 bl 8000dec + for(int i=0; i<200; i++) { + 800209c: 3c01 subs r4, #1 + 800209e: d1f3 bne.n 8002088 + } + + oled_factory_busy(); + 80020a0: f7fe ff92 bl 8000fc8 +#endif + + // .. but don't use those numbers, because those are semi-public now. + uint32_t secret[8]; + for(int i=0; i<8; i++) { + 80020a4: ad02 add r5, sp, #8 + oled_factory_busy(); + 80020a6: 462e mov r6, r5 + secret[i] = rng_sample(); + 80020a8: f000 fb14 bl 80026d4 + for(int i=0; i<8; i++) { + 80020ac: 3401 adds r4, #1 + 80020ae: 2c08 cmp r4, #8 + secret[i] = rng_sample(); + 80020b0: f846 0b04 str.w r0, [r6], #4 + for(int i=0; i<8; i++) { + 80020b4: d1f8 bne.n 80020a8 + } + + // enforce policy that first word is not all ones (so it never + // looks like unprogrammed flash). + while(secret[0] == ~0) { + 80020b6: 682b ldr r3, [r5, #0] + 80020b8: 3301 adds r3, #1 + 80020ba: d00c beq.n 80020d6 + + // Write pairing secret into flash + { + uint32_t dest = (uint32_t)&rom_secrets->pairing_secret; + + flash_unlock(); + 80020bc: f7ff ffa8 bl 8002010 + uint32_t dest = (uint32_t)&rom_secrets->pairing_secret; + 80020c0: 4c16 ldr r4, [pc, #88] ; (800211c ) + for(int i=0; i<8; i+=2, dest += 8) { + 80020c2: 4e17 ldr r6, [pc, #92] ; (8002120 ) + uint64_t val = (((uint64_t)secret[i]) << 32) | secret[i+1]; + + if(flash_burn(dest, val)) { + 80020c4: e9d5 3200 ldrd r3, r2, [r5] + 80020c8: 4620 mov r0, r4 + 80020ca: f00b fb11 bl 800d6f0 <__flash_burn_veneer> + 80020ce: b130 cbz r0, 80020de + INCONSISTENT("flash fail"); + 80020d0: 4814 ldr r0, [pc, #80] ; (8002124 ) + 80020d2: f7fe fcb9 bl 8000a48 + secret[0] = rng_sample(); + 80020d6: f000 fafd bl 80026d4 + 80020da: 6028 str r0, [r5, #0] + 80020dc: e7eb b.n 80020b6 + for(int i=0; i<8; i+=2, dest += 8) { + 80020de: 3408 adds r4, #8 + 80020e0: 42b4 cmp r4, r6 + 80020e2: f105 0508 add.w r5, r5, #8 + 80020e6: d1ed bne.n 80020c4 + } + } + flash_lock(); + 80020e8: f7ff ff8a bl 8002000 + + sizeof(rom_secrets->mcu_hmac_key); + + STATIC_ASSERT(offsetof(rom_secrets_t, hash_cache_secret) % 8 == 0); + STATIC_ASSERT(blen % 8 == 0); + + flash_unlock(); + 80020ec: f7ff ff90 bl 8002010 + uint32_t dest = (uint32_t)&rom_secrets->hash_cache_secret; + 80020f0: 4c0d ldr r4, [pc, #52] ; (8002128 ) + for(int i=0; i) + uint64_t val = ((uint64_t)rng_sample() << 32) | rng_sample(); + 80020f4: f000 faee bl 80026d4 + 80020f8: 9001 str r0, [sp, #4] + 80020fa: f000 faeb bl 80026d4 + + if(flash_burn(dest, val)) { + 80020fe: 9b01 ldr r3, [sp, #4] + uint64_t val = ((uint64_t)rng_sample() << 32) | rng_sample(); + 8002100: 4602 mov r2, r0 + if(flash_burn(dest, val)) { + 8002102: 4620 mov r0, r4 + 8002104: f00b faf4 bl 800d6f0 <__flash_burn_veneer> + 8002108: 2800 cmp r0, #0 + 800210a: d1e1 bne.n 80020d0 + for(int i=0; i + INCONSISTENT("flash fail"); + } + } + flash_lock(); + 8002112: f7ff ff75 bl 8002000 + } + +} + 8002116: f50d 6d85 add.w sp, sp, #1064 ; 0x428 + 800211a: bd70 pop {r4, r5, r6, pc} + 800211c: 0801c000 .word 0x0801c000 + 8002120: 0801c020 .word 0x0801c020 + 8002124: 0800d700 .word 0x0800d700 + 8002128: 0801c070 .word 0x0801c070 + 800212c: 0801c0b0 .word 0x0801c0b0 + +08002130 : +// +// Write the serial number of ATECC608 into flash forever. +// + void +flash_save_ae_serial(const uint8_t serial[9]) +{ + 8002130: b51f push {r0, r1, r2, r3, r4, lr} + 8002132: 4602 mov r2, r0 + uint64_t tmp[2]; + memset(&tmp, 0x0, sizeof(tmp)); + 8002134: 2300 movs r3, #0 + memcpy(&tmp, serial, 9); + 8002136: 6800 ldr r0, [r0, #0] + 8002138: 6851 ldr r1, [r2, #4] + 800213a: 7a12 ldrb r2, [r2, #8] + memset(&tmp, 0x0, sizeof(tmp)); + 800213c: e9cd 3302 strd r3, r3, [sp, #8] + memcpy(&tmp, serial, 9); + 8002140: 466b mov r3, sp + 8002142: c303 stmia r3!, {r0, r1} + 8002144: 701a strb r2, [r3, #0] + + flash_setup0(); + 8002146: f7ff ff3f bl 8001fc8 + flash_unlock(); + 800214a: f7ff ff61 bl 8002010 + + if(flash_burn((uint32_t)&rom_secrets->ae_serial_number[0], tmp[0])) { + 800214e: e9dd 2300 ldrd r2, r3, [sp] + 8002152: 4809 ldr r0, [pc, #36] ; (8002178 ) + 8002154: f00b facc bl 800d6f0 <__flash_burn_veneer> + 8002158: b110 cbz r0, 8002160 + INCONSISTENT("fail1"); + 800215a: 4808 ldr r0, [pc, #32] ; (800217c ) + 800215c: f7fe fc74 bl 8000a48 + } + if(flash_burn((uint32_t)&rom_secrets->ae_serial_number[1], tmp[1])) { + 8002160: e9dd 2302 ldrd r2, r3, [sp, #8] + 8002164: 4806 ldr r0, [pc, #24] ; (8002180 ) + 8002166: f00b fac3 bl 800d6f0 <__flash_burn_veneer> + 800216a: 2800 cmp r0, #0 + 800216c: d1f5 bne.n 800215a + INCONSISTENT("fail2"); + } + + flash_lock(); +} + 800216e: b005 add sp, #20 + 8002170: f85d eb04 ldr.w lr, [sp], #4 + flash_lock(); + 8002174: f7ff bf44 b.w 8002000 + 8002178: 0801c040 .word 0x0801c040 + 800217c: 0800d700 .word 0x0800d700 + 8002180: 0801c048 .word 0x0801c048 + +08002184 : +// +// Write bag number (probably a string) +// + void +flash_save_bag_number(const uint8_t new_number[32]) +{ + 8002184: b570 push {r4, r5, r6, lr} + 8002186: b088 sub sp, #32 + uint32_t dest = (uint32_t)&rom_secrets->bag_number[0]; + uint64_t tmp[4] = { 0 }; + uint64_t *src = tmp; + + STATIC_ASSERT(sizeof(tmp) == 32); + memcpy(tmp, new_number, 32); + 8002188: 4603 mov r3, r0 + 800218a: 466c mov r4, sp + 800218c: f100 0520 add.w r5, r0, #32 + 8002190: 6818 ldr r0, [r3, #0] + 8002192: 6859 ldr r1, [r3, #4] + 8002194: 4622 mov r2, r4 + 8002196: c203 stmia r2!, {r0, r1} + 8002198: 3308 adds r3, #8 + 800219a: 42ab cmp r3, r5 + 800219c: 4614 mov r4, r2 + 800219e: d1f7 bne.n 8002190 + + flash_setup0(); + 80021a0: f7ff ff12 bl 8001fc8 + flash_unlock(); + 80021a4: f7ff ff34 bl 8002010 + uint32_t dest = (uint32_t)&rom_secrets->bag_number[0]; + 80021a8: 4d09 ldr r5, [pc, #36] ; (80021d0 ) + + // NOTE: can only write once! No provision for read/check/update. + for(int i=0; i<(32/8); i++, dest+=8, src++) { + 80021aa: 4e0a ldr r6, [pc, #40] ; (80021d4 ) + 80021ac: 466c mov r4, sp + if(flash_burn(dest, *src)) { + 80021ae: e8f4 2302 ldrd r2, r3, [r4], #8 + 80021b2: 4628 mov r0, r5 + 80021b4: f00b fa9c bl 800d6f0 <__flash_burn_veneer> + 80021b8: b110 cbz r0, 80021c0 + INCONSISTENT("fail write"); + 80021ba: 4807 ldr r0, [pc, #28] ; (80021d8 ) + 80021bc: f7fe fc44 bl 8000a48 + for(int i=0; i<(32/8); i++, dest+=8, src++) { + 80021c0: 3508 adds r5, #8 + 80021c2: 42b5 cmp r5, r6 + 80021c4: d1f3 bne.n 80021ae + } + } + + flash_lock(); +} + 80021c6: b008 add sp, #32 + 80021c8: e8bd 4070 ldmia.w sp!, {r4, r5, r6, lr} + flash_lock(); + 80021cc: f7ff bf18 b.w 8002000 + 80021d0: 0801c050 .word 0x0801c050 + 80021d4: 0801c070 .word 0x0801c070 + 80021d8: 0800d700 .word 0x0800d700 + +080021dc : +// Save bunch of stuff related to SE2. Allow updates to sections that are +// given as ones at this point. +// + void +flash_save_se2_data(const se2_secrets_t *se2) +{ + 80021dc: e92d 41f3 stmdb sp!, {r0, r1, r4, r5, r6, r7, r8, lr} + 80021e0: 4605 mov r5, r0 + uint8_t *dest = (uint8_t *)&rom_secrets->se2; + 80021e2: 4c1a ldr r4, [pc, #104] ; (800224c ) + STATIC_ASSERT(offsetof(rom_secrets_t, se2) % 8 == 0); + + flash_setup0(); + flash_unlock(); + + for(int i=0; i<(sizeof(se2_secrets_t)/8); i++, dest+=8, src+=8) { + 80021e4: f8df 8070 ldr.w r8, [pc, #112] ; 8002258 + flash_setup0(); + 80021e8: f7ff feee bl 8001fc8 + flash_unlock(); + 80021ec: f7ff ff10 bl 8002010 + for(int i=0; i<(sizeof(se2_secrets_t)/8); i++, dest+=8, src+=8) { + 80021f0: 1b2d subs r5, r5, r4 + 80021f2: eb05 0c04 add.w ip, r5, r4 + uint64_t val; + memcpy(&val, src, sizeof(val)); + 80021f6: 5928 ldr r0, [r5, r4] + 80021f8: f8dc 1004 ldr.w r1, [ip, #4] + 80021fc: 466b mov r3, sp + + // don't write if all ones or already written correctly + if(val == ~0) continue; + 80021fe: f1b1 3fff cmp.w r1, #4294967295 ; 0xffffffff + 8002202: bf08 it eq + 8002204: f1b0 3fff cmpeq.w r0, #4294967295 ; 0xffffffff + memcpy(&val, src, sizeof(val)); + 8002208: c303 stmia r3!, {r0, r1} + if(val == ~0) continue; + 800220a: 4607 mov r7, r0 + 800220c: 460e mov r6, r1 + 800220e: d015 beq.n 800223c + if(check_equal(dest, src, 8)) continue; + 8002210: 2208 movs r2, #8 + 8002212: 4661 mov r1, ip + 8002214: 4620 mov r0, r4 + 8002216: f000 fa4c bl 80026b2 + 800221a: b978 cbnz r0, 800223c + + // can't write if not ones already + ASSERT(check_all_ones(dest, 8)); + 800221c: 2108 movs r1, #8 + 800221e: 4620 mov r0, r4 + 8002220: f000 fa2e bl 8002680 + 8002224: b910 cbnz r0, 800222c + 8002226: 480a ldr r0, [pc, #40] ; (8002250 ) + + if(flash_burn((uint32_t)dest, val)) { + INCONSISTENT("fail write"); + 8002228: f7fe fc0e bl 8000a48 + if(flash_burn((uint32_t)dest, val)) { + 800222c: 463a mov r2, r7 + 800222e: 4633 mov r3, r6 + 8002230: 4620 mov r0, r4 + 8002232: f00b fa5d bl 800d6f0 <__flash_burn_veneer> + 8002236: b108 cbz r0, 800223c + INCONSISTENT("fail write"); + 8002238: 4806 ldr r0, [pc, #24] ; (8002254 ) + 800223a: e7f5 b.n 8002228 + for(int i=0; i<(sizeof(se2_secrets_t)/8); i++, dest+=8, src+=8) { + 800223c: 3408 adds r4, #8 + 800223e: 4544 cmp r4, r8 + 8002240: d1d7 bne.n 80021f2 + } + } + + flash_lock(); +} + 8002242: b002 add sp, #8 + 8002244: e8bd 41f0 ldmia.w sp!, {r4, r5, r6, r7, r8, lr} + flash_lock(); + 8002248: f7ff beda b.w 8002000 + 800224c: 0801c0b0 .word 0x0801c0b0 + 8002250: 0800e3e0 .word 0x0800e3e0 + 8002254: 0800d700 .word 0x0800d700 + 8002258: 0801c190 .word 0x0801c190 + +0800225c : +// +// This is really a state-machine, to recover boards that are booted w/ missing AE chip. +// + void +flash_setup(void) +{ + 800225c: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + + // see if we have picked a pairing secret yet. + // NOTE: critical section for glitching (at least in past versions) + // - check_all.. functions have a rng_delay in them already + rng_delay(); + bool blank_ps = check_all_ones(rom_secrets->pairing_secret, 32); + 8002260: 4d3e ldr r5, [pc, #248] ; (800235c ) +{ + 8002262: b088 sub sp, #32 + flash_setup0(); + 8002264: f7ff feb0 bl 8001fc8 + rng_delay(); + 8002268: f000 fa88 bl 800277c + bool blank_ps = check_all_ones(rom_secrets->pairing_secret, 32); + 800226c: 2120 movs r1, #32 + 800226e: 4628 mov r0, r5 + 8002270: f000 fa06 bl 8002680 + bool zeroed_ps = check_all_zeros(rom_secrets->pairing_secret, 32); + 8002274: 2120 movs r1, #32 + bool blank_ps = check_all_ones(rom_secrets->pairing_secret, 32); + 8002276: 4606 mov r6, r0 + bool zeroed_ps = check_all_zeros(rom_secrets->pairing_secret, 32); + 8002278: 4628 mov r0, r5 + 800227a: f000 fa0b bl 8002694 + bool blank_xor = check_all_ones(rom_secrets->pairing_secret_xor, 32); + 800227e: 2120 movs r1, #32 + bool zeroed_ps = check_all_zeros(rom_secrets->pairing_secret, 32); + 8002280: 4607 mov r7, r0 + bool blank_xor = check_all_ones(rom_secrets->pairing_secret_xor, 32); + 8002282: 4837 ldr r0, [pc, #220] ; (8002360 ) + 8002284: f000 f9fc bl 8002680 + bool blank_ae = (~rom_secrets->ae_serial_number[0] == 0); + 8002288: e9d5 8510 ldrd r8, r5, [r5, #64] ; 0x40 + bool blank_xor = check_all_ones(rom_secrets->pairing_secret_xor, 32); + 800228c: 4604 mov r4, r0 + rng_delay(); + 800228e: f000 fa75 bl 800277c + + if(zeroed_ps) { + 8002292: b127 cbz r7, 800229e + // fast brick process leaves us w/ zero pairing secret + oled_show(screen_brick); + 8002294: 4833 ldr r0, [pc, #204] ; (8002364 ) + 8002296: f7fe fdd5 bl 8000e44 + LOCKUP_FOREVER(); + 800229a: bf30 wfi + 800229c: e7fd b.n 800229a + } + + if(blank_ps) { + 800229e: b10e cbz r6, 80022a4 + // get some good entropy, save it. + pick_pairing_secret(); + 80022a0: f7ff feec bl 800207c + + blank_ps = false; + } + + if(blank_xor || blank_ae) { + 80022a4: b92c cbnz r4, 80022b2 + 80022a6: f1b5 3fff cmp.w r5, #4294967295 ; 0xffffffff + 80022aa: bf08 it eq + 80022ac: f1b8 3fff cmpeq.w r8, #4294967295 ; 0xffffffff + 80022b0: d12f bne.n 8002312 + + // setup the SE2 (mostly). handles failures by dying + se2_setup_config(); + 80022b2: f005 faeb bl 800788c + + // configure and lock-down the SE1 + int rv = ae_setup_config(); + 80022b6: f001 f99b bl 80035f0 + 80022ba: 4605 mov r5, r0 + + rng_delay(); + 80022bc: f000 fa5e bl 800277c + if(rv) { + 80022c0: b13d cbz r5, 80022d2 + // Hardware fail speaking to AE chip ... be careful not to brick here. + // Do not continue!! We might fix the board, or add missing pullup, etc. + oled_show(screen_se1_issue); + 80022c2: 4829 ldr r0, [pc, #164] ; (8002368 ) + 80022c4: f7fe fdbe bl 8000e44 + puts("SE1 config fail"); + 80022c8: 4828 ldr r0, [pc, #160] ; (800236c ) + 80022ca: f002 fd6f bl 8004dac + + LOCKUP_FOREVER(); + 80022ce: bf30 wfi + 80022d0: e7fd b.n 80022ce + } + + rng_delay(); + 80022d2: f000 fa53 bl 800277c + if(blank_xor) { + 80022d6: b1a4 cbz r4, 8002302 + flash_unlock(); + 80022d8: f7ff fe9a bl 8002010 + uint64_t *src = (uint64_t *)&rom_secrets->pairing_secret; + 80022dc: 4c1f ldr r4, [pc, #124] ; (800235c ) + for(int i=0; i<(32/8); i++, dest+=8, src++) { + 80022de: 4d20 ldr r5, [pc, #128] ; (8002360 ) + uint64_t val = ~(*src); + 80022e0: e9d4 2300 ldrd r2, r3, [r4] + if(flash_burn(dest, val)) { + 80022e4: f104 0020 add.w r0, r4, #32 + 80022e8: 43d2 mvns r2, r2 + 80022ea: 43db mvns r3, r3 + 80022ec: f00b fa00 bl 800d6f0 <__flash_burn_veneer> + 80022f0: b110 cbz r0, 80022f8 + INCONSISTENT("flash xor fail"); + 80022f2: 481f ldr r0, [pc, #124] ; (8002370 ) + 80022f4: f7fe fba8 bl 8000a48 + for(int i=0; i<(32/8); i++, dest+=8, src++) { + 80022f8: 3408 adds r4, #8 + 80022fa: 42ac cmp r4, r5 + 80022fc: d1f0 bne.n 80022e0 + flash_lock(); + 80022fe: f7ff fe7f bl 8002000 + // Q: just do it (we warned them) + extern void turn_power_off(void); + turn_power_off(); +#else + // Mk: operator must do it + oled_show(screen_replug); + 8002302: 481c ldr r0, [pc, #112] ; (8002374 ) + 8002304: f7fe fd9e bl 8000e44 + puts("replug required"); + 8002308: 481b ldr r0, [pc, #108] ; (8002378 ) + 800230a: f002 fd4f bl 8004dac + LOCKUP_FOREVER(); + 800230e: bf30 wfi + 8002310: e7fd b.n 800230e + + rng_delay(); + if(!blank_ps && !blank_xor) { + // check the XOR value also written: 2 phase commit + uint8_t tmp[32]; + memcpy(tmp, rom_secrets->pairing_secret, 32); + 8002312: 4d12 ldr r5, [pc, #72] ; (800235c ) + rng_delay(); + 8002314: f000 fa32 bl 800277c + memcpy(tmp, rom_secrets->pairing_secret, 32); + 8002318: cd0f ldmia r5!, {r0, r1, r2, r3} + 800231a: 466c mov r4, sp + 800231c: c40f stmia r4!, {r0, r1, r2, r3} + 800231e: e895 000f ldmia.w r5, {r0, r1, r2, r3} + 8002322: e884 000f stmia.w r4, {r0, r1, r2, r3} + 8002326: 466b mov r3, sp + 8002328: 4a0d ldr r2, [pc, #52] ; (8002360 ) +bool check_equal(const void *aV, const void *bV, int len); + +// XOR-mixin more bytes; acc = acc XOR more for each byte +void static inline xor_mixin(uint8_t *acc, const uint8_t *more, int len) +{ + for(; len; len--, more++, acc++) { + 800232a: 4c14 ldr r4, [pc, #80] ; (800237c ) + 800232c: 4618 mov r0, r3 + *(acc) ^= *(more); + 800232e: 7819 ldrb r1, [r3, #0] + 8002330: f812 5b01 ldrb.w r5, [r2], #1 + 8002334: 4069 eors r1, r5 + for(; len; len--, more++, acc++) { + 8002336: 42a2 cmp r2, r4 + *(acc) ^= *(more); + 8002338: f803 1b01 strb.w r1, [r3], #1 + for(; len; len--, more++, acc++) { + 800233c: d1f7 bne.n 800232e + xor_mixin(tmp, rom_secrets->pairing_secret_xor, 32); + + if(!check_all_ones(tmp, 32)) { + 800233e: 2120 movs r1, #32 + 8002340: f000 f99e bl 8002680 + 8002344: b938 cbnz r0, 8002356 + oled_show(screen_corrupt); + 8002346: 480e ldr r0, [pc, #56] ; (8002380 ) + 8002348: f7fe fd7c bl 8000e44 + puts("corrupt pair sec"); + 800234c: 480d ldr r0, [pc, #52] ; (8002384 ) + 800234e: f002 fd2d bl 8004dac + + // dfu won't save them here, so just die + LOCKUP_FOREVER(); + 8002352: bf30 wfi + 8002354: e7fd b.n 8002352 + // That's fine if we intend to ship units locked already. + + // Do NOT do write every boot, as it might wear-out + // the flash bits in OB. + +} + 8002356: b008 add sp, #32 + 8002358: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + 800235c: 0801c000 .word 0x0801c000 + 8002360: 0801c020 .word 0x0801c020 + 8002364: 0800d80b .word 0x0800d80b + 8002368: 0800df27 .word 0x0800df27 + 800236c: 0800e5da .word 0x0800e5da + 8002370: 0800d700 .word 0x0800d700 + 8002374: 0800dec6 .word 0x0800dec6 + 8002378: 0800e5ea .word 0x0800e5ea + 800237c: 0801c040 .word 0x0801c040 + 8002380: 0800d875 .word 0x0800d875 + 8002384: 0800e5fa .word 0x0800e5fa + +08002388 : +// +// This is a one-way trip. Might need power cycle to (fully?) take effect. +// + void +flash_lockdown_hard(uint8_t rdp_level_code) +{ + 8002388: b510 push {r4, lr} + 800238a: 4604 mov r4, r0 +#if RELEASE + flash_setup0(); + 800238c: f7ff fe1c bl 8001fc8 + + // see FLASH_OB_WRPConfig() + + flash_ob_lock(false); + 8002390: 2000 movs r0, #0 + 8002392: f7ff fe55 bl 8002040 + // lock first 128k-8k against any writes + FLASH->WRP1AR = (num_pages_locked << 16); + 8002396: 4b08 ldr r3, [pc, #32] ; (80023b8 ) + 8002398: f44f 2260 mov.w r2, #917504 ; 0xe0000 + 800239c: 62da str r2, [r3, #44] ; 0x2c + FLASH->WRP1BR = 0xff; // unused. + 800239e: 22ff movs r2, #255 ; 0xff + 80023a0: 631a str r2, [r3, #48] ; 0x30 + FLASH->WRP2AR = 0xff; // unused. + 80023a2: 64da str r2, [r3, #76] ; 0x4c + FLASH->WRP2BR = 0xff; // unused. + 80023a4: 651a str r2, [r3, #80] ; 0x50 + // the RDP level is decreased from Level 1 to Level 0)." + // - D-bus access blocked, even for code running inside the PCROP area! (AN4758) + // So literal values and constant tables and such would need special linking. + + // set protection level + uint32_t was = FLASH->OPTR & ~0xff; + 80023a6: 6a1a ldr r2, [r3, #32] + 80023a8: f022 02ff bic.w r2, r2, #255 ; 0xff + FLASH->OPTR = was | rdp_level_code; // select level X, other values as observed + 80023ac: 4322 orrs r2, r4 + 80023ae: 621a str r2, [r3, #32] +#else + puts2("flash_lockdown_hard("); + puthex2(rdp_level_code); + puts(") skipped"); +#endif +} + 80023b0: e8bd 4010 ldmia.w sp!, {r4, lr} + 80023b4: f7ff bddc b.w 8001f70 + 80023b8: 40022000 .word 0x40022000 + +080023bc : + +// record_highwater_version() +// + int +record_highwater_version(const uint8_t timestamp[8]) +{ + 80023bc: b537 push {r0, r1, r2, r4, r5, lr} + const uint8_t *otp = (const uint8_t *)OPT_FLASH_BASE; + + ASSERT(timestamp[0] < 0x40); + ASSERT(timestamp[0] >= 0x10); + 80023be: 7802 ldrb r2, [r0, #0] + 80023c0: 3a10 subs r2, #16 + 80023c2: 2a2f cmp r2, #47 ; 0x2f +{ + 80023c4: 4603 mov r3, r0 + ASSERT(timestamp[0] >= 0x10); + 80023c6: d902 bls.n 80023ce + ASSERT(timestamp[0] < 0x40); + 80023c8: 4810 ldr r0, [pc, #64] ; (800240c ) + 80023ca: f7fe fb3d bl 8000a48 + + uint64_t val = 0; + memcpy(&val, timestamp, 8); + 80023ce: 6800 ldr r0, [r0, #0] + 80023d0: 6859 ldr r1, [r3, #4] + const uint8_t *otp = (const uint8_t *)OPT_FLASH_BASE; + 80023d2: 4c0f ldr r4, [pc, #60] ; (8002410 ) + + // just write to first blank slot we can find. + for(int i=0; i) + memcpy(&val, timestamp, 8); + 80023d6: 466a mov r2, sp + 80023d8: c203 stmia r2!, {r0, r1} + if(check_all_ones(otp, 8)) { + 80023da: 2108 movs r1, #8 + 80023dc: 4620 mov r0, r4 + 80023de: f000 f94f bl 8002680 + 80023e2: b168 cbz r0, 8002400 + // write here. + flash_setup0(); + 80023e4: f7ff fdf0 bl 8001fc8 + flash_unlock(); + 80023e8: f7ff fe12 bl 8002010 + flash_burn((uint32_t)otp, val); + 80023ec: e9dd 2300 ldrd r2, r3, [sp] + 80023f0: 4620 mov r0, r4 + 80023f2: f00b f97d bl 800d6f0 <__flash_burn_veneer> + flash_lock(); + 80023f6: f7ff fe03 bl 8002000 + + return 0; + 80023fa: 2000 movs r0, #0 + } + } + + // no space. + return 1; +} + 80023fc: b003 add sp, #12 + 80023fe: bd30 pop {r4, r5, pc} + for(int i=0; i + return 1; + 8002406: 2001 movs r0, #1 + 8002408: e7f8 b.n 80023fc + 800240a: bf00 nop + 800240c: 0800e3e0 .word 0x0800e3e0 + 8002410: 1fff7000 .word 0x1fff7000 + 8002414: 1fff7400 .word 0x1fff7400 + +08002418 : + +// mcu_key_get() +// + const mcu_key_t * +mcu_key_get(bool *valid) +{ + 8002418: b570 push {r4, r5, r6, lr} + // get current "mcu_key" value; first byte will never be 0x0 or 0xff + // - except if no key set yet/recently wiped + // - if none set, returns ptr to first available slot which will be all ones + const mcu_key_t *ptr = MCU_KEYS, *avail=NULL; + + for(int i=0; i) + const mcu_key_t *ptr = MCU_KEYS, *avail=NULL; + 800241c: 4c0d ldr r4, [pc, #52] ; (8002454 ) +{ + 800241e: 4606 mov r6, r0 + const mcu_key_t *ptr = MCU_KEYS, *avail=NULL; + 8002420: 2500 movs r5, #0 + if(ptr->value[0] == 0xff) { + 8002422: 7823 ldrb r3, [r4, #0] + 8002424: 2bff cmp r3, #255 ; 0xff + 8002426: d10b bne.n 8002440 + if(!avail) { + 8002428: 2d00 cmp r5, #0 + 800242a: bf08 it eq + 800242c: 4625 moveq r5, r4 + for(int i=0; i + *valid = true; + return ptr; + } + } + + rng_delay(); + 8002434: f000 f9a2 bl 800277c + *valid = false; + 8002438: 2300 movs r3, #0 + 800243a: 7033 strb r3, [r6, #0] + return avail; + 800243c: 462c mov r4, r5 + 800243e: e005 b.n 800244c + } else if(ptr->value[0] != 0x00) { + 8002440: 2b00 cmp r3, #0 + 8002442: d0f4 beq.n 800242e + rng_delay(); + 8002444: f000 f99a bl 800277c + *valid = true; + 8002448: 2301 movs r3, #1 + 800244a: 7033 strb r3, [r6, #0] +} + 800244c: 4620 mov r0, r4 + 800244e: bd70 pop {r4, r5, r6, pc} + 8002450: 08020000 .word 0x08020000 + 8002454: 0801e000 .word 0x0801e000 + +08002458 : + +// mcu_key_clear() +// + void +mcu_key_clear(const mcu_key_t *cur) +{ + 8002458: b513 push {r0, r1, r4, lr} + if(!cur) { + 800245a: 4604 mov r4, r0 + 800245c: b938 cbnz r0, 800246e + bool valid; + cur = mcu_key_get(&valid); + 800245e: f10d 0007 add.w r0, sp, #7 + 8002462: f7ff ffd9 bl 8002418 + + if(!valid) return; + 8002466: f89d 3007 ldrb.w r3, [sp, #7] + cur = mcu_key_get(&valid); + 800246a: 4604 mov r4, r0 + if(!valid) return; + 800246c: b1fb cbz r3, 80024ae + } + + // no delays here since decision has been made, and don't + // want to give them more time to interrupt us + flash_setup0(); + 800246e: f7ff fdab bl 8001fc8 + flash_unlock(); + 8002472: f7ff fdcd bl 8002010 + uint32_t pos = (uint32_t)cur; + flash_burn(pos, 0); pos += 8; + 8002476: 2200 movs r2, #0 + 8002478: 2300 movs r3, #0 + 800247a: 4620 mov r0, r4 + 800247c: f00b f938 bl 800d6f0 <__flash_burn_veneer> + flash_burn(pos, 0); pos += 8; + 8002480: 2200 movs r2, #0 + 8002482: 2300 movs r3, #0 + 8002484: f104 0008 add.w r0, r4, #8 + 8002488: f00b f932 bl 800d6f0 <__flash_burn_veneer> + flash_burn(pos, 0); pos += 8; + 800248c: 2200 movs r2, #0 + 800248e: 2300 movs r3, #0 + 8002490: f104 0010 add.w r0, r4, #16 + 8002494: f00b f92c bl 800d6f0 <__flash_burn_veneer> + flash_burn(pos, 0); + 8002498: 2200 movs r2, #0 + 800249a: 2300 movs r3, #0 + 800249c: f104 0018 add.w r0, r4, #24 + 80024a0: f00b f926 bl 800d6f0 <__flash_burn_veneer> + flash_lock(); +} + 80024a4: b002 add sp, #8 + 80024a6: e8bd 4010 ldmia.w sp!, {r4, lr} + flash_lock(); + 80024aa: f7ff bda9 b.w 8002000 +} + 80024ae: b002 add sp, #8 + 80024b0: bd10 pop {r4, pc} + ... + +080024b4 : + +// mcu_key_usage() +// + void +mcu_key_usage(int *avail_out, int *consumed_out, int *total_out) +{ + 80024b4: b5f0 push {r4, r5, r6, r7, lr} + const mcu_key_t *ptr = MCU_KEYS; + int avail = 0, used = 0; + 80024b6: 2300 movs r3, #0 + const mcu_key_t *ptr = MCU_KEYS; + 80024b8: 4c09 ldr r4, [pc, #36] ; (80024e0 ) + + for(int i=0; i) + int avail = 0, used = 0; + 80024bc: 461d mov r5, r3 + if(ptr->value[0] == 0xff) { + 80024be: 7826 ldrb r6, [r4, #0] + 80024c0: 2eff cmp r6, #255 ; 0xff + 80024c2: d109 bne.n 80024d8 + avail ++; + 80024c4: 3501 adds r5, #1 + for(int i=0; i + } else if(ptr->value[0] == 0x00) { + used ++; + } + } + + *avail_out = avail; + 80024cc: 6005 str r5, [r0, #0] + *consumed_out = used; + 80024ce: 600b str r3, [r1, #0] + *total_out = NUM_MCU_KEYS; + 80024d0: f44f 7380 mov.w r3, #256 ; 0x100 + 80024d4: 6013 str r3, [r2, #0] +} + 80024d6: bdf0 pop {r4, r5, r6, r7, pc} + } else if(ptr->value[0] == 0x00) { + 80024d8: 2e00 cmp r6, #0 + 80024da: d1f4 bne.n 80024c6 + used ++; + 80024dc: 3301 adds r3, #1 + 80024de: e7f2 b.n 80024c6 + 80024e0: 0801e000 .word 0x0801e000 + 80024e4: 08020000 .word 0x08020000 + +080024e8 : + +// mcu_key_pick() +// + const mcu_key_t * +mcu_key_pick(void) +{ + 80024e8: b5f0 push {r4, r5, r6, r7, lr} + 80024ea: b08b sub sp, #44 ; 0x2c + mcu_key_t n; + + // get some good entropy, and whiten it just in case. + do { + rng_buffer(n.value, 32); + 80024ec: ad02 add r5, sp, #8 + 80024ee: 2120 movs r1, #32 + 80024f0: 4628 mov r0, r5 + 80024f2: f000 f92d bl 8002750 + sha256_single(n.value, 32, n.value); + 80024f6: 462a mov r2, r5 + 80024f8: 2120 movs r1, #32 + 80024fa: 4628 mov r0, r5 + 80024fc: f003 f82e bl 800555c + sha256_single(n.value, 32, n.value); + 8002500: 462a mov r2, r5 + 8002502: 2120 movs r1, #32 + 8002504: 4628 mov r0, r5 + 8002506: f003 f829 bl 800555c + } while(n.value[0] == 0x0 || n.value[0] == 0xff); + 800250a: f89d 3008 ldrb.w r3, [sp, #8] + 800250e: 3b01 subs r3, #1 + 8002510: b2db uxtb r3, r3 + 8002512: 2bfd cmp r3, #253 ; 0xfd + 8002514: d8eb bhi.n 80024ee + + int err = 0; + const mcu_key_t *cur; + + do { + bool valid = false; + 8002516: 2300 movs r3, #0 + cur = mcu_key_get(&valid); + 8002518: 4668 mov r0, sp + bool valid = false; + 800251a: f88d 3000 strb.w r3, [sp] + cur = mcu_key_get(&valid); + 800251e: f7ff ff7b bl 8002418 + + if(!cur) { + 8002522: 4604 mov r4, r0 + 8002524: b938 cbnz r0, 8002536 + // no free slots. we are brick. + puts("mcu full"); + 8002526: 4828 ldr r0, [pc, #160] ; (80025c8 ) + 8002528: f002 fc40 bl 8004dac + oled_show(screen_brick); + 800252c: 4827 ldr r0, [pc, #156] ; (80025cc ) + 800252e: f7fe fc89 bl 8000e44 + + LOCKUP_FOREVER(); + 8002532: bf30 wfi + 8002534: e7fd b.n 8002532 + } + + if(valid) { + 8002536: f89d 3000 ldrb.w r3, [sp] + 800253a: b14b cbz r3, 8002550 + // clear existing key, if it's defined. + ASSERT(cur->value[0] != 0x00); + 800253c: 7803 ldrb r3, [r0, #0] + 800253e: 3b01 subs r3, #1 + 8002540: b2db uxtb r3, r3 + 8002542: 2bfd cmp r3, #253 ; 0xfd + 8002544: d902 bls.n 800254c + 8002546: 4822 ldr r0, [pc, #136] ; (80025d0 ) + 8002548: f7fe fa7e bl 8000a48 + ASSERT(cur->value[0] != 0xff); + + mcu_key_clear(cur); + 800254c: f7ff ff84 bl 8002458 + continue; + } + } while(0); + + // burn it + flash_setup0(); + 8002550: f7ff fd3a bl 8001fc8 + flash_unlock(); + 8002554: f7ff fd5c bl 8002010 + uint32_t pos = (uint32_t)cur; + const uint8_t *fr = n.value; + + for(int i=0; i<32; i+= 8, pos += 8, fr += 8) { + 8002558: 2700 movs r7, #0 + uint64_t v; + memcpy(&v, fr, sizeof(v)); + 800255a: 19ea adds r2, r5, r7 + 800255c: 59e8 ldr r0, [r5, r7] + 800255e: 6851 ldr r1, [r2, #4] + 8002560: 466b mov r3, sp + 8002562: c303 stmia r3!, {r0, r1} + + err = flash_burn(pos, v); + 8002564: 19e0 adds r0, r4, r7 + 8002566: e9dd 2300 ldrd r2, r3, [sp] + 800256a: f00b f8c1 bl 800d6f0 <__flash_burn_veneer> + if(err) break; + 800256e: 4606 mov r6, r0 + 8002570: b910 cbnz r0, 8002578 + for(int i=0; i<32; i+= 8, pos += 8, fr += 8) { + 8002572: 3708 adds r7, #8 + 8002574: 2f20 cmp r7, #32 + 8002576: d1f0 bne.n 800255a + } + flash_lock(); + 8002578: f7ff fd42 bl 8002000 + + // NOTE: Errors not expected, but lets be graceful about them. + + if(err) { + 800257c: b166 cbz r6, 8002598 + // what to do? + puts("burn fail: "); + 800257e: 4815 ldr r0, [pc, #84] ; (80025d4 ) + 8002580: f002 fc14 bl 8004dac + puthex2(err); + 8002584: b2f0 uxtb r0, r6 + 8002586: f002 fbb5 bl 8004cf4 + putchar('\n'); + 800258a: 200a movs r0, #10 + 800258c: f002 fb94 bl 8004cb8 + return NULL; + } + + if(after != cur || !check_equal(after->value, n.value, 32)) { + puts("bad val?"); + return NULL; + 8002590: 2400 movs r4, #0 + } + + return cur; +} + 8002592: 4620 mov r0, r4 + 8002594: b00b add sp, #44 ; 0x2c + 8002596: bdf0 pop {r4, r5, r6, r7, pc} + const mcu_key_t *after = mcu_key_get(&valid); + 8002598: 4668 mov r0, sp + bool valid = false; + 800259a: f88d 6000 strb.w r6, [sp] + const mcu_key_t *after = mcu_key_get(&valid); + 800259e: f7ff ff3b bl 8002418 + if(!valid) { + 80025a2: f89d 2000 ldrb.w r2, [sp] + 80025a6: b91a cbnz r2, 80025b0 + puts("!valid?"); + 80025a8: 480b ldr r0, [pc, #44] ; (80025d8 ) + puts("bad val?"); + 80025aa: f002 fbff bl 8004dac + 80025ae: e7ef b.n 8002590 + if(after != cur || !check_equal(after->value, n.value, 32)) { + 80025b0: 4284 cmp r4, r0 + 80025b2: d001 beq.n 80025b8 + puts("bad val?"); + 80025b4: 4809 ldr r0, [pc, #36] ; (80025dc ) + 80025b6: e7f8 b.n 80025aa + if(after != cur || !check_equal(after->value, n.value, 32)) { + 80025b8: 2220 movs r2, #32 + 80025ba: 4629 mov r1, r5 + 80025bc: f000 f879 bl 80026b2 + 80025c0: 2800 cmp r0, #0 + 80025c2: d1e6 bne.n 8002592 + 80025c4: e7f6 b.n 80025b4 + 80025c6: bf00 nop + 80025c8: 0800e60b .word 0x0800e60b + 80025cc: 0800d80b .word 0x0800d80b + 80025d0: 0800e3e0 .word 0x0800e3e0 + 80025d4: 0800e614 .word 0x0800e614 + 80025d8: 0800e620 .word 0x0800e620 + 80025dc: 0800e628 .word 0x0800e628 + +080025e0 : + +// fast_brick() +// + void +fast_brick(void) +{ + 80025e0: b538 push {r3, r4, r5, lr} +#ifndef RELEASE + puts2("DISABLED fast brick... "); + oled_show(screen_brick); +#else + // do a fast wipe of our key + mcu_key_clear(NULL); + 80025e2: 2000 movs r0, #0 + 80025e4: f7ff ff38 bl 8002458 + + // brick SE1 for future + ae_brick_myself(); + 80025e8: f001 f970 bl 80038cc + + // NOTE: could brick SE1 (somewhat) by dec'ing the counter, which will + // invalidate all PIN hashes + + // no going back from that -- but for privacy, wipe more stuff + oled_show(screen_brick); + 80025ec: 480e ldr r0, [pc, #56] ; (8002628 ) + uint32_t bot = (uint32_t)MCU_KEYS; + flash_page_erase(bot); + + // 2: LFS area first, since holds settings (AES'ed w/ lost key, but yeah) + // 3: the firmware, not a secret anyway + for(uint32_t pos=(FLASH_BASE + 0x200000 - FLASH_ERASE_SIZE); + 80025ee: 4c0f ldr r4, [pc, #60] ; (800262c ) + 80025f0: 4d0f ldr r5, [pc, #60] ; (8002630 ) + oled_show(screen_brick); + 80025f2: f7fe fc27 bl 8000e44 + puts2("fast brick... "); + 80025f6: 480f ldr r0, [pc, #60] ; (8002634 ) + 80025f8: f002 fb4a bl 8004c90 + flash_setup0(); + 80025fc: f7ff fce4 bl 8001fc8 + flash_unlock(); + 8002600: f7ff fd06 bl 8002010 + flash_page_erase(bot); + 8002604: 480a ldr r0, [pc, #40] ; (8002630 ) + 8002606: f00b f877 bl 800d6f8 <__flash_page_erase_veneer> + pos > bot; pos -= FLASH_ERASE_SIZE) { + flash_page_erase(pos); + 800260a: 4620 mov r0, r4 + pos > bot; pos -= FLASH_ERASE_SIZE) { + 800260c: f5a4 5480 sub.w r4, r4, #4096 ; 0x1000 + flash_page_erase(pos); + 8002610: f00b f872 bl 800d6f8 <__flash_page_erase_veneer> + for(uint32_t pos=(FLASH_BASE + 0x200000 - FLASH_ERASE_SIZE); + 8002614: 42ac cmp r4, r5 + 8002616: d1f8 bne.n 800260a + } + flash_lock(); + puts(" done"); + 8002618: 4807 ldr r0, [pc, #28] ; (8002638 ) + flash_lock(); + 800261a: f7ff fcf1 bl 8002000 + puts(" done"); + 800261e: f002 fbc5 bl 8004dac +#endif + + LOCKUP_FOREVER(); + 8002622: bf30 wfi + 8002624: e7fd b.n 8002622 + 8002626: bf00 nop + 8002628: 0800d80b .word 0x0800d80b + 800262c: 081ff000 .word 0x081ff000 + 8002630: 0801e000 .word 0x0801e000 + 8002634: 0800e631 .word 0x0800e631 + 8002638: 0800e640 .word 0x0800e640 + +0800263c : + +// fast_wipe() +// + void +fast_wipe(void) +{ + 800263c: b508 push {r3, lr} + // dump (part of) the main seed key and become a new Coldcard + // - lots of other code can and will detect a missing MCU key as "blank" + // - and the check value on main seed will be garbage now + mcu_key_clear(NULL); + 800263e: 2000 movs r0, #0 + 8002640: f7ff ff0a bl 8002458 + __ASM volatile ("dsb 0xF":::"memory"); + 8002644: f3bf 8f4f dsb sy + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 8002648: 4905 ldr r1, [pc, #20] ; (8002660 ) + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 800264a: 4b06 ldr r3, [pc, #24] ; (8002664 ) + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 800264c: 68ca ldr r2, [r1, #12] + 800264e: f402 62e0 and.w r2, r2, #1792 ; 0x700 + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 8002652: 4313 orrs r3, r2 + 8002654: 60cb str r3, [r1, #12] + 8002656: f3bf 8f4f dsb sy + __NOP(); + 800265a: bf00 nop + for(;;) /* wait until reset */ + 800265c: e7fd b.n 800265a + 800265e: bf00 nop + 8002660: e000ed00 .word 0xe000ed00 + 8002664: 05fa0004 .word 0x05fa0004 + +08002668 : +check_all_ones_raw(const void *ptrV, int len) +{ + uint8_t rv = 0xff; + const uint8_t *ptr = (const uint8_t *)ptrV; + + for(; len; len--, ptr++) { + 8002668: 4401 add r1, r0 + uint8_t rv = 0xff; + 800266a: 23ff movs r3, #255 ; 0xff + for(; len; len--, ptr++) { + 800266c: 4288 cmp r0, r1 + 800266e: d103 bne.n 8002678 + rv &= *ptr; + } + + return (rv == 0xff); +} + 8002670: 3bff subs r3, #255 ; 0xff + 8002672: 4258 negs r0, r3 + 8002674: 4158 adcs r0, r3 + 8002676: 4770 bx lr + rv &= *ptr; + 8002678: f810 2b01 ldrb.w r2, [r0], #1 + 800267c: 4013 ands r3, r2 + for(; len; len--, ptr++) { + 800267e: e7f5 b.n 800266c + +08002680 : +// +// Return T if all bytes are 0xFF +// + bool +check_all_ones(const void *ptrV, int len) +{ + 8002680: b507 push {r0, r1, r2, lr} + bool rv = check_all_ones_raw(ptrV, len); + 8002682: f7ff fff1 bl 8002668 + 8002686: 9001 str r0, [sp, #4] + + rng_delay(); + 8002688: f000 f878 bl 800277c + + return rv; +} + 800268c: 9801 ldr r0, [sp, #4] + 800268e: b003 add sp, #12 + 8002690: f85d fb04 ldr.w pc, [sp], #4 + +08002694 : +// +// Return T if all bytes are 0x00 +// + bool +check_all_zeros(const void *ptrV, int len) +{ + 8002694: b510 push {r4, lr} + 8002696: 4401 add r1, r0 + uint8_t rv = 0x0; + 8002698: 2400 movs r4, #0 + const uint8_t *ptr = (const uint8_t *)ptrV; + + for(; len; len--, ptr++) { + 800269a: 4288 cmp r0, r1 + 800269c: d105 bne.n 80026aa + rv |= *ptr; + } + + rng_delay(); + 800269e: f000 f86d bl 800277c + return (rv == 0x00); +} + 80026a2: fab4 f084 clz r0, r4 + 80026a6: 0940 lsrs r0, r0, #5 + 80026a8: bd10 pop {r4, pc} + rv |= *ptr; + 80026aa: f810 3b01 ldrb.w r3, [r0], #1 + 80026ae: 431c orrs r4, r3 + for(; len; len--, ptr++) { + 80026b0: e7f3 b.n 800269a + +080026b2 : + const uint8_t *left = (const uint8_t *)aV; + const uint8_t *right = (const uint8_t *)bV; + uint8_t diff = 0; + int i; + + for (i = 0; i < len; i++) { + 80026b2: 2300 movs r3, #0 +{ + 80026b4: b570 push {r4, r5, r6, lr} + uint8_t diff = 0; + 80026b6: 461c mov r4, r3 + for (i = 0; i < len; i++) { + 80026b8: 4293 cmp r3, r2 + 80026ba: db05 blt.n 80026c8 + diff |= (left[i] ^ right[i]); + } + + rng_delay(); + 80026bc: f000 f85e bl 800277c + return (diff == 0); +} + 80026c0: fab4 f084 clz r0, r4 + 80026c4: 0940 lsrs r0, r0, #5 + 80026c6: bd70 pop {r4, r5, r6, pc} + diff |= (left[i] ^ right[i]); + 80026c8: 5cc5 ldrb r5, [r0, r3] + 80026ca: 5cce ldrb r6, [r1, r3] + 80026cc: 4075 eors r5, r6 + 80026ce: 432c orrs r4, r5 + for (i = 0; i < len; i++) { + 80026d0: 3301 adds r3, #1 + 80026d2: e7f1 b.n 80026b8 + +080026d4 : + } + + // Get the new number + uint32_t rv = RNG->DR; + + if(rv != last_rng_result && rv) { + 80026d4: 4b06 ldr r3, [pc, #24] ; (80026f0 ) + while(!(RNG->SR & RNG_FLAG_DRDY)) { + 80026d6: 4a07 ldr r2, [pc, #28] ; (80026f4 ) + if(rv != last_rng_result && rv) { + 80026d8: 6819 ldr r1, [r3, #0] + while(!(RNG->SR & RNG_FLAG_DRDY)) { + 80026da: 6850 ldr r0, [r2, #4] + 80026dc: 07c0 lsls r0, r0, #31 + 80026de: d5fc bpl.n 80026da + uint32_t rv = RNG->DR; + 80026e0: 6890 ldr r0, [r2, #8] + if(rv != last_rng_result && rv) { + 80026e2: 4281 cmp r1, r0 + 80026e4: d0f9 beq.n 80026da + 80026e6: 2800 cmp r0, #0 + 80026e8: d0f7 beq.n 80026da + last_rng_result = rv; + 80026ea: 6018 str r0, [r3, #0] + + // keep trying if not a new number + } + + // NOT-REACHED +} + 80026ec: 4770 bx lr + 80026ee: bf00 nop + 80026f0: 2009e1b8 .word 0x2009e1b8 + 80026f4: 50060800 .word 0x50060800 + +080026f8 : + if(RNG->CR & RNG_CR_RNGEN) { + 80026f8: 4b12 ldr r3, [pc, #72] ; (8002744 ) + 80026fa: 681a ldr r2, [r3, #0] + 80026fc: 0752 lsls r2, r2, #29 +{ + 80026fe: b513 push {r0, r1, r4, lr} + if(RNG->CR & RNG_CR_RNGEN) { + 8002700: d41d bmi.n 800273e + __HAL_RCC_RNG_CLK_ENABLE(); + 8002702: 4a11 ldr r2, [pc, #68] ; (8002748 ) + 8002704: 6cd1 ldr r1, [r2, #76] ; 0x4c + 8002706: f441 2180 orr.w r1, r1, #262144 ; 0x40000 + 800270a: 64d1 str r1, [r2, #76] ; 0x4c + 800270c: 6cd2 ldr r2, [r2, #76] ; 0x4c + 800270e: f402 2280 and.w r2, r2, #262144 ; 0x40000 + 8002712: 9201 str r2, [sp, #4] + 8002714: 9a01 ldr r2, [sp, #4] + RNG->CR |= RNG_CR_RNGEN; + 8002716: 681a ldr r2, [r3, #0] + 8002718: f042 0204 orr.w r2, r2, #4 + 800271c: 601a str r2, [r3, #0] + uint32_t chk = rng_sample(); + 800271e: f7ff ffd9 bl 80026d4 + 8002722: 4604 mov r4, r0 + uint32_t chk2 = rng_sample(); + 8002724: f7ff ffd6 bl 80026d4 + if(chk == 0 || chk == ~0 + 8002728: 1e63 subs r3, r4, #1 + 800272a: 3303 adds r3, #3 + 800272c: d804 bhi.n 8002738 + || chk2 == 0 || chk2 == ~0 + 800272e: 1e43 subs r3, r0, #1 + 8002730: 3303 adds r3, #3 + 8002732: d801 bhi.n 8002738 + || chk == chk2 + 8002734: 4284 cmp r4, r0 + 8002736: d102 bne.n 800273e + INCONSISTENT("bad rng"); + 8002738: 4804 ldr r0, [pc, #16] ; (800274c ) + 800273a: f7fe f985 bl 8000a48 +} + 800273e: b002 add sp, #8 + 8002740: bd10 pop {r4, pc} + 8002742: bf00 nop + 8002744: 50060800 .word 0x50060800 + 8002748: 40021000 .word 0x40021000 + 800274c: 0800d700 .word 0x0800d700 + +08002750 : + +// rng_buffer() +// + void +rng_buffer(uint8_t *result, int len) +{ + 8002750: b573 push {r0, r1, r4, r5, r6, lr} + 8002752: 460c mov r4, r1 + 8002754: 1845 adds r5, r0, r1 + while(len > 0) { + 8002756: 2c00 cmp r4, #0 + 8002758: eba5 0604 sub.w r6, r5, r4 + 800275c: dc01 bgt.n 8002762 + memcpy(result, &t, MIN(4, len)); + + len -= 4; + result += 4; + } +} + 800275e: b002 add sp, #8 + 8002760: bd70 pop {r4, r5, r6, pc} + uint32_t t = rng_sample(); + 8002762: f7ff ffb7 bl 80026d4 + memcpy(result, &t, MIN(4, len)); + 8002766: 2c04 cmp r4, #4 + 8002768: 4622 mov r2, r4 + uint32_t t = rng_sample(); + 800276a: 9001 str r0, [sp, #4] + memcpy(result, &t, MIN(4, len)); + 800276c: bfa8 it ge + 800276e: 2204 movge r2, #4 + 8002770: a901 add r1, sp, #4 + 8002772: 4630 mov r0, r6 + 8002774: f00a ff56 bl 800d624 + len -= 4; + 8002778: 3c04 subs r4, #4 + result += 4; + 800277a: e7ec b.n 8002756 + +0800277c : +// +// Call anytime. Delays for a random time period to fustrate glitchers. +// + void +rng_delay(void) +{ + 800277c: b508 push {r3, lr} + uint32_t r = rng_sample() % 8; + 800277e: f7ff ffa9 bl 80026d4 + uint32_t cnt = (1< + cnt--; + } +} + 8002792: bd08 pop {r3, pc} + +08002794 <_send_byte>: + static inline void +_send_byte(uint8_t ch) +{ + // reset timeout timer (Systick) + uint32_t ticks = 0; + SysTick->VAL = 0; + 8002794: f04f 22e0 mov.w r2, #3758153728 ; 0xe000e000 +{ + 8002798: b510 push {r4, lr} + SysTick->VAL = 0; + 800279a: 2300 movs r3, #0 + + while(!(MY_UART->ISR & UART_FLAG_TXE)) { + 800279c: 4c07 ldr r4, [pc, #28] ; (80027bc <_send_byte+0x28>) + SysTick->VAL = 0; + 800279e: 6193 str r3, [r2, #24] + while(!(MY_UART->ISR & UART_FLAG_TXE)) { + 80027a0: 230b movs r3, #11 + 80027a2: 69e1 ldr r1, [r4, #28] + 80027a4: 0609 lsls r1, r1, #24 + 80027a6: d404 bmi.n 80027b2 <_send_byte+0x1e> + // busy-wait until able to send (no fifo?) + if(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) { + 80027a8: 6911 ldr r1, [r2, #16] + 80027aa: 03c9 lsls r1, r1, #15 + 80027ac: d5f9 bpl.n 80027a2 <_send_byte+0xe> + // failsafe timeout + ticks += 1; + if(ticks > 10) break; + 80027ae: 3b01 subs r3, #1 + 80027b0: d1f7 bne.n 80027a2 <_send_byte+0xe> + } + } + MY_UART->TDR = ch; + 80027b2: 4b02 ldr r3, [pc, #8] ; (80027bc <_send_byte+0x28>) + 80027b4: b280 uxth r0, r0 + 80027b6: 8518 strh r0, [r3, #40] ; 0x28 +} + 80027b8: bd10 pop {r4, pc} + 80027ba: bf00 nop + 80027bc: 40004c00 .word 0x40004c00 + +080027c0 <_send_bits>: + +// _send_bits() +// + static void +_send_bits(uint8_t tx) +{ + 80027c0: b570 push {r4, r5, r6, lr} + 80027c2: 4606 mov r6, r0 + 80027c4: 2508 movs r5, #8 + // serialize and send one byte + uint8_t mask = 0x1; + 80027c6: 2401 movs r4, #1 + + for(int i=0; i<8; i++, mask <<= 1) { + uint8_t h = (tx & mask) ? BIT1 : BIT0; + 80027c8: 4226 tst r6, r4 + + _send_byte(h); + 80027ca: bf14 ite ne + 80027cc: 207f movne r0, #127 ; 0x7f + 80027ce: 207d moveq r0, #125 ; 0x7d + 80027d0: f7ff ffe0 bl 8002794 <_send_byte> + for(int i=0; i<8; i++, mask <<= 1) { + 80027d4: 0064 lsls r4, r4, #1 + 80027d6: 3d01 subs r5, #1 + 80027d8: b2e4 uxtb r4, r4 + 80027da: d1f5 bne.n 80027c8 <_send_bits+0x8> + } +} + 80027dc: bd70 pop {r4, r5, r6, pc} + +080027de <_send_serialized>: + +// _send_serialized() +// + static void +_send_serialized(const uint8_t *buf, int len) +{ + 80027de: b538 push {r3, r4, r5, lr} + 80027e0: 4604 mov r4, r0 + 80027e2: 1845 adds r5, r0, r1 + for(int i=0; i + for(int i=0; i + } +} + 80027f0: bd38 pop {r3, r4, r5, pc} + ... + +080027f4 <_flush_rx>: +// + static inline void +_flush_rx(void) +{ + // reset timeout timer (Systick) + SysTick->VAL = 0; + 80027f4: f04f 23e0 mov.w r3, #3758153728 ; 0xe000e000 + 80027f8: 2200 movs r2, #0 + + while(!(MY_UART->ISR & UART_FLAG_TC)) { + 80027fa: 490b ldr r1, [pc, #44] ; (8002828 <_flush_rx+0x34>) + SysTick->VAL = 0; + 80027fc: 619a str r2, [r3, #24] + while(!(MY_UART->ISR & UART_FLAG_TC)) { + 80027fe: 69ca ldr r2, [r1, #28] + 8002800: 0652 lsls r2, r2, #25 + 8002802: d402 bmi.n 800280a <_flush_rx+0x16> + // wait for last bit(byte) to be serialized and sent + + if(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) { + 8002804: 691a ldr r2, [r3, #16] + 8002806: 03d0 lsls r0, r2, #15 + 8002808: d5f9 bpl.n 80027fe <_flush_rx+0xa> + break; + } + } + + // We actually need this delay here! + __NOP(); + 800280a: bf00 nop + __NOP(); + 800280c: bf00 nop + __NOP(); + 800280e: bf00 nop + __NOP(); + 8002810: bf00 nop + __NOP(); + 8002812: bf00 nop + __NOP(); + 8002814: bf00 nop + __NOP(); + 8002816: bf00 nop + __NOP(); + 8002818: bf00 nop + + // clear junk in rx buffer + MY_UART->RQR = USART_RQR_RXFRQ; + 800281a: 4b03 ldr r3, [pc, #12] ; (8002828 <_flush_rx+0x34>) + 800281c: 2208 movs r2, #8 + 800281e: 831a strh r2, [r3, #24] + + // clear overrun error + // clear rx timeout flag + // clear framing error + MY_UART->ICR = USART_ICR_ORECF | USART_ICR_RTOCF | USART_ICR_FECF; + 8002820: f640 020a movw r2, #2058 ; 0x80a + 8002824: 621a str r2, [r3, #32] +} + 8002826: 4770 bx lr + 8002828: 40004c00 .word 0x40004c00 + +0800282c : + uint16_t crc_register = 0; + uint16_t polynom = 0x8005; + uint8_t shift_register; + uint8_t data_bit, crc_bit; + + crc_register = (((uint16_t) crc[0]) & 0x00FF) | (((uint16_t) crc[1]) << 8); + 800282c: 8813 ldrh r3, [r2, #0] +{ + 800282e: b5f0 push {r4, r5, r6, r7, lr} + 8002830: 4408 add r0, r1 + + // Shift CRC to the left by 1. + crc_register <<= 1; + + if ((data_bit ^ crc_bit) != 0) + crc_register ^= polynom; + 8002832: f248 0605 movw r6, #32773 ; 0x8005 + for (counter = 0; counter < length; counter++) { + 8002836: 4281 cmp r1, r0 + 8002838: d103 bne.n 8002842 + } + } + + crc[0] = (uint8_t) (crc_register & 0x00FF); + 800283a: 7013 strb r3, [r2, #0] + crc[1] = (uint8_t) (crc_register >> 8); + 800283c: 0a1b lsrs r3, r3, #8 + 800283e: 7053 strb r3, [r2, #1] +} + 8002840: bdf0 pop {r4, r5, r6, r7, pc} + data_bit = (data[counter] & shift_register) ? 1 : 0; + 8002842: f811 7b01 ldrb.w r7, [r1], #1 + 8002846: 2508 movs r5, #8 + for (shift_register = 0x01; shift_register > 0x00; shift_register <<= 1) { + 8002848: 2401 movs r4, #1 + data_bit = (data[counter] & shift_register) ? 1 : 0; + 800284a: 4227 tst r7, r4 + crc_bit = crc_register >> 15; + 800284c: ea4f 3cd3 mov.w ip, r3, lsr #15 + if ((data_bit ^ crc_bit) != 0) + 8002850: bf18 it ne + 8002852: f04f 0e01 movne.w lr, #1 + crc_register <<= 1; + 8002856: ea4f 0343 mov.w r3, r3, lsl #1 + if ((data_bit ^ crc_bit) != 0) + 800285a: bf08 it eq + 800285c: f04f 0e00 moveq.w lr, #0 + 8002860: 45e6 cmp lr, ip + crc_register <<= 1; + 8002862: b29b uxth r3, r3 + crc_register ^= polynom; + 8002864: bf18 it ne + 8002866: 4073 eorne r3, r6 + for (shift_register = 0x01; shift_register > 0x00; shift_register <<= 1) { + 8002868: 0064 lsls r4, r4, #1 + 800286a: 3d01 subs r5, #1 + 800286c: b2e4 uxtb r4, r4 + 800286e: d1ec bne.n 800284a + 8002870: e7e1 b.n 8002836 + +08002872 : + +// ae_check_crc() +// + static bool +ae_check_crc(const uint8_t *data, uint8_t length) +{ + 8002872: b573 push {r0, r1, r4, r5, r6, lr} + uint8_t obs[2] = { 0, 0 }; + + if(data[0] != length) { + 8002874: 7806 ldrb r6, [r0, #0] + uint8_t obs[2] = { 0, 0 }; + 8002876: 2400 movs r4, #0 + if(data[0] != length) { + 8002878: 428e cmp r6, r1 +{ + 800287a: 4605 mov r5, r0 + uint8_t obs[2] = { 0, 0 }; + 800287c: f8ad 4004 strh.w r4, [sp, #4] + if(data[0] != length) { + 8002880: d113 bne.n 80028aa + // length is wrong + STATS(crc_len_error++); + return false; + } + + crc16_chain(length-2, data, obs); + 8002882: 4629 mov r1, r5 + 8002884: 1eb0 subs r0, r6, #2 + + return (obs[0] == data[length-2] && obs[1] == data[length-1]); + 8002886: 4435 add r5, r6 + crc16_chain(length-2, data, obs); + 8002888: aa01 add r2, sp, #4 + 800288a: b2c0 uxtb r0, r0 + 800288c: f7ff ffce bl 800282c + return (obs[0] == data[length-2] && obs[1] == data[length-1]); + 8002890: f89d 2004 ldrb.w r2, [sp, #4] + 8002894: f815 3c02 ldrb.w r3, [r5, #-2] + 8002898: 429a cmp r2, r3 + 800289a: d106 bne.n 80028aa + 800289c: f815 4c01 ldrb.w r4, [r5, #-1] + 80028a0: f89d 0005 ldrb.w r0, [sp, #5] + 80028a4: 1a23 subs r3, r4, r0 + 80028a6: 425c negs r4, r3 + 80028a8: 415c adcs r4, r3 + return false; + 80028aa: 4620 mov r0, r4 +} + 80028ac: b002 add sp, #8 + 80028ae: bd70 pop {r4, r5, r6, pc} + +080028b0 : +{ + 80028b0: b508 push {r3, lr} + _send_byte(0x00); + 80028b2: 2000 movs r0, #0 + 80028b4: f7ff ff6e bl 8002794 <_send_byte> + delay_ms(3); // measured: ~2.9ms + 80028b8: 2003 movs r0, #3 + 80028ba: f001 f81d bl 80038f8 +} + 80028be: e8bd 4008 ldmia.w sp!, {r3, lr} + _flush_rx(); + 80028c2: f7ff bf97 b.w 80027f4 <_flush_rx> + +080028c6 : +{ + 80028c6: b508 push {r3, lr} + ae_wake(); + 80028c8: f7ff fff2 bl 80028b0 +} + 80028cc: e8bd 4008 ldmia.w sp!, {r3, lr} + _send_bits(IOFLAG_IDLE); + 80028d0: 20bb movs r0, #187 ; 0xbb + 80028d2: f7ff bf75 b.w 80027c0 <_send_bits> + ... + +080028d8 : +{ + 80028d8: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + int max_expect = (max_len+1) * 8; + 80028dc: 3101 adds r1, #1 + uint8_t raw[max_expect]; + 80028de: 466b mov r3, sp + 80028e0: eba3 03c1 sub.w r3, r3, r1, lsl #3 +{ + 80028e4: af00 add r7, sp, #0 + 80028e6: 4606 mov r6, r0 + uint8_t raw[max_expect]; + 80028e8: 469d mov sp, r3 + _send_bits(IOFLAG_TX); + 80028ea: 2088 movs r0, #136 ; 0x88 + int max_expect = (max_len+1) * 8; + 80028ec: 00cd lsls r5, r1, #3 + _send_bits(IOFLAG_TX); + 80028ee: f7ff ff67 bl 80027c0 <_send_bits> + _flush_rx(); + 80028f2: f7ff ff7f bl 80027f4 <_flush_rx> + int actual = 0; + 80028f6: 2200 movs r2, #0 + while(!(MY_UART->ISR & UART_FLAG_RXNE) && !(MY_UART->ISR & UART_FLAG_RTOF)) { + 80028f8: 4829 ldr r0, [pc, #164] ; (80029a0 ) + uint8_t raw[max_expect]; + 80028fa: 466c mov r4, sp + for(uint8_t *p = raw; ; actual++) { + 80028fc: 4669 mov r1, sp + SysTick->VAL = 0; + 80028fe: f04f 2ce0 mov.w ip, #3758153728 ; 0xe000e000 + 8002902: 4696 mov lr, r2 + 8002904: f8cc e018 str.w lr, [ip, #24] + while(!(MY_UART->ISR & UART_FLAG_RXNE) && !(MY_UART->ISR & UART_FLAG_RTOF)) { + 8002908: 2305 movs r3, #5 + 800290a: f8d0 801c ldr.w r8, [r0, #28] + 800290e: f018 0f20 tst.w r8, #32 + 8002912: d104 bne.n 800291e + 8002914: f8d0 801c ldr.w r8, [r0, #28] + 8002918: f418 6f00 tst.w r8, #2048 ; 0x800 + 800291c: d008 beq.n 8002930 + if(MY_UART->ISR & UART_FLAG_RXNE) { + 800291e: 69c3 ldr r3, [r0, #28] + 8002920: 069b lsls r3, r3, #26 + 8002922: d52e bpl.n 8002982 + return MY_UART->RDR & 0x7f; + 8002924: 8c83 ldrh r3, [r0, #36] ; 0x24 + if(actual < max_expect) { + 8002926: 42aa cmp r2, r5 + return MY_UART->RDR & 0x7f; + 8002928: b29b uxth r3, r3 + if(actual < max_expect) { + 800292a: db34 blt.n 8002996 + for(uint8_t *p = raw; ; actual++) { + 800292c: 3201 adds r2, #1 + 800292e: e7e9 b.n 8002904 + if(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) { + 8002930: f8dc 8010 ldr.w r8, [ip, #16] + 8002934: f418 3f80 tst.w r8, #65536 ; 0x10000 + 8002938: d0e7 beq.n 800290a + if(ticks >= 5) { + 800293a: 3b01 subs r3, #1 + 800293c: d1e5 bne.n 800290a + actual &= ~7; + 800293e: f022 0107 bic.w r1, r2, #7 + while(from_len > 0) { + 8002942: 3d08 subs r5, #8 + 8002944: 4425 add r5, r4 + 8002946: 4623 mov r3, r4 + 8002948: 4421 add r1, r4 + 800294a: 1ac8 subs r0, r1, r3 + 800294c: 2800 cmp r0, #0 + 800294e: dd14 ble.n 800297a + 8002950: f103 3cff add.w ip, r3, #4294967295 ; 0xffffffff + uint8_t rv = 0, mask = 0x1; + 8002954: 2001 movs r0, #1 + 8002956: 2400 movs r4, #0 + for(int i=0; i<8; i++, mask <<= 1) { + 8002958: f103 0e07 add.w lr, r3, #7 + if(from[i] == BIT1) { + 800295c: f81c 8f01 ldrb.w r8, [ip, #1]! + 8002960: f1b8 0f7f cmp.w r8, #127 ; 0x7f + rv |= mask; + 8002964: bf08 it eq + 8002966: 4304 orreq r4, r0 + for(int i=0; i<8; i++, mask <<= 1) { + 8002968: 0040 lsls r0, r0, #1 + 800296a: 45f4 cmp ip, lr + 800296c: b2c0 uxtb r0, r0 + 800296e: d1f5 bne.n 800295c + from += 8; + 8002970: 3308 adds r3, #8 + if(max_into <= 0) break; + 8002972: 42ab cmp r3, r5 + *(into++) = rv; + 8002974: f806 4b01 strb.w r4, [r6], #1 + if(max_into <= 0) break; + 8002978: d1e7 bne.n 800294a + return actual / 8; + 800297a: 10d0 asrs r0, r2, #3 +} + 800297c: 46bd mov sp, r7 + 800297e: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + if(MY_UART->ISR & UART_FLAG_RTOF) { + 8002982: 69c3 ldr r3, [r0, #28] + 8002984: 051b lsls r3, r3, #20 + 8002986: d503 bpl.n 8002990 + MY_UART->ICR = USART_ICR_RTOCF; + 8002988: f44f 6300 mov.w r3, #2048 ; 0x800 + 800298c: 6203 str r3, [r0, #32] + if(ch < 0) { + 800298e: e7d6 b.n 800293e + INCONSISTENT("rxf"); + 8002990: 4804 ldr r0, [pc, #16] ; (80029a4 ) + 8002992: f7fe f859 bl 8000a48 + *(p++) = ch; + 8002996: f003 037f and.w r3, r3, #127 ; 0x7f + 800299a: f801 3b01 strb.w r3, [r1], #1 + 800299e: e7c5 b.n 800292c + 80029a0: 40004c00 .word 0x40004c00 + 80029a4: 0800d700 .word 0x0800d700 + +080029a8 : + if(ae_chip_is_setup == AE_CHIP_IS_SETUP) { + 80029a8: 4b04 ldr r3, [pc, #16] ; (80029bc ) + 80029aa: 681a ldr r2, [r3, #0] + 80029ac: 4b04 ldr r3, [pc, #16] ; (80029c0 ) + 80029ae: 429a cmp r2, r3 + 80029b0: d102 bne.n 80029b8 + _send_bits(IOFLAG_SLEEP); + 80029b2: 20cc movs r0, #204 ; 0xcc + 80029b4: f7ff bf04 b.w 80027c0 <_send_bits> +} + 80029b8: 4770 bx lr + 80029ba: bf00 nop + 80029bc: 2009e1bc .word 0x2009e1bc + 80029c0: 35d25d63 .word 0x35d25d63 + +080029c4 : + __HAL_RCC_UART4_CLK_ENABLE(); + 80029c4: 4b13 ldr r3, [pc, #76] ; (8002a14 ) + 80029c6: 6d9a ldr r2, [r3, #88] ; 0x58 + 80029c8: f442 2200 orr.w r2, r2, #524288 ; 0x80000 + 80029cc: 659a str r2, [r3, #88] ; 0x58 + 80029ce: 6d9b ldr r3, [r3, #88] ; 0x58 +{ + 80029d0: b082 sub sp, #8 + __HAL_RCC_UART4_CLK_ENABLE(); + 80029d2: f403 2300 and.w r3, r3, #524288 ; 0x80000 + 80029d6: 9301 str r3, [sp, #4] + 80029d8: 9b01 ldr r3, [sp, #4] + MY_UART->CR1 = 0; + 80029da: 4b0f ldr r3, [pc, #60] ; (8002a18 ) + 80029dc: 2200 movs r2, #0 + 80029de: 601a str r2, [r3, #0] + MY_UART->CR1 = 0x1000002d & ~(0 + 80029e0: 4a0e ldr r2, [pc, #56] ; (8002a1c ) + 80029e2: 601a str r2, [r3, #0] + MY_UART->RTOR = 24; // timeout in bit periods: 3 chars or so + 80029e4: 2218 movs r2, #24 + 80029e6: 615a str r2, [r3, #20] + MY_UART->CR2 = USART_CR2_RTOEN; // rx timeout enable + 80029e8: f44f 0200 mov.w r2, #8388608 ; 0x800000 + 80029ec: 605a str r2, [r3, #4] + MY_UART->CR3 = USART_CR3_HDSEL | USART_CR3_ONEBIT; + 80029ee: f640 0208 movw r2, #2056 ; 0x808 + 80029f2: 609a str r2, [r3, #8] + MY_UART->BRR = 521; // 230400 bps @ 120 Mhz SYSCLK + 80029f4: f240 2209 movw r2, #521 ; 0x209 + 80029f8: 60da str r2, [r3, #12] + MY_UART->ICR = USART_ICR_RTOCF; + 80029fa: f44f 6200 mov.w r2, #2048 ; 0x800 + 80029fe: 621a str r2, [r3, #32] + MY_UART->CR1 |= USART_CR1_UE; + 8002a00: 681a ldr r2, [r3, #0] + 8002a02: f042 0201 orr.w r2, r2, #1 + 8002a06: 601a str r2, [r3, #0] + ae_chip_is_setup = AE_CHIP_IS_SETUP; + 8002a08: 4b05 ldr r3, [pc, #20] ; (8002a20 ) + 8002a0a: 4a06 ldr r2, [pc, #24] ; (8002a24 ) + 8002a0c: 601a str r2, [r3, #0] +} + 8002a0e: b002 add sp, #8 + 8002a10: 4770 bx lr + 8002a12: bf00 nop + 8002a14: 40021000 .word 0x40021000 + 8002a18: 40004c00 .word 0x40004c00 + 8002a1c: 1000002c .word 0x1000002c + 8002a20: 2009e1bc .word 0x2009e1bc + 8002a24: 35d25d63 .word 0x35d25d63 + +08002a28 : + ae_send_idle(); + 8002a28: f7ff bf4d b.w 80028c6 + +08002a2c : +// Read a one-byte status/error code response from chip. It's wrapped as 4 bytes: +// (len=4) (value) (crc16) (crc16) +// + int +ae_read1(void) +{ + 8002a2c: b513 push {r0, r1, r4, lr} + 8002a2e: 2408 movs r4, #8 + uint8_t msg[4]; + + for(int retry=7; retry >= 0; retry--) { + // tell it we want to read a response, read it, and deserialize + int rv = ae_read_response(msg, 4); + 8002a30: 2104 movs r1, #4 + 8002a32: eb0d 0001 add.w r0, sp, r1 + 8002a36: f7ff ff4f bl 80028d8 + + if(rv == 0) { + 8002a3a: 4601 mov r1, r0 + 8002a3c: b938 cbnz r0, 8002a4e + // nothing heard, it's probably still processing + ERR("not rdy"); + STATS(not_ready++); + + delay_ms(5); + 8002a3e: 2005 movs r0, #5 + 8002a40: f000 ff5a bl 80038f8 + for(int retry=7; retry >= 0; retry--) { + 8002a44: 3c01 subs r4, #1 + 8002a46: d1f3 bne.n 8002a30 + try_again: + STATS(l1_retry++); + } + + // fail. + return -1; + 8002a48: f04f 30ff mov.w r0, #4294967295 ; 0xffffffff + 8002a4c: e008 b.n 8002a60 + if(rv != 4) { + 8002a4e: 2804 cmp r0, #4 + 8002a50: d1f8 bne.n 8002a44 + if(!ae_check_crc(msg, 4)) { + 8002a52: a801 add r0, sp, #4 + 8002a54: f7ff ff0d bl 8002872 + 8002a58: 2800 cmp r0, #0 + 8002a5a: d0f3 beq.n 8002a44 + return msg[1]; + 8002a5c: f89d 0005 ldrb.w r0, [sp, #5] +} + 8002a60: b002 add sp, #8 + 8002a62: bd10 pop {r4, pc} + +08002a64 : +// Read and check CRC over N bytes, wrapped in 3-bytes of framing overhead. +// Return -1 for timeout, zero for normal, and one-byte error code otherwise. +// + int +ae_read_n(uint8_t len, uint8_t *body) +{ + 8002a64: e92d 43f8 stmdb sp!, {r3, r4, r5, r6, r7, r8, r9, lr} + uint8_t tmp[1+len+2]; + 8002a68: f100 030a add.w r3, r0, #10 + 8002a6c: f403 73fc and.w r3, r3, #504 ; 0x1f8 +{ + 8002a70: af00 add r7, sp, #0 + uint8_t tmp[1+len+2]; + 8002a72: ebad 0d03 sub.w sp, sp, r3 +{ + 8002a76: 460d mov r5, r1 + uint8_t tmp[1+len+2]; + 8002a78: 1cc6 adds r6, r0, #3 + 8002a7a: 46e8 mov r8, sp + 8002a7c: f04f 0908 mov.w r9, #8 + + for(int retry=7; retry >= 0; retry--) { + + int actual = ae_read_response(tmp, len+3); + 8002a80: 4631 mov r1, r6 + 8002a82: 4640 mov r0, r8 + 8002a84: f7ff ff28 bl 80028d8 + if(actual < 4) { + 8002a88: 2803 cmp r0, #3 + int actual = ae_read_response(tmp, len+3); + 8002a8a: 4604 mov r4, r0 + if(actual < 4) { + 8002a8c: dc0b bgt.n 8002aa6 + + if(actual == 0) { + 8002a8e: b910 cbnz r0, 8002a96 + // nothing heard, it's probably still processing + delay_ms(5); + 8002a90: 2005 movs r0, #5 + 8002a92: f000 ff31 bl 80038f8 + + return 0; + + try_again: + STATS(ln_retry++); + ae_wake(); + 8002a96: f7ff ff0b bl 80028b0 + for(int retry=7; retry >= 0; retry--) { + 8002a9a: f1b9 0901 subs.w r9, r9, #1 + 8002a9e: d1ef bne.n 8002a80 + } + + return -1; + 8002aa0: f04f 30ff mov.w r0, #4294967295 ; 0xffffffff + 8002aa4: e007 b.n 8002ab6 + uint8_t resp_len = tmp[0]; + 8002aa6: f898 3000 ldrb.w r3, [r8] + if(resp_len != (len + 3)) { + 8002aaa: 42b3 cmp r3, r6 + 8002aac: d006 beq.n 8002abc + if(resp_len == 4) { + 8002aae: 2b04 cmp r3, #4 + 8002ab0: d1f1 bne.n 8002a96 + return tmp[1]; + 8002ab2: f898 0001 ldrb.w r0, [r8, #1] +} + 8002ab6: 46bd mov sp, r7 + 8002ab8: e8bd 83f8 ldmia.w sp!, {r3, r4, r5, r6, r7, r8, r9, pc} + if(!ae_check_crc(tmp, actual)) { + 8002abc: b2c1 uxtb r1, r0 + 8002abe: 4640 mov r0, r8 + 8002ac0: f7ff fed7 bl 8002872 + 8002ac4: 2800 cmp r0, #0 + 8002ac6: d0e6 beq.n 8002a96 + memcpy(body, tmp+1, actual-3); + 8002ac8: 1ee2 subs r2, r4, #3 + 8002aca: f108 0101 add.w r1, r8, #1 + 8002ace: 4628 mov r0, r5 + 8002ad0: f00a fda8 bl 800d624 + return 0; + 8002ad4: 2000 movs r0, #0 + 8002ad6: e7ee b.n 8002ab6 + +08002ad8 : + +// ae_send_n() +// + void +ae_send_n(aeopcode_t opcode, uint8_t p1, uint16_t p2, const uint8_t *data, uint8_t data_len) +{ + 8002ad8: b530 push {r4, r5, lr} + 8002ada: b085 sub sp, #20 + 8002adc: 461d mov r5, r3 + 8002ade: f89d 4020 ldrb.w r4, [sp, #32] + uint8_t framed_len; + uint8_t op; + uint8_t p1; + uint8_t p2_lsb; + uint8_t p2_msb; + } known = { + 8002ae2: f88d 200c strb.w r2, [sp, #12] + 8002ae6: 2377 movs r3, #119 ; 0x77 + 8002ae8: 0a12 lsrs r2, r2, #8 + 8002aea: f88d 3008 strb.w r3, [sp, #8] + .ioflag = IOFLAG_CMD, + .framed_len = (data_len + 7), // 7 = (1 len) + (4 bytes of msg) + (2 crc) + 8002aee: 1de3 adds r3, r4, #7 + } known = { + 8002af0: f88d 3009 strb.w r3, [sp, #9] + 8002af4: f88d 200d strb.w r2, [sp, #13] + 8002af8: f88d 000a strb.w r0, [sp, #10] + 8002afc: f88d 100b strb.w r1, [sp, #11] + STATS(last_op = opcode); + STATS(last_p1 = p1); + STATS(last_p2 = p2); + + // important to wake chip at this point. + ae_wake(); + 8002b00: f7ff fed6 bl 80028b0 + + _send_serialized((const uint8_t *)&known, sizeof(known)); + 8002b04: 2106 movs r1, #6 + 8002b06: a802 add r0, sp, #8 + 8002b08: f7ff fe69 bl 80027de <_send_serialized> + + // CRC will start from frame_len onwards + uint8_t crc[2] = {0, 0}; + 8002b0c: 2300 movs r3, #0 + crc16_chain(sizeof(known)-1, &known.framed_len, crc); + 8002b0e: aa01 add r2, sp, #4 + 8002b10: f10d 0109 add.w r1, sp, #9 + 8002b14: 2005 movs r0, #5 + uint8_t crc[2] = {0, 0}; + 8002b16: f8ad 3004 strh.w r3, [sp, #4] + crc16_chain(sizeof(known)-1, &known.framed_len, crc); + 8002b1a: f7ff fe87 bl 800282c + + // insert a variable-length body area (sometimes) + if(data_len) { + 8002b1e: b144 cbz r4, 8002b32 + _send_serialized(data, data_len); + 8002b20: 4621 mov r1, r4 + 8002b22: 4628 mov r0, r5 + 8002b24: f7ff fe5b bl 80027de <_send_serialized> + + crc16_chain(data_len, data, crc); + 8002b28: aa01 add r2, sp, #4 + 8002b2a: 4629 mov r1, r5 + 8002b2c: 4620 mov r0, r4 + 8002b2e: f7ff fe7d bl 800282c + } + + // send final CRC bytes + _send_serialized(crc, 2); + 8002b32: 2102 movs r1, #2 + 8002b34: a801 add r0, sp, #4 + 8002b36: f7ff fe52 bl 80027de <_send_serialized> +} + 8002b3a: b005 add sp, #20 + 8002b3c: bd30 pop {r4, r5, pc} + +08002b3e : +{ + 8002b3e: b507 push {r0, r1, r2, lr} + ae_send_n(opcode, p1, p2, NULL, 0); + 8002b40: 2300 movs r3, #0 + 8002b42: 9300 str r3, [sp, #0] + 8002b44: f7ff ffc8 bl 8002ad8 +} + 8002b48: b003 add sp, #12 + 8002b4a: f85d fb04 ldr.w pc, [sp], #4 + +08002b4e : +// +// Do Info(p1=2) command, and return result. +// + uint16_t +ae_get_info(void) +{ + 8002b4e: b507 push {r0, r1, r2, lr} + // not doing error checking here + ae_send(OP_Info, 0x2, 0); + 8002b50: 2200 movs r2, #0 + 8002b52: 2102 movs r1, #2 + 8002b54: 2030 movs r0, #48 ; 0x30 + 8002b56: f7ff fff2 bl 8002b3e + + // note: always returns 4 bytes, but most are garbage and unused. + uint8_t tmp[4]; + ae_read_n(4, tmp); + 8002b5a: a901 add r1, sp, #4 + 8002b5c: 2004 movs r0, #4 + 8002b5e: f7ff ff81 bl 8002a64 + + return (tmp[0] << 8) | tmp[1]; + 8002b62: f8bd 0004 ldrh.w r0, [sp, #4] + 8002b66: ba40 rev16 r0, r0 +} + 8002b68: b280 uxth r0, r0 + 8002b6a: b003 add sp, #12 + 8002b6c: f85d fb04 ldr.w pc, [sp], #4 + +08002b70 : +// Load Tempkey with a specific value. Resulting Tempkey cannot be +// used with many commands/keys, but is needed for signing. +// + int +ae_load_nonce(const uint8_t nonce[32]) +{ + 8002b70: b507 push {r0, r1, r2, lr} + // p1=3 + ae_send_n(OP_Nonce, 3, 0, nonce, 32); // 608a ok + 8002b72: 2220 movs r2, #32 +{ + 8002b74: 4603 mov r3, r0 + ae_send_n(OP_Nonce, 3, 0, nonce, 32); // 608a ok + 8002b76: 9200 str r2, [sp, #0] + 8002b78: 2103 movs r1, #3 + 8002b7a: 2200 movs r2, #0 + 8002b7c: 2016 movs r0, #22 + 8002b7e: f7ff ffab bl 8002ad8 + + return ae_read1(); +} + 8002b82: b003 add sp, #12 + 8002b84: f85d eb04 ldr.w lr, [sp], #4 + return ae_read1(); + 8002b88: f7ff bf50 b.w 8002a2c + +08002b8c : +// Load 32bytes of message digest with a specific value. +// Needed for signing. +// + int +ae_load_msgdigest(const uint8_t md[32]) +{ + 8002b8c: b507 push {r0, r1, r2, lr} + ae_send_n(OP_Nonce, (1<<6) | 3, 0, md, 32); + 8002b8e: 2220 movs r2, #32 +{ + 8002b90: 4603 mov r3, r0 + ae_send_n(OP_Nonce, (1<<6) | 3, 0, md, 32); + 8002b92: 9200 str r2, [sp, #0] + 8002b94: 2143 movs r1, #67 ; 0x43 + 8002b96: 2200 movs r2, #0 + 8002b98: 2016 movs r0, #22 + 8002b9a: f7ff ff9d bl 8002ad8 + + return ae_read1(); +} + 8002b9e: b003 add sp, #12 + 8002ba0: f85d eb04 ldr.w lr, [sp], #4 + return ae_read1(); + 8002ba4: f7ff bf42 b.w 8002a2c + +08002ba8 : +// Load Tempkey with a nonce value that we both know, but +// is random and we both know is random! Tricky! +// + int +ae_pick_nonce(const uint8_t num_in[20], uint8_t tempkey[32]) +{ + 8002ba8: b5f0 push {r4, r5, r6, r7, lr} + 8002baa: b09f sub sp, #124 ; 0x7c + // We provide some 20 bytes of randomness to chip + // The chip must provide 32-bytes of random-ness, + // so no choice in args to OP.Nonce here (due to ReqRandom). + ae_send_n(OP_Nonce, 0, 0, num_in, 20); + 8002bac: 2200 movs r2, #0 + 8002bae: 2714 movs r7, #20 + 8002bb0: 4603 mov r3, r0 +{ + 8002bb2: 4605 mov r5, r0 + 8002bb4: 460e mov r6, r1 + ae_send_n(OP_Nonce, 0, 0, num_in, 20); + 8002bb6: 2016 movs r0, #22 + 8002bb8: 4611 mov r1, r2 + 8002bba: 9700 str r7, [sp, #0] + 8002bbc: f7ff ff8c bl 8002ad8 + + // Nonce command returns the RNG result, but not contents of TempKey + uint8_t randout[32]; + int rv = ae_read_n(32, randout); + 8002bc0: a903 add r1, sp, #12 + 8002bc2: 2020 movs r0, #32 + 8002bc4: f7ff ff4e bl 8002a64 + RET_IF_BAD(rv); + 8002bc8: 4604 mov r4, r0 + 8002bca: b9e0 cbnz r0, 8002c06 + // + // return sha256(rndout + num_in + b'\x16\0\0').digest() + // + SHA256_CTX ctx; + + sha256_init(&ctx); + 8002bcc: a80b add r0, sp, #44 ; 0x2c + 8002bce: f002 fc5d bl 800548c + sha256_update(&ctx, randout, 32); + 8002bd2: 2220 movs r2, #32 + 8002bd4: a903 add r1, sp, #12 + 8002bd6: a80b add r0, sp, #44 ; 0x2c + 8002bd8: f002 fc66 bl 80054a8 + sha256_update(&ctx, num_in, 20); + 8002bdc: 463a mov r2, r7 + 8002bde: 4629 mov r1, r5 + 8002be0: a80b add r0, sp, #44 ; 0x2c + 8002be2: f002 fc61 bl 80054a8 + const uint8_t fixed[3] = { 0x16, 0, 0 }; + 8002be6: 4b09 ldr r3, [pc, #36] ; (8002c0c ) + 8002be8: 881a ldrh r2, [r3, #0] + 8002bea: f8ad 2008 strh.w r2, [sp, #8] + 8002bee: 789b ldrb r3, [r3, #2] + 8002bf0: f88d 300a strb.w r3, [sp, #10] + sha256_update(&ctx, fixed, 3); + 8002bf4: a902 add r1, sp, #8 + 8002bf6: a80b add r0, sp, #44 ; 0x2c + 8002bf8: 2203 movs r2, #3 + 8002bfa: f002 fc55 bl 80054a8 + + sha256_final(&ctx, tempkey); + 8002bfe: 4631 mov r1, r6 + 8002c00: a80b add r0, sp, #44 ; 0x2c + 8002c02: f002 fc97 bl 8005534 + + return 0; +} + 8002c06: 4620 mov r0, r4 + 8002c08: b01f add sp, #124 ; 0x7c + 8002c0a: bdf0 pop {r4, r5, r6, r7, pc} + 8002c0c: 0800e674 .word 0x0800e674 + +08002c10 : +// Check that TempKey is holding what we think it does. Uses the MAC +// command over contents of Tempkey and our shared secret. +// + bool +ae_is_correct_tempkey(const uint8_t expected_tempkey[32]) +{ + 8002c10: b570 push {r4, r5, r6, lr} + const uint8_t mode = (1<<6) // include full serial number + | (0<<2) // TempKey.SourceFlag == 0 == 'rand' + | (0<<1) // first 32 bytes are the shared secret + | (1<<0); // second 32 bytes are tempkey + + ae_send(OP_MAC, mode, KEYNUM_pairing); + 8002c12: 2141 movs r1, #65 ; 0x41 +{ + 8002c14: b0a8 sub sp, #160 ; 0xa0 + 8002c16: 4604 mov r4, r0 + ae_send(OP_MAC, mode, KEYNUM_pairing); + 8002c18: 2201 movs r2, #1 + 8002c1a: 2008 movs r0, #8 + 8002c1c: f7ff ff8f bl 8002b3e + + // read chip's answer + uint8_t resp[32]; + int rv = ae_read_n(32, resp); + 8002c20: a905 add r1, sp, #20 + 8002c22: 2020 movs r0, #32 + 8002c24: f7ff ff1e bl 8002a64 + if(rv) return false; + 8002c28: 2800 cmp r0, #0 + 8002c2a: d135 bne.n 8002c98 + ae_send_idle(); + 8002c2c: f7ff fe4b bl 80028c6 + ae_keep_alive(); + + // Duplicate the hash process, and then compare. + SHA256_CTX ctx; + + sha256_init(&ctx); + 8002c30: a815 add r0, sp, #84 ; 0x54 + 8002c32: f002 fc2b bl 800548c + sha256_update(&ctx, rom_secrets->pairing_secret, 32); + 8002c36: 4919 ldr r1, [pc, #100] ; (8002c9c ) + 8002c38: 2220 movs r2, #32 + 8002c3a: a815 add r0, sp, #84 ; 0x54 + 8002c3c: f002 fc34 bl 80054a8 + sha256_update(&ctx, expected_tempkey, 32); + 8002c40: 2220 movs r2, #32 + 8002c42: 4621 mov r1, r4 + 8002c44: a815 add r0, sp, #84 ; 0x54 + 8002c46: f002 fc2f bl 80054a8 + + const uint8_t fixed[16] = { OP_MAC, mode, KEYNUM_pairing, 0x0, + 8002c4a: 4b15 ldr r3, [pc, #84] ; (8002ca0 ) + 8002c4c: aa01 add r2, sp, #4 + 8002c4e: f103 0610 add.w r6, r3, #16 + 8002c52: 4615 mov r5, r2 + 8002c54: 6818 ldr r0, [r3, #0] + 8002c56: 6859 ldr r1, [r3, #4] + 8002c58: 4614 mov r4, r2 + 8002c5a: c403 stmia r4!, {r0, r1} + 8002c5c: 3308 adds r3, #8 + 8002c5e: 42b3 cmp r3, r6 + 8002c60: 4622 mov r2, r4 + 8002c62: d1f7 bne.n 8002c54 + 0,0,0,0, 0,0,0,0, // eight zeros + 0,0,0, // three zeros + 0xEE }; + sha256_update(&ctx, fixed, sizeof(fixed)); + 8002c64: 2210 movs r2, #16 + 8002c66: 4629 mov r1, r5 + 8002c68: a815 add r0, sp, #84 ; 0x54 + 8002c6a: f002 fc1d bl 80054a8 + + sha256_update(&ctx, ((const uint8_t *)rom_secrets->ae_serial_number)+4, 4); + 8002c6e: 490d ldr r1, [pc, #52] ; (8002ca4 ) + 8002c70: 2204 movs r2, #4 + 8002c72: a815 add r0, sp, #84 ; 0x54 + 8002c74: f002 fc18 bl 80054a8 + sha256_update(&ctx, ((const uint8_t *)rom_secrets->ae_serial_number)+0, 4); + 8002c78: 2204 movs r2, #4 + 8002c7a: 490b ldr r1, [pc, #44] ; (8002ca8 ) + 8002c7c: a815 add r0, sp, #84 ; 0x54 + 8002c7e: f002 fc13 bl 80054a8 + // this verifies no problem. + ASSERT(ctx.datalen + (ctx.bitlen/8) == 32+32+1+1+2+8+3+1+4+2+2); // == 88 +#endif + + uint8_t actual[32]; + sha256_final(&ctx, actual); + 8002c82: a90d add r1, sp, #52 ; 0x34 + 8002c84: a815 add r0, sp, #84 ; 0x54 + 8002c86: f002 fc55 bl 8005534 + + return check_equal(actual, resp, 32); + 8002c8a: 2220 movs r2, #32 + 8002c8c: a905 add r1, sp, #20 + 8002c8e: a80d add r0, sp, #52 ; 0x34 + 8002c90: f7ff fd0f bl 80026b2 +} + 8002c94: b028 add sp, #160 ; 0xa0 + 8002c96: bd70 pop {r4, r5, r6, pc} + if(rv) return false; + 8002c98: 2000 movs r0, #0 + 8002c9a: e7fb b.n 8002c94 + 8002c9c: 0801c000 .word 0x0801c000 + 8002ca0: 0800e677 .word 0x0800e677 + 8002ca4: 0801c044 .word 0x0801c044 + 8002ca8: 0801c040 .word 0x0801c040 + +08002cac : +// inside the 508a/608a, like use of a specific key, but not for us to +// authenticate the 508a/608a or its contents/state. +// + int +ae_checkmac(uint8_t keynum, const uint8_t secret[32]) +{ + 8002cac: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + 8002cb0: b0c2 sub sp, #264 ; 0x108 + + // Since this is part of the hash, we want random bytes + // for our "other data". Also a number for "numin" of nonce + uint8_t od[32], numin[20]; + + rng_buffer(od, sizeof(od)); + 8002cb2: ad0b add r5, sp, #44 ; 0x2c +{ + 8002cb4: 4607 mov r7, r0 + 8002cb6: 460e mov r6, r1 + rng_buffer(od, sizeof(od)); + 8002cb8: 4628 mov r0, r5 + 8002cba: 2120 movs r1, #32 + 8002cbc: f7ff fd48 bl 8002750 + rng_buffer(numin, sizeof(numin)); + 8002cc0: 2114 movs r1, #20 + 8002cc2: a806 add r0, sp, #24 + 8002cc4: f7ff fd44 bl 8002750 + ae_send_idle(); + 8002cc8: f7ff fdfd bl 80028c6 + + // need this one, want to reset watchdog to this point. + ae_keep_alive(); + + // - load tempkey with a known nonce value + uint8_t zeros[8] = {0}; + 8002ccc: 2300 movs r3, #0 + uint8_t tempkey[32]; + rv = ae_pick_nonce(numin, tempkey); + 8002cce: a913 add r1, sp, #76 ; 0x4c + 8002cd0: a806 add r0, sp, #24 + uint8_t zeros[8] = {0}; + 8002cd2: e9cd 3304 strd r3, r3, [sp, #16] + rv = ae_pick_nonce(numin, tempkey); + 8002cd6: f7ff ff67 bl 8002ba8 + RET_IF_BAD(rv); + 8002cda: 4604 mov r4, r0 + 8002cdc: 2800 cmp r0, #0 + 8002cde: d15d bne.n 8002d9c + + // - hash nonce and lots of other bits together + SHA256_CTX ctx; + sha256_init(&ctx); + 8002ce0: a81b add r0, sp, #108 ; 0x6c + 8002ce2: f002 fbd3 bl 800548c + + // shared secret is 32 bytes from flash + sha256_update(&ctx, secret, 32); + 8002ce6: 2220 movs r2, #32 + 8002ce8: 4631 mov r1, r6 + 8002cea: a81b add r0, sp, #108 ; 0x6c + 8002cec: f002 fbdc bl 80054a8 + + sha256_update(&ctx, tempkey, 32); + 8002cf0: 2220 movs r2, #32 + 8002cf2: a913 add r1, sp, #76 ; 0x4c + 8002cf4: a81b add r0, sp, #108 ; 0x6c + 8002cf6: f002 fbd7 bl 80054a8 + sha256_update(&ctx, &od[0], 4); + 8002cfa: 2204 movs r2, #4 + 8002cfc: 4629 mov r1, r5 + 8002cfe: a81b add r0, sp, #108 ; 0x6c + 8002d00: f002 fbd2 bl 80054a8 + + sha256_update(&ctx, zeros, 8); + 8002d04: 2208 movs r2, #8 + 8002d06: a904 add r1, sp, #16 + 8002d08: a81b add r0, sp, #108 ; 0x6c + 8002d0a: f002 fbcd bl 80054a8 + + sha256_update(&ctx, &od[4], 3); + 8002d0e: 2203 movs r2, #3 + 8002d10: a90c add r1, sp, #48 ; 0x30 + 8002d12: a81b add r0, sp, #108 ; 0x6c + 8002d14: f002 fbc8 bl 80054a8 + + uint8_t ee = 0xEE; + 8002d18: 23ee movs r3, #238 ; 0xee + sha256_update(&ctx, &ee, 1); + 8002d1a: 2201 movs r2, #1 + 8002d1c: f10d 010b add.w r1, sp, #11 + 8002d20: a81b add r0, sp, #108 ; 0x6c + uint8_t ee = 0xEE; + 8002d22: f88d 300b strb.w r3, [sp, #11] + sha256_update(&ctx, &ee, 1); + 8002d26: f002 fbbf bl 80054a8 + sha256_update(&ctx, &od[7], 4); + 8002d2a: 2204 movs r2, #4 + 8002d2c: f10d 0133 add.w r1, sp, #51 ; 0x33 + 8002d30: a81b add r0, sp, #108 ; 0x6c + 8002d32: f002 fbb9 bl 80054a8 + + uint8_t snp[2] = { 0x01, 0x23 }; + 8002d36: f242 3301 movw r3, #8961 ; 0x2301 + sha256_update(&ctx, snp, 2); + 8002d3a: 2202 movs r2, #2 + 8002d3c: a903 add r1, sp, #12 + 8002d3e: a81b add r0, sp, #108 ; 0x6c + uint8_t snp[2] = { 0x01, 0x23 }; + 8002d40: f8ad 300c strh.w r3, [sp, #12] + sha256_update(&ctx, snp, 2); + 8002d44: f002 fbb0 bl 80054a8 + sha256_update(&ctx, &od[11], 2); + 8002d48: 2202 movs r2, #2 + 8002d4a: f10d 0137 add.w r1, sp, #55 ; 0x37 + 8002d4e: a81b add r0, sp, #108 ; 0x6c + 8002d50: f002 fbaa bl 80054a8 + uint8_t resp[32]; + uint8_t od[13]; + } req; + + // content doesn't matter, but nice and visible: + memcpy(req.ch3, copyright_msg, 32); + 8002d54: 4b15 ldr r3, [pc, #84] ; (8002dac ) + 8002d56: ac2e add r4, sp, #184 ; 0xb8 + 8002d58: f103 0220 add.w r2, r3, #32 + 8002d5c: 46a0 mov r8, r4 + 8002d5e: 6818 ldr r0, [r3, #0] + 8002d60: 6859 ldr r1, [r3, #4] + 8002d62: 4626 mov r6, r4 + 8002d64: c603 stmia r6!, {r0, r1} + 8002d66: 3308 adds r3, #8 + 8002d68: 4293 cmp r3, r2 + 8002d6a: 4634 mov r4, r6 + 8002d6c: d1f7 bne.n 8002d5e + // this verifies no problem. + int l = (ctx.blocks * 64) + ctx.npartial; + ASSERT(l == 32+32+4+8+3+1+4+2+2); // == 88 +#endif + + sha256_final(&ctx, req.resp); + 8002d6e: a936 add r1, sp, #216 ; 0xd8 + 8002d70: a81b add r0, sp, #108 ; 0x6c + 8002d72: f002 fbdf bl 8005534 + memcpy(req.od, od, 13); + 8002d76: e895 000f ldmia.w r5, {r0, r1, r2, r3} + 8002d7a: ac3e add r4, sp, #248 ; 0xf8 + 8002d7c: c407 stmia r4!, {r0, r1, r2} + 8002d7e: 7023 strb r3, [r4, #0] + + STATIC_ASSERT(sizeof(req) == 32 + 32 + 13); + + // Give our answer to the chip. + ae_send_n(OP_CheckMac, 0x01, keynum, (uint8_t *)&req, sizeof(req)); + 8002d80: 234d movs r3, #77 ; 0x4d + 8002d82: 9300 str r3, [sp, #0] + 8002d84: 463a mov r2, r7 + 8002d86: 4643 mov r3, r8 + 8002d88: 2101 movs r1, #1 + 8002d8a: 2028 movs r0, #40 ; 0x28 + 8002d8c: f7ff fea4 bl 8002ad8 + + rv = ae_read1(); + 8002d90: f7ff fe4c bl 8002a2c + if(rv != 0) { + 8002d94: 4604 mov r4, r0 + 8002d96: b928 cbnz r0, 8002da4 + ae_send_idle(); + 8002d98: f7ff fd95 bl 80028c6 + + // just in case ... always restart watchdog timer. + ae_keep_alive(); + + return 0; +} + 8002d9c: 4620 mov r0, r4 + 8002d9e: b042 add sp, #264 ; 0x108 + 8002da0: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + return -1; + 8002da4: f04f 34ff mov.w r4, #4294967295 ; 0xffffffff + 8002da8: e7f8 b.n 8002d9c + 8002daa: bf00 nop + 8002dac: 0800e646 .word 0x0800e646 + +08002db0 : + return ae_checkmac(KEYNUM_pairing, rom_secrets->pairing_secret); + 8002db0: 4901 ldr r1, [pc, #4] ; (8002db8 ) + 8002db2: 2001 movs r0, #1 + 8002db4: f7ff bf7a b.w 8002cac + 8002db8: 0801c000 .word 0x0801c000 + +08002dbc : +// Sign a message (already digested) +// + int +ae_sign_authed(uint8_t keynum, const uint8_t msg_hash[32], + uint8_t signature[64], int auth_kn, const uint8_t auth_digest[32]) +{ + 8002dbc: b570 push {r4, r5, r6, lr} + 8002dbe: 460e mov r6, r1 + 8002dc0: 4604 mov r4, r0 + 8002dc2: 4615 mov r5, r2 + // indicate we know the PIN + ae_pair_unlock(); + 8002dc4: f7ff fff4 bl 8002db0 + int rv = ae_checkmac(KEYNUM_main_pin, auth_digest); + 8002dc8: 9904 ldr r1, [sp, #16] + 8002dca: 2003 movs r0, #3 + 8002dcc: f7ff ff6e bl 8002cac + RET_IF_BAD(rv); + 8002dd0: b990 cbnz r0, 8002df8 + + // send what we need signed + rv = ae_load_msgdigest(msg_hash); + 8002dd2: 4630 mov r0, r6 + 8002dd4: f7ff feda bl 8002b8c + RET_IF_BAD(rv); + 8002dd8: b970 cbnz r0, 8002df8 + + do { + ae_send(OP_Sign, (7<<5), keynum); + 8002dda: b2a4 uxth r4, r4 + 8002ddc: 4622 mov r2, r4 + 8002dde: 21e0 movs r1, #224 ; 0xe0 + 8002de0: 2041 movs r0, #65 ; 0x41 + 8002de2: f7ff feac bl 8002b3e + + delay_ms(60); // min time for processing + 8002de6: 203c movs r0, #60 ; 0x3c + 8002de8: f000 fd86 bl 80038f8 + + rv = ae_read_n(64, signature); + 8002dec: 4629 mov r1, r5 + 8002dee: 2040 movs r0, #64 ; 0x40 + 8002df0: f7ff fe38 bl 8002a64 + } while(rv == AE_ECC_FAULT); + 8002df4: 2805 cmp r0, #5 + 8002df6: d0f1 beq.n 8002ddc + + return rv; +} + 8002df8: bd70 pop {r4, r5, r6, pc} + ... + +08002dfc : + +// ae_gen_ecc_key() +// + int +ae_gen_ecc_key(uint8_t keynum, uint8_t pubkey_out[64]) +{ + 8002dfc: b530 push {r4, r5, lr} + int rv; + uint8_t junk[3] = { 0 }; + 8002dfe: 4b0f ldr r3, [pc, #60] ; (8002e3c ) +{ + 8002e00: b085 sub sp, #20 + uint8_t junk[3] = { 0 }; + 8002e02: f8b3 3013 ldrh.w r3, [r3, #19] + 8002e06: f8ad 300c strh.w r3, [sp, #12] + 8002e0a: 2300 movs r3, #0 +{ + 8002e0c: 460c mov r4, r1 + uint8_t junk[3] = { 0 }; + 8002e0e: f88d 300e strb.w r3, [sp, #14] + + do { + ae_send_n(OP_GenKey, (1<<2), keynum, junk, 3); + 8002e12: 4605 mov r5, r0 + 8002e14: 2303 movs r3, #3 + 8002e16: 462a mov r2, r5 + 8002e18: 2104 movs r1, #4 + 8002e1a: 9300 str r3, [sp, #0] + 8002e1c: 2040 movs r0, #64 ; 0x40 + 8002e1e: ab03 add r3, sp, #12 + 8002e20: f7ff fe5a bl 8002ad8 + + delay_ms(100); // to avoid timeouts + 8002e24: 2064 movs r0, #100 ; 0x64 + 8002e26: f000 fd67 bl 80038f8 + + rv = ae_read_n(64, pubkey_out); + 8002e2a: 4621 mov r1, r4 + 8002e2c: 2040 movs r0, #64 ; 0x40 + 8002e2e: f7ff fe19 bl 8002a64 + } while(rv == AE_ECC_FAULT); + 8002e32: 2805 cmp r0, #5 + 8002e34: d0ee beq.n 8002e14 + + return rv; +} + 8002e36: b005 add sp, #20 + 8002e38: bd30 pop {r4, r5, pc} + 8002e3a: bf00 nop + 8002e3c: 0800e674 .word 0x0800e674 + +08002e40 : +// 508a: Different opcode, OP_HMAC does exactly 32 bytes w/ less steps. +// 608a: Use old SHA256 command, but with new flags. +// + int +ae_hmac32(uint8_t keynum, const uint8_t msg[32], uint8_t digest[32]) +{ + 8002e40: b530 push {r4, r5, lr} + 8002e42: b085 sub sp, #20 + 8002e44: 4615 mov r5, r2 + 8002e46: 9103 str r1, [sp, #12] + // Start SHA w/ HMAC setup + ae_send(OP_SHA, 4, keynum); // 4 = HMAC_Init + 8002e48: 4602 mov r2, r0 + 8002e4a: 2104 movs r1, #4 + 8002e4c: 2047 movs r0, #71 ; 0x47 + 8002e4e: f7ff fe76 bl 8002b3e + + // expect zero, meaning "ready" + int rv = ae_read1(); + 8002e52: f7ff fdeb bl 8002a2c + RET_IF_BAD(rv); + 8002e56: b970 cbnz r0, 8002e76 + + // send the contents to be hashed + ae_send_n(OP_SHA, (3<<6) | 2, 32, msg, 32); // 2 = Finalize, 3=Place output + 8002e58: 2420 movs r4, #32 + 8002e5a: 9b03 ldr r3, [sp, #12] + 8002e5c: 9400 str r4, [sp, #0] + 8002e5e: 4622 mov r2, r4 + 8002e60: 21c2 movs r1, #194 ; 0xc2 + 8002e62: 2047 movs r0, #71 ; 0x47 + 8002e64: f7ff fe38 bl 8002ad8 + + // read result + return ae_read_n(32, digest); + 8002e68: 4629 mov r1, r5 + 8002e6a: 4620 mov r0, r4 +} + 8002e6c: b005 add sp, #20 + 8002e6e: e8bd 4030 ldmia.w sp!, {r4, r5, lr} + return ae_read_n(32, digest); + 8002e72: f7ff bdf7 b.w 8002a64 +} + 8002e76: b005 add sp, #20 + 8002e78: bd30 pop {r4, r5, pc} + +08002e7a : +// +// Return the serial number: it's 9 bytes, altho 3 are fixed. +// + int +ae_get_serial(uint8_t serial[6]) +{ + 8002e7a: b510 push {r4, lr} + ae_send(OP_Read, 0x80, 0x0); + 8002e7c: 2200 movs r2, #0 +{ + 8002e7e: b08c sub sp, #48 ; 0x30 + ae_send(OP_Read, 0x80, 0x0); + 8002e80: 2180 movs r1, #128 ; 0x80 +{ + 8002e82: 4604 mov r4, r0 + ae_send(OP_Read, 0x80, 0x0); + 8002e84: 2002 movs r0, #2 + 8002e86: f7ff fe5a bl 8002b3e + + uint8_t temp[32]; + int rv = ae_read_n(32, temp); + 8002e8a: a904 add r1, sp, #16 + 8002e8c: 2020 movs r0, #32 + 8002e8e: f7ff fde9 bl 8002a64 + RET_IF_BAD(rv); + 8002e92: 4603 mov r3, r0 + 8002e94: b9b8 cbnz r0, 8002ec6 + + // reformat to 9 bytes. + uint8_t ts[9]; + memcpy(ts, &temp[0], 4); + memcpy(&ts[4], &temp[8], 5); + 8002e96: e9dd 0106 ldrd r0, r1, [sp, #24] + 8002e9a: 9a04 ldr r2, [sp, #16] + 8002e9c: f88d 100c strb.w r1, [sp, #12] + + // check the hard-coded values + if((ts[0] != 0x01) || (ts[1] != 0x23) || (ts[8] != 0xEE)) return 1; + 8002ea0: b2d1 uxtb r1, r2 + 8002ea2: 2901 cmp r1, #1 + memcpy(ts, &temp[0], 4); + 8002ea4: 9201 str r2, [sp, #4] + memcpy(&ts[4], &temp[8], 5); + 8002ea6: 9002 str r0, [sp, #8] + if((ts[0] != 0x01) || (ts[1] != 0x23) || (ts[8] != 0xEE)) return 1; + 8002ea8: d110 bne.n 8002ecc + 8002eaa: f3c2 2207 ubfx r2, r2, #8, #8 + 8002eae: 2a23 cmp r2, #35 ; 0x23 + 8002eb0: d10c bne.n 8002ecc + 8002eb2: f89d 200c ldrb.w r2, [sp, #12] + 8002eb6: 2aee cmp r2, #238 ; 0xee + 8002eb8: d10a bne.n 8002ed0 + + // save only the unique bits. + memcpy(serial, ts+2, 6); + 8002eba: f8dd 2006 ldr.w r2, [sp, #6] + 8002ebe: 6022 str r2, [r4, #0] + 8002ec0: f8bd 200a ldrh.w r2, [sp, #10] + 8002ec4: 80a2 strh r2, [r4, #4] + + return 0; +} + 8002ec6: 4618 mov r0, r3 + 8002ec8: b00c add sp, #48 ; 0x30 + 8002eca: bd10 pop {r4, pc} + if((ts[0] != 0x01) || (ts[1] != 0x23) || (ts[8] != 0xEE)) return 1; + 8002ecc: 2301 movs r3, #1 + 8002ece: e7fa b.n 8002ec6 + 8002ed0: 460b mov r3, r1 + 8002ed2: e7f8 b.n 8002ec6 + +08002ed4 : +{ + 8002ed4: b513 push {r0, r1, r4, lr} + ae_wake(); + 8002ed6: f7ff fceb bl 80028b0 + _send_bits(IOFLAG_SLEEP); + 8002eda: 20cc movs r0, #204 ; 0xcc + 8002edc: f7ff fc70 bl 80027c0 <_send_bits> + ae_wake(); + 8002ee0: f7ff fce6 bl 80028b0 + ae_read1(); + 8002ee4: f7ff fda2 bl 8002a2c + uint8_t chk = ae_read1(); + 8002ee8: f7ff fda0 bl 8002a2c + if(chk != AE_AFTER_WAKE) return "wk fl"; + 8002eec: b2c0 uxtb r0, r0 + 8002eee: 2811 cmp r0, #17 + 8002ef0: d10e bne.n 8002f10 + if(ae_get_serial(serial)) return "no ser"; + 8002ef2: 4668 mov r0, sp + 8002ef4: f7ff ffc1 bl 8002e7a + 8002ef8: 4604 mov r4, r0 + 8002efa: b938 cbnz r0, 8002f0c + ae_wake(); + 8002efc: f7ff fcd8 bl 80028b0 + _send_bits(IOFLAG_SLEEP); + 8002f00: 20cc movs r0, #204 ; 0xcc + 8002f02: f7ff fc5d bl 80027c0 <_send_bits> + return NULL; + 8002f06: 4620 mov r0, r4 +} + 8002f08: b002 add sp, #8 + 8002f0a: bd10 pop {r4, pc} + if(ae_get_serial(serial)) return "no ser"; + 8002f0c: 4801 ldr r0, [pc, #4] ; (8002f14 ) + 8002f0e: e7fb b.n 8002f08 + if(chk != AE_AFTER_WAKE) return "wk fl"; + 8002f10: 4801 ldr r0, [pc, #4] ; (8002f18 ) + 8002f12: e7f9 b.n 8002f08 + 8002f14: 0800e667 .word 0x0800e667 + 8002f18: 0800e66e .word 0x0800e66e + +08002f1c : +// +// -- can also lock it. +// + int +ae_write_data_slot(int slot_num, const uint8_t *data, int len, bool lock_it) +{ + 8002f1c: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + 8002f20: 4699 mov r9, r3 + ASSERT(len >= 32); + 8002f22: f1a2 0320 sub.w r3, r2, #32 +{ + 8002f26: b085 sub sp, #20 + ASSERT(len >= 32); + 8002f28: f5b3 7fc0 cmp.w r3, #384 ; 0x180 +{ + 8002f2c: 4604 mov r4, r0 + 8002f2e: af02 add r7, sp, #8 + 8002f30: 460d mov r5, r1 + 8002f32: 4690 mov r8, r2 + ASSERT(len >= 32); + 8002f34: d902 bls.n 8002f3c + 8002f36: 482d ldr r0, [pc, #180] ; (8002fec ) + 8002f38: f7fd fd86 bl 8000a48 + ASSERT(len <= 416); + + for(int blk=0, xlen=len; xlen>0; blk++, xlen-=32) { + // have to write each "block" of 32-bytes, separately + // zone => data + ae_send_n(OP_Write, 0x80|2, (blk<<8) | (slot_num<<3), data+(blk*32), 32); + 8002f3c: ea4f 0ac0 mov.w sl, r0, lsl #3 + 8002f40: fa0f fa8a sxth.w sl, sl + 8002f44: 2600 movs r6, #0 + 8002f46: f04f 0b20 mov.w fp, #32 + 8002f4a: ebc6 3246 rsb r2, r6, r6, lsl #13 + 8002f4e: ea4a 02c2 orr.w r2, sl, r2, lsl #3 + 8002f52: b292 uxth r2, r2 + 8002f54: 1bab subs r3, r5, r6 + 8002f56: 2182 movs r1, #130 ; 0x82 + 8002f58: 2012 movs r0, #18 + 8002f5a: f8cd b000 str.w fp, [sp] + 8002f5e: f7ff fdbb bl 8002ad8 + + int rv = ae_read1(); + 8002f62: f7ff fd63 bl 8002a2c + RET_IF_BAD(rv); + 8002f66: 2800 cmp r0, #0 + 8002f68: d13c bne.n 8002fe4 + for(int blk=0, xlen=len; xlen>0; blk++, xlen-=32) { + 8002f6a: 3e20 subs r6, #32 + 8002f6c: eb06 0308 add.w r3, r6, r8 + 8002f70: 2b00 cmp r3, #0 + 8002f72: dcea bgt.n 8002f4a + } + + if(lock_it) { + 8002f74: f1b9 0f00 cmp.w r9, #0 + 8002f78: d034 beq.n 8002fe4 + ASSERT(slot_num != 8); // no support for mega slot 8 + 8002f7a: 2c08 cmp r4, #8 + if(lock_it) { + 8002f7c: 466e mov r6, sp + ASSERT(slot_num != 8); // no support for mega slot 8 + 8002f7e: d0da beq.n 8002f36 + ASSERT(len == 32); // probably not a limitation here + 8002f80: f1b8 0f20 cmp.w r8, #32 + 8002f84: d1d7 bne.n 8002f36 + + // Assume 36/72-byte long slot, which will be partially written, and rest + // should be ones. + const int slot_len = (slot_num <= 7) ? 36 : 72; + 8002f86: 2c08 cmp r4, #8 + 8002f88: bfb4 ite lt + 8002f8a: f04f 0824 movlt.w r8, #36 ; 0x24 + 8002f8e: f04f 0848 movge.w r8, #72 ; 0x48 + uint8_t copy[slot_len]; + 8002f92: f108 0307 add.w r3, r8, #7 + 8002f96: f003 03f8 and.w r3, r3, #248 ; 0xf8 + 8002f9a: ebad 0d03 sub.w sp, sp, r3 + 8002f9e: ab02 add r3, sp, #8 + + memset(copy, 0xff, slot_len); + 8002fa0: 4642 mov r2, r8 + 8002fa2: 21ff movs r1, #255 ; 0xff + 8002fa4: 4618 mov r0, r3 + 8002fa6: f00a fb65 bl 800d674 + memcpy(copy, data, len); + 8002faa: f105 0120 add.w r1, r5, #32 + memset(copy, 0xff, slot_len); + 8002fae: 4603 mov r3, r0 + memcpy(copy, data, len); + 8002fb0: 4602 mov r2, r0 + 8002fb2: f855 0b04 ldr.w r0, [r5], #4 + 8002fb6: f842 0b04 str.w r0, [r2], #4 + 8002fba: 428d cmp r5, r1 + 8002fbc: d1f9 bne.n 8002fb2 + + // calc expected CRC + uint8_t crc[2] = {0, 0}; + 8002fbe: 2200 movs r2, #0 + crc16_chain(slot_len, copy, crc); + 8002fc0: 4619 mov r1, r3 + uint8_t crc[2] = {0, 0}; + 8002fc2: 80ba strh r2, [r7, #4] + crc16_chain(slot_len, copy, crc); + 8002fc4: 4640 mov r0, r8 + 8002fc6: 1d3a adds r2, r7, #4 + 8002fc8: f7ff fc30 bl 800282c + + // do the lock + ae_send(OP_Lock, 2 | (slot_num << 2), (crc[1]<<8) | crc[0]); + 8002fcc: 00a1 lsls r1, r4, #2 + 8002fce: f041 0102 orr.w r1, r1, #2 + 8002fd2: 88ba ldrh r2, [r7, #4] + 8002fd4: f001 01fe and.w r1, r1, #254 ; 0xfe + 8002fd8: 2017 movs r0, #23 + 8002fda: f7ff fdb0 bl 8002b3e + + int rv = ae_read1(); + 8002fde: f7ff fd25 bl 8002a2c + RET_IF_BAD(rv); + 8002fe2: 46b5 mov sp, r6 + } + + return 0; +} + 8002fe4: 370c adds r7, #12 + 8002fe6: 46bd mov sp, r7 + 8002fe8: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + 8002fec: 0800e3e0 .word 0x0800e3e0 + +08002ff0 : + +// ae_gendig_slot() +// + int +ae_gendig_slot(int slot_num, const uint8_t slot_contents[32], uint8_t digest[32]) +{ + 8002ff0: b5f0 push {r4, r5, r6, r7, lr} + 8002ff2: b0ab sub sp, #172 ; 0xac + 8002ff4: 4605 mov r5, r0 + 8002ff6: 460f mov r7, r1 + // Construct a digest on the device (and here) that depends on the secret + // contents of a specific slot. + uint8_t num_in[20], tempkey[32]; + + rng_buffer(num_in, sizeof(num_in)); + 8002ff8: a803 add r0, sp, #12 + 8002ffa: 2114 movs r1, #20 +{ + 8002ffc: 4616 mov r6, r2 + rng_buffer(num_in, sizeof(num_in)); + 8002ffe: f7ff fba7 bl 8002750 + int rv = ae_pick_nonce(num_in, tempkey); + 8003002: a90f add r1, sp, #60 ; 0x3c + 8003004: a803 add r0, sp, #12 + 8003006: f7ff fdcf bl 8002ba8 + RET_IF_BAD(rv); + 800300a: 4604 mov r4, r0 + 800300c: 2800 cmp r0, #0 + 800300e: d13d bne.n 800308c + + //using Zone=2="Data" => "KeyID specifies a slot in the Data zone" + ae_send(OP_GenDig, 0x2, slot_num); + 8003010: b2aa uxth r2, r5 + 8003012: 2102 movs r1, #2 + 8003014: 2015 movs r0, #21 + 8003016: f7ff fd92 bl 8002b3e + + rv = ae_read1(); + 800301a: f7ff fd07 bl 8002a2c + RET_IF_BAD(rv); + 800301e: 4604 mov r4, r0 + 8003020: bba0 cbnz r0, 800308c + ae_send_idle(); + 8003022: f7ff fc50 bl 80028c6 + // msg = hkey + b'\x15\x02' + ustruct.pack(" + + uint8_t args[7] = { OP_GenDig, 2, slot_num, 0, 0xEE, 0x01, 0x23 }; + 800302c: 2302 movs r3, #2 + 800302e: f88d 3005 strb.w r3, [sp, #5] + 8003032: 23ee movs r3, #238 ; 0xee + 8003034: f88d 3008 strb.w r3, [sp, #8] + 8003038: 2301 movs r3, #1 + 800303a: 2215 movs r2, #21 + 800303c: f88d 3009 strb.w r3, [sp, #9] + uint8_t zeros[25] = { 0 }; + 8003040: 4621 mov r1, r4 + uint8_t args[7] = { OP_GenDig, 2, slot_num, 0, 0xEE, 0x01, 0x23 }; + 8003042: 2323 movs r3, #35 ; 0x23 + uint8_t zeros[25] = { 0 }; + 8003044: a809 add r0, sp, #36 ; 0x24 + uint8_t args[7] = { OP_GenDig, 2, slot_num, 0, 0xEE, 0x01, 0x23 }; + 8003046: f88d 300a strb.w r3, [sp, #10] + 800304a: f88d 2004 strb.w r2, [sp, #4] + 800304e: f88d 5006 strb.w r5, [sp, #6] + 8003052: f88d 4007 strb.w r4, [sp, #7] + uint8_t zeros[25] = { 0 }; + 8003056: 9408 str r4, [sp, #32] + 8003058: f00a fb0c bl 800d674 + + sha256_update(&ctx, slot_contents, 32); + 800305c: 2220 movs r2, #32 + 800305e: 4639 mov r1, r7 + 8003060: a817 add r0, sp, #92 ; 0x5c + 8003062: f002 fa21 bl 80054a8 + sha256_update(&ctx, args, sizeof(args)); + 8003066: 2207 movs r2, #7 + 8003068: a901 add r1, sp, #4 + 800306a: a817 add r0, sp, #92 ; 0x5c + 800306c: f002 fa1c bl 80054a8 + sha256_update(&ctx, zeros, sizeof(zeros)); + 8003070: 2219 movs r2, #25 + 8003072: a908 add r1, sp, #32 + 8003074: a817 add r0, sp, #92 ; 0x5c + 8003076: f002 fa17 bl 80054a8 + sha256_update(&ctx, tempkey, 32); + 800307a: a90f add r1, sp, #60 ; 0x3c + 800307c: a817 add r0, sp, #92 ; 0x5c + 800307e: 2220 movs r2, #32 + 8003080: f002 fa12 bl 80054a8 + + sha256_final(&ctx, digest); + 8003084: 4631 mov r1, r6 + 8003086: a817 add r0, sp, #92 ; 0x5c + 8003088: f002 fa54 bl 8005534 + + return 0; +} + 800308c: 4620 mov r0, r4 + 800308e: b02b add sp, #172 ; 0xac + 8003090: bdf0 pop {r4, r5, r6, r7, pc} + ... + +08003094 : +{ + 8003094: b507 push {r0, r1, r2, lr} + 8003096: 4602 mov r2, r0 + int rv = ae_gendig_slot(KEYNUM_pairing, rom_secrets->pairing_secret, randout); + 8003098: 9001 str r0, [sp, #4] + 800309a: 490b ldr r1, [pc, #44] ; (80030c8 ) + 800309c: 2001 movs r0, #1 + 800309e: f7ff ffa7 bl 8002ff0 + if(rv || !ae_is_correct_tempkey(randout)) { + 80030a2: 9a01 ldr r2, [sp, #4] + 80030a4: b108 cbz r0, 80030aa + fatal_mitm(); + 80030a6: f7fd fcd9 bl 8000a5c + if(rv || !ae_is_correct_tempkey(randout)) { + 80030aa: 4610 mov r0, r2 + 80030ac: 9201 str r2, [sp, #4] + 80030ae: f7ff fdaf bl 8002c10 + 80030b2: 2800 cmp r0, #0 + 80030b4: d0f7 beq.n 80030a6 + sha256_single(randout, 32, randout); + 80030b6: 9a01 ldr r2, [sp, #4] + 80030b8: 2120 movs r1, #32 + 80030ba: 4610 mov r0, r2 +} + 80030bc: b003 add sp, #12 + 80030be: f85d eb04 ldr.w lr, [sp], #4 + sha256_single(randout, 32, randout); + 80030c2: f002 ba4b b.w 800555c + 80030c6: bf00 nop + 80030c8: 0801c000 .word 0x0801c000 + +080030cc : +{ + 80030cc: b510 push {r4, lr} + 80030ce: b088 sub sp, #32 + int rv = ae_gendig_slot(keynum, secret, digest); + 80030d0: 466a mov r2, sp + 80030d2: f7ff ff8d bl 8002ff0 + RET_IF_BAD(rv); + 80030d6: 4604 mov r4, r0 + 80030d8: b930 cbnz r0, 80030e8 + if(!ae_is_correct_tempkey(digest)) return -2; + 80030da: 4668 mov r0, sp + 80030dc: f7ff fd98 bl 8002c10 + 80030e0: 2800 cmp r0, #0 + 80030e2: bf08 it eq + 80030e4: f06f 0401 mvneq.w r4, #1 +} + 80030e8: 4620 mov r0, r4 + 80030ea: b008 add sp, #32 + 80030ec: bd10 pop {r4, pc} + +080030ee : +// the digest should be, and ask the chip to do the same. Verify we match +// using MAC command (done elsewhere). +// + int +ae_gendig_counter(int counter_num, const uint32_t expected_value, uint8_t digest[32]) +{ + 80030ee: b5f0 push {r4, r5, r6, r7, lr} + 80030f0: b0ad sub sp, #180 ; 0xb4 + 80030f2: 4605 mov r5, r0 + 80030f4: 9101 str r1, [sp, #4] + uint8_t num_in[20], tempkey[32]; + + rng_buffer(num_in, sizeof(num_in)); + 80030f6: a804 add r0, sp, #16 + 80030f8: 2114 movs r1, #20 +{ + 80030fa: 4616 mov r6, r2 + rng_buffer(num_in, sizeof(num_in)); + 80030fc: f7ff fb28 bl 8002750 + int rv = ae_pick_nonce(num_in, tempkey); + 8003100: a909 add r1, sp, #36 ; 0x24 + 8003102: a804 add r0, sp, #16 + 8003104: f7ff fd50 bl 8002ba8 + RET_IF_BAD(rv); + 8003108: 4604 mov r4, r0 + 800310a: 2800 cmp r0, #0 + 800310c: d148 bne.n 80031a0 + + //using Zone=4="Counter" => "KeyID specifies the monotonic counter ID" + ae_send(OP_GenDig, 0x4, counter_num); + 800310e: b2aa uxth r2, r5 + 8003110: 2104 movs r1, #4 + 8003112: 2015 movs r0, #21 + 8003114: f7ff fd13 bl 8002b3e + + rv = ae_read1(); + 8003118: f7ff fc88 bl 8002a2c + RET_IF_BAD(rv); + 800311c: 4604 mov r4, r0 + 800311e: 2800 cmp r0, #0 + 8003120: d13e bne.n 80031a0 + ae_send_idle(); + 8003122: f7ff fbd0 bl 80028c6 + // msg = hkey + b'\x15\x02' + ustruct.pack(" + + uint8_t zeros[32] = { 0 }; + 800312c: 221c movs r2, #28 + 800312e: 4621 mov r1, r4 + 8003130: a812 add r0, sp, #72 ; 0x48 + 8003132: 9411 str r4, [sp, #68] ; 0x44 + 8003134: f00a fa9e bl 800d674 + uint8_t args[8] = { OP_GenDig, 0x4, counter_num, 0, 0xEE, 0x01, 0x23, 0x0 }; + 8003138: 2315 movs r3, #21 + 800313a: f88d 3008 strb.w r3, [sp, #8] + 800313e: 23ee movs r3, #238 ; 0xee + 8003140: f88d 300c strb.w r3, [sp, #12] + 8003144: 2301 movs r3, #1 + 8003146: 2704 movs r7, #4 + 8003148: f88d 300d strb.w r3, [sp, #13] + + sha256_update(&ctx, zeros, 32); + 800314c: 2220 movs r2, #32 + uint8_t args[8] = { OP_GenDig, 0x4, counter_num, 0, 0xEE, 0x01, 0x23, 0x0 }; + 800314e: 2323 movs r3, #35 ; 0x23 + sha256_update(&ctx, zeros, 32); + 8003150: a911 add r1, sp, #68 ; 0x44 + 8003152: a819 add r0, sp, #100 ; 0x64 + uint8_t args[8] = { OP_GenDig, 0x4, counter_num, 0, 0xEE, 0x01, 0x23, 0x0 }; + 8003154: f88d 300e strb.w r3, [sp, #14] + 8003158: f88d 7009 strb.w r7, [sp, #9] + 800315c: f88d 500a strb.w r5, [sp, #10] + 8003160: f88d 400b strb.w r4, [sp, #11] + 8003164: f88d 400f strb.w r4, [sp, #15] + sha256_update(&ctx, zeros, 32); + 8003168: f002 f99e bl 80054a8 + sha256_update(&ctx, args, sizeof(args)); + 800316c: 2208 movs r2, #8 + 800316e: eb0d 0102 add.w r1, sp, r2 + 8003172: a819 add r0, sp, #100 ; 0x64 + 8003174: f002 f998 bl 80054a8 + sha256_update(&ctx, (const uint8_t *)&expected_value, 4); + 8003178: 463a mov r2, r7 + 800317a: eb0d 0107 add.w r1, sp, r7 + 800317e: a819 add r0, sp, #100 ; 0x64 + 8003180: f002 f992 bl 80054a8 + sha256_update(&ctx, zeros, 20); + 8003184: 2214 movs r2, #20 + 8003186: a911 add r1, sp, #68 ; 0x44 + 8003188: a819 add r0, sp, #100 ; 0x64 + 800318a: f002 f98d bl 80054a8 + sha256_update(&ctx, tempkey, 32); + 800318e: a909 add r1, sp, #36 ; 0x24 + 8003190: a819 add r0, sp, #100 ; 0x64 + 8003192: 2220 movs r2, #32 + 8003194: f002 f988 bl 80054a8 + + sha256_final(&ctx, digest); + 8003198: 4631 mov r1, r6 + 800319a: a819 add r0, sp, #100 ; 0x64 + 800319c: f002 f9ca bl 8005534 + + return 0; +} + 80031a0: 4620 mov r0, r4 + 80031a2: b02d add sp, #180 ; 0xb4 + 80031a4: bdf0 pop {r4, r5, r6, r7, pc} + +080031a6 : +{ + 80031a6: b570 push {r4, r5, r6, lr} + ae_send(OP_Counter, 0x0, counter_number); + 80031a8: 460a mov r2, r1 +{ + 80031aa: b088 sub sp, #32 + 80031ac: 4606 mov r6, r0 + 80031ae: 460d mov r5, r1 + ae_send(OP_Counter, 0x0, counter_number); + 80031b0: 2024 movs r0, #36 ; 0x24 + 80031b2: 2100 movs r1, #0 + 80031b4: f7ff fcc3 bl 8002b3e + int rv = ae_read_n(4, (uint8_t *)result); + 80031b8: 4631 mov r1, r6 + 80031ba: 2004 movs r0, #4 + 80031bc: f7ff fc52 bl 8002a64 + RET_IF_BAD(rv); + 80031c0: 4604 mov r4, r0 + 80031c2: b960 cbnz r0, 80031de + rv = ae_gendig_counter(counter_number, *result, digest); + 80031c4: 6831 ldr r1, [r6, #0] + 80031c6: 466a mov r2, sp + 80031c8: 4628 mov r0, r5 + 80031ca: f7ff ff90 bl 80030ee + RET_IF_BAD(rv); + 80031ce: 4604 mov r4, r0 + 80031d0: b928 cbnz r0, 80031de + if(!ae_is_correct_tempkey(digest)) { + 80031d2: 4668 mov r0, sp + 80031d4: f7ff fd1c bl 8002c10 + 80031d8: b908 cbnz r0, 80031de + fatal_mitm(); + 80031da: f7fd fc3f bl 8000a5c +} + 80031de: 4620 mov r0, r4 + 80031e0: b008 add sp, #32 + 80031e2: bd70 pop {r4, r5, r6, pc} + +080031e4 : +{ + 80031e4: e92d 43f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, lr} + 80031e8: 4606 mov r6, r0 + 80031ea: b089 sub sp, #36 ; 0x24 + 80031ec: 460d mov r5, r1 + 80031ee: 4617 mov r7, r2 + for(int i=0; i + int rv = ae_gendig_counter(counter_number, *result, digest); + 80031fc: 6831 ldr r1, [r6, #0] + 80031fe: 466a mov r2, sp + 8003200: 4628 mov r0, r5 + 8003202: f7ff ff74 bl 80030ee + RET_IF_BAD(rv); + 8003206: 4604 mov r4, r0 + 8003208: b998 cbnz r0, 8003232 + if(!ae_is_correct_tempkey(digest)) { + 800320a: 4668 mov r0, sp + 800320c: f7ff fd00 bl 8002c10 + 8003210: b978 cbnz r0, 8003232 + fatal_mitm(); + 8003212: f7fd fc23 bl 8000a5c + ae_send(OP_Counter, 0x1, counter_number); + 8003216: 464a mov r2, r9 + 8003218: 2101 movs r1, #1 + 800321a: 2024 movs r0, #36 ; 0x24 + 800321c: f7ff fc8f bl 8002b3e + int rv = ae_read_n(4, (uint8_t *)result); + 8003220: 4631 mov r1, r6 + 8003222: 2004 movs r0, #4 + 8003224: f7ff fc1e bl 8002a64 + RET_IF_BAD(rv); + 8003228: 4604 mov r4, r0 + 800322a: b910 cbnz r0, 8003232 + for(int i=0; i +} + 8003232: 4620 mov r0, r4 + 8003234: b009 add sp, #36 ; 0x24 + 8003236: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + +0800323a : +// ae_encrypted_read32() +// + int +ae_encrypted_read32(int data_slot, int blk, + int read_kn, const uint8_t read_key[32], uint8_t data[32]) +{ + 800323a: b5f0 push {r4, r5, r6, r7, lr} + 800323c: b08b sub sp, #44 ; 0x2c + 800323e: 4617 mov r7, r2 + 8003240: 460e mov r6, r1 + 8003242: 9d10 ldr r5, [sp, #64] ; 0x40 + 8003244: 9301 str r3, [sp, #4] + 8003246: 4604 mov r4, r0 + uint8_t digest[32]; + + ae_pair_unlock(); + 8003248: f7ff fdb2 bl 8002db0 + + int rv = ae_gendig_slot(read_kn, read_key, digest); + 800324c: 9901 ldr r1, [sp, #4] + 800324e: aa02 add r2, sp, #8 + 8003250: 4638 mov r0, r7 + 8003252: f7ff fecd bl 8002ff0 + RET_IF_BAD(rv); + 8003256: b9c0 cbnz r0, 800328a + + // read nth 32-byte "block" + ae_send(OP_Read, 0x82, (blk << 8) | (data_slot<<3)); + 8003258: 00e4 lsls r4, r4, #3 + 800325a: ea44 2206 orr.w r2, r4, r6, lsl #8 + 800325e: 2182 movs r1, #130 ; 0x82 + 8003260: 2002 movs r0, #2 + 8003262: b292 uxth r2, r2 + 8003264: f7ff fc6b bl 8002b3e + + rv = ae_read_n(32, data); + 8003268: 4629 mov r1, r5 + 800326a: 2020 movs r0, #32 + 800326c: f7ff fbfa bl 8002a64 + RET_IF_BAD(rv); + 8003270: b958 cbnz r0, 800328a + 8003272: 1e6a subs r2, r5, #1 + 8003274: ab02 add r3, sp, #8 + 8003276: 351f adds r5, #31 + *(acc) ^= *(more); + 8003278: f812 1f01 ldrb.w r1, [r2, #1]! + 800327c: f813 4b01 ldrb.w r4, [r3], #1 + for(; len; len--, more++, acc++) { + 8003280: 4295 cmp r5, r2 + *(acc) ^= *(more); + 8003282: ea81 0104 eor.w r1, r1, r4 + 8003286: 7011 strb r1, [r2, #0] + for(; len; len--, more++, acc++) { + 8003288: d1f6 bne.n 8003278 + + xor_mixin(data, digest, 32); + + return 0; +} + 800328a: b00b add sp, #44 ; 0x2c + 800328c: bdf0 pop {r4, r5, r6, r7, pc} + ... + +08003290 : + +// ae_encrypted_read() +// + int +ae_encrypted_read(int data_slot, int read_kn, const uint8_t read_key[32], uint8_t *data, int len) +{ + 8003290: e92d 43f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, lr} + 8003294: b08b sub sp, #44 ; 0x2c + 8003296: 4607 mov r7, r0 + 8003298: 9d12 ldr r5, [sp, #72] ; 0x48 + // not clear if chip supports 4-byte encrypted reads + ASSERT((len == 32) || (len == 72)); + 800329a: 2d20 cmp r5, #32 +{ + 800329c: 4688 mov r8, r1 + 800329e: 4691 mov r9, r2 + 80032a0: 461e mov r6, r3 + ASSERT((len == 32) || (len == 72)); + 80032a2: d004 beq.n 80032ae + 80032a4: 2d48 cmp r5, #72 ; 0x48 + 80032a6: d002 beq.n 80032ae + 80032a8: 4815 ldr r0, [pc, #84] ; (8003300 ) + 80032aa: f7fd fbcd bl 8000a48 + + int rv = ae_encrypted_read32(data_slot, 0, read_kn, read_key, data); + 80032ae: 9600 str r6, [sp, #0] + 80032b0: 464b mov r3, r9 + 80032b2: 4642 mov r2, r8 + 80032b4: 2100 movs r1, #0 + 80032b6: 4638 mov r0, r7 + 80032b8: f7ff ffbf bl 800323a + RET_IF_BAD(rv); + 80032bc: 4604 mov r4, r0 + 80032be: b9d0 cbnz r0, 80032f6 + + if(len == 32) return 0; + 80032c0: 2d20 cmp r5, #32 + 80032c2: d018 beq.n 80032f6 + + rv = ae_encrypted_read32(data_slot, 1, read_kn, read_key, data+32); + 80032c4: f106 0320 add.w r3, r6, #32 + 80032c8: 9300 str r3, [sp, #0] + 80032ca: 4642 mov r2, r8 + 80032cc: 464b mov r3, r9 + 80032ce: 2101 movs r1, #1 + 80032d0: 4638 mov r0, r7 + 80032d2: f7ff ffb2 bl 800323a + RET_IF_BAD(rv); + 80032d6: 4604 mov r4, r0 + 80032d8: b968 cbnz r0, 80032f6 + + uint8_t tmp[32]; + rv = ae_encrypted_read32(data_slot, 2, read_kn, read_key, tmp); + 80032da: ad02 add r5, sp, #8 + 80032dc: 9500 str r5, [sp, #0] + 80032de: 464b mov r3, r9 + 80032e0: 4642 mov r2, r8 + 80032e2: 2102 movs r1, #2 + 80032e4: 4638 mov r0, r7 + 80032e6: f7ff ffa8 bl 800323a + RET_IF_BAD(rv); + 80032ea: 4604 mov r4, r0 + 80032ec: b918 cbnz r0, 80032f6 + + memcpy(data+64, tmp, 72-64); + 80032ee: 462a mov r2, r5 + 80032f0: ca03 ldmia r2!, {r0, r1} + 80032f2: 6430 str r0, [r6, #64] ; 0x40 + 80032f4: 6471 str r1, [r6, #68] ; 0x44 + + return 0; +} + 80032f6: 4620 mov r0, r4 + 80032f8: b00b add sp, #44 ; 0x2c + 80032fa: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + 80032fe: bf00 nop + 8003300: 0800e3e0 .word 0x0800e3e0 + +08003304 : +// ae_encrypted_write() +// + int +ae_encrypted_write32(int data_slot, int blk, int write_kn, + const uint8_t write_key[32], const uint8_t data[32]) +{ + 8003304: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + 8003308: b0b8 sub sp, #224 ; 0xe0 + 800330a: 4617 mov r7, r2 + 800330c: 460d mov r5, r1 + 800330e: 9e3e ldr r6, [sp, #248] ; 0xf8 + 8003310: 9303 str r3, [sp, #12] + 8003312: 4604 mov r4, r0 + uint8_t digest[32]; + + ae_pair_unlock(); + 8003314: f7ff fd4c bl 8002db0 + + // generate a hash over shared secret and rng + int rv = ae_gendig_slot(write_kn, write_key, digest); + 8003318: 9903 ldr r1, [sp, #12] + 800331a: aa0d add r2, sp, #52 ; 0x34 + 800331c: 4638 mov r0, r7 + 800331e: f7ff fe67 bl 8002ff0 + RET_IF_BAD(rv); + 8003322: 2800 cmp r0, #0 + 8003324: d151 bne.n 80033ca + 8003326: 1e72 subs r2, r6, #1 + 8003328: af0d add r7, sp, #52 ; 0x34 + 800332a: a915 add r1, sp, #84 ; 0x54 + 800332c: f106 0c1f add.w ip, r6, #31 + + // encrypt the data to be written, and append an authenticating MAC + uint8_t body[32 + 32]; + + for(int i=0; i<32; i++) { + body[i] = data[i] ^ digest[i]; + 8003330: f812 ef01 ldrb.w lr, [r2, #1]! + 8003334: f817 0b01 ldrb.w r0, [r7], #1 + for(int i=0; i<32; i++) { + 8003338: 4562 cmp r2, ip + body[i] = data[i] ^ digest[i]; + 800333a: ea80 000e eor.w r0, r0, lr + 800333e: f801 0b01 strb.w r0, [r1], #1 + for(int i=0; i<32; i++) { + 8003342: d1f5 bne.n 8003330 + // + (b'\0'*25) + // + new_value) + // assert len(msg) == 32+1+1+2+1+2+25+32 + // + SHA256_CTX ctx; + sha256_init(&ctx); + 8003344: a825 add r0, sp, #148 ; 0x94 + 8003346: f002 f8a1 bl 800548c + + uint8_t p1 = 0x80|2; // 32 bytes into a data slot + uint8_t p2_lsb = (data_slot << 3); + uint8_t p2_msb = blk; + + uint8_t args[7] = { OP_Write, p1, p2_lsb, p2_msb, 0xEE, 0x01, 0x23 }; + 800334a: 22ee movs r2, #238 ; 0xee + 800334c: f88d 2014 strb.w r2, [sp, #20] + 8003350: 2201 movs r2, #1 + 8003352: f88d 2015 strb.w r2, [sp, #21] + uint8_t p2_lsb = (data_slot << 3); + 8003356: 00e4 lsls r4, r4, #3 + uint8_t args[7] = { OP_Write, p1, p2_lsb, p2_msb, 0xEE, 0x01, 0x23 }; + 8003358: 2223 movs r2, #35 ; 0x23 + uint8_t zeros[25] = { 0 }; + 800335a: 2100 movs r1, #0 + uint8_t p2_lsb = (data_slot << 3); + 800335c: b2e4 uxtb r4, r4 + uint8_t args[7] = { OP_Write, p1, p2_lsb, p2_msb, 0xEE, 0x01, 0x23 }; + 800335e: 2712 movs r7, #18 + 8003360: f04f 0882 mov.w r8, #130 ; 0x82 + 8003364: f88d 2016 strb.w r2, [sp, #22] + uint8_t zeros[25] = { 0 }; + 8003368: a807 add r0, sp, #28 + 800336a: 2215 movs r2, #21 + 800336c: 9106 str r1, [sp, #24] + uint8_t args[7] = { OP_Write, p1, p2_lsb, p2_msb, 0xEE, 0x01, 0x23 }; + 800336e: f88d 7010 strb.w r7, [sp, #16] + 8003372: f88d 8011 strb.w r8, [sp, #17] + 8003376: f88d 4012 strb.w r4, [sp, #18] + uint8_t p2_msb = blk; + 800337a: f88d 5013 strb.w r5, [sp, #19] + uint8_t zeros[25] = { 0 }; + 800337e: f00a f979 bl 800d674 + + sha256_update(&ctx, digest, 32); + 8003382: 2220 movs r2, #32 + 8003384: a90d add r1, sp, #52 ; 0x34 + 8003386: a825 add r0, sp, #148 ; 0x94 + 8003388: f002 f88e bl 80054a8 + sha256_update(&ctx, args, sizeof(args)); + 800338c: 2207 movs r2, #7 + 800338e: a904 add r1, sp, #16 + 8003390: a825 add r0, sp, #148 ; 0x94 + 8003392: f002 f889 bl 80054a8 + sha256_update(&ctx, zeros, sizeof(zeros)); + 8003396: 2219 movs r2, #25 + 8003398: a906 add r1, sp, #24 + 800339a: a825 add r0, sp, #148 ; 0x94 + 800339c: f002 f884 bl 80054a8 + sha256_update(&ctx, data, 32); + 80033a0: 2220 movs r2, #32 + 80033a2: 4631 mov r1, r6 + 80033a4: a825 add r0, sp, #148 ; 0x94 + 80033a6: f002 f87f bl 80054a8 + + sha256_final(&ctx, &body[32]); + 80033aa: a91d add r1, sp, #116 ; 0x74 + 80033ac: a825 add r0, sp, #148 ; 0x94 + 80033ae: f002 f8c1 bl 8005534 + + ae_send_n(OP_Write, p1, (p2_msb << 8) | p2_lsb, body, sizeof(body)); + 80033b2: 2140 movs r1, #64 ; 0x40 + 80033b4: ea44 2205 orr.w r2, r4, r5, lsl #8 + 80033b8: b292 uxth r2, r2 + 80033ba: 9100 str r1, [sp, #0] + 80033bc: ab15 add r3, sp, #84 ; 0x54 + 80033be: 4641 mov r1, r8 + 80033c0: 4638 mov r0, r7 + 80033c2: f7ff fb89 bl 8002ad8 + + return ae_read1(); + 80033c6: f7ff fb31 bl 8002a2c +} + 80033ca: b038 add sp, #224 ; 0xe0 + 80033cc: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + +080033d0 : +// ae_encrypted_write() +// + int +ae_encrypted_write(int data_slot, int write_kn, const uint8_t write_key[32], + const uint8_t *data, int len) +{ + 80033d0: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + 80033d4: b08a sub sp, #40 ; 0x28 + ASSERT(data_slot >= 0); + ASSERT(data_slot <= 15); + 80033d6: 280f cmp r0, #15 +{ + 80033d8: 9d12 ldr r5, [sp, #72] ; 0x48 + 80033da: 4606 mov r6, r0 + 80033dc: 460f mov r7, r1 + 80033de: 4690 mov r8, r2 + 80033e0: 4699 mov r9, r3 + ASSERT(data_slot <= 15); + 80033e2: d902 bls.n 80033ea + ASSERT(data_slot >= 0); + 80033e4: 4814 ldr r0, [pc, #80] ; (8003438 ) + 80033e6: f7fd fb2f bl 8000a48 + + for(int blk=0; blk<3 && len>0; blk++, len-=32) { + 80033ea: 2400 movs r4, #0 + int here = MIN(32, len); + + // be nice and don't read past end of input buffer + uint8_t tmp[32] = { 0 }; + 80033ec: 46a2 mov sl, r4 + for(int blk=0; blk<3 && len>0; blk++, len-=32) { + 80033ee: 2d00 cmp r5, #0 + 80033f0: dd1d ble.n 800342e + uint8_t tmp[32] = { 0 }; + 80033f2: 221c movs r2, #28 + 80033f4: 2100 movs r1, #0 + 80033f6: a803 add r0, sp, #12 + 80033f8: f8cd a008 str.w sl, [sp, #8] + 80033fc: f00a f93a bl 800d674 + memcpy(tmp, data+(32*blk), here); + 8003400: ab02 add r3, sp, #8 + 8003402: 2d20 cmp r5, #32 + 8003404: 462a mov r2, r5 + 8003406: eb09 1144 add.w r1, r9, r4, lsl #5 + 800340a: bfa8 it ge + 800340c: 2220 movge r2, #32 + 800340e: 4618 mov r0, r3 + 8003410: f00a f908 bl 800d624 + + int rv = ae_encrypted_write32(data_slot, blk, write_kn, write_key, tmp); + 8003414: 4643 mov r3, r8 + 8003416: 9000 str r0, [sp, #0] + 8003418: 463a mov r2, r7 + 800341a: 4621 mov r1, r4 + 800341c: 4630 mov r0, r6 + 800341e: f7ff ff71 bl 8003304 + RET_IF_BAD(rv); + 8003422: b928 cbnz r0, 8003430 + for(int blk=0; blk<3 && len>0; blk++, len-=32) { + 8003424: 3401 adds r4, #1 + 8003426: 2c03 cmp r4, #3 + 8003428: f1a5 0520 sub.w r5, r5, #32 + 800342c: d1df bne.n 80033ee + } + + return 0; + 800342e: 2000 movs r0, #0 +} + 8003430: b00a add sp, #40 ; 0x28 + 8003432: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + 8003436: bf00 nop + 8003438: 0800e3e0 .word 0x0800e3e0 + +0800343c : + +// ae_read_data_slot() +// + int +ae_read_data_slot(int slot_num, uint8_t *data, int len) +{ + 800343c: b570 push {r4, r5, r6, lr} + ASSERT((len == 4) || (len == 32) || (len == 72)); + 800343e: 2a04 cmp r2, #4 +{ + 8003440: b088 sub sp, #32 + 8003442: 460d mov r5, r1 + 8003444: 4616 mov r6, r2 + ASSERT((len == 4) || (len == 32) || (len == 72)); + 8003446: d006 beq.n 8003456 + 8003448: 2a20 cmp r2, #32 + 800344a: d038 beq.n 80034be + 800344c: 2a48 cmp r2, #72 ; 0x48 + 800344e: d036 beq.n 80034be + 8003450: 481c ldr r0, [pc, #112] ; (80034c4 ) + 8003452: f7fd faf9 bl 8000a48 + + // zone => data + // only reading first block of 32 bytes. ignore the rest + ae_send(OP_Read, (len == 4 ? 0x00 : 0x80) | 2, (slot_num<<3)); + 8003456: 2102 movs r1, #2 + 8003458: 00c4 lsls r4, r0, #3 + 800345a: b2a2 uxth r2, r4 + 800345c: 2002 movs r0, #2 + 800345e: f7ff fb6e bl 8002b3e + + int rv = ae_read_n((len == 4) ? 4 : 32, data); + 8003462: 2e04 cmp r6, #4 + 8003464: 4629 mov r1, r5 + 8003466: bf0c ite eq + 8003468: 2004 moveq r0, #4 + 800346a: 2020 movne r0, #32 + 800346c: f7ff fafa bl 8002a64 + RET_IF_BAD(rv); + 8003470: 4603 mov r3, r0 + 8003472: bb08 cbnz r0, 80034b8 + + if(len == 72) { + 8003474: 2e48 cmp r6, #72 ; 0x48 + 8003476: d11f bne.n 80034b8 + // read second block + ae_send(OP_Read, 0x82, (1<<8) | (slot_num<<3)); + 8003478: b224 sxth r4, r4 + 800347a: f444 7280 orr.w r2, r4, #256 ; 0x100 + 800347e: b292 uxth r2, r2 + 8003480: 2182 movs r1, #130 ; 0x82 + 8003482: 2002 movs r0, #2 + 8003484: f7ff fb5b bl 8002b3e + + int rv = ae_read_n(32, data+32); + 8003488: f105 0120 add.w r1, r5, #32 + 800348c: 2020 movs r0, #32 + 800348e: f7ff fae9 bl 8002a64 + RET_IF_BAD(rv); + 8003492: 4603 mov r3, r0 + 8003494: b980 cbnz r0, 80034b8 + + // read third block, but only using part of it + uint8_t tmp[32]; + ae_send(OP_Read, 0x82, (2<<8) | (slot_num<<3)); + 8003496: f444 7400 orr.w r4, r4, #512 ; 0x200 + 800349a: b2a2 uxth r2, r4 + 800349c: 2182 movs r1, #130 ; 0x82 + 800349e: 2002 movs r0, #2 + 80034a0: f7ff fb4d bl 8002b3e + + rv = ae_read_n(32, tmp); + 80034a4: 4669 mov r1, sp + 80034a6: 2020 movs r0, #32 + 80034a8: f7ff fadc bl 8002a64 + RET_IF_BAD(rv); + 80034ac: 4603 mov r3, r0 + 80034ae: b918 cbnz r0, 80034b8 + + memcpy(data+64, tmp, 72-64); + 80034b0: 466a mov r2, sp + 80034b2: ca03 ldmia r2!, {r0, r1} + 80034b4: 6428 str r0, [r5, #64] ; 0x40 + 80034b6: 6469 str r1, [r5, #68] ; 0x44 + } + + return 0; +} + 80034b8: 4618 mov r0, r3 + 80034ba: b008 add sp, #32 + 80034bc: bd70 pop {r4, r5, r6, pc} + ae_send(OP_Read, (len == 4 ? 0x00 : 0x80) | 2, (slot_num<<3)); + 80034be: 2182 movs r1, #130 ; 0x82 + 80034c0: e7ca b.n 8003458 + 80034c2: bf00 nop + 80034c4: 0800e3e0 .word 0x0800e3e0 + +080034c8 : + +// ae_set_gpio() +// + int +ae_set_gpio(int state) +{ + 80034c8: b513 push {r0, r1, r4, lr} + // 1=turn on green, 0=red light (if not yet configured to be secure) + ae_send(OP_Info, 3, 2 | (!!state)); + 80034ca: 1e04 subs r4, r0, #0 + 80034cc: bf14 ite ne + 80034ce: 2203 movne r2, #3 + 80034d0: 2202 moveq r2, #2 + 80034d2: 2103 movs r1, #3 + 80034d4: 2030 movs r0, #48 ; 0x30 + 80034d6: f7ff fb32 bl 8002b3e + + // "Always return the current state in the first byte followed by three bytes of 0x00" + // - simple 1/0, in LSB. + uint8_t resp[4]; + + int rv = ae_read_n(4, resp); + 80034da: a901 add r1, sp, #4 + 80034dc: 2004 movs r0, #4 + 80034de: f7ff fac1 bl 8002a64 + RET_IF_BAD(rv); + 80034e2: b928 cbnz r0, 80034f0 + + return (resp[0] != state) ? -1 : 0; + 80034e4: f89d 0004 ldrb.w r0, [sp, #4] + 80034e8: 1b00 subs r0, r0, r4 + 80034ea: bf18 it ne + 80034ec: f04f 30ff movne.w r0, #4294967295 ; 0xffffffff +} + 80034f0: b002 add sp, #8 + 80034f2: bd10 pop {r4, pc} + +080034f4 : +// +// Set the GPIO using secure hash generated somehow already. +// + int +ae_set_gpio_secure(uint8_t digest[32]) +{ + 80034f4: b538 push {r3, r4, r5, lr} + 80034f6: 4605 mov r5, r0 + ae_pair_unlock(); + 80034f8: f7ff fc5a bl 8002db0 + ae_checkmac(KEYNUM_firmware, digest); + 80034fc: 4629 mov r1, r5 + 80034fe: 200e movs r0, #14 + 8003500: f7ff fbd4 bl 8002cac + + int rv = ae_set_gpio(1); + 8003504: 2001 movs r0, #1 + 8003506: f7ff ffdf bl 80034c8 + + if(rv == 0) { + 800350a: 4604 mov r4, r0 + 800350c: b940 cbnz r0, 8003520 + // trust that readback, and so do a verify that the chip has + // the digest we think it does. If MitM wanted to turn off the output, + // they can do that anytime regardless. We just don't want them to be + // able to fake it being set, and therefore bypass the + // "unsigned firmware" delay and warning. + ae_pair_unlock(); + 800350e: f7ff fc4f bl 8002db0 + + if(ae_checkmac_hard(KEYNUM_firmware, digest) != 0) { + 8003512: 4629 mov r1, r5 + 8003514: 200e movs r0, #14 + 8003516: f7ff fdd9 bl 80030cc + 800351a: b108 cbz r0, 8003520 + fatal_mitm(); + 800351c: f7fd fa9e bl 8000a5c + } + } + + return rv; +} + 8003520: 4620 mov r0, r4 + 8003522: bd38 pop {r3, r4, r5, pc} + +08003524 : +// +// IMPORTANT: do not trust this result, could be MitM'ed. +// + uint8_t +ae_get_gpio(void) +{ + 8003524: b507 push {r0, r1, r2, lr} + // not doing error checking here + ae_send(OP_Info, 0x3, 0); + 8003526: 2200 movs r2, #0 + 8003528: 2103 movs r1, #3 + 800352a: 2030 movs r0, #48 ; 0x30 + 800352c: f7ff fb07 bl 8002b3e + + // note: always returns 4 bytes, but most are garbage and unused. + uint8_t tmp[4]; + ae_read_n(4, tmp); + 8003530: a901 add r1, sp, #4 + 8003532: 2004 movs r0, #4 + 8003534: f7ff fa96 bl 8002a64 + + return tmp[0]; +} + 8003538: f89d 0004 ldrb.w r0, [sp, #4] + 800353c: b003 add sp, #12 + 800353e: f85d fb04 ldr.w pc, [sp], #4 + +08003542 : +// +// Read a 4-byte area from config area, or -1 if fail. +// + int +ae_read_config_word(int offset, uint8_t *dest) +{ + 8003542: b510 push {r4, lr} + offset &= 0x7f; + + // read 32 bits (aligned) + ae_send(OP_Read, 0x00, offset/4); + 8003544: f3c0 0284 ubfx r2, r0, #2, #5 +{ + 8003548: 460c mov r4, r1 + ae_send(OP_Read, 0x00, offset/4); + 800354a: 2002 movs r0, #2 + 800354c: 2100 movs r1, #0 + 800354e: f7ff faf6 bl 8002b3e + + int rv = ae_read_n(4, dest); + 8003552: 4621 mov r1, r4 + 8003554: 2004 movs r0, #4 + 8003556: f7ff fa85 bl 8002a64 + if(rv) return -1; + 800355a: 3800 subs r0, #0 + 800355c: bf18 it ne + 800355e: 2001 movne r0, #1 + + return 0; +} + 8003560: 4240 negs r0, r0 + 8003562: bd10 pop {r4, pc} + +08003564 : +{ + 8003564: b513 push {r0, r1, r4, lr} + 8003566: 4604 mov r4, r0 + ae_read_config_word(offset, tmp); + 8003568: a901 add r1, sp, #4 + 800356a: f7ff ffea bl 8003542 + return tmp[offset % 4]; + 800356e: 4263 negs r3, r4 + 8003570: f003 0303 and.w r3, r3, #3 + 8003574: f004 0403 and.w r4, r4, #3 + 8003578: bf58 it pl + 800357a: 425c negpl r4, r3 + 800357c: f104 0308 add.w r3, r4, #8 + 8003580: eb0d 0403 add.w r4, sp, r3 +} + 8003584: f814 0c04 ldrb.w r0, [r4, #-4] + 8003588: b002 add sp, #8 + 800358a: bd10 pop {r4, pc} + +0800358c : + +// ae_destroy_key() +// + int +ae_destroy_key(int keynum) +{ + 800358c: b510 push {r4, lr} + 800358e: b090 sub sp, #64 ; 0x40 + uint8_t numin[20]; + + // Load tempkey with a known (random) nonce value + rng_buffer(numin, sizeof(numin)); + 8003590: 2114 movs r1, #20 +{ + 8003592: 4604 mov r4, r0 + rng_buffer(numin, sizeof(numin)); + 8003594: a803 add r0, sp, #12 + 8003596: f7ff f8db bl 8002750 + ae_send_n(OP_Nonce, 0, 0, numin, 20); + 800359a: 2314 movs r3, #20 + 800359c: 2200 movs r2, #0 + 800359e: 9300 str r3, [sp, #0] + 80035a0: 4611 mov r1, r2 + 80035a2: 2016 movs r0, #22 + 80035a4: ab03 add r3, sp, #12 + 80035a6: f7ff fa97 bl 8002ad8 + + // Nonce command returns the RNG result, not contents of TempKey, + // but since we are destroying, no need to calculate what it is. + uint8_t randout[32]; + int rv = ae_read_n(32, randout); + 80035aa: a908 add r1, sp, #32 + 80035ac: 2020 movs r0, #32 + 80035ae: f7ff fa59 bl 8002a64 + RET_IF_BAD(rv); + 80035b2: b930 cbnz r0, 80035c2 + + // do a "DeriveKey" operation, based on that! + ae_send(OP_DeriveKey, 0x00, keynum); + 80035b4: 4601 mov r1, r0 + 80035b6: b2a2 uxth r2, r4 + 80035b8: 201c movs r0, #28 + 80035ba: f7ff fac0 bl 8002b3e + + return ae_read1(); + 80035be: f7ff fa35 bl 8002a2c +} + 80035c2: b010 add sp, #64 ; 0x40 + 80035c4: bd10 pop {r4, pc} + +080035c6 : + +// ae_config_read() +// + int +ae_config_read(uint8_t config[128]) +{ + 80035c6: b538 push {r3, r4, r5, lr} + 80035c8: 4605 mov r5, r0 + for(int blk=0; blk<4; blk++) { + 80035ca: 2400 movs r4, #0 + // read 32 bytes (aligned) from config "zone" + ae_send(OP_Read, 0x80, blk<<3); + 80035cc: 00e2 lsls r2, r4, #3 + 80035ce: 2180 movs r1, #128 ; 0x80 + 80035d0: 2002 movs r0, #2 + 80035d2: b292 uxth r2, r2 + 80035d4: f7ff fab3 bl 8002b3e + + int rv = ae_read_n(32, &config[32*blk]); + 80035d8: eb05 1144 add.w r1, r5, r4, lsl #5 + 80035dc: 2020 movs r0, #32 + 80035de: f7ff fa41 bl 8002a64 + if(rv) return EIO; + 80035e2: b918 cbnz r0, 80035ec + for(int blk=0; blk<4; blk++) { + 80035e4: 3401 adds r4, #1 + 80035e6: 2c04 cmp r4, #4 + 80035e8: d1f0 bne.n 80035cc + } + + return 0; +} + 80035ea: bd38 pop {r3, r4, r5, pc} + if(rv) return EIO; + 80035ec: 2005 movs r0, #5 + 80035ee: e7fc b.n 80035ea + +080035f0 : +// us to write the (existing) pairing secret into, they would see the pairing +// secret in cleartext. They could then restore original chip and access freely. +// + int +ae_setup_config(void) +{ + 80035f0: b5f0 push {r4, r5, r6, r7, lr} + 80035f2: 2405 movs r4, #5 + 80035f4: f5ad 7d41 sub.w sp, sp, #772 ; 0x304 + // Need to wake up AE, since many things happen before this point. + for(int retry=0; retry<5; retry++) { + if(!ae_probe()) break; + 80035f8: f7ff fc6c bl 8002ed4 + 80035fc: b108 cbz r0, 8003602 + for(int retry=0; retry<5; retry++) { + 80035fe: 3c01 subs r4, #1 + 8003600: d1fa bne.n 80035f8 + // Is data zone is locked? + // Allow rest of function to happen if it's not. + +#if 1 + // 0x55 = unlocked; 0x00 = locked + bool data_locked = (ae_read_config_byte(86) != 0x55); + 8003602: 2056 movs r0, #86 ; 0x56 + 8003604: f7ff ffae bl 8003564 + if(data_locked) return 0; // basically success + 8003608: 2855 cmp r0, #85 ; 0x55 + 800360a: f040 80df bne.w 80037cc + + // To lock, we need a CRC over whole thing, but we + // only set a few values... plus the serial number is + // in there, so start with some readout. + uint8_t config[128]; + int rv = ae_config_read(config); + 800360e: a838 add r0, sp, #224 ; 0xe0 + 8003610: f7ff ffd9 bl 80035c6 + if(rv) return rv; + 8003614: 4604 mov r4, r0 + 8003616: 2800 cmp r0, #0 + 8003618: f040 80d9 bne.w 80037ce + uint8_t config[128]; + while(ae_config_read(config)) ; +#endif + + // verify some fixed values + ASSERT(config[0] == 0x01); + 800361c: f89d 30e0 ldrb.w r3, [sp, #224] ; 0xe0 + 8003620: 2b01 cmp r3, #1 + 8003622: d002 beq.n 800362a + 8003624: 486f ldr r0, [pc, #444] ; (80037e4 ) + + ae_keep_alive(); + + // lock config zone + if(ae_lock_config_zone(config)) { + INCONSISTENT("conf lock"); + 8003626: f7fd fa0f bl 8000a48 + ASSERT(config[1] == 0x23); + 800362a: f89d 30e1 ldrb.w r3, [sp, #225] ; 0xe1 + 800362e: 2b23 cmp r3, #35 ; 0x23 + 8003630: d1f8 bne.n 8003624 + ASSERT(config[12] == 0xee); + 8003632: f89d 30ec ldrb.w r3, [sp, #236] ; 0xec + 8003636: 2bee cmp r3, #238 ; 0xee + 8003638: d1f4 bne.n 8003624 + int8_t partno = ((config[6]>>4)&0xf); + 800363a: f89d 30e6 ldrb.w r3, [sp, #230] ; 0xe6 + ASSERT(partno == 6); + 800363e: 091b lsrs r3, r3, #4 + 8003640: 2b06 cmp r3, #6 + 8003642: d1ef bne.n 8003624 + memcpy(serial, &config[0], 4); + 8003644: 9b38 ldr r3, [sp, #224] ; 0xe0 + 8003646: 9303 str r3, [sp, #12] + memcpy(&serial[4], &config[8], 5); + 8003648: ab3a add r3, sp, #232 ; 0xe8 + 800364a: e893 0003 ldmia.w r3, {r0, r1} + 800364e: 9004 str r0, [sp, #16] + 8003650: f88d 1014 strb.w r1, [sp, #20] + if(check_all_ones(rom_secrets->ae_serial_number, 9)) { + 8003654: 4864 ldr r0, [pc, #400] ; (80037e8 ) + 8003656: 2109 movs r1, #9 + 8003658: f7ff f812 bl 8002680 + 800365c: b110 cbz r0, 8003664 + flash_save_ae_serial(serial); + 800365e: a803 add r0, sp, #12 + 8003660: f7fe fd66 bl 8002130 + if(!check_equal(rom_secrets->ae_serial_number, serial, 9)) { + 8003664: 4860 ldr r0, [pc, #384] ; (80037e8 ) + 8003666: 2209 movs r2, #9 + 8003668: a903 add r1, sp, #12 + 800366a: f7ff f822 bl 80026b2 + 800366e: 2800 cmp r0, #0 + 8003670: f000 80b6 beq.w 80037e0 + if(config[87] == 0x55) { + 8003674: f89d 3137 ldrb.w r3, [sp, #311] ; 0x137 + 8003678: 2b55 cmp r3, #85 ; 0x55 + 800367a: d12b bne.n 80036d4 + memcpy(&config[16], config_1, sizeof(config_1)); + 800367c: 495b ldr r1, [pc, #364] ; (80037ec ) + 800367e: 2244 movs r2, #68 ; 0x44 + 8003680: a83c add r0, sp, #240 ; 0xf0 + 8003682: f009 ffcf bl 800d624 + memcpy(&config[90], config_2, sizeof(config_2)); + 8003686: 4b5a ldr r3, [pc, #360] ; (80037f0 ) + 8003688: f50d 729d add.w r2, sp, #314 ; 0x13a + 800368c: f103 0124 add.w r1, r3, #36 ; 0x24 + 8003690: f853 0b04 ldr.w r0, [r3], #4 + 8003694: f842 0b04 str.w r0, [r2], #4 + 8003698: 428b cmp r3, r1 + 800369a: d1f9 bne.n 8003690 + 800369c: 881b ldrh r3, [r3, #0] + 800369e: 8013 strh r3, [r2, #0] + for(int n=16; n<128; n+= 4) { + 80036a0: 2510 movs r5, #16 + ae_send_n(OP_Write, 0, n/4, &config[n], 4); + 80036a2: 2604 movs r6, #4 + if(n == 84) continue; // that word not writable + 80036a4: 2d54 cmp r5, #84 ; 0x54 + 80036a6: d130 bne.n 800370a + for(int n=16; n<128; n+= 4) { + 80036a8: 3504 adds r5, #4 + 80036aa: 2d80 cmp r5, #128 ; 0x80 + 80036ac: d1fa bne.n 80036a4 + ae_send_idle(); + 80036ae: f7ff f90a bl 80028c6 + uint8_t crc[2] = {0, 0}; + 80036b2: 2600 movs r6, #0 + crc16_chain(128, config, crc); + 80036b4: aa58 add r2, sp, #352 ; 0x160 + 80036b6: a938 add r1, sp, #224 ; 0xe0 + 80036b8: 4628 mov r0, r5 + uint8_t crc[2] = {0, 0}; + 80036ba: f8ad 6160 strh.w r6, [sp, #352] ; 0x160 + crc16_chain(128, config, crc); + 80036be: f7ff f8b5 bl 800282c + ae_send(OP_Lock, 0x0, (crc[1]<<8) | crc[0]); + 80036c2: f8bd 2160 ldrh.w r2, [sp, #352] ; 0x160 + 80036c6: 4631 mov r1, r6 + 80036c8: 2017 movs r0, #23 + 80036ca: f7ff fa38 bl 8002b3e + return ae_read1(); + 80036ce: f7ff f9ad bl 8002a2c + if(ae_lock_config_zone(config)) { + 80036d2: bb38 cbnz r0, 8003724 + // Load data zone with some known values. + // The datazone still unlocked, so no encryption needed (nor possible). + + // will use zeros for all PIN codes, and customer-defined-secret starting values + uint8_t zeros[72]; + memset(zeros, 0, sizeof(zeros)); + 80036d4: 2248 movs r2, #72 ; 0x48 + 80036d6: 2100 movs r1, #0 + 80036d8: a826 add r0, sp, #152 ; 0x98 + 80036da: f009 ffcb bl 800d674 + se2_save_auth_pubkey(pubkey); + break; + } + + case 0: + if(ae_write_data_slot(kn, (const uint8_t *)copyright_msg, 32, true)) { + 80036de: 4e45 ldr r6, [pc, #276] ; (80037f4 ) + 80036e0: f8bd 5138 ldrh.w r5, [sp, #312] ; 0x138 + if(ae_write_data_slot(kn, rom_secrets->pairing_secret, 32, false)) { + 80036e4: 4f44 ldr r7, [pc, #272] ; (80037f8 ) + ae_send_idle(); + 80036e6: f7ff f8ee bl 80028c6 + if(!(unlocked & (1< + switch(kn) { + 80036f2: 2c0e cmp r4, #14 + 80036f4: d85c bhi.n 80037b0 + 80036f6: e8df f004 tbb [pc, r4] + 80036fa: 176e .short 0x176e + 80036fc: 29202920 .word 0x29202920 + 8003700: 2d304c3e .word 0x2d304c3e + 8003704: 2d2d2d2d .word 0x2d2d2d2d + 8003708: 29 .byte 0x29 + 8003709: 00 .byte 0x00 + ae_send_n(OP_Write, 0, n/4, &config[n], 4); + 800370a: ab38 add r3, sp, #224 ; 0xe0 + 800370c: 442b add r3, r5 + 800370e: f3c5 028f ubfx r2, r5, #2, #16 + 8003712: 2100 movs r1, #0 + 8003714: 2012 movs r0, #18 + 8003716: 9600 str r6, [sp, #0] + 8003718: f7ff f9de bl 8002ad8 + int rv = ae_read1(); + 800371c: f7ff f986 bl 8002a2c + if(rv) return rv; + 8003720: 2800 cmp r0, #0 + 8003722: d0c1 beq.n 80036a8 + INCONSISTENT("conf lock"); + 8003724: 4835 ldr r0, [pc, #212] ; (80037fc ) + 8003726: e77e b.n 8003626 + if(ae_write_data_slot(kn, rom_secrets->pairing_secret, 32, false)) { + 8003728: 2300 movs r3, #0 + 800372a: 2220 movs r2, #32 + 800372c: 4639 mov r1, r7 + 800372e: 2001 movs r0, #1 + if(ae_write_data_slot(kn, (const uint8_t *)copyright_msg, 32, true)) { + 8003730: f7ff fbf4 bl 8002f1c + 8003734: 2800 cmp r0, #0 + 8003736: d03b beq.n 80037b0 + 8003738: e7f4 b.n 8003724 + rng_buffer(tmp, sizeof(tmp)); + 800373a: 2120 movs r1, #32 + 800373c: a806 add r0, sp, #24 + 800373e: f7ff f807 bl 8002750 + if(ae_write_data_slot(kn, tmp, 32, true)) { + 8003742: 2301 movs r3, #1 + 8003744: 2220 movs r2, #32 + 8003746: a906 add r1, sp, #24 + if(ae_write_data_slot(kn, zeros, 32, false)) { + 8003748: 4620 mov r0, r4 + 800374a: e7f1 b.n 8003730 + 800374c: 2300 movs r3, #0 + 800374e: 2220 movs r2, #32 + 8003750: a926 add r1, sp, #152 ; 0x98 + 8003752: e7f9 b.n 8003748 + if(ae_write_data_slot(kn, zeros, 72, false)) { + 8003754: 2300 movs r3, #0 + 8003756: 2248 movs r2, #72 ; 0x48 + 8003758: e7fa b.n 8003750 + uint8_t long_zeros[416] = {0}; + 800375a: 2300 movs r3, #0 + 800375c: 4619 mov r1, r3 + 800375e: f44f 72ce mov.w r2, #412 ; 0x19c + 8003762: a859 add r0, sp, #356 ; 0x164 + 8003764: 9358 str r3, [sp, #352] ; 0x160 + 8003766: f009 ff85 bl 800d674 + if(ae_write_data_slot(kn, long_zeros, 416, false)) { + 800376a: 2300 movs r3, #0 + 800376c: f44f 72d0 mov.w r2, #416 ; 0x1a0 + 8003770: a958 add r1, sp, #352 ; 0x160 + 8003772: 2008 movs r0, #8 + 8003774: e7dc b.n 8003730 + uint32_t buf[32/4] = { 1024, 1024 }; + 8003776: 2218 movs r2, #24 + 8003778: 2100 movs r1, #0 + 800377a: a810 add r0, sp, #64 ; 0x40 + 800377c: f009 ff7a bl 800d674 + 8003780: f44f 6380 mov.w r3, #1024 ; 0x400 + 8003784: e9cd 330e strd r3, r3, [sp, #56] ; 0x38 + if(ae_write_data_slot(KEYNUM_match_count, (const uint8_t *)buf,sizeof(buf),false)) { + 8003788: 2220 movs r2, #32 + 800378a: 2300 movs r3, #0 + 800378c: a90e add r1, sp, #56 ; 0x38 + 800378e: 2006 movs r0, #6 + 8003790: e7ce b.n 8003730 + if(ae_checkmac_hard(KEYNUM_main_pin, zeros) != 0) { + 8003792: a926 add r1, sp, #152 ; 0x98 + 8003794: 2003 movs r0, #3 + 8003796: f7ff fc99 bl 80030cc + 800379a: 2800 cmp r0, #0 + 800379c: d1c2 bne.n 8003724 + if(ae_gen_ecc_key(KEYNUM_joiner_key, pubkey)) { + 800379e: a916 add r1, sp, #88 ; 0x58 + 80037a0: 2007 movs r0, #7 + 80037a2: f7ff fb2b bl 8002dfc + 80037a6: 2800 cmp r0, #0 + 80037a8: d1bc bne.n 8003724 + se2_save_auth_pubkey(pubkey); + 80037aa: a816 add r0, sp, #88 ; 0x58 + 80037ac: f004 f932 bl 8007a14 + for(int kn=0; kn<16; kn++) { + 80037b0: 3401 adds r4, #1 + 80037b2: 2c10 cmp r4, #16 + 80037b4: d197 bne.n 80036e6 + ae_send_idle(); + 80037b6: f7ff f886 bl 80028c6 + ae_send(OP_Lock, 0x81, 0x0000); + 80037ba: 2200 movs r2, #0 + 80037bc: 2181 movs r1, #129 ; 0x81 + 80037be: 2017 movs r0, #23 + 80037c0: f7ff f9bd bl 8002b3e + return ae_read1(); + 80037c4: f7ff f932 bl 8002a2c + } + } + + // lock the data zone and effectively enter normal operation. + ae_keep_alive(); + if(ae_lock_data_zone()) { + 80037c8: 2800 cmp r0, #0 + 80037ca: d1ab bne.n 8003724 + if(data_locked) return 0; // basically success + 80037cc: 2400 movs r4, #0 + INCONSISTENT("data lock"); + } + + return 0; +} + 80037ce: 4620 mov r0, r4 + 80037d0: f50d 7d41 add.w sp, sp, #772 ; 0x304 + 80037d4: bdf0 pop {r4, r5, r6, r7, pc} + if(ae_write_data_slot(kn, (const uint8_t *)copyright_msg, 32, true)) { + 80037d6: 2301 movs r3, #1 + 80037d8: 2220 movs r2, #32 + 80037da: 4631 mov r1, r6 + 80037dc: 2000 movs r0, #0 + 80037de: e7a7 b.n 8003730 + return EPERM; + 80037e0: 2401 movs r4, #1 + 80037e2: e7f4 b.n 80037ce + 80037e4: 0800e3e0 .word 0x0800e3e0 + 80037e8: 0801c040 .word 0x0801c040 + 80037ec: 0800e68a .word 0x0800e68a + 80037f0: 0800e6ce .word 0x0800e6ce + 80037f4: 0800e646 .word 0x0800e646 + 80037f8: 0801c000 .word 0x0801c000 + 80037fc: 0800d700 .word 0x0800d700 + +08003800 : +// - but our time to do each iteration is limited by software SHA256 in ae_pair_unlock +// + int +ae_stretch_iter(const uint8_t start[32], uint8_t end[32], int iterations) +{ + ASSERT(start != end); // we can't work inplace + 8003800: 4288 cmp r0, r1 +{ + 8003802: b570 push {r4, r5, r6, lr} + 8003804: 460c mov r4, r1 + 8003806: 4615 mov r5, r2 + ASSERT(start != end); // we can't work inplace + 8003808: d102 bne.n 8003810 + 800380a: 4810 ldr r0, [pc, #64] ; (800384c ) + 800380c: f7fd f91c bl 8000a48 + memcpy(end, start, 32); + 8003810: 460b mov r3, r1 + 8003812: f100 0220 add.w r2, r0, #32 + 8003816: f850 1b04 ldr.w r1, [r0], #4 + 800381a: f843 1b04 str.w r1, [r3], #4 + 800381e: 4290 cmp r0, r2 + 8003820: d1f9 bne.n 8003816 + + for(int i=0; i + + int rv = ae_hmac32(KEYNUM_pin_stretch, end, end); + RET_IF_BAD(rv); + } + + return 0; + 8003828: 2000 movs r0, #0 +} + 800382a: bd70 pop {r4, r5, r6, pc} + if(ae_pair_unlock()) return -2; + 800382c: f7ff fac0 bl 8002db0 + 8003830: b940 cbnz r0, 8003844 + int rv = ae_hmac32(KEYNUM_pin_stretch, end, end); + 8003832: 4622 mov r2, r4 + 8003834: 4621 mov r1, r4 + 8003836: 2002 movs r0, #2 + 8003838: f7ff fb02 bl 8002e40 + RET_IF_BAD(rv); + 800383c: 2800 cmp r0, #0 + 800383e: d1f4 bne.n 800382a + for(int i=0; i + if(ae_pair_unlock()) return -2; + 8003844: f06f 0001 mvn.w r0, #1 + 8003848: e7ef b.n 800382a + 800384a: bf00 nop + 800384c: 0800e3e0 .word 0x0800e3e0 + +08003850 : +// Apply HMAC using secret in chip as a HMAC key, then encrypt +// the result a little because read in clear over bus. +// + int +ae_mixin_key(uint8_t keynum, const uint8_t start[32], uint8_t end[32]) +{ + 8003850: b570 push {r4, r5, r6, lr} + 8003852: b096 sub sp, #88 ; 0x58 + ASSERT(start != end); // we can't work inplace + 8003854: 4291 cmp r1, r2 +{ + 8003856: 460e mov r6, r1 + 8003858: 4614 mov r4, r2 + 800385a: f88d 0007 strb.w r0, [sp, #7] + ASSERT(start != end); // we can't work inplace + 800385e: d102 bne.n 8003866 + 8003860: 4818 ldr r0, [pc, #96] ; (80038c4 ) + 8003862: f7fd f8f1 bl 8000a48 + + if(ae_pair_unlock()) return -1; + 8003866: f7ff faa3 bl 8002db0 + 800386a: bb40 cbnz r0, 80038be + + ASSERT(keynum != 0); + 800386c: f89d 0007 ldrb.w r0, [sp, #7] + 8003870: 2800 cmp r0, #0 + 8003872: d0f5 beq.n 8003860 + int rv = ae_hmac32(keynum, start, end); + 8003874: 4622 mov r2, r4 + 8003876: 4631 mov r1, r6 + 8003878: f7ff fae2 bl 8002e40 + RET_IF_BAD(rv); + 800387c: 4605 mov r5, r0 + 800387e: b9d8 cbnz r0, 80038b8 + // use the value provided in cleartext[sic--it's not] write back shortly (to test it). + // Solution: one more SHA256, and to be safe, mixin lots of values! + + SHA256_CTX ctx; + + sha256_init(&ctx); + 8003880: a803 add r0, sp, #12 + 8003882: f001 fe03 bl 800548c + sha256_update(&ctx, rom_secrets->pairing_secret, 32); + 8003886: 4910 ldr r1, [pc, #64] ; (80038c8 ) + 8003888: 2220 movs r2, #32 + 800388a: a803 add r0, sp, #12 + 800388c: f001 fe0c bl 80054a8 + sha256_update(&ctx, start, 32); + 8003890: 2220 movs r2, #32 + 8003892: 4631 mov r1, r6 + 8003894: a803 add r0, sp, #12 + 8003896: f001 fe07 bl 80054a8 + sha256_update(&ctx, &keynum, 1); + 800389a: 2201 movs r2, #1 + 800389c: f10d 0107 add.w r1, sp, #7 + 80038a0: a803 add r0, sp, #12 + 80038a2: f001 fe01 bl 80054a8 + sha256_update(&ctx, end, 32); + 80038a6: 4621 mov r1, r4 + 80038a8: a803 add r0, sp, #12 + 80038aa: 2220 movs r2, #32 + 80038ac: f001 fdfc bl 80054a8 + sha256_final(&ctx, end); + 80038b0: 4621 mov r1, r4 + 80038b2: a803 add r0, sp, #12 + 80038b4: f001 fe3e bl 8005534 + + return 0; +} + 80038b8: 4628 mov r0, r5 + 80038ba: b016 add sp, #88 ; 0x58 + 80038bc: bd70 pop {r4, r5, r6, pc} + if(ae_pair_unlock()) return -1; + 80038be: f04f 35ff mov.w r5, #4294967295 ; 0xffffffff + 80038c2: e7f9 b.n 80038b8 + 80038c4: 0800e3e0 .word 0x0800e3e0 + 80038c8: 0801c000 .word 0x0801c000 + +080038cc : +// Immediately destroy the pairing secret so that we become +// a useless brick. Ignore errors but retry. +// + void +ae_brick_myself(void) +{ + 80038cc: b510 push {r4, lr} + for(int retry=0; retry<10; retry++) { + 80038ce: 2400 movs r4, #0 + ae_reset_chip(); + 80038d0: f7ff f86a bl 80029a8 + + if(retry) rng_delay(); + 80038d4: b10c cbz r4, 80038da + 80038d6: f7fe ff51 bl 800277c + + ae_pair_unlock(); + 80038da: f7ff fa69 bl 8002db0 + + // Concern: MitM could block this by trashing our write + // - but they have to do it without causing CRC or other comm error + // - ten times + int rv = ae_destroy_key(KEYNUM_pairing); + 80038de: 2001 movs r0, #1 + 80038e0: f7ff fe54 bl 800358c + if(rv == 0) break; + 80038e4: b120 cbz r0, 80038f0 + for(int retry=0; retry<10; retry++) { + 80038e6: 3401 adds r4, #1 + + rng_delay(); + 80038e8: f7fe ff48 bl 800277c + for(int retry=0; retry<10; retry++) { + 80038ec: 2c0a cmp r4, #10 + 80038ee: d1ef bne.n 80038d0 + } + + ae_reset_chip(); +} + 80038f0: e8bd 4010 ldmia.w sp!, {r4, lr} + ae_reset_chip(); + 80038f4: f7ff b858 b.w 80029a8 + +080038f8 : +// + void +delay_ms(int ms) +{ + // Clear the COUNTFLAG and reset value to zero + SysTick->VAL = 0; + 80038f8: f04f 23e0 mov.w r3, #3758153728 ; 0xe000e000 + 80038fc: 2200 movs r2, #0 + 80038fe: 619a str r2, [r3, #24] + //SysTick->CTRL; + + // Wait for ticks to happen + while(ms > 0) { + 8003900: 2800 cmp r0, #0 + 8003902: dc00 bgt.n 8003906 + if(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) { + ms--; + } + } +} + 8003904: 4770 bx lr + if(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) { + 8003906: 691a ldr r2, [r3, #16] + 8003908: 03d2 lsls r2, r2, #15 + ms--; + 800390a: bf48 it mi + 800390c: f100 30ff addmi.w r0, r0, #4294967295 ; 0xffffffff + 8003910: e7f6 b.n 8003900 + +08003912 : +// Replace HAL version which needs interrupts +// + void +HAL_Delay(uint32_t Delay) +{ + delay_ms(Delay); + 8003912: f7ff bff1 b.w 80038f8 + ... + +08003918 : + // NOTES: + // - try not to limit PCB changes for future revs; leave unused unchanged. + // - oled_setup() uses pins on PA4 thru PA8 + + // enable clock to GPIO's ... we will be using them all at some point + __HAL_RCC_GPIOA_CLK_ENABLE(); + 8003918: 4b39 ldr r3, [pc, #228] ; (8003a00 ) +{ + 800391a: b570 push {r4, r5, r6, lr} + __HAL_RCC_GPIOA_CLK_ENABLE(); + 800391c: 6cda ldr r2, [r3, #76] ; 0x4c + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + + { // Onewire bus pins used for ATECC608 comms + GPIO_InitTypeDef setup = { + 800391e: 4c39 ldr r4, [pc, #228] ; (8003a04 ) + __HAL_RCC_GPIOA_CLK_ENABLE(); + 8003920: f042 0201 orr.w r2, r2, #1 + 8003924: 64da str r2, [r3, #76] ; 0x4c + 8003926: 6cda ldr r2, [r3, #76] ; 0x4c +{ + 8003928: b08a sub sp, #40 ; 0x28 + __HAL_RCC_GPIOA_CLK_ENABLE(); + 800392a: f002 0201 and.w r2, r2, #1 + 800392e: 9200 str r2, [sp, #0] + 8003930: 9a00 ldr r2, [sp, #0] + __HAL_RCC_GPIOB_CLK_ENABLE(); + 8003932: 6cda ldr r2, [r3, #76] ; 0x4c + 8003934: f042 0202 orr.w r2, r2, #2 + 8003938: 64da str r2, [r3, #76] ; 0x4c + 800393a: 6cda ldr r2, [r3, #76] ; 0x4c + 800393c: f002 0202 and.w r2, r2, #2 + 8003940: 9201 str r2, [sp, #4] + 8003942: 9a01 ldr r2, [sp, #4] + __HAL_RCC_GPIOC_CLK_ENABLE(); + 8003944: 6cda ldr r2, [r3, #76] ; 0x4c + 8003946: f042 0204 orr.w r2, r2, #4 + 800394a: 64da str r2, [r3, #76] ; 0x4c + 800394c: 6cda ldr r2, [r3, #76] ; 0x4c + 800394e: f002 0204 and.w r2, r2, #4 + 8003952: 9202 str r2, [sp, #8] + 8003954: 9a02 ldr r2, [sp, #8] + __HAL_RCC_GPIOD_CLK_ENABLE(); + 8003956: 6cda ldr r2, [r3, #76] ; 0x4c + 8003958: f042 0208 orr.w r2, r2, #8 + 800395c: 64da str r2, [r3, #76] ; 0x4c + 800395e: 6cda ldr r2, [r3, #76] ; 0x4c + 8003960: f002 0208 and.w r2, r2, #8 + 8003964: 9203 str r2, [sp, #12] + 8003966: 9a03 ldr r2, [sp, #12] + __HAL_RCC_GPIOE_CLK_ENABLE(); + 8003968: 6cda ldr r2, [r3, #76] ; 0x4c + 800396a: f042 0210 orr.w r2, r2, #16 + 800396e: 64da str r2, [r3, #76] ; 0x4c + 8003970: 6cdb ldr r3, [r3, #76] ; 0x4c + 8003972: f003 0310 and.w r3, r3, #16 + 8003976: 9304 str r3, [sp, #16] + 8003978: 9b04 ldr r3, [sp, #16] + GPIO_InitTypeDef setup = { + 800397a: cc0f ldmia r4!, {r0, r1, r2, r3} + 800397c: ad05 add r5, sp, #20 + 800397e: c50f stmia r5!, {r0, r1, r2, r3} + 8003980: 6823 ldr r3, [r4, #0] + 8003982: 602b str r3, [r5, #0] + .Mode = GPIO_MODE_AF_OD, + .Pull = GPIO_NOPULL, + .Speed = GPIO_SPEED_FREQ_MEDIUM, + .Alternate = GPIO_AF8_UART4, + }; + HAL_GPIO_Init(ONEWIRE_PORT, &setup); + 8003984: a905 add r1, sp, #20 + 8003986: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 800398a: f7fd fb41 bl 8001010 + } + + // Bugfix: re-init of console port pins seems to wreck + // the mpy uart code, so avoid after first time. + if(USART1->BRR == 0) { + 800398e: 4b1e ldr r3, [pc, #120] ; (8003a08 ) + 8003990: 68de ldr r6, [r3, #12] + 8003992: b9ae cbnz r6, 80039c0 + // debug console: USART1 = PA9=Tx & PA10=Rx + GPIO_InitTypeDef setup = { + 8003994: 3404 adds r4, #4 + 8003996: cc0f ldmia r4!, {r0, r1, r2, r3} + 8003998: ad05 add r5, sp, #20 + 800399a: c50f stmia r5!, {r0, r1, r2, r3} + 800399c: 6823 ldr r3, [r4, #0] + 800399e: 602b str r3, [r5, #0] + .Mode = GPIO_MODE_AF_PP, + .Pull = GPIO_NOPULL, + .Speed = GPIO_SPEED_FREQ_MEDIUM, + .Alternate = GPIO_AF7_USART1, + }; + HAL_GPIO_Init(GPIOA, &setup); + 80039a0: a905 add r1, sp, #20 + 80039a2: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 80039a6: f7fd fb33 bl 8001010 + + setup.Pin = GPIO_PIN_10; + 80039aa: f44f 6380 mov.w r3, #1024 ; 0x400 + setup.Mode = GPIO_MODE_INPUT; + 80039ae: e9cd 3605 strd r3, r6, [sp, #20] + setup.Pull = GPIO_PULLUP; + HAL_GPIO_Init(GPIOA, &setup); + 80039b2: a905 add r1, sp, #20 + setup.Pull = GPIO_PULLUP; + 80039b4: 2301 movs r3, #1 + HAL_GPIO_Init(GPIOA, &setup); + 80039b6: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + setup.Pull = GPIO_PULLUP; + 80039ba: 9307 str r3, [sp, #28] + HAL_GPIO_Init(GPIOA, &setup); + 80039bc: f7fd fb28 bl 8001010 + } + + // SD active LED: PC7 + // USB active LED: PC6 + { GPIO_InitTypeDef setup = { + 80039c0: 2400 movs r4, #0 + 80039c2: 26c0 movs r6, #192 ; 0xc0 + 80039c4: 2501 movs r5, #1 + .Pin = GPIO_PIN_7 | GPIO_PIN_6, + .Mode = GPIO_MODE_OUTPUT_PP, + .Pull = GPIO_NOPULL, + .Speed = GPIO_SPEED_FREQ_LOW, + }; + HAL_GPIO_Init(GPIOC, &setup); + 80039c6: a905 add r1, sp, #20 + 80039c8: 4810 ldr r0, [pc, #64] ; (8003a0c ) + { GPIO_InitTypeDef setup = { + 80039ca: 9409 str r4, [sp, #36] ; 0x24 + 80039cc: e9cd 4407 strd r4, r4, [sp, #28] + 80039d0: e9cd 6505 strd r6, r5, [sp, #20] + HAL_GPIO_Init(GPIOC, &setup); + 80039d4: f7fd fb1c bl 8001010 + + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7|GPIO_PIN_6, 0); // turn LEDs off + 80039d8: 4622 mov r2, r4 + 80039da: 4631 mov r1, r6 + 80039dc: 480b ldr r0, [pc, #44] ; (8003a0c ) + 80039de: f7fd fc91 bl 8001304 + } + + // SD card detect switch: PC13 + { GPIO_InitTypeDef setup = { + 80039e2: 2210 movs r2, #16 + 80039e4: 4621 mov r1, r4 + 80039e6: a806 add r0, sp, #24 + 80039e8: f009 fe44 bl 800d674 + 80039ec: f44f 5300 mov.w r3, #8192 ; 0x2000 + .Pin = GPIO_PIN_13, + .Mode = GPIO_MODE_INPUT, + .Pull = GPIO_PULLUP, + .Speed = GPIO_SPEED_FREQ_LOW, + }; + HAL_GPIO_Init(GPIOC, &setup); + 80039f0: 4806 ldr r0, [pc, #24] ; (8003a0c ) + { GPIO_InitTypeDef setup = { + 80039f2: 9305 str r3, [sp, #20] + HAL_GPIO_Init(GPIOC, &setup); + 80039f4: a905 add r1, sp, #20 + { GPIO_InitTypeDef setup = { + 80039f6: 9507 str r5, [sp, #28] + HAL_GPIO_Init(GPIOC, &setup); + 80039f8: f7fd fb0a bl 8001010 + + // elsewhere... + //HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, 1); + //HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, 0); +#endif +} + 80039fc: b00a add sp, #40 ; 0x28 + 80039fe: bd70 pop {r4, r5, r6, pc} + 8003a00: 40021000 .word 0x40021000 + 8003a04: 0800e6f4 .word 0x0800e6f4 + 8003a08: 40013800 .word 0x40013800 + 8003a0c: 48000800 .word 0x48000800 + +08003a10 : + +// reboot_nonce() +// + static inline void +reboot_nonce(SHA256_CTX *ctx) +{ + 8003a10: b537 push {r0, r1, r2, r4, r5, lr} + uint32_t a = CRC->INIT; + 8003a12: 4d09 ldr r5, [pc, #36] ; (8003a38 ) + sha256_update(ctx, (const uint8_t *)&a, 4); + 8003a14: 2204 movs r2, #4 + uint32_t a = CRC->INIT; + 8003a16: 692b ldr r3, [r5, #16] + 8003a18: 9301 str r3, [sp, #4] + sha256_update(ctx, (const uint8_t *)&a, 4); + 8003a1a: eb0d 0102 add.w r1, sp, r2 +{ + 8003a1e: 4604 mov r4, r0 + sha256_update(ctx, (const uint8_t *)&a, 4); + 8003a20: f001 fd42 bl 80054a8 + + a = CRC->POL; + sha256_update(ctx, (const uint8_t *)&a, 4); + 8003a24: 2204 movs r2, #4 + a = CRC->POL; + 8003a26: 696b ldr r3, [r5, #20] + 8003a28: 9301 str r3, [sp, #4] + sha256_update(ctx, (const uint8_t *)&a, 4); + 8003a2a: eb0d 0102 add.w r1, sp, r2 + 8003a2e: 4620 mov r0, r4 + 8003a30: f001 fd3a bl 80054a8 +} + 8003a34: b003 add sp, #12 + 8003a36: bd30 pop {r4, r5, pc} + 8003a38: 40023000 .word 0x40023000 + +08003a3c : +// +// Hash up a string of digits into 32-bytes of goodness. +// + static void +pin_hash(const char *pin, int pin_len, uint8_t result[32], uint32_t purpose) +{ + 8003a3c: b570 push {r4, r5, r6, lr} + 8003a3e: b096 sub sp, #88 ; 0x58 + ASSERT(pin_len <= MAX_PIN_LEN); + 8003a40: 2920 cmp r1, #32 +{ + 8003a42: 4606 mov r6, r0 + 8003a44: 460d mov r5, r1 + 8003a46: 4614 mov r4, r2 + 8003a48: 9301 str r3, [sp, #4] + ASSERT(pin_len <= MAX_PIN_LEN); + 8003a4a: dd02 ble.n 8003a52 + 8003a4c: 4817 ldr r0, [pc, #92] ; (8003aac ) + 8003a4e: f7fc fffb bl 8000a48 + + if(pin_len == 0) { + 8003a52: b929 cbnz r1, 8003a60 + // zero-length PIN is considered the "blank" one: all zero + memset(result, 0, 32); + 8003a54: 2220 movs r2, #32 + 8003a56: 4620 mov r0, r4 + 8003a58: f009 fe0c bl 800d674 + // and run that thru SE2 as well + se2_pin_hash(result, purpose); + + // and a second-sha256 on that, just in case. + sha256_single(result, 32, result); +} + 8003a5c: b016 add sp, #88 ; 0x58 + 8003a5e: bd70 pop {r4, r5, r6, pc} + sha256_init(&ctx); + 8003a60: a803 add r0, sp, #12 + 8003a62: f001 fd13 bl 800548c + sha256_update(&ctx, rom_secrets->hash_cache_secret, 32); + 8003a66: a803 add r0, sp, #12 + 8003a68: 4911 ldr r1, [pc, #68] ; (8003ab0 ) + 8003a6a: 2220 movs r2, #32 + 8003a6c: f001 fd1c bl 80054a8 + sha256_update(&ctx, (uint8_t *)&purpose, 4); + 8003a70: 2204 movs r2, #4 + 8003a72: eb0d 0102 add.w r1, sp, r2 + 8003a76: a803 add r0, sp, #12 + 8003a78: f001 fd16 bl 80054a8 + sha256_update(&ctx, (uint8_t *)pin, pin_len); + 8003a7c: 462a mov r2, r5 + 8003a7e: 4631 mov r1, r6 + 8003a80: a803 add r0, sp, #12 + 8003a82: f001 fd11 bl 80054a8 + sha256_update(&ctx, rom_secrets->pairing_secret, 32); + 8003a86: 2220 movs r2, #32 + 8003a88: a803 add r0, sp, #12 + 8003a8a: 490a ldr r1, [pc, #40] ; (8003ab4 ) + 8003a8c: f001 fd0c bl 80054a8 + sha256_final(&ctx, result); + 8003a90: 4621 mov r1, r4 + 8003a92: a803 add r0, sp, #12 + 8003a94: f001 fd4e bl 8005534 + se2_pin_hash(result, purpose); + 8003a98: 9901 ldr r1, [sp, #4] + 8003a9a: 4620 mov r0, r4 + 8003a9c: f004 fc32 bl 8008304 + sha256_single(result, 32, result); + 8003aa0: 4622 mov r2, r4 + 8003aa2: 2120 movs r1, #32 + 8003aa4: 4620 mov r0, r4 + 8003aa6: f001 fd59 bl 800555c + 8003aaa: e7d7 b.n 8003a5c + 8003aac: 0800e3e0 .word 0x0800e3e0 + 8003ab0: 0801c070 .word 0x0801c070 + 8003ab4: 0801c000 .word 0x0801c000 + +08003ab8 <_hmac_attempt>: +// +// Maybe should be proper HMAC from fips std? Can be changed later. +// + static void +_hmac_attempt(const pinAttempt_t *args, uint8_t result[32]) +{ + 8003ab8: b530 push {r4, r5, lr} + 8003aba: b095 sub sp, #84 ; 0x54 + 8003abc: 4604 mov r4, r0 + SHA256_CTX ctx; + + sha256_init(&ctx); + 8003abe: a801 add r0, sp, #4 +{ + 8003ac0: 460d mov r5, r1 + sha256_init(&ctx); + 8003ac2: f001 fce3 bl 800548c + sha256_update(&ctx, rom_secrets->pairing_secret, 32); + 8003ac6: 4911 ldr r1, [pc, #68] ; (8003b0c <_hmac_attempt+0x54>) + 8003ac8: 2220 movs r2, #32 + 8003aca: a801 add r0, sp, #4 + 8003acc: f001 fcec bl 80054a8 + reboot_nonce(&ctx); + 8003ad0: a801 add r0, sp, #4 + 8003ad2: f7ff ff9d bl 8003a10 + sha256_update(&ctx, (uint8_t *)args, offsetof(pinAttempt_t, hmac)); + 8003ad6: 2244 movs r2, #68 ; 0x44 + 8003ad8: 4621 mov r1, r4 + 8003ada: a801 add r0, sp, #4 + 8003adc: f001 fce4 bl 80054a8 + + if(args->magic_value == PA_MAGIC_V2) { + 8003ae0: 6822 ldr r2, [r4, #0] + 8003ae2: 4b0b ldr r3, [pc, #44] ; (8003b10 <_hmac_attempt+0x58>) + 8003ae4: 429a cmp r2, r3 + 8003ae6: d105 bne.n 8003af4 <_hmac_attempt+0x3c> + sha256_update(&ctx, (uint8_t *)args->cached_main_pin, + 8003ae8: 2220 movs r2, #32 + 8003aea: f104 01f8 add.w r1, r4, #248 ; 0xf8 + 8003aee: a801 add r0, sp, #4 + 8003af0: f001 fcda bl 80054a8 + msizeof(pinAttempt_t, cached_main_pin)); + } + + sha256_final(&ctx, result); + 8003af4: 4629 mov r1, r5 + 8003af6: a801 add r0, sp, #4 + 8003af8: f001 fd1c bl 8005534 + + // and a second-sha256 on that, just in case. + sha256_single(result, 32, result); + 8003afc: 462a mov r2, r5 + 8003afe: 2120 movs r1, #32 + 8003b00: 4628 mov r0, r5 + 8003b02: f001 fd2b bl 800555c +} + 8003b06: b015 add sp, #84 ; 0x54 + 8003b08: bd30 pop {r4, r5, pc} + 8003b0a: bf00 nop + 8003b0c: 0801c000 .word 0x0801c000 + 8003b10: 2eaf6312 .word 0x2eaf6312 + +08003b14 <_validate_attempt>: + +// _validate_attempt() +// + static int +_validate_attempt(const pinAttempt_t *args, bool first_time) +{ + 8003b14: b510 push {r4, lr} + 8003b16: 4604 mov r4, r0 + 8003b18: b088 sub sp, #32 + if(first_time) { + 8003b1a: b969 cbnz r1, 8003b38 <_validate_attempt+0x24> + // no hmac needed for setup call + } else { + // if hmac is defined, better be right. + uint8_t actual[32]; + + _hmac_attempt(args, actual); + 8003b1c: 4669 mov r1, sp + 8003b1e: f7ff ffcb bl 8003ab8 <_hmac_attempt> + + if(!check_equal(actual, args->hmac, 32)) { + 8003b22: 2220 movs r2, #32 + 8003b24: f104 0144 add.w r1, r4, #68 ; 0x44 + 8003b28: 4668 mov r0, sp + 8003b2a: f7fe fdc2 bl 80026b2 + 8003b2e: b918 cbnz r0, 8003b38 <_validate_attempt+0x24> + // hmac is wrong? + return EPIN_HMAC_FAIL; + 8003b30: f06f 0063 mvn.w r0, #99 ; 0x63 + if((args->change_flags & CHANGE__MASK) != args->change_flags) return EPIN_RANGE_ERR; + + if((args->is_secondary & 0x1) != args->is_secondary) return EPIN_RANGE_ERR; + + return 0; +} + 8003b34: b008 add sp, #32 + 8003b36: bd10 pop {r4, pc} + if(args->magic_value == PA_MAGIC_V2) { + 8003b38: 6822 ldr r2, [r4, #0] + 8003b3a: 4b10 ldr r3, [pc, #64] ; (8003b7c <_validate_attempt+0x68>) + 8003b3c: 429a cmp r2, r3 + 8003b3e: d117 bne.n 8003b70 <_validate_attempt+0x5c> + if(args->pin_len > MAX_PIN_LEN) return EPIN_RANGE_ERR; + 8003b40: 6aa3 ldr r3, [r4, #40] ; 0x28 + 8003b42: 2b20 cmp r3, #32 + 8003b44: dc17 bgt.n 8003b76 <_validate_attempt+0x62> + if(args->old_pin_len > MAX_PIN_LEN) return EPIN_RANGE_ERR; + 8003b46: f8d4 3088 ldr.w r3, [r4, #136] ; 0x88 + 8003b4a: 2b20 cmp r3, #32 + 8003b4c: dc13 bgt.n 8003b76 <_validate_attempt+0x62> + if(args->new_pin_len > MAX_PIN_LEN) return EPIN_RANGE_ERR; + 8003b4e: f8d4 30ac ldr.w r3, [r4, #172] ; 0xac + 8003b52: 2b20 cmp r3, #32 + 8003b54: dc0f bgt.n 8003b76 <_validate_attempt+0x62> + if((args->change_flags & CHANGE__MASK) != args->change_flags) return EPIN_RANGE_ERR; + 8003b56: 6e63 ldr r3, [r4, #100] ; 0x64 + 8003b58: f640 727f movw r2, #3967 ; 0xf7f + 8003b5c: 4393 bics r3, r2 + 8003b5e: d10a bne.n 8003b76 <_validate_attempt+0x62> + if((args->is_secondary & 0x1) != args->is_secondary) return EPIN_RANGE_ERR; + 8003b60: 6863 ldr r3, [r4, #4] + return 0; + 8003b62: f033 0301 bics.w r3, r3, #1 + 8003b66: bf14 ite ne + 8003b68: f06f 0066 mvnne.w r0, #102 ; 0x66 + 8003b6c: 2000 moveq r0, #0 + 8003b6e: e7e1 b.n 8003b34 <_validate_attempt+0x20> + return EPIN_BAD_MAGIC; + 8003b70: f06f 0065 mvn.w r0, #101 ; 0x65 + 8003b74: e7de b.n 8003b34 <_validate_attempt+0x20> + if((args->is_secondary & 0x1) != args->is_secondary) return EPIN_RANGE_ERR; + 8003b76: f06f 0066 mvn.w r0, #102 ; 0x66 + 8003b7a: e7db b.n 8003b34 <_validate_attempt+0x20> + 8003b7c: 2eaf6312 .word 0x2eaf6312 + +08003b80 : + +// warmup_ae() +// + static int +warmup_ae(void) +{ + 8003b80: b510 push {r4, lr} + ae_setup(); + 8003b82: f7fe ff1f bl 80029c4 + 8003b86: 2405 movs r4, #5 + + for(int retry=0; retry<5; retry++) { + if(!ae_probe()) break; + 8003b88: f7ff f9a4 bl 8002ed4 + 8003b8c: b108 cbz r0, 8003b92 + for(int retry=0; retry<5; retry++) { + 8003b8e: 3c01 subs r4, #1 + 8003b90: d1fa bne.n 8003b88 + } + + if(ae_pair_unlock()) return -1; + 8003b92: f7ff f90d bl 8002db0 + 8003b96: 4604 mov r4, r0 + 8003b98: b918 cbnz r0, 8003ba2 + + // reset watchdog timer + ae_keep_alive(); + 8003b9a: f7fe ff45 bl 8002a28 + + return 0; +} + 8003b9e: 4620 mov r0, r4 + 8003ba0: bd10 pop {r4, pc} + if(ae_pair_unlock()) return -1; + 8003ba2: f04f 34ff mov.w r4, #4294967295 ; 0xffffffff + 8003ba6: e7fa b.n 8003b9e + +08003ba8 <_read_slot_as_counter>: +{ + 8003ba8: b530 push {r4, r5, lr} + 8003baa: b091 sub sp, #68 ; 0x44 + uint32_t padded[32/4] = { 0 }; + 8003bac: 2220 movs r2, #32 +{ + 8003bae: 4604 mov r4, r0 + 8003bb0: 460d mov r5, r1 + uint32_t padded[32/4] = { 0 }; + 8003bb2: 4668 mov r0, sp + 8003bb4: 2100 movs r1, #0 + 8003bb6: f009 fd5d bl 800d674 + ae_pair_unlock(); + 8003bba: f7ff f8f9 bl 8002db0 + if(ae_read_data_slot(slot, (uint8_t *)padded, 32)) return -1; + 8003bbe: 2220 movs r2, #32 + 8003bc0: 4669 mov r1, sp + 8003bc2: 4620 mov r0, r4 + 8003bc4: f7ff fc3a bl 800343c + 8003bc8: b120 cbz r0, 8003bd4 <_read_slot_as_counter+0x2c> + 8003bca: f04f 34ff mov.w r4, #4294967295 ; 0xffffffff +} + 8003bce: 4620 mov r0, r4 + 8003bd0: b011 add sp, #68 ; 0x44 + 8003bd2: bd30 pop {r4, r5, pc} + ae_pair_unlock(); + 8003bd4: f7ff f8ec bl 8002db0 + if(ae_gendig_slot(slot, (const uint8_t *)padded, tempkey)) return -1; + 8003bd8: 4620 mov r0, r4 + 8003bda: aa08 add r2, sp, #32 + 8003bdc: 4669 mov r1, sp + 8003bde: f7ff fa07 bl 8002ff0 + 8003be2: 4604 mov r4, r0 + 8003be4: 2800 cmp r0, #0 + 8003be6: d1f0 bne.n 8003bca <_read_slot_as_counter+0x22> + if(!ae_is_correct_tempkey(tempkey)) fatal_mitm(); + 8003be8: a808 add r0, sp, #32 + 8003bea: f7ff f811 bl 8002c10 + 8003bee: b908 cbnz r0, 8003bf4 <_read_slot_as_counter+0x4c> + 8003bf0: f7fc ff34 bl 8000a5c + *dest = padded[0]; + 8003bf4: 9b00 ldr r3, [sp, #0] + 8003bf6: 602b str r3, [r5, #0] + return 0; + 8003bf8: e7e9 b.n 8003bce <_read_slot_as_counter+0x26> + +08003bfa : +{ + 8003bfa: b530 push {r4, r5, lr} + 8003bfc: b095 sub sp, #84 ; 0x54 + 8003bfe: 4605 mov r5, r0 + ae_pair_unlock(); + 8003c00: f7ff f8d6 bl 8002db0 + uint32_t padded[32/4] = { 0 }; + 8003c04: 2220 movs r2, #32 + 8003c06: 2100 movs r1, #0 + 8003c08: a804 add r0, sp, #16 + 8003c0a: f009 fd33 bl 800d674 + if(ae_read_data_slot(slot, (uint8_t *)padded, 32)) return -1; + 8003c0e: 2220 movs r2, #32 + 8003c10: a904 add r1, sp, #16 + 8003c12: 2005 movs r0, #5 + 8003c14: f7ff fc12 bl 800343c + 8003c18: b118 cbz r0, 8003c22 + 8003c1a: f04f 30ff mov.w r0, #4294967295 ; 0xffffffff +} + 8003c1e: b015 add sp, #84 ; 0x54 + 8003c20: bd30 pop {r4, r5, pc} + ae_pair_unlock(); + 8003c22: f7ff f8c5 bl 8002db0 + if(ae_gendig_slot(slot, (const uint8_t *)padded, tempkey)) return -1; + 8003c26: aa0c add r2, sp, #48 ; 0x30 + 8003c28: a904 add r1, sp, #16 + 8003c2a: 2005 movs r0, #5 + 8003c2c: f7ff f9e0 bl 8002ff0 + 8003c30: 4604 mov r4, r0 + 8003c32: 2800 cmp r0, #0 + 8003c34: d1f1 bne.n 8003c1a + if(!ae_is_correct_tempkey(tempkey)) fatal_mitm(); + 8003c36: a80c add r0, sp, #48 ; 0x30 + 8003c38: f7fe ffea bl 8002c10 + 8003c3c: b908 cbnz r0, 8003c42 + 8003c3e: f7fc ff0d bl 8000a5c + if(_read_slot_as_counter(KEYNUM_lastgood, &lastgood)) return -1; + 8003c42: a901 add r1, sp, #4 + 8003c44: 2005 movs r0, #5 + uint32_t lastgood=0, match_count=0, counter=0; + 8003c46: e9cd 4401 strd r4, r4, [sp, #4] + 8003c4a: 9403 str r4, [sp, #12] + if(_read_slot_as_counter(KEYNUM_lastgood, &lastgood)) return -1; + 8003c4c: f7ff ffac bl 8003ba8 <_read_slot_as_counter> + 8003c50: 2800 cmp r0, #0 + 8003c52: d1e2 bne.n 8003c1a + if(_read_slot_as_counter(KEYNUM_match_count, &match_count)) return -1; + 8003c54: a902 add r1, sp, #8 + 8003c56: 2006 movs r0, #6 + 8003c58: f7ff ffa6 bl 8003ba8 <_read_slot_as_counter> + 8003c5c: 4601 mov r1, r0 + 8003c5e: 2800 cmp r0, #0 + 8003c60: d1db bne.n 8003c1a + if(ae_get_counter(&counter, 0)) return -1; + 8003c62: a803 add r0, sp, #12 + 8003c64: f7ff fa9f bl 80031a6 + 8003c68: 2800 cmp r0, #0 + 8003c6a: d1d6 bne.n 8003c1a + if(lastgood > counter) { + 8003c6c: 9a01 ldr r2, [sp, #4] + 8003c6e: 9903 ldr r1, [sp, #12] + match_count &= ~31; + 8003c70: 9b02 ldr r3, [sp, #8] + if(lastgood > counter) { + 8003c72: 428a cmp r2, r1 + match_count &= ~31; + 8003c74: f023 031f bic.w r3, r3, #31 + args->num_fails = counter - lastgood; + 8003c78: bf94 ite ls + 8003c7a: 1a8a subls r2, r1, r2 + args->num_fails = 99; + 8003c7c: 2263 movhi r2, #99 ; 0x63 + if(counter < match_count) { + 8003c7e: 4299 cmp r1, r3 + args->attempts_left = match_count - counter; + 8003c80: bf34 ite cc + 8003c82: 1a5b subcc r3, r3, r1 + args->attempts_left = 0; + 8003c84: 2300 movcs r3, #0 + 8003c86: 636a str r2, [r5, #52] ; 0x34 + 8003c88: 63ab str r3, [r5, #56] ; 0x38 + 8003c8a: e7c8 b.n 8003c1e + +08003c8c : + +// updates_for_good_login() +// + static int +updates_for_good_login(uint8_t digest[32]) +{ + 8003c8c: b5f0 push {r4, r5, r6, r7, lr} + 8003c8e: b08d sub sp, #52 ; 0x34 + // User got the main PIN right: update the attempt counters, + // to document this (lastgood) and also bump the match counter if needed + + uint32_t count; + int rv = ae_get_counter(&count, 0); + 8003c90: 2100 movs r1, #0 +{ + 8003c92: 4606 mov r6, r0 + int rv = ae_get_counter(&count, 0); + 8003c94: a802 add r0, sp, #8 + 8003c96: f7ff fa86 bl 80031a6 + if(rv) goto fail; + 8003c9a: 4601 mov r1, r0 + 8003c9c: 2800 cmp r0, #0 + 8003c9e: d13b bne.n 8003d18 + + // Challenge: Have to update both the counter, and the target match value because + // no other way to have exact value. + + uint32_t mc = (count + MAX_TARGET_ATTEMPTS + 32) & ~31; + 8003ca0: 9b02 ldr r3, [sp, #8] + 8003ca2: f103 042d add.w r4, r3, #45 ; 0x2d + 8003ca6: f024 041f bic.w r4, r4, #31 + ASSERT(mc >= count); + 8003caa: 42a3 cmp r3, r4 + 8003cac: d902 bls.n 8003cb4 + 8003cae: 481d ldr r0, [pc, #116] ; (8003d24 ) + 8003cb0: f7fc feca bl 8000a48 + + int bump = (mc - MAX_TARGET_ATTEMPTS) - count; + 8003cb4: 1ae3 subs r3, r4, r3 + 8003cb6: f1a3 050d sub.w r5, r3, #13 + ASSERT(bump >= 1); + 8003cba: 3b0e subs r3, #14 + 8003cbc: 2b1f cmp r3, #31 + 8003cbe: d8f6 bhi.n 8003cae + // Would rather update the counter first, so that a hostile interruption can't increase + // attempts (altho the attacker knows the pin at that point?!) .. but chip won't + // let the counter go past the match value, so that has to be first. + + // set the new "match count" + { uint32_t tmp[32/4] = {mc, mc} ; + 8003cc0: 2218 movs r2, #24 + 8003cc2: eb0d 0002 add.w r0, sp, r2 + rv = ae_encrypted_write(KEYNUM_match_count, KEYNUM_main_pin, digest, (void *)tmp, 32); + 8003cc6: 2720 movs r7, #32 + { uint32_t tmp[32/4] = {mc, mc} ; + 8003cc8: f009 fcd4 bl 800d674 + rv = ae_encrypted_write(KEYNUM_match_count, KEYNUM_main_pin, digest, (void *)tmp, 32); + 8003ccc: 2103 movs r1, #3 + 8003cce: 9700 str r7, [sp, #0] + 8003cd0: ab04 add r3, sp, #16 + 8003cd2: 4632 mov r2, r6 + 8003cd4: 2006 movs r0, #6 + { uint32_t tmp[32/4] = {mc, mc} ; + 8003cd6: e9cd 4404 strd r4, r4, [sp, #16] + rv = ae_encrypted_write(KEYNUM_match_count, KEYNUM_main_pin, digest, (void *)tmp, 32); + 8003cda: f7ff fb79 bl 80033d0 + if(rv) goto fail; + 8003cde: 4601 mov r1, r0 + 8003ce0: b9d0 cbnz r0, 8003d18 + } + + // incr the counter a bunch to get to that-13 + uint32_t new_count = 0; + 8003ce2: 9003 str r0, [sp, #12] + rv = ae_add_counter(&new_count, 0, bump); + 8003ce4: 462a mov r2, r5 + 8003ce6: a803 add r0, sp, #12 + 8003ce8: f7ff fa7c bl 80031e4 + if(rv) goto fail; + 8003cec: 4601 mov r1, r0 + 8003cee: b998 cbnz r0, 8003d18 + + ASSERT(new_count == count + bump); + 8003cf0: 9b02 ldr r3, [sp, #8] + 8003cf2: 441d add r5, r3 + 8003cf4: 9b03 ldr r3, [sp, #12] + 8003cf6: 429d cmp r5, r3 + 8003cf8: d1d9 bne.n 8003cae + ASSERT(mc > new_count); + 8003cfa: 42a5 cmp r5, r4 + 8003cfc: d2d7 bcs.n 8003cae + + // Update the "last good" counter + { uint32_t tmp[32/4] = {new_count, 0 }; + 8003cfe: 221c movs r2, #28 + 8003d00: a805 add r0, sp, #20 + 8003d02: f009 fcb7 bl 800d674 + rv = ae_encrypted_write(KEYNUM_lastgood, KEYNUM_main_pin, digest, (void *)tmp, 32); + 8003d06: 9700 str r7, [sp, #0] + 8003d08: ab04 add r3, sp, #16 + 8003d0a: 4632 mov r2, r6 + 8003d0c: 2103 movs r1, #3 + 8003d0e: 2005 movs r0, #5 + { uint32_t tmp[32/4] = {new_count, 0 }; + 8003d10: 9504 str r5, [sp, #16] + rv = ae_encrypted_write(KEYNUM_lastgood, KEYNUM_main_pin, digest, (void *)tmp, 32); + 8003d12: f7ff fb5d bl 80033d0 + if(rv) goto fail; + 8003d16: b118 cbz r0, 8003d20 + // just be reducing attempts. + + return 0; + +fail: + ae_reset_chip(); + 8003d18: f7fe fe46 bl 80029a8 + return EPIN_AE_FAIL; + 8003d1c: f06f 0069 mvn.w r0, #105 ; 0x69 +} + 8003d20: b00d add sp, #52 ; 0x34 + 8003d22: bdf0 pop {r4, r5, r6, r7, pc} + 8003d24: 0800e3e0 .word 0x0800e3e0 + +08003d28 : +{ + 8003d28: b5f0 push {r4, r5, r6, r7, lr} + 8003d2a: 4615 mov r5, r2 + 8003d2c: b089 sub sp, #36 ; 0x24 + if(pin_len == 0) { + 8003d2e: 460c mov r4, r1 + 8003d30: b931 cbnz r1, 8003d40 + memset(result, 0, 32); + 8003d32: 2220 movs r2, #32 + 8003d34: 4628 mov r0, r5 + 8003d36: f009 fc9d bl 800d674 +} + 8003d3a: 4620 mov r0, r4 + 8003d3c: b009 add sp, #36 ; 0x24 + 8003d3e: bdf0 pop {r4, r5, r6, r7, pc} + pin_hash(pin, pin_len, tmp, PIN_PURPOSE_NORMAL); + 8003d40: 4b0f ldr r3, [pc, #60] ; (8003d80 ) + 8003d42: 466a mov r2, sp + 8003d44: f7ff fe7a bl 8003a3c + int rv = ae_stretch_iter(tmp, result, KDF_ITER_PIN); + 8003d48: 2208 movs r2, #8 + 8003d4a: 4629 mov r1, r5 + 8003d4c: 4668 mov r0, sp + 8003d4e: f7ff fd57 bl 8003800 + if(rv) return EPIN_AE_FAIL; + 8003d52: 4604 mov r4, r0 + 8003d54: b988 cbnz r0, 8003d7a + memcpy(tmp, result, 32); + 8003d56: 462b mov r3, r5 + 8003d58: 466e mov r6, sp + 8003d5a: f105 0720 add.w r7, r5, #32 + 8003d5e: 6818 ldr r0, [r3, #0] + 8003d60: 6859 ldr r1, [r3, #4] + 8003d62: 4632 mov r2, r6 + 8003d64: c203 stmia r2!, {r0, r1} + 8003d66: 3308 adds r3, #8 + 8003d68: 42bb cmp r3, r7 + 8003d6a: 4616 mov r6, r2 + 8003d6c: d1f7 bne.n 8003d5e + ae_mixin_key(KEYNUM_pin_attempt, tmp, result); + 8003d6e: 462a mov r2, r5 + 8003d70: 4669 mov r1, sp + 8003d72: 2004 movs r0, #4 + 8003d74: f7ff fd6c bl 8003850 + return 0; + 8003d78: e7df b.n 8003d3a + if(rv) return EPIN_AE_FAIL; + 8003d7a: f06f 0469 mvn.w r4, #105 ; 0x69 + 8003d7e: e7dc b.n 8003d3a + 8003d80: 334d1858 .word 0x334d1858 + +08003d84 : +set_is_trick(pinAttempt_t *args, const trick_slot_t *slot) + 8003d84: b5f0 push {r4, r5, r6, r7, lr} + args->delay_achieved = slot->tc_arg; + 8003d86: 88cb ldrh r3, [r1, #6] + 8003d88: 62c3 str r3, [r0, #44] ; 0x2c +set_is_trick(pinAttempt_t *args, const trick_slot_t *slot) + 8003d8a: f5ad 7d0d sub.w sp, sp, #564 ; 0x234 + memcpy(key, &args->private_state, sizeof(args->private_state)); + 8003d8e: 6c03 ldr r3, [r0, #64] ; 0x40 + memcpy(key+4, rom_secrets->hash_cache_secret+4, sizeof(rom_secrets->hash_cache_secret)-4); + 8003d90: 4d0f ldr r5, [pc, #60] ; (8003dd0 ) + memcpy(key, &args->private_state, sizeof(args->private_state)); + 8003d92: 9303 str r3, [sp, #12] +set_is_trick(pinAttempt_t *args, const trick_slot_t *slot) + 8003d94: 4606 mov r6, r0 + 8003d96: 460f mov r7, r1 + memcpy(key+4, rom_secrets->hash_cache_secret+4, sizeof(rom_secrets->hash_cache_secret)-4); + 8003d98: cd0f ldmia r5!, {r0, r1, r2, r3} + 8003d9a: ac04 add r4, sp, #16 + 8003d9c: c40f stmia r4!, {r0, r1, r2, r3} + 8003d9e: e895 0007 ldmia.w r5, {r0, r1, r2} + 8003da2: e884 0007 stmia.w r4, {r0, r1, r2} + aes_init(&ctx); + 8003da6: a80b add r0, sp, #44 ; 0x2c + 8003da8: f004 fb5a bl 8008460 + aes_add(&ctx, (uint8_t *)slot, 32); + 8003dac: 4639 mov r1, r7 + 8003dae: a80b add r0, sp, #44 ; 0x2c + 8003db0: 2220 movs r2, #32 + 8003db2: f004 fb5b bl 800846c + aes_done(&ctx, args->cached_main_pin, 32, key, NULL); + 8003db6: 2300 movs r3, #0 + 8003db8: 9300 str r3, [sp, #0] + 8003dba: 2220 movs r2, #32 + 8003dbc: ab03 add r3, sp, #12 + 8003dbe: f106 01f8 add.w r1, r6, #248 ; 0xf8 + 8003dc2: a80b add r0, sp, #44 ; 0x2c + 8003dc4: f004 fb68 bl 8008498 +} + 8003dc8: f50d 7d0d add.w sp, sp, #564 ; 0x234 + 8003dcc: bdf0 pop {r4, r5, r6, r7, pc} + 8003dce: bf00 nop + 8003dd0: 0801c074 .word 0x0801c074 + +08003dd4 : + __HAL_RCC_CRC_CLK_ENABLE(); + 8003dd4: 4b09 ldr r3, [pc, #36] ; (8003dfc ) + 8003dd6: 6c9a ldr r2, [r3, #72] ; 0x48 +{ + 8003dd8: b513 push {r0, r1, r4, lr} + __HAL_RCC_CRC_CLK_ENABLE(); + 8003dda: f442 5280 orr.w r2, r2, #4096 ; 0x1000 + 8003dde: 649a str r2, [r3, #72] ; 0x48 + 8003de0: 6c9b ldr r3, [r3, #72] ; 0x48 + CRC->INIT = rng_sample(); + 8003de2: 4c07 ldr r4, [pc, #28] ; (8003e00 ) + __HAL_RCC_CRC_CLK_ENABLE(); + 8003de4: f403 5380 and.w r3, r3, #4096 ; 0x1000 + 8003de8: 9301 str r3, [sp, #4] + 8003dea: 9b01 ldr r3, [sp, #4] + CRC->INIT = rng_sample(); + 8003dec: f7fe fc72 bl 80026d4 + 8003df0: 6120 str r0, [r4, #16] + CRC->POL = rng_sample(); + 8003df2: f7fe fc6f bl 80026d4 + 8003df6: 6160 str r0, [r4, #20] +} + 8003df8: b002 add sp, #8 + 8003dfa: bd10 pop {r4, pc} + 8003dfc: 40021000 .word 0x40021000 + 8003e00: 40023000 .word 0x40023000 + +08003e04 : +{ + 8003e04: b510 push {r4, lr} + 8003e06: b094 sub sp, #80 ; 0x50 + 8003e08: 4604 mov r4, r0 + sha256_init(&ctx); + 8003e0a: a801 add r0, sp, #4 + 8003e0c: f001 fb3e bl 800548c + reboot_nonce(&ctx); + 8003e10: a801 add r0, sp, #4 + 8003e12: f7ff fdfd bl 8003a10 + sha256_update(&ctx, rom_secrets->hash_cache_secret, 32); + 8003e16: 2220 movs r2, #32 + 8003e18: a801 add r0, sp, #4 + 8003e1a: 4904 ldr r1, [pc, #16] ; (8003e2c ) + 8003e1c: f001 fb44 bl 80054a8 + sha256_final(&ctx, key); + 8003e20: 4621 mov r1, r4 + 8003e22: a801 add r0, sp, #4 + 8003e24: f001 fb86 bl 8005534 +} + 8003e28: b014 add sp, #80 ; 0x50 + 8003e2a: bd10 pop {r4, pc} + 8003e2c: 0801c070 .word 0x0801c070 + +08003e30 : +{ + 8003e30: b530 push {r4, r5, lr} + 8003e32: 460d mov r5, r1 + 8003e34: b089 sub sp, #36 ; 0x24 + 8003e36: 4604 mov r4, r0 + if(!check_all_zeros(digest, 32)) { + 8003e38: 2120 movs r1, #32 + 8003e3a: 4628 mov r0, r5 + 8003e3c: f7fe fc2a bl 8002694 + 8003e40: b9a0 cbnz r0, 8003e6c + pin_cache_get_key(value); + 8003e42: 4668 mov r0, sp + 8003e44: f7ff ffde bl 8003e04 + 8003e48: 466b mov r3, sp + 8003e4a: f105 0120 add.w r1, r5, #32 + *(acc) ^= *(more); + 8003e4e: 781a ldrb r2, [r3, #0] + 8003e50: f815 0b01 ldrb.w r0, [r5], #1 + 8003e54: 4042 eors r2, r0 + for(; len; len--, more++, acc++) { + 8003e56: 428d cmp r5, r1 + *(acc) ^= *(more); + 8003e58: f803 2b01 strb.w r2, [r3], #1 + for(; len; len--, more++, acc++) { + 8003e5c: d1f7 bne.n 8003e4e + ASSERT(args->magic_value == PA_MAGIC_V2); + 8003e5e: 6822 ldr r2, [r4, #0] + 8003e60: 4b0d ldr r3, [pc, #52] ; (8003e98 ) + 8003e62: 429a cmp r2, r3 + 8003e64: d008 beq.n 8003e78 + 8003e66: 480d ldr r0, [pc, #52] ; (8003e9c ) + 8003e68: f7fc fdee bl 8000a48 + memset(value, 0, 32); + 8003e6c: 2220 movs r2, #32 + 8003e6e: 2100 movs r1, #0 + 8003e70: 4668 mov r0, sp + 8003e72: f009 fbff bl 800d674 + 8003e76: e7f2 b.n 8003e5e + memcpy(args->cached_main_pin, value, 32); + 8003e78: 466b mov r3, sp + 8003e7a: f104 02f8 add.w r2, r4, #248 ; 0xf8 + 8003e7e: ad08 add r5, sp, #32 + 8003e80: 461c mov r4, r3 + 8003e82: cc03 ldmia r4!, {r0, r1} + 8003e84: 42ac cmp r4, r5 + 8003e86: 6010 str r0, [r2, #0] + 8003e88: 6051 str r1, [r2, #4] + 8003e8a: 4623 mov r3, r4 + 8003e8c: f102 0208 add.w r2, r2, #8 + 8003e90: d1f6 bne.n 8003e80 +} + 8003e92: b009 add sp, #36 ; 0x24 + 8003e94: bd30 pop {r4, r5, pc} + 8003e96: bf00 nop + 8003e98: 2eaf6312 .word 0x2eaf6312 + 8003e9c: 0800e3e0 .word 0x0800e3e0 + +08003ea0 : +{ + 8003ea0: b510 push {r4, lr} + ASSERT(args->magic_value == PA_MAGIC_V2); + 8003ea2: 6802 ldr r2, [r0, #0] + 8003ea4: 4b14 ldr r3, [pc, #80] ; (8003ef8 ) + 8003ea6: 429a cmp r2, r3 +{ + 8003ea8: b088 sub sp, #32 + 8003eaa: 460c mov r4, r1 + ASSERT(args->magic_value == PA_MAGIC_V2); + 8003eac: d002 beq.n 8003eb4 + 8003eae: 4813 ldr r0, [pc, #76] ; (8003efc ) + 8003eb0: f7fc fdca bl 8000a48 + memcpy(digest, args->cached_main_pin, 32); + 8003eb4: f100 03f8 add.w r3, r0, #248 ; 0xf8 + 8003eb8: 460a mov r2, r1 + 8003eba: f500 708c add.w r0, r0, #280 ; 0x118 + 8003ebe: f853 1b04 ldr.w r1, [r3], #4 + 8003ec2: f842 1b04 str.w r1, [r2], #4 + 8003ec6: 4283 cmp r3, r0 + 8003ec8: d1f9 bne.n 8003ebe + if(!check_all_zeros(digest, 32)) { + 8003eca: 2120 movs r1, #32 + 8003ecc: 4620 mov r0, r4 + 8003ece: f7fe fbe1 bl 8002694 + 8003ed2: b970 cbnz r0, 8003ef2 + pin_cache_get_key(key); + 8003ed4: 4668 mov r0, sp + 8003ed6: f7ff ff95 bl 8003e04 + 8003eda: 1e62 subs r2, r4, #1 + 8003edc: 466b mov r3, sp + 8003ede: 341f adds r4, #31 + *(acc) ^= *(more); + 8003ee0: f812 1f01 ldrb.w r1, [r2, #1]! + 8003ee4: f813 0b01 ldrb.w r0, [r3], #1 + for(; len; len--, more++, acc++) { + 8003ee8: 42a2 cmp r2, r4 + *(acc) ^= *(more); + 8003eea: ea81 0100 eor.w r1, r1, r0 + 8003eee: 7011 strb r1, [r2, #0] + for(; len; len--, more++, acc++) { + 8003ef0: d1f6 bne.n 8003ee0 +} + 8003ef2: b008 add sp, #32 + 8003ef4: bd10 pop {r4, pc} + 8003ef6: bf00 nop + 8003ef8: 2eaf6312 .word 0x2eaf6312 + 8003efc: 0800e3e0 .word 0x0800e3e0 + +08003f00 : +{ + 8003f00: b530 push {r4, r5, lr} + 8003f02: b091 sub sp, #68 ; 0x44 + pin_hash(pin_prefix, prefix_len, tmp, PIN_PURPOSE_WORDS); + 8003f04: 4b0b ldr r3, [pc, #44] ; (8003f34 ) +{ + 8003f06: 4615 mov r5, r2 + pin_hash(pin_prefix, prefix_len, tmp, PIN_PURPOSE_WORDS); + 8003f08: 466a mov r2, sp + 8003f0a: f7ff fd97 bl 8003a3c + ae_setup(); + 8003f0e: f7fe fd59 bl 80029c4 + int rv = ae_stretch_iter(tmp, digest, KDF_ITER_WORDS); + 8003f12: 2206 movs r2, #6 + 8003f14: a908 add r1, sp, #32 + 8003f16: 4668 mov r0, sp + 8003f18: f7ff fc72 bl 8003800 + 8003f1c: 4604 mov r4, r0 + ae_reset_chip(); + 8003f1e: f7fe fd43 bl 80029a8 + if(rv) return -1; + 8003f22: b924 cbnz r4, 8003f2e + memcpy(result, digest, 4); + 8003f24: 9b08 ldr r3, [sp, #32] + 8003f26: 602b str r3, [r5, #0] +} + 8003f28: 4620 mov r0, r4 + 8003f2a: b011 add sp, #68 ; 0x44 + 8003f2c: bd30 pop {r4, r5, pc} + if(rv) return -1; + 8003f2e: f04f 34ff mov.w r4, #4294967295 ; 0xffffffff + 8003f32: e7f9 b.n 8003f28 + 8003f34: 2e6d6773 .word 0x2e6d6773 + +08003f38 : +} + 8003f38: 2000 movs r0, #0 + 8003f3a: 4770 bx lr + +08003f3c : +{ + 8003f3c: b5f0 push {r4, r5, r6, r7, lr} + int rv = _validate_attempt(args, true); + 8003f3e: 2101 movs r1, #1 +{ + 8003f40: b091 sub sp, #68 ; 0x44 + 8003f42: 4605 mov r5, r0 + int rv = _validate_attempt(args, true); + 8003f44: f7ff fde6 bl 8003b14 <_validate_attempt> + if(rv) return rv; + 8003f48: 4604 mov r4, r0 + 8003f4a: bb28 cbnz r0, 8003f98 + if(args->is_secondary) { + 8003f4c: 686b ldr r3, [r5, #4] + 8003f4e: 2b00 cmp r3, #0 + 8003f50: d158 bne.n 8004004 + int pin_len = args->pin_len; + 8003f52: 6aaf ldr r7, [r5, #40] ; 0x28 + memcpy(pin_copy, args->pin, pin_len); + 8003f54: f105 0608 add.w r6, r5, #8 + 8003f58: 463a mov r2, r7 + 8003f5a: 4631 mov r1, r6 + 8003f5c: 4668 mov r0, sp + 8003f5e: f009 fb61 bl 800d624 + memset(args, 0, PIN_ATTEMPT_SIZE_V2); + 8003f62: f44f 728c mov.w r2, #280 ; 0x118 + 8003f66: 4621 mov r1, r4 + 8003f68: 4628 mov r0, r5 + 8003f6a: f009 fb83 bl 800d674 + args->magic_value = PA_MAGIC_V2; + 8003f6e: 4b28 ldr r3, [pc, #160] ; (8004010 ) + 8003f70: 602b str r3, [r5, #0] + memcpy(args->pin, pin_copy, pin_len); + 8003f72: 463a mov r2, r7 + 8003f74: 4669 mov r1, sp + args->pin_len = pin_len; + 8003f76: 62af str r7, [r5, #40] ; 0x28 + memcpy(args->pin, pin_copy, pin_len); + 8003f78: 4630 mov r0, r6 + 8003f7a: f009 fb53 bl 800d624 + if(warmup_ae()) { + 8003f7e: f7ff fdff bl 8003b80 + 8003f82: 2800 cmp r0, #0 + 8003f84: d141 bne.n 800400a + if(get_last_success(args)) { + 8003f86: 4628 mov r0, r5 + 8003f88: f7ff fe37 bl 8003bfa + 8003f8c: 4604 mov r4, r0 + 8003f8e: b130 cbz r0, 8003f9e + ae_reset_chip(); + 8003f90: f7fe fd0a bl 80029a8 + return EPIN_AE_FAIL; + 8003f94: f06f 0469 mvn.w r4, #105 ; 0x69 +} + 8003f98: 4620 mov r0, r4 + 8003f9a: b011 add sp, #68 ; 0x44 + 8003f9c: bdf0 pop {r4, r5, r6, r7, pc} + uint8_t blank[32] = {0}; + 8003f9e: 4601 mov r1, r0 + 8003fa0: 221c movs r2, #28 + args->delay_achieved = 0; + 8003fa2: e9c5 000b strd r0, r0, [r5, #44] ; 0x2c + uint8_t blank[32] = {0}; + 8003fa6: 9008 str r0, [sp, #32] + 8003fa8: a809 add r0, sp, #36 ; 0x24 + 8003faa: f009 fb63 bl 800d674 + ae_reset_chip(); + 8003fae: f7fe fcfb bl 80029a8 + ae_pair_unlock(); + 8003fb2: f7fe fefd bl 8002db0 + int is_blank = (ae_checkmac_hard(keynum, blank) == 0); + 8003fb6: a908 add r1, sp, #32 + 8003fb8: 2003 movs r0, #3 + 8003fba: f7ff f887 bl 80030cc + 8003fbe: 4606 mov r6, r0 + ae_reset_chip(); + 8003fc0: f7fe fcf2 bl 80029a8 + if(pin_is_blank(KEYNUM_main_pin)) { + 8003fc4: b9c6 cbnz r6, 8003ff8 + args->state_flags |= PA_SUCCESSFUL | PA_IS_BLANK; + 8003fc6: 6beb ldr r3, [r5, #60] ; 0x3c + const uint8_t zeros[32] = {0}; + 8003fc8: 9408 str r4, [sp, #32] + args->state_flags |= PA_SUCCESSFUL | PA_IS_BLANK; + 8003fca: f043 0303 orr.w r3, r3, #3 + 8003fce: 63eb str r3, [r5, #60] ; 0x3c + const uint8_t zeros[32] = {0}; + 8003fd0: 221c movs r2, #28 + 8003fd2: 4621 mov r1, r4 + 8003fd4: a809 add r0, sp, #36 ; 0x24 + 8003fd6: f009 fb4d bl 800d674 + pin_cache_save(args, zeros); + 8003fda: a908 add r1, sp, #32 + 8003fdc: 4628 mov r0, r5 + 8003fde: f7ff ff27 bl 8003e30 + args->private_state = ((rng_sample() & ~1) | is_trick_pin) ^ rom_secrets->hash_cache_secret[0]; + 8003fe2: f7fe fb77 bl 80026d4 + 8003fe6: 4b0b ldr r3, [pc, #44] ; (8004014 ) + 8003fe8: f893 3070 ldrb.w r3, [r3, #112] ; 0x70 + 8003fec: f020 0001 bic.w r0, r0, #1 + args->delay_achieved = 0; + 8003ff0: e9c5 440b strd r4, r4, [r5, #44] ; 0x2c + args->private_state = ((rng_sample() & ~1) | is_trick_pin) ^ rom_secrets->hash_cache_secret[0]; + 8003ff4: 4058 eors r0, r3 + 8003ff6: 6428 str r0, [r5, #64] ; 0x40 + _hmac_attempt(args, args->hmac); + 8003ff8: f105 0144 add.w r1, r5, #68 ; 0x44 + 8003ffc: 4628 mov r0, r5 + 8003ffe: f7ff fd5b bl 8003ab8 <_hmac_attempt> +} + 8004002: e7c9 b.n 8003f98 + return EPIN_PRIMARY_ONLY; + 8004004: f06f 0471 mvn.w r4, #113 ; 0x71 + 8004008: e7c6 b.n 8003f98 + return EPIN_I_AM_BRICK; + 800400a: f06f 0468 mvn.w r4, #104 ; 0x68 + 800400e: e7c3 b.n 8003f98 + 8004010: 2eaf6312 .word 0x2eaf6312 + 8004014: 0801c000 .word 0x0801c000 + +08004018 : +} + 8004018: 2000 movs r0, #0 + 800401a: 4770 bx lr + +0800401c : +// +// Do the PIN check, and return a value. Or fail. +// + int +pin_login_attempt(pinAttempt_t *args) +{ + 800401c: e92d 43f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, lr} + bool deltamode = false; + char tmp_pin[32]; + + int rv = _validate_attempt(args, false); + 8004020: 2100 movs r1, #0 +{ + 8004022: b0c7 sub sp, #284 ; 0x11c + 8004024: 4604 mov r4, r0 + int rv = _validate_attempt(args, false); + 8004026: f7ff fd75 bl 8003b14 <_validate_attempt> + if(rv) return rv; + 800402a: 4605 mov r5, r0 + 800402c: 2800 cmp r0, #0 + 800402e: d179 bne.n 8004124 + + if(args->state_flags & PA_SUCCESSFUL) { + 8004030: 6be3 ldr r3, [r4, #60] ; 0x3c + 8004032: 07d9 lsls r1, r3, #31 + 8004034: f100 80c5 bmi.w 80041c2 + } + + // Mk4: Check SE2 first to see if this is a "trick" pin. + // - this call may have side-effects, like wiping keys, bricking, etc. + trick_slot_t slot; + bool is_trick = se2_test_trick_pin(args->pin, args->pin_len, &slot, false); + 8004038: f104 0808 add.w r8, r4, #8 + 800403c: 4603 mov r3, r0 + 800403e: 6aa1 ldr r1, [r4, #40] ; 0x28 + 8004040: aa26 add r2, sp, #152 ; 0x98 + 8004042: 4640 mov r0, r8 + 8004044: f003 fee8 bl 8007e18 + + if(is_trick) { + 8004048: 4606 mov r6, r0 + 800404a: 2800 cmp r0, #0 + 800404c: d04b beq.n 80040e6 + // Mark as success + args->state_flags = PA_SUCCESSFUL; + args->num_fails = 0; + args->attempts_left = MAX_TARGET_ATTEMPTS; + + bool wipe = (slot.tc_flags & TC_WIPE) && !(slot.tc_flags & (TC_WORD_WALLET|TC_XPRV_WALLET)); + 800404e: f9bd 209c ldrsh.w r2, [sp, #156] ; 0x9c + args->num_fails = 0; + 8004052: 6365 str r5, [r4, #52] ; 0x34 + args->state_flags = PA_SUCCESSFUL; + 8004054: 2301 movs r3, #1 + 8004056: 63e3 str r3, [r4, #60] ; 0x3c + bool wipe = (slot.tc_flags & TC_WIPE) && !(slot.tc_flags & (TC_WORD_WALLET|TC_XPRV_WALLET)); + 8004058: 2a00 cmp r2, #0 + args->attempts_left = MAX_TARGET_ATTEMPTS; + 800405a: f04f 030d mov.w r3, #13 + 800405e: 63a3 str r3, [r4, #56] ; 0x38 + bool wipe = (slot.tc_flags & TC_WIPE) && !(slot.tc_flags & (TC_WORD_WALLET|TC_XPRV_WALLET)); + 8004060: f8bd 309c ldrh.w r3, [sp, #156] ; 0x9c + 8004064: da4f bge.n 8004106 + 8004066: f413 5fc0 tst.w r3, #6144 ; 0x1800 + 800406a: bf0c ite eq + 800406c: 2701 moveq r7, #1 + 800406e: 2700 movne r7, #0 + if(check_all_zeros(slot.xdata, 32) || wipe) { + 8004070: 2120 movs r1, #32 + 8004072: a828 add r0, sp, #160 ; 0xa0 + 8004074: f7fe fb0e bl 8002694 + 8004078: b900 cbnz r0, 800407c + 800407a: b11f cbz r7, 8004084 + args->state_flags |= PA_ZERO_SECRET; + 800407c: 6be3 ldr r3, [r4, #60] ; 0x3c + 800407e: f043 0310 orr.w r3, r3, #16 + 8004082: 63e3 str r3, [r4, #60] ; 0x3c + args->private_state = ((rng_sample() & ~1) | is_trick_pin) ^ rom_secrets->hash_cache_secret[0]; + 8004084: f7fe fb26 bl 80026d4 + 8004088: 4b51 ldr r3, [pc, #324] ; (80041d0 ) + 800408a: f893 3070 ldrb.w r3, [r3, #112] ; 0x70 + 800408e: f040 0001 orr.w r0, r0, #1 + 8004092: 4058 eors r0, r3 + args->delay_required = (slot->tc_flags & ~TC_HIDDEN_MASK); + 8004094: f8bd 309c ldrh.w r3, [sp, #156] ; 0x9c + args->private_state = ((rng_sample() & ~1) | is_trick_pin) ^ rom_secrets->hash_cache_secret[0]; + 8004098: 6420 str r0, [r4, #64] ; 0x40 + args->delay_required = (slot->tc_flags & ~TC_HIDDEN_MASK); + 800409a: f423 4278 bic.w r2, r3, #63488 ; 0xf800 + 800409e: 6322 str r2, [r4, #48] ; 0x30 + if(slot->tc_flags & TC_DELTA_MODE) { + 80040a0: 055a lsls r2, r3, #21 + 80040a2: d532 bpl.n 800410a + args->delay_achieved = 0; + 80040a4: 2300 movs r3, #0 + 80040a6: 62e3 str r3, [r4, #44] ; 0x2c + memcpy(tmp_pin, pin, pin_len); + 80040a8: 6aa7 ldr r7, [r4, #40] ; 0x28 + // Thug gave wrong PIN, but we are going to let them + // past (by calculating correct PIN, up to 4 digits different), + // and the mpy firmware can do tricky stuff to protect funds + // even though the private key is known at that point. + deltamode = true; + apply_pin_delta(args->pin, args->pin_len, slot.tc_arg, tmp_pin); + 80040aa: f8bd 909e ldrh.w r9, [sp, #158] ; 0x9e + memcpy(tmp_pin, pin, pin_len); + 80040ae: ab04 add r3, sp, #16 + 80040b0: 463a mov r2, r7 + 80040b2: 4641 mov r1, r8 + 80040b4: 4618 mov r0, r3 + 80040b6: f009 fab5 bl 800d624 + tmp_pin[pin_len] = 0; + 80040ba: 2200 movs r2, #0 + 80040bc: 55c2 strb r2, [r0, r7] + char *p = &tmp_pin[pin_len-1]; + 80040be: 1e7a subs r2, r7, #1 + 80040c0: 4402 add r2, r0 + 80040c2: 2104 movs r1, #4 + if(*p == '-') p--; + 80040c4: 7813 ldrb r3, [r2, #0] + 80040c6: 2b2d cmp r3, #45 ; 0x2d + 80040c8: f009 030f and.w r3, r9, #15 + 80040cc: bf08 it eq + 80040ce: f102 32ff addeq.w r2, r2, #4294967295 ; 0xffffffff + if((here >= 0) && (here <= 9)) { + 80040d2: 2b09 cmp r3, #9 + *p = '0' + here; + 80040d4: bf9c itt ls + 80040d6: 3330 addls r3, #48 ; 0x30 + 80040d8: 7013 strbls r3, [r2, #0] + for(int i=0; i<4; i++, p--) { + 80040da: 3901 subs r1, #1 + replacement >>= 4; + 80040dc: ea4f 1919 mov.w r9, r9, lsr #4 + for(int i=0; i<4; i++, p--) { + 80040e0: f102 32ff add.w r2, r2, #4294967295 ; 0xffffffff + 80040e4: d1ee bne.n 80040c4 + return 0; + } + +real_login: + // unlock the AE chip + if(warmup_ae()) return EPIN_I_AM_BRICK; + 80040e6: f7ff fd4b bl 8003b80 + 80040ea: 2800 cmp r0, #0 + 80040ec: d16c bne.n 80041c8 + + // hash up the pin now, assuming we'll use it on main PIN + uint8_t digest[32]; + rv = pin_hash_attempt(deltamode ? tmp_pin : args->pin, args->pin_len, digest); + 80040ee: b10e cbz r6, 80040f4 + 80040f0: f10d 0810 add.w r8, sp, #16 + 80040f4: 6aa1 ldr r1, [r4, #40] ; 0x28 + 80040f6: aa0c add r2, sp, #48 ; 0x30 + 80040f8: 4640 mov r0, r8 + 80040fa: f7ff fe15 bl 8003d28 + if(rv) return EPIN_AE_FAIL; + 80040fe: b1a8 cbz r0, 800412c + + rv = ae_encrypted_read(KEYNUM_secret, KEYNUM_main_pin, digest, ts, AE_SECRET_LEN); + if(rv) { + ae_reset_chip(); + + return EPIN_AE_FAIL; + 8004100: f06f 0569 mvn.w r5, #105 ; 0x69 + 8004104: e00e b.n 8004124 + bool wipe = (slot.tc_flags & TC_WIPE) && !(slot.tc_flags & (TC_WORD_WALLET|TC_XPRV_WALLET)); + 8004106: 462f mov r7, r5 + 8004108: e7b2 b.n 8004070 + 800410a: a926 add r1, sp, #152 ; 0x98 + 800410c: 4620 mov r0, r4 + 800410e: f7ff fe39 bl 8003d84 + if(slot.tc_flags & TC_DELTA_MODE) { + 8004112: f8bd 309c ldrh.w r3, [sp, #156] ; 0x9c + 8004116: 055b lsls r3, r3, #21 + 8004118: d4c6 bmi.n 80040a8 + _hmac_attempt(args, args->hmac); + 800411a: f104 0144 add.w r1, r4, #68 ; 0x44 + 800411e: 4620 mov r0, r4 + 8004120: f7ff fcca bl 8003ab8 <_hmac_attempt> + } + + _sign_attempt(args); + + return 0; +} + 8004124: 4628 mov r0, r5 + 8004126: b047 add sp, #284 ; 0x11c + 8004128: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + ae_reset_chip(); + 800412c: f7fe fc3c bl 80029a8 + ae_pair_unlock(); + 8004130: f7fe fe3e bl 8002db0 + return (ae_checkmac_hard(KEYNUM_main_pin, digest) == 0); + 8004134: a90c add r1, sp, #48 ; 0x30 + 8004136: 2003 movs r0, #3 + 8004138: f7fe ffc8 bl 80030cc + if(!is_main_pin(digest)) { + 800413c: b130 cbz r0, 800414c + se2_handle_bad_pin(args->num_fails + 1); + 800413e: 6b60 ldr r0, [r4, #52] ; 0x34 + 8004140: 3001 adds r0, #1 + 8004142: f003 ff45 bl 8007fd0 + return EPIN_AUTH_FAIL; + 8004146: f06f 056f mvn.w r5, #111 ; 0x6f + 800414a: e7eb b.n 8004124 + rv = updates_for_good_login(digest); + 800414c: a80c add r0, sp, #48 ; 0x30 + 800414e: f7ff fd9d bl 8003c8c + if(rv) return EPIN_AE_FAIL; + 8004152: 4607 mov r7, r0 + 8004154: 2800 cmp r0, #0 + 8004156: d1d3 bne.n 8004100 + pin_cache_save(args, digest); + 8004158: a90c add r1, sp, #48 ; 0x30 + 800415a: 4620 mov r0, r4 + 800415c: f7ff fe68 bl 8003e30 + args->state_flags = PA_SUCCESSFUL; + 8004160: 2301 movs r3, #1 + 8004162: 63e3 str r3, [r4, #60] ; 0x3c + args->num_fails = 0; + 8004164: 6367 str r7, [r4, #52] ; 0x34 + args->attempts_left = MAX_TARGET_ATTEMPTS; + 8004166: 230d movs r3, #13 + rv = ae_encrypted_read(KEYNUM_secret, KEYNUM_main_pin, digest, ts, AE_SECRET_LEN); + 8004168: 2748 movs r7, #72 ; 0x48 + args->attempts_left = MAX_TARGET_ATTEMPTS; + 800416a: 63a3 str r3, [r4, #56] ; 0x38 + rv = ae_encrypted_read(KEYNUM_secret, KEYNUM_main_pin, digest, ts, AE_SECRET_LEN); + 800416c: 9700 str r7, [sp, #0] + 800416e: ab14 add r3, sp, #80 ; 0x50 + 8004170: aa0c add r2, sp, #48 ; 0x30 + 8004172: 2103 movs r1, #3 + 8004174: 2009 movs r0, #9 + 8004176: f7ff f88b bl 8003290 + if(rv) { + 800417a: b110 cbz r0, 8004182 + ae_reset_chip(); + 800417c: f7fe fc14 bl 80029a8 + 8004180: e7be b.n 8004100 + ae_reset_chip(); + 8004182: f7fe fc11 bl 80029a8 + mcu_key_get(&mcu_key_valid); + 8004186: f10d 000f add.w r0, sp, #15 + 800418a: f7fe f945 bl 8002418 + if(check_all_zeros(ts, AE_SECRET_LEN) || !mcu_key_valid) { + 800418e: 4639 mov r1, r7 + 8004190: a814 add r0, sp, #80 ; 0x50 + 8004192: f7fe fa7f bl 8002694 + 8004196: b910 cbnz r0, 800419e + 8004198: f89d 300f ldrb.w r3, [sp, #15] + 800419c: b91b cbnz r3, 80041a6 + args->state_flags |= PA_ZERO_SECRET; + 800419e: 6be3 ldr r3, [r4, #60] ; 0x3c + 80041a0: f043 0310 orr.w r3, r3, #16 + 80041a4: 63e3 str r3, [r4, #60] ; 0x3c + if(!deltamode) { + 80041a6: 2e00 cmp r6, #0 + 80041a8: d1b7 bne.n 800411a + args->private_state = ((rng_sample() & ~1) | is_trick_pin) ^ rom_secrets->hash_cache_secret[0]; + 80041aa: f7fe fa93 bl 80026d4 + 80041ae: 4b08 ldr r3, [pc, #32] ; (80041d0 ) + 80041b0: f893 3070 ldrb.w r3, [r3, #112] ; 0x70 + 80041b4: f020 0001 bic.w r0, r0, #1 + 80041b8: 4058 eors r0, r3 + args->delay_achieved = 0; + 80041ba: e9c4 660b strd r6, r6, [r4, #44] ; 0x2c + args->private_state = ((rng_sample() & ~1) | is_trick_pin) ^ rom_secrets->hash_cache_secret[0]; + 80041be: 6420 str r0, [r4, #64] ; 0x40 + return; + 80041c0: e7ab b.n 800411a + return EPIN_WRONG_SUCCESS; + 80041c2: f06f 056c mvn.w r5, #108 ; 0x6c + 80041c6: e7ad b.n 8004124 + if(warmup_ae()) return EPIN_I_AM_BRICK; + 80041c8: f06f 0568 mvn.w r5, #104 ; 0x68 + 80041cc: e7aa b.n 8004124 + 80041ce: bf00 nop + 80041d0: 0801c000 .word 0x0801c000 + +080041d4 : +// +// Verify we know the main PIN, but don't do anything with it. +// + int +pin_check_logged_in(const pinAttempt_t *args, bool *is_trick) +{ + 80041d4: b570 push {r4, r5, r6, lr} + 80041d6: 460e mov r6, r1 + 80041d8: b088 sub sp, #32 + int rv = _validate_attempt(args, false); + 80041da: 2100 movs r1, #0 +{ + 80041dc: 4605 mov r5, r0 + int rv = _validate_attempt(args, false); + 80041de: f7ff fc99 bl 8003b14 <_validate_attempt> + if(rv) return rv; + 80041e2: 4604 mov r4, r0 + 80041e4: b980 cbnz r0, 8004208 + + if((args->state_flags & PA_SUCCESSFUL) != PA_SUCCESSFUL) { + 80041e6: 6beb ldr r3, [r5, #60] ; 0x3c + 80041e8: 07da lsls r2, r3, #31 + 80041ea: d520 bpl.n 800422e + bool is_trick = ((args->private_state ^ rom_secrets->hash_cache_secret[0]) & 0x1); + 80041ec: 4b11 ldr r3, [pc, #68] ; (8004234 ) + 80041ee: 6c2a ldr r2, [r5, #64] ; 0x40 + 80041f0: f893 3070 ldrb.w r3, [r3, #112] ; 0x70 + 80041f4: 4053 eors r3, r2 + // must come here with a successful PIN login (so it's rate limited nicely) + return EPIN_WRONG_SUCCESS; + } + + if(get_is_trick(args, NULL)) { + 80041f6: 07db lsls r3, r3, #31 + 80041f8: d509 bpl.n 800420e + // they used a trick pin to get this far. Amuse them more. + *is_trick = true; + 80041fa: 2301 movs r3, #1 + 80041fc: 7033 strb r3, [r6, #0] + + // should calibrate this, but smart money will just look at the bus + delay_ms(10); + 80041fe: 200a movs r0, #10 + 8004200: f7ff fb7a bl 80038f8 + rng_delay(); + 8004204: f7fe faba bl 800277c + int rv = ae_checkmac(KEYNUM_main_pin, auth_digest); + if(rv) return EPIN_AUTH_FAIL; + } + + return 0; +} + 8004208: 4620 mov r0, r4 + 800420a: b008 add sp, #32 + 800420c: bd70 pop {r4, r5, r6, pc} + pin_cache_restore(args, auth_digest); + 800420e: 4669 mov r1, sp + *is_trick = false; + 8004210: 7030 strb r0, [r6, #0] + pin_cache_restore(args, auth_digest); + 8004212: 4628 mov r0, r5 + 8004214: f7ff fe44 bl 8003ea0 + ae_pair_unlock(); + 8004218: f7fe fdca bl 8002db0 + int rv = ae_checkmac(KEYNUM_main_pin, auth_digest); + 800421c: 4669 mov r1, sp + 800421e: 2003 movs r0, #3 + 8004220: f7fe fd44 bl 8002cac + if(rv) return EPIN_AUTH_FAIL; + 8004224: 1e04 subs r4, r0, #0 + 8004226: bf18 it ne + 8004228: f06f 046f mvnne.w r4, #111 ; 0x6f + 800422c: e7ec b.n 8004208 + return EPIN_WRONG_SUCCESS; + 800422e: f06f 046c mvn.w r4, #108 ; 0x6c + 8004232: e7e9 b.n 8004208 + 8004234: 0801c000 .word 0x0801c000 + +08004238 : +// +// Change the PIN and/or the secret. (Must also know the previous value, or it must be blank) +// + int +pin_change(pinAttempt_t *args) +{ + 8004238: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + // Validate args and signature + int rv = _validate_attempt(args, false); + 800423c: 2100 movs r1, #0 +{ + 800423e: b0a4 sub sp, #144 ; 0x90 + 8004240: 4604 mov r4, r0 + int rv = _validate_attempt(args, false); + 8004242: f7ff fc67 bl 8003b14 <_validate_attempt> + if(rv) return rv; + 8004246: 4605 mov r5, r0 + 8004248: 2800 cmp r0, #0 + 800424a: f040 8094 bne.w 8004376 + + if((args->state_flags & PA_SUCCESSFUL) != PA_SUCCESSFUL) { + 800424e: 6be3 ldr r3, [r4, #60] ; 0x3c + 8004250: 07d9 lsls r1, r3, #31 + 8004252: f140 809c bpl.w 800438e + // must come here with a successful PIN login (so it's rate limited nicely) + return EPIN_WRONG_SUCCESS; + } + + if(args->state_flags & PA_IS_BLANK) { + 8004256: 079a lsls r2, r3, #30 + 8004258: d502 bpl.n 8004260 + // if blank, must provide blank value + if(args->pin_len) return EPIN_RANGE_ERR; + 800425a: 6aa3 ldr r3, [r4, #40] ; 0x28 + 800425c: 2b00 cmp r3, #0 + 800425e: d158 bne.n 8004312 + } + + // Look at change flags. + const uint32_t cf = args->change_flags; + + ASSERT(!args->is_secondary); + 8004260: 6863 ldr r3, [r4, #4] + const uint32_t cf = args->change_flags; + 8004262: f8d4 9064 ldr.w r9, [r4, #100] ; 0x64 + ASSERT(!args->is_secondary); + 8004266: b113 cbz r3, 800426e + 8004268: 484c ldr r0, [pc, #304] ; (800439c ) + 800426a: f7fc fbed bl 8000a48 + if(cf & CHANGE_SECONDARY_WALLET_PIN) { + // obsolete secondary support, can't support. + return EPIN_BAD_REQUEST; + } + if(cf & (CHANGE_DURESS_PIN | CHANGE_DURESS_SECRET | CHANGE_BRICKME_PIN)) { + 800426e: f019 0f36 tst.w r9, #54 ; 0x36 + 8004272: d10b bne.n 800428c + // we need some new API for trick PIN lookup/changes. + return EPIN_BAD_REQUEST; + } + if(!(cf & (CHANGE_WALLET_PIN | CHANGE_SECRET))) { + 8004274: f019 0f09 tst.w r9, #9 + 8004278: d04b beq.n 8004312 + bool is_trick = ((args->private_state ^ rom_secrets->hash_cache_secret[0]) & 0x1); + 800427a: 4b49 ldr r3, [pc, #292] ; (80043a0 ) + 800427c: 6c22 ldr r2, [r4, #64] ; 0x40 + 800427e: f893 3070 ldrb.w r3, [r3, #112] ; 0x70 + 8004282: 4053 eors r3, r2 + // If they authorized w/ a trick PIN, new policy is to wipe ourselves if + // they try to change PIN code or the secret. + // - it's hard to fake them out here, and they may be onto us. + // - this protects the seed, but does end the game somewhat + // - all trick PINs will still be in effect, and looks like random reset + if(get_is_trick(args, NULL)) { + 8004284: 07db lsls r3, r3, #31 + 8004286: d504 bpl.n 8004292 + // User is a thug.. kill secret and reboot w/o any notice + fast_wipe(); + 8004288: f7fe f9d8 bl 800263c + return EPIN_BAD_REQUEST; + 800428c: f06f 0567 mvn.w r5, #103 ; 0x67 + 8004290: e071 b.n 8004376 + // NOT-REACHED + return EPIN_BAD_REQUEST; + } + + // unlock the AE chip + if(warmup_ae()) return EPIN_I_AM_BRICK; + 8004292: f7ff fc75 bl 8003b80 + 8004296: 4605 mov r5, r0 + 8004298: 2800 cmp r0, #0 + 800429a: d17b bne.n 8004394 + // If they tricked us to get to this point, doesn't matter as + // below SE1 validates it all again. + + // Restore cached version of PIN digest: fast + uint8_t required_digest[32]; + pin_cache_restore(args, required_digest); + 800429c: f10d 0808 add.w r8, sp, #8 + 80042a0: 4641 mov r1, r8 + 80042a2: 4620 mov r0, r4 + 80042a4: f7ff fdfc bl 8003ea0 + + // Calculate new PIN hashed value: will be slow to do + if(cf & CHANGE_WALLET_PIN) { + 80042a8: f019 0f01 tst.w r9, #1 + 80042ac: d021 beq.n 80042f2 + uint8_t new_digest[32]; + rv = pin_hash_attempt(args->new_pin, args->new_pin_len, new_digest); + 80042ae: f8d4 10ac ldr.w r1, [r4, #172] ; 0xac + 80042b2: aa12 add r2, sp, #72 ; 0x48 + 80042b4: f104 008c add.w r0, r4, #140 ; 0x8c + 80042b8: f7ff fd36 bl 8003d28 + if(rv) goto ae_fail; + 80042bc: 2800 cmp r0, #0 + 80042be: d161 bne.n 8004384 + + if(ae_encrypted_write(KEYNUM_main_pin, KEYNUM_main_pin, required_digest, new_digest, 32)) { + 80042c0: 2320 movs r3, #32 + 80042c2: 2103 movs r1, #3 + 80042c4: 9300 str r3, [sp, #0] + 80042c6: 4642 mov r2, r8 + 80042c8: ab12 add r3, sp, #72 ; 0x48 + 80042ca: 4608 mov r0, r1 + 80042cc: f7ff f880 bl 80033d0 + 80042d0: 2800 cmp r0, #0 + 80042d2: d157 bne.n 8004384 + goto ae_fail; + } + + memcpy(required_digest, new_digest, 32); + 80042d4: af12 add r7, sp, #72 ; 0x48 + 80042d6: cf0f ldmia r7!, {r0, r1, r2, r3} + 80042d8: 4646 mov r6, r8 + 80042da: c60f stmia r6!, {r0, r1, r2, r3} + 80042dc: e897 000f ldmia.w r7, {r0, r1, r2, r3} + 80042e0: e886 000f stmia.w r6, {r0, r1, r2, r3} + + // main pin is changing; reset counter to zero (good login) and our cache + pin_cache_save(args, new_digest); + 80042e4: 4620 mov r0, r4 + 80042e6: a912 add r1, sp, #72 ; 0x48 + 80042e8: f7ff fda2 bl 8003e30 + + updates_for_good_login(new_digest); + 80042ec: a812 add r0, sp, #72 ; 0x48 + 80042ee: f7ff fccd bl 8003c8c + } + + // Recording new secret. + // Note the required_digest might have just changed above. + if(cf & CHANGE_SECRET) { + 80042f2: f019 0f08 tst.w r9, #8 + 80042f6: d037 beq.n 8004368 + int which = (args->change_flags >> 8) & 0xf; + 80042f8: 6e63 ldr r3, [r4, #100] ; 0x64 + 80042fa: 121b asrs r3, r3, #8 + switch(which) { + 80042fc: f013 020c ands.w r2, r3, #12 + 8004300: d107 bne.n 8004312 + 8004302: 4928 ldr r1, [pc, #160] ; (80043a4 ) + int which = (args->change_flags >> 8) & 0xf; + 8004304: f003 030f and.w r3, r3, #15 + 8004308: f911 a003 ldrsb.w sl, [r1, r3] + uint8_t tmp[AE_SECRET_LEN]; + uint8_t check[32]; + + // what slot (key number) are updating? (probably: KEYNUM_secret) + int target_slot = keynum_for_secret(args); + if(target_slot < 0) return EPIN_RANGE_ERR; + 800430c: f1ba 0f00 cmp.w sl, #0 + 8004310: da02 bge.n 8004318 + if(args->pin_len) return EPIN_RANGE_ERR; + 8004312: f06f 0566 mvn.w r5, #102 ; 0x66 + 8004316: e02e b.n 8004376 + + se2_encrypt_secret(args->secret, AE_SECRET_LEN, 0, tmp, check, required_digest); + 8004318: f104 07b0 add.w r7, r4, #176 ; 0xb0 + 800431c: ae0a add r6, sp, #40 ; 0x28 + 800431e: ab12 add r3, sp, #72 ; 0x48 + 8004320: 2148 movs r1, #72 ; 0x48 + + // write into two slots + if(ae_encrypted_write(target_slot, KEYNUM_main_pin, + 8004322: f04f 0948 mov.w r9, #72 ; 0x48 + se2_encrypt_secret(args->secret, AE_SECRET_LEN, 0, tmp, check, required_digest); + 8004326: f8cd 8004 str.w r8, [sp, #4] + 800432a: 9600 str r6, [sp, #0] + 800432c: 4638 mov r0, r7 + 800432e: f003 ff33 bl 8008198 + if(ae_encrypted_write(target_slot, KEYNUM_main_pin, + 8004332: 2103 movs r1, #3 + 8004334: f8cd 9000 str.w r9, [sp] + 8004338: eb0d 0309 add.w r3, sp, r9 + 800433c: 4642 mov r2, r8 + 800433e: 4650 mov r0, sl + 8004340: f7ff f846 bl 80033d0 + 8004344: 4601 mov r1, r0 + 8004346: b9e8 cbnz r0, 8004384 + required_digest, tmp, AE_SECRET_LEN)){ + goto ae_fail; + } + if(ae_encrypted_write32(KEYNUM_check_secret, 0, KEYNUM_main_pin, required_digest, check)){ + 8004348: 9600 str r6, [sp, #0] + 800434a: 4643 mov r3, r8 + 800434c: 2203 movs r2, #3 + 800434e: 200a movs r0, #10 + 8004350: f7fe ffd8 bl 8003304 + 8004354: b9b0 cbnz r0, 8004384 + goto ae_fail; + } + + // update the zero-secret flag to be correct. + if(cf & CHANGE_SECRET) { + if(check_all_zeros(args->secret, AE_SECRET_LEN)) { + 8004356: 4649 mov r1, r9 + 8004358: 4638 mov r0, r7 + 800435a: f7fe f99b bl 8002694 + 800435e: 6be3 ldr r3, [r4, #60] ; 0x3c + 8004360: b168 cbz r0, 800437e + args->state_flags |= PA_ZERO_SECRET; + 8004362: f043 0310 orr.w r3, r3, #16 + 8004366: 63e3 str r3, [r4, #60] ; 0x3c + args->state_flags &= ~PA_ZERO_SECRET; + } + } + } + + ae_reset_chip(); + 8004368: f7fe fb1e bl 80029a8 + _hmac_attempt(args, args->hmac); + 800436c: f104 0144 add.w r1, r4, #68 ; 0x44 + 8004370: 4620 mov r0, r4 + 8004372: f7ff fba1 bl 8003ab8 <_hmac_attempt> + +ae_fail: + ae_reset_chip(); + + return EPIN_AE_FAIL; +} + 8004376: 4628 mov r0, r5 + 8004378: b024 add sp, #144 ; 0x90 + 800437a: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + args->state_flags &= ~PA_ZERO_SECRET; + 800437e: f023 0310 bic.w r3, r3, #16 + 8004382: e7f0 b.n 8004366 + ae_reset_chip(); + 8004384: f7fe fb10 bl 80029a8 + return EPIN_AE_FAIL; + 8004388: f06f 0569 mvn.w r5, #105 ; 0x69 + 800438c: e7f3 b.n 8004376 + return EPIN_WRONG_SUCCESS; + 800438e: f06f 056c mvn.w r5, #108 ; 0x6c + 8004392: e7f0 b.n 8004376 + if(warmup_ae()) return EPIN_I_AM_BRICK; + 8004394: f06f 0568 mvn.w r5, #104 ; 0x68 + 8004398: e7ed b.n 8004376 + 800439a: bf00 nop + 800439c: 0800e3e0 .word 0x0800e3e0 + 80043a0: 0801c000 .word 0x0801c000 + 80043a4: 0800e71c .word 0x0800e71c + +080043a8 : +// To encourage not keeping the secret in memory, a way to fetch it after you've already +// proven you know the PIN. +// + int +pin_fetch_secret(pinAttempt_t *args) +{ + 80043a8: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + // Validate args and signature + int rv = _validate_attempt(args, false); + 80043ac: 2100 movs r1, #0 +{ + 80043ae: f5ad 7d38 sub.w sp, sp, #736 ; 0x2e0 + 80043b2: 4604 mov r4, r0 + int rv = _validate_attempt(args, false); + 80043b4: f7ff fbae bl 8003b14 <_validate_attempt> + if(rv) return rv; + 80043b8: 4605 mov r5, r0 + 80043ba: 2800 cmp r0, #0 + 80043bc: d144 bne.n 8004448 + + if((args->state_flags & PA_SUCCESSFUL) != PA_SUCCESSFUL) { + 80043be: 6be3 ldr r3, [r4, #60] ; 0x3c + 80043c0: 07db lsls r3, r3, #31 + 80043c2: f140 80e3 bpl.w 800458c + // must come here with a successful PIN login (so it's rate limited nicely) + return EPIN_WRONG_SUCCESS; + } + if(args->change_flags & CHANGE_DURESS_SECRET) { + 80043c6: 6e65 ldr r5, [r4, #100] ; 0x64 + 80043c8: f015 0510 ands.w r5, r5, #16 + 80043cc: f040 80e1 bne.w 8004592 + + // fetch the already-hashed pin + // - no real need to re-prove PIN knowledge. + // - if they tricked us, doesn't matter as below the SE validates it all again + uint8_t digest[32]; + pin_cache_restore(args, digest); + 80043d0: f10d 081c add.w r8, sp, #28 + 80043d4: 4641 mov r1, r8 + 80043d6: 4620 mov r0, r4 + 80043d8: f7ff fd62 bl 8003ea0 + bool is_trick = ((args->private_state ^ rom_secrets->hash_cache_secret[0]) & 0x1); + 80043dc: 4b70 ldr r3, [pc, #448] ; (80045a0 ) + 80043de: 6c26 ldr r6, [r4, #64] ; 0x40 + 80043e0: f893 3070 ldrb.w r3, [r3, #112] ; 0x70 + 80043e4: 4073 eors r3, r6 + if(!slot || !is_trick) return is_trick; + 80043e6: 07df lsls r7, r3, #31 + 80043e8: d577 bpl.n 80044da + memset(slot, 0, sizeof(trick_slot_t)); + 80043ea: 2280 movs r2, #128 ; 0x80 + 80043ec: 4629 mov r1, r5 + 80043ee: a817 add r0, sp, #92 ; 0x5c + 80043f0: f009 f940 bl 800d674 + if(args->delay_required & TC_DELTA_MODE) { + 80043f4: 6b23 ldr r3, [r4, #48] ; 0x30 + 80043f6: 0558 lsls r0, r3, #21 + 80043f8: d52b bpl.n 8004452 + slot->tc_flags = args->delay_required; + 80043fa: f8ad 3060 strh.w r3, [sp, #96] ; 0x60 + slot->slot_num = -1; // unknown + 80043fe: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 8004402: 9317 str r3, [sp, #92] ; 0x5c + + // determine if we should proceed under duress + trick_slot_t slot; + bool is_trick = get_is_trick(args, &slot); + + if(is_trick && !(slot.tc_flags & TC_DELTA_MODE)) { + 8004404: f8bd 6060 ldrh.w r6, [sp, #96] ; 0x60 + 8004408: f416 6180 ands.w r1, r6, #1024 ; 0x400 + 800440c: d165 bne.n 80044da + // emulate a 24-word wallet, or xprv based wallet + // see stash.py for encoding details + memset(args->secret, 0, AE_SECRET_LEN); + 800440e: 2248 movs r2, #72 ; 0x48 + 8004410: f104 00b0 add.w r0, r4, #176 ; 0xb0 + 8004414: f009 f92e bl 800d674 + + if(slot.tc_flags & TC_WORD_WALLET) { + 8004418: 04f1 lsls r1, r6, #19 + 800441a: d54c bpl.n 80044b6 + if(check_all_zeros(&slot.xdata[16], 16)) { + 800441c: ae1d add r6, sp, #116 ; 0x74 + 800441e: 2110 movs r1, #16 + 8004420: 4630 mov r0, r6 + 8004422: f7fe f937 bl 8002694 + // 2nd half is zeros, must be 12-word wallet + args->secret[0] = 0x80; // 12 word phrase + memcpy(&args->secret[1], slot.xdata, 16); + 8004426: f104 03b1 add.w r3, r4, #177 ; 0xb1 + if(check_all_zeros(&slot.xdata[16], 16)) { + 800442a: 2800 cmp r0, #0 + 800442c: d034 beq.n 8004498 + args->secret[0] = 0x80; // 12 word phrase + 800442e: 2280 movs r2, #128 ; 0x80 + 8004430: f884 20b0 strb.w r2, [r4, #176] ; 0xb0 + memcpy(&args->secret[1], slot.xdata, 16); + 8004434: ac19 add r4, sp, #100 ; 0x64 + 8004436: 4622 mov r2, r4 + 8004438: ca03 ldmia r2!, {r0, r1} + 800443a: 42b2 cmp r2, r6 + 800443c: 6018 str r0, [r3, #0] + 800443e: 6059 str r1, [r3, #4] + 8004440: 4614 mov r4, r2 + 8004442: f103 0308 add.w r3, r3, #8 + 8004446: d1f6 bne.n 8004436 + ae_reset_chip(); + + if(rv) return EPIN_AE_FAIL; + + return 0; +} + 8004448: 4628 mov r0, r5 + 800444a: f50d 7d38 add.w sp, sp, #736 ; 0x2e0 + 800444e: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + memcpy(key+4, rom_secrets->hash_cache_secret+4, sizeof(rom_secrets->hash_cache_secret)-4); + 8004452: 4f54 ldr r7, [pc, #336] ; (80045a4 ) + memcpy(key, &args->private_state, sizeof(args->private_state)); + 8004454: 960f str r6, [sp, #60] ; 0x3c + memcpy(key+4, rom_secrets->hash_cache_secret+4, sizeof(rom_secrets->hash_cache_secret)-4); + 8004456: cf0f ldmia r7!, {r0, r1, r2, r3} + 8004458: ae10 add r6, sp, #64 ; 0x40 + 800445a: c60f stmia r6!, {r0, r1, r2, r3} + 800445c: e897 0007 ldmia.w r7, {r0, r1, r2} + 8004460: e886 0007 stmia.w r6, {r0, r1, r2} + aes_init(&ctx); + 8004464: a837 add r0, sp, #220 ; 0xdc + 8004466: f003 fffb bl 8008460 + aes_add(&ctx, args->cached_main_pin, 32); + 800446a: 2220 movs r2, #32 + 800446c: f104 01f8 add.w r1, r4, #248 ; 0xf8 + 8004470: a837 add r0, sp, #220 ; 0xdc + 8004472: f003 fffb bl 800846c + aes_done(&ctx, (uint8_t *)slot, 32, key, NULL); + 8004476: a917 add r1, sp, #92 ; 0x5c + 8004478: 9500 str r5, [sp, #0] + 800447a: ab0f add r3, sp, #60 ; 0x3c + 800447c: 2220 movs r2, #32 + 800447e: a837 add r0, sp, #220 ; 0xdc + 8004480: f004 f80a bl 8008498 + if(slot->tc_flags & (TC_WORD_WALLET|TC_XPRV_WALLET)) { + 8004484: f8bd 1060 ldrh.w r1, [sp, #96] ; 0x60 + 8004488: f411 5fc0 tst.w r1, #6144 ; 0x1800 + 800448c: d0ba beq.n 8004404 + se2_read_trick_data(slot->slot_num, slot->tc_flags, slot->xdata); + 800448e: 9817 ldr r0, [sp, #92] ; 0x5c + 8004490: aa19 add r2, sp, #100 ; 0x64 + 8004492: f003 fc87 bl 8007da4 + if(is_trick && !(slot.tc_flags & TC_DELTA_MODE)) { + 8004496: e7b5 b.n 8004404 + args->secret[0] = 0x82; // 24 word phrase + 8004498: 2282 movs r2, #130 ; 0x82 + 800449a: f884 20b0 strb.w r2, [r4, #176] ; 0xb0 + memcpy(&args->secret[1], slot.xdata, 32); + 800449e: ae21 add r6, sp, #132 ; 0x84 + 80044a0: aa19 add r2, sp, #100 ; 0x64 + 80044a2: 4614 mov r4, r2 + 80044a4: cc03 ldmia r4!, {r0, r1} + 80044a6: 42b4 cmp r4, r6 + 80044a8: 6018 str r0, [r3, #0] + 80044aa: 6059 str r1, [r3, #4] + 80044ac: 4622 mov r2, r4 + 80044ae: f103 0308 add.w r3, r3, #8 + 80044b2: d1f6 bne.n 80044a2 + 80044b4: e7c8 b.n 8004448 + } else if(slot.tc_flags & TC_XPRV_WALLET) { + 80044b6: 0532 lsls r2, r6, #20 + 80044b8: d5c6 bpl.n 8004448 + args->secret[0] = 0x01; // XPRV mode + 80044ba: 2301 movs r3, #1 + 80044bc: f884 30b0 strb.w r3, [r4, #176] ; 0xb0 + memcpy(&args->secret[1], slot.xdata, 64); + 80044c0: aa19 add r2, sp, #100 ; 0x64 + 80044c2: 34b1 adds r4, #177 ; 0xb1 + 80044c4: ae29 add r6, sp, #164 ; 0xa4 + 80044c6: 4613 mov r3, r2 + 80044c8: cb03 ldmia r3!, {r0, r1} + 80044ca: 42b3 cmp r3, r6 + 80044cc: 6020 str r0, [r4, #0] + 80044ce: 6061 str r1, [r4, #4] + 80044d0: 461a mov r2, r3 + 80044d2: f104 0408 add.w r4, r4, #8 + 80044d6: d1f6 bne.n 80044c6 + 80044d8: e7b6 b.n 8004448 + int which = (args->change_flags >> 8) & 0xf; + 80044da: 6e63 ldr r3, [r4, #100] ; 0x64 + 80044dc: 121b asrs r3, r3, #8 + switch(which) { + 80044de: f013 0f0c tst.w r3, #12 + 80044e2: d159 bne.n 8004598 + 80044e4: 4a30 ldr r2, [pc, #192] ; (80045a8 ) + int which = (args->change_flags >> 8) & 0xf; + 80044e6: f003 030f and.w r3, r3, #15 + 80044ea: f912 9003 ldrsb.w r9, [r2, r3] + if(kn < 0) return EPIN_RANGE_ERR; + 80044ee: f1b9 0f00 cmp.w r9, #0 + 80044f2: db51 blt.n 8004598 + 80044f4: 2703 movs r7, #3 + rv = ae_encrypted_read(kn, KEYNUM_main_pin, digest, tmp, AE_SECRET_LEN); + 80044f6: f04f 0a48 mov.w sl, #72 ; 0x48 + 80044fa: 2103 movs r1, #3 + 80044fc: f8cd a000 str.w sl, [sp] + 8004500: ab37 add r3, sp, #220 ; 0xdc + 8004502: 4642 mov r2, r8 + 8004504: 4648 mov r0, r9 + 8004506: f7fe fec3 bl 8003290 + if(rv) continue; + 800450a: 4601 mov r1, r0 + 800450c: b130 cbz r0, 800451c + for(int retry=0; retry<3; retry++) { + 800450e: 3f01 subs r7, #1 + 8004510: d1f3 bne.n 80044fa + ae_reset_chip(); + 8004512: f7fe fa49 bl 80029a8 + if(rv) return EPIN_AE_FAIL; + 8004516: f06f 0569 mvn.w r5, #105 ; 0x69 + 800451a: e795 b.n 8004448 + rv = ae_encrypted_read32(KEYNUM_check_secret, 0, KEYNUM_main_pin, digest, check); + 800451c: ae0f add r6, sp, #60 ; 0x3c + 800451e: 9600 str r6, [sp, #0] + 8004520: 4643 mov r3, r8 + 8004522: 2203 movs r2, #3 + 8004524: 200a movs r0, #10 + 8004526: f7fe fe88 bl 800323a + if(rv) continue; + 800452a: 4605 mov r5, r0 + 800452c: 2800 cmp r0, #0 + 800452e: d1ee bne.n 800450e + se2_decrypt_secret(args->secret, AE_SECRET_LEN, 0, tmp, check, digest, &is_valid); + 8004530: f10d 071b add.w r7, sp, #27 + 8004534: f104 00b0 add.w r0, r4, #176 ; 0xb0 + 8004538: ab37 add r3, sp, #220 ; 0xdc + 800453a: e9cd 8701 strd r8, r7, [sp, #4] + 800453e: 9600 str r6, [sp, #0] + 8004540: 462a mov r2, r5 + 8004542: 2148 movs r1, #72 ; 0x48 + 8004544: 9005 str r0, [sp, #20] + 8004546: f003 fe7d bl 8008244 + if(!is_valid) { + 800454a: f89d 301b ldrb.w r3, [sp, #27] + 800454e: 9805 ldr r0, [sp, #20] + 8004550: b993 cbnz r3, 8004578 + memset(args->secret, 0, AE_SECRET_LEN); + 8004552: 2248 movs r2, #72 ; 0x48 + 8004554: 4629 mov r1, r5 + 8004556: f009 f88d bl 800d674 + if(!(args->state_flags & PA_ZERO_SECRET)) { + 800455a: 6be3 ldr r3, [r4, #60] ; 0x3c + 800455c: 06db lsls r3, r3, #27 + 800455e: d408 bmi.n 8004572 + args->state_flags |= PA_ZERO_SECRET; + 8004560: 6be3 ldr r3, [r4, #60] ; 0x3c + 8004562: f043 0310 orr.w r3, r3, #16 + 8004566: 63e3 str r3, [r4, #60] ; 0x3c + _hmac_attempt(args, args->hmac); + 8004568: f104 0144 add.w r1, r4, #68 ; 0x44 + 800456c: 4620 mov r0, r4 + 800456e: f7ff faa3 bl 8003ab8 <_hmac_attempt> + ae_reset_chip(); + 8004572: f7fe fa19 bl 80029a8 + if(rv) return EPIN_AE_FAIL; + 8004576: e767 b.n 8004448 + if(!args->secret[0] && check_all_zeros(args->secret, AE_SECRET_LEN)) { + 8004578: f894 30b0 ldrb.w r3, [r4, #176] ; 0xb0 + 800457c: 2b00 cmp r3, #0 + 800457e: d1f8 bne.n 8004572 + 8004580: 2148 movs r1, #72 ; 0x48 + 8004582: f7fe f887 bl 8002694 + 8004586: 2800 cmp r0, #0 + 8004588: d0f3 beq.n 8004572 + 800458a: e7e9 b.n 8004560 + return EPIN_WRONG_SUCCESS; + 800458c: f06f 056c mvn.w r5, #108 ; 0x6c + 8004590: e75a b.n 8004448 + return EPIN_BAD_REQUEST; + 8004592: f06f 0567 mvn.w r5, #103 ; 0x67 + 8004596: e757 b.n 8004448 + if(kn < 0) return EPIN_RANGE_ERR; + 8004598: f06f 0566 mvn.w r5, #102 ; 0x66 + 800459c: e754 b.n 8004448 + 800459e: bf00 nop + 80045a0: 0801c000 .word 0x0801c000 + 80045a4: 0801c074 .word 0x0801c074 + 80045a8: 0800e71c .word 0x0800e71c + +080045ac : +// - new API so whole thing provided in one shot? encryption issues: provide +// "dest" and all 416 bytes end up there (read case only). +// + int +pin_long_secret(pinAttempt_t *args, uint8_t *dest) +{ + 80045ac: e92d 43f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, lr} + 80045b0: 460f mov r7, r1 + 80045b2: b099 sub sp, #100 ; 0x64 + // Validate args and signature + int rv = _validate_attempt(args, false); + 80045b4: 2100 movs r1, #0 +{ + 80045b6: 4606 mov r6, r0 + int rv = _validate_attempt(args, false); + 80045b8: f7ff faac bl 8003b14 <_validate_attempt> + if(rv) return rv; + 80045bc: 4604 mov r4, r0 + 80045be: b9b8 cbnz r0, 80045f0 + + if((args->state_flags & PA_SUCCESSFUL) != PA_SUCCESSFUL) { + 80045c0: 6bf3 ldr r3, [r6, #60] ; 0x3c + 80045c2: 07da lsls r2, r3, #31 + 80045c4: f140 80a5 bpl.w 8004712 + bool is_trick = ((args->private_state ^ rom_secrets->hash_cache_secret[0]) & 0x1); + 80045c8: 4b55 ldr r3, [pc, #340] ; (8004720 ) + 80045ca: 6c32 ldr r2, [r6, #64] ; 0x40 + 80045cc: f893 3070 ldrb.w r3, [r3, #112] ; 0x70 + 80045d0: 4053 eors r3, r2 + } + + // determine if we should proceed under duress/in some trick way + bool is_trick = get_is_trick(args, NULL); + + if(is_trick) { + 80045d2: 07db lsls r3, r3, #31 + 80045d4: d510 bpl.n 80045f8 + // Not supported in trick mode. Pretend it's all zeros. Accept all writes. + memset(args->secret, 0, 32); + 80045d6: 4601 mov r1, r0 + 80045d8: 2220 movs r2, #32 + 80045da: f106 00b0 add.w r0, r6, #176 ; 0xb0 + 80045de: f009 f849 bl 800d674 + if(dest) memset(dest, 0, AE_LONG_SECRET_LEN); + 80045e2: b12f cbz r7, 80045f0 + 80045e4: f44f 72d0 mov.w r2, #416 ; 0x1a0 + 80045e8: 4621 mov r1, r4 + 80045ea: 4638 mov r0, r7 + 80045ec: f009 f842 bl 800d674 + +se2_fail: + ae_reset_chip(); + + return EPIN_SE2_FAIL; +} + 80045f0: 4620 mov r0, r4 + 80045f2: b019 add sp, #100 ; 0x64 + 80045f4: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + int blk = (args->change_flags >> 8) & 0xf; + 80045f8: 6e73 ldr r3, [r6, #100] ; 0x64 + 80045fa: f3c3 2803 ubfx r8, r3, #8, #4 + if(blk > 13) return EPIN_RANGE_ERR; + 80045fe: f1b8 0f0d cmp.w r8, #13 + 8004602: f300 8089 bgt.w 8004718 + pin_cache_restore(args, digest); + 8004606: a908 add r1, sp, #32 + 8004608: 4630 mov r0, r6 + 800460a: f7ff fc49 bl 8003ea0 + if(!(args->change_flags & CHANGE_SECRET)) { + 800460e: 6e71 ldr r1, [r6, #100] ; 0x64 + 8004610: f011 0908 ands.w r9, r1, #8 + 8004614: d156 bne.n 80046c4 + if(!dest) { + 8004616: bb27 cbnz r7, 8004662 + rv = ae_encrypted_read32(KEYNUM_long_secret, blk, KEYNUM_main_pin, digest, tmp); + 8004618: af10 add r7, sp, #64 ; 0x40 + 800461a: 9700 str r7, [sp, #0] + 800461c: ab08 add r3, sp, #32 + 800461e: 2203 movs r2, #3 + 8004620: 4641 mov r1, r8 + 8004622: 2008 movs r0, #8 + 8004624: f7fe fe09 bl 800323a + if(rv) goto fail; + 8004628: 4605 mov r5, r0 + 800462a: 2800 cmp r0, #0 + 800462c: d16a bne.n 8004704 + se2_decrypt_secret(args->secret, 32, blk*32, tmp, NULL, digest, &is_valid); + 800462e: f10d 031f add.w r3, sp, #31 + 8004632: 9302 str r3, [sp, #8] + 8004634: ab08 add r3, sp, #32 + 8004636: f106 00b0 add.w r0, r6, #176 ; 0xb0 + 800463a: e9cd 4300 strd r4, r3, [sp] + 800463e: ea4f 1248 mov.w r2, r8, lsl #5 + 8004642: 463b mov r3, r7 + 8004644: 2120 movs r1, #32 + 8004646: 9005 str r0, [sp, #20] + 8004648: f003 fdfc bl 8008244 + if(!is_valid) { + 800464c: f89d 301f ldrb.w r3, [sp, #31] + 8004650: 9805 ldr r0, [sp, #20] + 8004652: b91b cbnz r3, 800465c + memset(args->secret, 0, 32); + 8004654: 2220 movs r2, #32 + 8004656: 4621 mov r1, r4 + memset(dest, 0, AE_LONG_SECRET_LEN); + 8004658: f009 f80c bl 800d674 + ae_reset_chip(); + 800465c: f7fe f9a4 bl 80029a8 + if(rv) return EPIN_AE_FAIL; + 8004660: e7c6 b.n 80045f0 + 8004662: 463e mov r6, r7 + rv = ae_encrypted_read32(KEYNUM_long_secret, blk, KEYNUM_main_pin, digest, p); + 8004664: 9600 str r6, [sp, #0] + 8004666: ab08 add r3, sp, #32 + 8004668: 2203 movs r2, #3 + 800466a: 4649 mov r1, r9 + 800466c: 2008 movs r0, #8 + 800466e: f7fe fde4 bl 800323a + if(rv) goto fail; + 8004672: 4605 mov r5, r0 + 8004674: 2800 cmp r0, #0 + 8004676: d145 bne.n 8004704 + for(blk=0; blk<13; blk++, p += 32) { + 8004678: f109 0901 add.w r9, r9, #1 + 800467c: f1b9 0f0d cmp.w r9, #13 + 8004680: f106 0620 add.w r6, r6, #32 + 8004684: d1ee bne.n 8004664 + ASSERT(p == dest+AE_LONG_SECRET_LEN); + 8004686: f507 73d0 add.w r3, r7, #416 ; 0x1a0 + 800468a: 429e cmp r6, r3 + 800468c: d002 beq.n 8004694 + 800468e: 4825 ldr r0, [pc, #148] ; (8004724 ) + 8004690: f7fc f9da bl 8000a48 + se2_decrypt_secret(dest, AE_LONG_SECRET_LEN, 0, dest, NULL, digest, &is_valid); + 8004694: ab10 add r3, sp, #64 ; 0x40 + 8004696: 9302 str r3, [sp, #8] + 8004698: ab08 add r3, sp, #32 + 800469a: e9cd 0300 strd r0, r3, [sp] + 800469e: 4602 mov r2, r0 + 80046a0: 463b mov r3, r7 + 80046a2: f44f 71d0 mov.w r1, #416 ; 0x1a0 + 80046a6: 4638 mov r0, r7 + 80046a8: f003 fdcc bl 8008244 + if(!is_valid) { + 80046ac: f89d 4040 ldrb.w r4, [sp, #64] ; 0x40 + 80046b0: b924 cbnz r4, 80046bc + memset(dest, 0, AE_LONG_SECRET_LEN); + 80046b2: f44f 72d0 mov.w r2, #416 ; 0x1a0 + 80046b6: 4621 mov r1, r4 + 80046b8: 4638 mov r0, r7 + 80046ba: e7cd b.n 8004658 + ae_reset_chip(); + 80046bc: f7fe f974 bl 80029a8 + return 0; + 80046c0: 462c mov r4, r5 + 80046c2: e795 b.n 80045f0 + uint8_t tmp[32] = {0}; + 80046c4: 221c movs r2, #28 + 80046c6: 4621 mov r1, r4 + 80046c8: a811 add r0, sp, #68 ; 0x44 + 80046ca: 9410 str r4, [sp, #64] ; 0x40 + if(se2_encrypt_secret(args->secret, 32, blk*32, tmp, NULL, digest)) { + 80046cc: ad10 add r5, sp, #64 ; 0x40 + uint8_t tmp[32] = {0}; + 80046ce: f008 ffd1 bl 800d674 + if(se2_encrypt_secret(args->secret, 32, blk*32, tmp, NULL, digest)) { + 80046d2: ab08 add r3, sp, #32 + 80046d4: e9cd 4300 strd r4, r3, [sp] + 80046d8: ea4f 1248 mov.w r2, r8, lsl #5 + 80046dc: 462b mov r3, r5 + 80046de: 2120 movs r1, #32 + 80046e0: f106 00b0 add.w r0, r6, #176 ; 0xb0 + 80046e4: f003 fd58 bl 8008198 + 80046e8: b120 cbz r0, 80046f4 + ae_reset_chip(); + 80046ea: f7fe f95d bl 80029a8 + return EPIN_SE2_FAIL; + 80046ee: f06f 0472 mvn.w r4, #114 ; 0x72 + 80046f2: e77d b.n 80045f0 + rv = ae_encrypted_write32(KEYNUM_long_secret, blk, KEYNUM_main_pin, digest, tmp); + 80046f4: 9500 str r5, [sp, #0] + 80046f6: ab08 add r3, sp, #32 + 80046f8: 2203 movs r2, #3 + 80046fa: 4641 mov r1, r8 + 80046fc: 2008 movs r0, #8 + 80046fe: f7fe fe01 bl 8003304 + 8004702: 4605 mov r5, r0 + ae_reset_chip(); + 8004704: f7fe f950 bl 80029a8 + if(rv) return EPIN_AE_FAIL; + 8004708: 2d00 cmp r5, #0 + 800470a: bf18 it ne + 800470c: f06f 0469 mvnne.w r4, #105 ; 0x69 + 8004710: e76e b.n 80045f0 + return EPIN_WRONG_SUCCESS; + 8004712: f06f 046c mvn.w r4, #108 ; 0x6c + 8004716: e76b b.n 80045f0 + if(blk > 13) return EPIN_RANGE_ERR; + 8004718: f06f 0466 mvn.w r4, #102 ; 0x66 + 800471c: e768 b.n 80045f0 + 800471e: bf00 nop + 8004720: 0801c000 .word 0x0801c000 + 8004724: 0800e3e0 .word 0x0800e3e0 + +08004728 : +// +// Record current flash checksum and make green light go on. +// + int +pin_firmware_greenlight(pinAttempt_t *args) +{ + 8004728: b530 push {r4, r5, lr} + // Validate args and signature + int rv = _validate_attempt(args, false); + 800472a: 2100 movs r1, #0 +{ + 800472c: b09b sub sp, #108 ; 0x6c + 800472e: 4604 mov r4, r0 + int rv = _validate_attempt(args, false); + 8004730: f7ff f9f0 bl 8003b14 <_validate_attempt> + if(rv) return rv; + 8004734: bb20 cbnz r0, 8004780 + + if((args->state_flags & PA_SUCCESSFUL) != PA_SUCCESSFUL) { + 8004736: 6be3 ldr r3, [r4, #60] ; 0x3c + 8004738: 07da lsls r2, r3, #31 + 800473a: d529 bpl.n 8004790 + // must come here with a successful PIN login (so it's rate limited nicely) + return EPIN_WRONG_SUCCESS; + } + + if(args->is_secondary) { + 800473c: 6865 ldr r5, [r4, #4] + 800473e: bb55 cbnz r5, 8004796 + return EPIN_PRIMARY_ONLY; + } + + // load existing PIN's hash + uint8_t digest[32]; + pin_cache_restore(args, digest); + 8004740: a902 add r1, sp, #8 + 8004742: 4620 mov r0, r4 + 8004744: f7ff fbac bl 8003ea0 + + // step 1: calc the value to use + uint8_t fw_check[32], world_check[32]; + checksum_flash(fw_check, world_check, 0); + 8004748: 462a mov r2, r5 + 800474a: a912 add r1, sp, #72 ; 0x48 + 800474c: a80a add r0, sp, #40 ; 0x28 + 800474e: f7fd f973 bl 8001a38 + + // step 2: write it out to chip. + if(warmup_ae()) return EPIN_I_AM_BRICK; + 8004752: f7ff fa15 bl 8003b80 + 8004756: bb08 cbnz r0, 800479c + bool is_trick = ((args->private_state ^ rom_secrets->hash_cache_secret[0]) & 0x1); + 8004758: 4b12 ldr r3, [pc, #72] ; (80047a4 ) + 800475a: 6c22 ldr r2, [r4, #64] ; 0x40 + 800475c: f893 3070 ldrb.w r3, [r3, #112] ; 0x70 + 8004760: 4053 eors r3, r2 + + // under duress, we can't fake this, but we go through the motions anyway + if(!get_is_trick(args, NULL)) { + 8004762: 07db lsls r3, r3, #31 + 8004764: d40e bmi.n 8004784 + rv = ae_encrypted_write(KEYNUM_firmware, KEYNUM_main_pin, digest, world_check, 32); + 8004766: 2320 movs r3, #32 + 8004768: 9300 str r3, [sp, #0] + 800476a: aa02 add r2, sp, #8 + 800476c: ab12 add r3, sp, #72 ; 0x48 + 800476e: 2103 movs r1, #3 + 8004770: 200e movs r0, #14 + 8004772: f7fe fe2d bl 80033d0 + + if(rv) { + 8004776: b128 cbz r0, 8004784 + ae_reset_chip(); + 8004778: f7fe f916 bl 80029a8 + + return EPIN_AE_FAIL; + 800477c: f06f 0069 mvn.w r0, #105 ; 0x69 + + return EPIN_AE_FAIL; + } + + return 0; +} + 8004780: b01b add sp, #108 ; 0x6c + 8004782: bd30 pop {r4, r5, pc} + rv = ae_set_gpio_secure(world_check); + 8004784: a812 add r0, sp, #72 ; 0x48 + 8004786: f7fe feb5 bl 80034f4 + if(rv) { + 800478a: 2800 cmp r0, #0 + 800478c: d0f8 beq.n 8004780 + 800478e: e7f3 b.n 8004778 + return EPIN_WRONG_SUCCESS; + 8004790: f06f 006c mvn.w r0, #108 ; 0x6c + 8004794: e7f4 b.n 8004780 + return EPIN_PRIMARY_ONLY; + 8004796: f06f 0071 mvn.w r0, #113 ; 0x71 + 800479a: e7f1 b.n 8004780 + if(warmup_ae()) return EPIN_I_AM_BRICK; + 800479c: f06f 0068 mvn.w r0, #104 ; 0x68 + 80047a0: e7ee b.n 8004780 + 80047a2: bf00 nop + 80047a4: 0801c000 .word 0x0801c000 + +080047a8 : +// Update the system firmware via file in PSRAM. Arrange for +// light to stay green through out process. +// + int +pin_firmware_upgrade(pinAttempt_t *args) +{ + 80047a8: b570 push {r4, r5, r6, lr} + // Validate args and signature + int rv = _validate_attempt(args, false); + 80047aa: 2100 movs r1, #0 +{ + 80047ac: b092 sub sp, #72 ; 0x48 + 80047ae: 4604 mov r4, r0 + int rv = _validate_attempt(args, false); + 80047b0: f7ff f9b0 bl 8003b14 <_validate_attempt> + if(rv) return rv; + 80047b4: 2800 cmp r0, #0 + 80047b6: d14e bne.n 8004856 + + if((args->state_flags & PA_SUCCESSFUL) != PA_SUCCESSFUL) { + 80047b8: 6be3 ldr r3, [r4, #60] ; 0x3c + 80047ba: 07da lsls r2, r3, #31 + 80047bc: d54d bpl.n 800485a + // must come here with a successful PIN login + return EPIN_WRONG_SUCCESS; + } + + if(args->change_flags != CHANGE_FIRMWARE) { + 80047be: 6e63 ldr r3, [r4, #100] ; 0x64 + 80047c0: 2b40 cmp r3, #64 ; 0x40 + 80047c2: d11c bne.n 80047fe + } + + // expecting start/length relative to psram start + uint32_t *about = (uint32_t *)args->secret; + uint32_t start = about[0]; + uint32_t len = about[1]; + 80047c4: e9d4 562c ldrd r5, r6, [r4, #176] ; 0xb0 + + if(len < 32768) return EPIN_RANGE_ERR; + 80047c8: f5a6 4300 sub.w r3, r6, #32768 ; 0x8000 + 80047cc: f5b3 1ffc cmp.w r3, #2064384 ; 0x1f8000 + 80047d0: d846 bhi.n 8004860 + if(len > 2<<20) return EPIN_RANGE_ERR; + if(start+len > PSRAM_SIZE) return EPIN_RANGE_ERR; + 80047d2: 19ab adds r3, r5, r6 + 80047d4: f5b3 0f00 cmp.w r3, #8388608 ; 0x800000 + 80047d8: d842 bhi.n 8004860 + + const uint8_t *data = (const uint8_t *)PSRAM_BASE+start; + 80047da: f105 4510 add.w r5, r5, #2415919104 ; 0x90000000 + + // verify a firmware image that's in RAM, and calc its digest + // - also applies watermark policy, etc + uint8_t world_check[32]; + bool ok = verify_firmware_in_ram(data, len, world_check); + 80047de: aa02 add r2, sp, #8 + 80047e0: 4631 mov r1, r6 + 80047e2: 4628 mov r0, r5 + 80047e4: f7fd fa36 bl 8001c54 + if(!ok) { + 80047e8: 2800 cmp r0, #0 + 80047ea: d03c beq.n 8004866 + bool is_trick = ((args->private_state ^ rom_secrets->hash_cache_secret[0]) & 0x1); + 80047ec: 4b21 ldr r3, [pc, #132] ; (8004874 ) + 80047ee: 6c22 ldr r2, [r4, #64] ; 0x40 + 80047f0: f893 3070 ldrb.w r3, [r3, #112] ; 0x70 + 80047f4: 4053 eors r3, r2 + return EPIN_AUTH_FAIL; + } + + // under duress, we can't fake this, so kill ourselves. + if(get_is_trick(args, NULL)) { + 80047f6: 07db lsls r3, r3, #31 + 80047f8: d504 bpl.n 8004804 + // User is a thug.. kill secret and reboot w/o any notice + fast_wipe(); + 80047fa: f7fd ff1f bl 800263c + return EPIN_BAD_REQUEST; + 80047fe: f06f 0067 mvn.w r0, #103 ; 0x67 + 8004802: e028 b.n 8004856 + return EPIN_BAD_REQUEST; + } + + // load existing PIN's hash + uint8_t digest[32]; + pin_cache_restore(args, digest); + 8004804: a90a add r1, sp, #40 ; 0x28 + 8004806: 4620 mov r0, r4 + 8004808: f7ff fb4a bl 8003ea0 + + // step 1: calc the value to use, see above + if(warmup_ae()) return EPIN_I_AM_BRICK; + 800480c: f7ff f9b8 bl 8003b80 + 8004810: bb60 cbnz r0, 800486c + + // step 2: write it out to chip. + rv = ae_encrypted_write(KEYNUM_firmware, KEYNUM_main_pin, digest, world_check, 32); + 8004812: 2320 movs r3, #32 + 8004814: 9300 str r3, [sp, #0] + 8004816: aa0a add r2, sp, #40 ; 0x28 + 8004818: ab02 add r3, sp, #8 + 800481a: 2103 movs r1, #3 + 800481c: 200e movs r0, #14 + 800481e: f7fe fdd7 bl 80033d0 + if(rv) goto fail; + 8004822: b9a0 cbnz r0, 800484e + + // this turns on green light + rv = ae_set_gpio_secure(world_check); + 8004824: a802 add r0, sp, #8 + 8004826: f7fe fe65 bl 80034f4 + if(rv) goto fail; + 800482a: b980 cbnz r0, 800484e + + // -- point of no return -- + + // burn it, shows progress + psram_do_upgrade(data, len); + 800482c: 4631 mov r1, r6 + 800482e: 4628 mov r0, r5 + 8004830: f000 fbf4 bl 800501c + 8004834: f3bf 8f4f dsb sy + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 8004838: 490f ldr r1, [pc, #60] ; (8004878 ) + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 800483a: 4b10 ldr r3, [pc, #64] ; (800487c ) + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 800483c: 68ca ldr r2, [r1, #12] + 800483e: f402 62e0 and.w r2, r2, #1792 ; 0x700 + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 8004842: 4313 orrs r3, r2 + 8004844: 60cb str r3, [r1, #12] + 8004846: f3bf 8f4f dsb sy + __NOP(); + 800484a: bf00 nop + for(;;) /* wait until reset */ + 800484c: e7fd b.n 800484a + NVIC_SystemReset(); + + return 0; + +fail: + ae_reset_chip(); + 800484e: f7fe f8ab bl 80029a8 + + return EPIN_AE_FAIL; + 8004852: f06f 0069 mvn.w r0, #105 ; 0x69 +} + 8004856: b012 add sp, #72 ; 0x48 + 8004858: bd70 pop {r4, r5, r6, pc} + return EPIN_WRONG_SUCCESS; + 800485a: f06f 006c mvn.w r0, #108 ; 0x6c + 800485e: e7fa b.n 8004856 + if(len < 32768) return EPIN_RANGE_ERR; + 8004860: f06f 0066 mvn.w r0, #102 ; 0x66 + 8004864: e7f7 b.n 8004856 + return EPIN_AUTH_FAIL; + 8004866: f06f 006f mvn.w r0, #111 ; 0x6f + 800486a: e7f4 b.n 8004856 + if(warmup_ae()) return EPIN_I_AM_BRICK; + 800486c: f06f 0068 mvn.w r0, #104 ; 0x68 + 8004870: e7f1 b.n 8004856 + 8004872: bf00 nop + 8004874: 0801c000 .word 0x0801c000 + 8004878: e000ed00 .word 0xe000ed00 + 800487c: 05fa0004 .word 0x05fa0004 + +08004880 : + +// strcat_hex() +// + void +strcat_hex(char *msg, const void *d, int len) +{ + 8004880: b570 push {r4, r5, r6, lr} + 8004882: 4616 mov r6, r2 + 8004884: 4604 mov r4, r0 + 8004886: 460d mov r5, r1 + char *p = msg+strlen(msg); + 8004888: f008 ff27 bl 800d6da + const uint8_t *h = (const uint8_t *)d; + + for(; len; len--, h++) { + *(p++) = hexmap[(*h>>4) & 0xf]; + 800488c: 4a0b ldr r2, [pc, #44] ; (80048bc ) + char *p = msg+strlen(msg); + 800488e: 4420 add r0, r4 + for(; len; len--, h++) { + 8004890: 1e69 subs r1, r5, #1 + 8004892: eb00 0646 add.w r6, r0, r6, lsl #1 + 8004896: 42b0 cmp r0, r6 + 8004898: d102 bne.n 80048a0 + *(p++) = hexmap[(*h>>0) & 0xf]; + } + + *(p++) = 0; + 800489a: 2300 movs r3, #0 + 800489c: 7003 strb r3, [r0, #0] +} + 800489e: bd70 pop {r4, r5, r6, pc} + *(p++) = hexmap[(*h>>4) & 0xf]; + 80048a0: f811 3f01 ldrb.w r3, [r1, #1]! + 80048a4: 091b lsrs r3, r3, #4 + 80048a6: 5cd3 ldrb r3, [r2, r3] + 80048a8: f800 3b02 strb.w r3, [r0], #2 + *(p++) = hexmap[(*h>>0) & 0xf]; + 80048ac: 780b ldrb r3, [r1, #0] + 80048ae: f003 030f and.w r3, r3, #15 + 80048b2: 5cd3 ldrb r3, [r2, r3] + 80048b4: f800 3c01 strb.w r3, [r0, #-1] + for(; len; len--, h++) { + 80048b8: e7ed b.n 8004896 + 80048ba: bf00 nop + 80048bc: 0800e752 .word 0x0800e752 + +080048c0 : + * parameters in the USART_InitTypeDef and initialize the associated handle. + * @param husart USART handle. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_USART_Init(USART_HandleTypeDef *husart) +{ + 80048c0: b5f8 push {r3, r4, r5, r6, r7, lr} + /* Check the USART handle allocation */ + if (husart == NULL) + 80048c2: 4604 mov r4, r0 + 80048c4: b910 cbnz r0, 80048cc + { + return HAL_ERROR; + 80048c6: 2501 movs r5, #1 + /* Enable the Peripheral */ + __HAL_USART_ENABLE(husart); + + /* TEACK and/or REACK to check before moving husart->State to Ready */ + return (USART_CheckIdleState(husart)); +} + 80048c8: 4628 mov r0, r5 + 80048ca: bdf8 pop {r3, r4, r5, r6, r7, pc} + if (husart->State == HAL_USART_STATE_RESET) + 80048cc: f890 3059 ldrb.w r3, [r0, #89] ; 0x59 + 80048d0: f003 02ff and.w r2, r3, #255 ; 0xff + 80048d4: b90b cbnz r3, 80048da + husart->Lock = HAL_UNLOCKED; + 80048d6: f880 2058 strb.w r2, [r0, #88] ; 0x58 + __HAL_USART_DISABLE(husart); + 80048da: 6823 ldr r3, [r4, #0] + tmpreg = (uint32_t)husart->Init.WordLength | husart->Init.Parity | husart->Init.Mode | USART_CR1_OVER8; + 80048dc: 6921 ldr r1, [r4, #16] + husart->State = HAL_USART_STATE_BUSY; + 80048de: 2502 movs r5, #2 + 80048e0: f884 5059 strb.w r5, [r4, #89] ; 0x59 + __HAL_USART_DISABLE(husart); + 80048e4: 681a ldr r2, [r3, #0] + 80048e6: f022 0201 bic.w r2, r2, #1 + 80048ea: 601a str r2, [r3, #0] + tmpreg = (uint32_t)husart->Init.WordLength | husart->Init.Parity | husart->Init.Mode | USART_CR1_OVER8; + 80048ec: 68a2 ldr r2, [r4, #8] + MODIFY_REG(husart->Instance->CR1, USART_CR1_FIELDS, tmpreg); + 80048ee: 6818 ldr r0, [r3, #0] + tmpreg = (uint32_t)husart->Init.WordLength | husart->Init.Parity | husart->Init.Mode | USART_CR1_OVER8; + 80048f0: 430a orrs r2, r1 + MODIFY_REG(husart->Instance->CR1, USART_CR1_FIELDS, tmpreg); + 80048f2: 49a9 ldr r1, [pc, #676] ; (8004b98 ) + 80048f4: 4001 ands r1, r0 + 80048f6: 430a orrs r2, r1 + 80048f8: 6961 ldr r1, [r4, #20] + MODIFY_REG(husart->Instance->CR2, USART_CR2_FIELDS, tmpreg); + 80048fa: 69a0 ldr r0, [r4, #24] + MODIFY_REG(husart->Instance->CR1, USART_CR1_FIELDS, tmpreg); + 80048fc: 430a orrs r2, r1 + 80048fe: f442 4200 orr.w r2, r2, #32768 ; 0x8000 + 8004902: 601a str r2, [r3, #0] + MODIFY_REG(husart->Instance->CR2, USART_CR2_FIELDS, tmpreg); + 8004904: 6859 ldr r1, [r3, #4] + 8004906: 6a22 ldr r2, [r4, #32] + 8004908: f421 517c bic.w r1, r1, #16128 ; 0x3f00 + 800490c: f021 0109 bic.w r1, r1, #9 + 8004910: 4302 orrs r2, r0 + 8004912: 430a orrs r2, r1 + 8004914: 69e1 ldr r1, [r4, #28] + 8004916: 430a orrs r2, r1 + 8004918: 68e1 ldr r1, [r4, #12] + 800491a: 430a orrs r2, r1 + 800491c: f442 6200 orr.w r2, r2, #2048 ; 0x800 + 8004920: 605a str r2, [r3, #4] + MODIFY_REG(husart->Instance->PRESC, USART_PRESC_PRESCALER, husart->Init.ClockPrescaler); + 8004922: 6ad9 ldr r1, [r3, #44] ; 0x2c + 8004924: 6a62 ldr r2, [r4, #36] ; 0x24 + 8004926: f021 010f bic.w r1, r1, #15 + 800492a: 4311 orrs r1, r2 + 800492c: 62d9 str r1, [r3, #44] ; 0x2c + USART_GETCLOCKSOURCE(husart, clocksource); + 800492e: 499b ldr r1, [pc, #620] ; (8004b9c ) + 8004930: 428b cmp r3, r1 + 8004932: d10e bne.n 8004952 + 8004934: 4b9a ldr r3, [pc, #616] ; (8004ba0 ) + 8004936: f8d3 3088 ldr.w r3, [r3, #136] ; 0x88 + 800493a: f003 0303 and.w r3, r3, #3 + 800493e: 42ab cmp r3, r5 + 8004940: f000 80cd beq.w 8004ade + 8004944: 2b03 cmp r3, #3 + 8004946: d01a beq.n 800497e + 8004948: 2b01 cmp r3, #1 + 800494a: d153 bne.n 80049f4 + pclk = HAL_RCC_GetSysClockFreq(); + 800494c: f003 ff3e bl 80087cc + 8004950: e052 b.n 80049f8 + USART_GETCLOCKSOURCE(husart, clocksource); + 8004952: 4994 ldr r1, [pc, #592] ; (8004ba4 ) + 8004954: 428b cmp r3, r1 + 8004956: d13c bne.n 80049d2 + 8004958: 4b91 ldr r3, [pc, #580] ; (8004ba0 ) + 800495a: f8d3 3088 ldr.w r3, [r3, #136] ; 0x88 + 800495e: f003 030c and.w r3, r3, #12 + 8004962: 2b08 cmp r3, #8 + 8004964: f000 80bb beq.w 8004ade + 8004968: d807 bhi.n 800497a + 800496a: 2b00 cmp r3, #0 + 800496c: f000 80b4 beq.w 8004ad8 + 8004970: 2b04 cmp r3, #4 + 8004972: d0eb beq.n 800494c + uint32_t usartdiv = 0x00000000; + 8004974: 2300 movs r3, #0 + ret = HAL_ERROR; + 8004976: 2501 movs r5, #1 + 8004978: e06e b.n 8004a58 + USART_GETCLOCKSOURCE(husart, clocksource); + 800497a: 2b0c cmp r3, #12 + 800497c: d1fa bne.n 8004974 + usartdiv = (uint32_t)(USART_DIV_SAMPLING8(LSE_VALUE, husart->Init.BaudRate, husart->Init.ClockPrescaler)); + 800497e: 2a00 cmp r2, #0 + 8004980: f000 80fb beq.w 8004b7a + 8004984: 2a01 cmp r2, #1 + 8004986: f000 80fa beq.w 8004b7e + 800498a: 2a02 cmp r2, #2 + 800498c: f000 80f9 beq.w 8004b82 + 8004990: 2a03 cmp r2, #3 + 8004992: f000 80f8 beq.w 8004b86 + 8004996: 2a04 cmp r2, #4 + 8004998: f000 80f7 beq.w 8004b8a + 800499c: 2a05 cmp r2, #5 + 800499e: f000 80f6 beq.w 8004b8e + 80049a2: 2a06 cmp r2, #6 + 80049a4: f000 80f5 beq.w 8004b92 + 80049a8: 2a07 cmp r2, #7 + 80049aa: f000 8101 beq.w 8004bb0 + 80049ae: 2a08 cmp r2, #8 + 80049b0: f000 8100 beq.w 8004bb4 + 80049b4: 2a09 cmp r2, #9 + 80049b6: f000 80ff beq.w 8004bb8 + 80049ba: 2a0a cmp r2, #10 + 80049bc: f000 80fe beq.w 8004bbc + 80049c0: 2a0b cmp r2, #11 + 80049c2: bf14 ite ne + 80049c4: 2201 movne r2, #1 + 80049c6: f44f 7280 moveq.w r2, #256 ; 0x100 + 80049ca: 6861 ldr r1, [r4, #4] + 80049cc: f44f 4300 mov.w r3, #32768 ; 0x8000 + 80049d0: e0a1 b.n 8004b16 + USART_GETCLOCKSOURCE(husart, clocksource); + 80049d2: 4975 ldr r1, [pc, #468] ; (8004ba8 ) + 80049d4: 428b cmp r3, r1 + 80049d6: d1cd bne.n 8004974 + 80049d8: 4b71 ldr r3, [pc, #452] ; (8004ba0 ) + 80049da: f8d3 3088 ldr.w r3, [r3, #136] ; 0x88 + 80049de: f003 0330 and.w r3, r3, #48 ; 0x30 + 80049e2: 2b20 cmp r3, #32 + 80049e4: d07b beq.n 8004ade + 80049e6: d803 bhi.n 80049f0 + 80049e8: 2b00 cmp r3, #0 + 80049ea: d075 beq.n 8004ad8 + 80049ec: 2b10 cmp r3, #16 + 80049ee: e7c0 b.n 8004972 + 80049f0: 2b30 cmp r3, #48 ; 0x30 + 80049f2: e7c3 b.n 800497c + pclk = HAL_RCC_GetPCLK2Freq(); + 80049f4: f004 faf8 bl 8008fe8 + usartdiv = (uint32_t)(USART_DIV_SAMPLING8(pclk, husart->Init.BaudRate, husart->Init.ClockPrescaler)); + 80049f8: 6a62 ldr r2, [r4, #36] ; 0x24 + 80049fa: 2a00 cmp r2, #0 + 80049fc: f000 80a7 beq.w 8004b4e + 8004a00: 2a01 cmp r2, #1 + 8004a02: f000 80a6 beq.w 8004b52 + 8004a06: 2a02 cmp r2, #2 + 8004a08: f000 80a5 beq.w 8004b56 + 8004a0c: 2a03 cmp r2, #3 + 8004a0e: f000 80a4 beq.w 8004b5a + 8004a12: 2a04 cmp r2, #4 + 8004a14: f000 80a3 beq.w 8004b5e + 8004a18: 2a05 cmp r2, #5 + 8004a1a: f000 80a2 beq.w 8004b62 + 8004a1e: 2a06 cmp r2, #6 + 8004a20: f000 80a1 beq.w 8004b66 + 8004a24: 2a07 cmp r2, #7 + 8004a26: f000 80a0 beq.w 8004b6a + 8004a2a: 2a08 cmp r2, #8 + 8004a2c: f000 809f beq.w 8004b6e + 8004a30: 2a09 cmp r2, #9 + 8004a32: f000 809e beq.w 8004b72 + 8004a36: 2a0a cmp r2, #10 + 8004a38: f000 809d beq.w 8004b76 + 8004a3c: 2a0b cmp r2, #11 + 8004a3e: bf14 ite ne + 8004a40: 2201 movne r2, #1 + 8004a42: f44f 7280 moveq.w r2, #256 ; 0x100 + 8004a46: 6861 ldr r1, [r4, #4] + 8004a48: fbb0 f0f2 udiv r0, r0, r2 + 8004a4c: 084b lsrs r3, r1, #1 + 8004a4e: eb03 0340 add.w r3, r3, r0, lsl #1 + HAL_StatusTypeDef ret = HAL_OK; + 8004a52: 2500 movs r5, #0 + usartdiv = (uint32_t)(USART_DIV_SAMPLING8(LSE_VALUE, husart->Init.BaudRate, husart->Init.ClockPrescaler)); + 8004a54: fbb3 f3f1 udiv r3, r3, r1 + if ((usartdiv >= USART_BRR_MIN) && (usartdiv <= USART_BRR_MAX)) + 8004a58: f1a3 0110 sub.w r1, r3, #16 + 8004a5c: f64f 72ef movw r2, #65519 ; 0xffef + 8004a60: 4291 cmp r1, r2 + brrtemp = (uint16_t)(usartdiv & 0xFFF0U); + 8004a62: bf9f itttt ls + 8004a64: f023 020f bicls.w r2, r3, #15 + 8004a68: b292 uxthls r2, r2 + brrtemp |= (uint16_t)((usartdiv & (uint16_t)0x000FU) >> 1U); + 8004a6a: f3c3 0342 ubfxls r3, r3, #1, #3 + husart->Instance->BRR = brrtemp; + 8004a6e: 6821 ldrls r1, [r4, #0] + 8004a70: bf9a itte ls + 8004a72: 4313 orrls r3, r2 + 8004a74: 60cb strls r3, [r1, #12] + ret = HAL_ERROR; + 8004a76: 2501 movhi r5, #1 + husart->NbTxDataToProcess = 1U; + 8004a78: 2301 movs r3, #1 + husart->RxISR = NULL; + 8004a7a: 2200 movs r2, #0 + if (USART_SetConfig(husart) == HAL_ERROR) + 8004a7c: 429d cmp r5, r3 + husart->TxISR = NULL; + 8004a7e: e9c4 2212 strd r2, r2, [r4, #72] ; 0x48 + husart->NbTxDataToProcess = 1U; + 8004a82: 87a3 strh r3, [r4, #60] ; 0x3c + husart->NbRxDataToProcess = 1U; + 8004a84: 8763 strh r3, [r4, #58] ; 0x3a + if (USART_SetConfig(husart) == HAL_ERROR) + 8004a86: f43f af1e beq.w 80048c6 + husart->Instance->CR2 &= ~USART_CR2_LINEN; + 8004a8a: 6823 ldr r3, [r4, #0] + 8004a8c: 6859 ldr r1, [r3, #4] + 8004a8e: f421 4180 bic.w r1, r1, #16384 ; 0x4000 + 8004a92: 6059 str r1, [r3, #4] + husart->Instance->CR3 &= ~(USART_CR3_SCEN | USART_CR3_HDSEL | USART_CR3_IREN); + 8004a94: 6899 ldr r1, [r3, #8] + 8004a96: f021 012a bic.w r1, r1, #42 ; 0x2a + 8004a9a: 6099 str r1, [r3, #8] + __HAL_USART_ENABLE(husart); + 8004a9c: 6819 ldr r1, [r3, #0] + 8004a9e: f041 0101 orr.w r1, r1, #1 + 8004aa2: 6019 str r1, [r3, #0] + husart->ErrorCode = HAL_USART_ERROR_NONE; + 8004aa4: 65e2 str r2, [r4, #92] ; 0x5c + tickstart = HAL_GetTick(); + 8004aa6: f002 fb21 bl 80070ec + if ((husart->Instance->CR1 & USART_CR1_TE) == USART_CR1_TE) + 8004aaa: 6823 ldr r3, [r4, #0] + 8004aac: 681b ldr r3, [r3, #0] + 8004aae: 071a lsls r2, r3, #28 + tickstart = HAL_GetTick(); + 8004ab0: 4607 mov r7, r0 + if ((husart->Instance->CR1 & USART_CR1_TE) == USART_CR1_TE) + 8004ab2: f100 8085 bmi.w 8004bc0 + if ((husart->Instance->CR1 & USART_CR1_RE) == USART_CR1_RE) + 8004ab6: 6823 ldr r3, [r4, #0] + 8004ab8: 681b ldr r3, [r3, #0] + 8004aba: 075b lsls r3, r3, #29 + 8004abc: d505 bpl.n 8004aca + while ((__HAL_USART_GET_FLAG(husart, Flag) ? SET : RESET) == Status) + 8004abe: 6823 ldr r3, [r4, #0] + 8004ac0: 69de ldr r6, [r3, #28] + 8004ac2: f416 0680 ands.w r6, r6, #4194304 ; 0x400000 + 8004ac6: f000 808e beq.w 8004be6 + husart->State = HAL_USART_STATE_READY; + 8004aca: 2301 movs r3, #1 + 8004acc: f884 3059 strb.w r3, [r4, #89] ; 0x59 + __HAL_UNLOCK(husart); + 8004ad0: 2300 movs r3, #0 + 8004ad2: f884 3058 strb.w r3, [r4, #88] ; 0x58 + return HAL_OK; + 8004ad6: e6f7 b.n 80048c8 + pclk = HAL_RCC_GetPCLK1Freq(); + 8004ad8: f004 fa74 bl 8008fc4 + usartdiv = (uint32_t)(USART_DIV_SAMPLING8(pclk, husart->Init.BaudRate, husart->Init.ClockPrescaler)); + 8004adc: e78c b.n 80049f8 + usartdiv = (uint32_t)(USART_DIV_SAMPLING8(HSI_VALUE, husart->Init.BaudRate, husart->Init.ClockPrescaler)); + 8004ade: b302 cbz r2, 8004b22 + 8004ae0: 2a01 cmp r2, #1 + 8004ae2: d020 beq.n 8004b26 + 8004ae4: 2a02 cmp r2, #2 + 8004ae6: d020 beq.n 8004b2a + 8004ae8: 2a03 cmp r2, #3 + 8004aea: d020 beq.n 8004b2e + 8004aec: 2a04 cmp r2, #4 + 8004aee: d020 beq.n 8004b32 + 8004af0: 2a05 cmp r2, #5 + 8004af2: d020 beq.n 8004b36 + 8004af4: 2a06 cmp r2, #6 + 8004af6: d020 beq.n 8004b3a + 8004af8: 2a07 cmp r2, #7 + 8004afa: d020 beq.n 8004b3e + 8004afc: 2a08 cmp r2, #8 + 8004afe: d020 beq.n 8004b42 + 8004b00: 2a09 cmp r2, #9 + 8004b02: d020 beq.n 8004b46 + 8004b04: 2a0a cmp r2, #10 + 8004b06: d020 beq.n 8004b4a + 8004b08: 2a0b cmp r2, #11 + 8004b0a: bf14 ite ne + 8004b0c: 2201 movne r2, #1 + 8004b0e: f44f 7280 moveq.w r2, #256 ; 0x100 + 8004b12: 6861 ldr r1, [r4, #4] + 8004b14: 4b25 ldr r3, [pc, #148] ; (8004bac ) + usartdiv = (uint32_t)(USART_DIV_SAMPLING8(LSE_VALUE, husart->Init.BaudRate, husart->Init.ClockPrescaler)); + 8004b16: fbb3 f2f2 udiv r2, r3, r2 + 8004b1a: 084b lsrs r3, r1, #1 + 8004b1c: eb03 0342 add.w r3, r3, r2, lsl #1 + 8004b20: e797 b.n 8004a52 + usartdiv = (uint32_t)(USART_DIV_SAMPLING8(HSI_VALUE, husart->Init.BaudRate, husart->Init.ClockPrescaler)); + 8004b22: 2201 movs r2, #1 + 8004b24: e7f5 b.n 8004b12 + 8004b26: 2202 movs r2, #2 + 8004b28: e7f3 b.n 8004b12 + 8004b2a: 2204 movs r2, #4 + 8004b2c: e7f1 b.n 8004b12 + 8004b2e: 2206 movs r2, #6 + 8004b30: e7ef b.n 8004b12 + 8004b32: 2208 movs r2, #8 + 8004b34: e7ed b.n 8004b12 + 8004b36: 220a movs r2, #10 + 8004b38: e7eb b.n 8004b12 + 8004b3a: 220c movs r2, #12 + 8004b3c: e7e9 b.n 8004b12 + 8004b3e: 2210 movs r2, #16 + 8004b40: e7e7 b.n 8004b12 + 8004b42: 2220 movs r2, #32 + 8004b44: e7e5 b.n 8004b12 + 8004b46: 2240 movs r2, #64 ; 0x40 + 8004b48: e7e3 b.n 8004b12 + 8004b4a: 2280 movs r2, #128 ; 0x80 + 8004b4c: e7e1 b.n 8004b12 + usartdiv = (uint32_t)(USART_DIV_SAMPLING8(pclk, husart->Init.BaudRate, husart->Init.ClockPrescaler)); + 8004b4e: 2201 movs r2, #1 + 8004b50: e779 b.n 8004a46 + 8004b52: 2202 movs r2, #2 + 8004b54: e777 b.n 8004a46 + 8004b56: 2204 movs r2, #4 + 8004b58: e775 b.n 8004a46 + 8004b5a: 2206 movs r2, #6 + 8004b5c: e773 b.n 8004a46 + 8004b5e: 2208 movs r2, #8 + 8004b60: e771 b.n 8004a46 + 8004b62: 220a movs r2, #10 + 8004b64: e76f b.n 8004a46 + 8004b66: 220c movs r2, #12 + 8004b68: e76d b.n 8004a46 + 8004b6a: 2210 movs r2, #16 + 8004b6c: e76b b.n 8004a46 + 8004b6e: 2220 movs r2, #32 + 8004b70: e769 b.n 8004a46 + 8004b72: 2240 movs r2, #64 ; 0x40 + 8004b74: e767 b.n 8004a46 + 8004b76: 2280 movs r2, #128 ; 0x80 + 8004b78: e765 b.n 8004a46 + usartdiv = (uint32_t)(USART_DIV_SAMPLING8(LSE_VALUE, husart->Init.BaudRate, husart->Init.ClockPrescaler)); + 8004b7a: 2201 movs r2, #1 + 8004b7c: e725 b.n 80049ca + 8004b7e: 2202 movs r2, #2 + 8004b80: e723 b.n 80049ca + 8004b82: 2204 movs r2, #4 + 8004b84: e721 b.n 80049ca + 8004b86: 2206 movs r2, #6 + 8004b88: e71f b.n 80049ca + 8004b8a: 2208 movs r2, #8 + 8004b8c: e71d b.n 80049ca + 8004b8e: 220a movs r2, #10 + 8004b90: e71b b.n 80049ca + 8004b92: 220c movs r2, #12 + 8004b94: e719 b.n 80049ca + 8004b96: bf00 nop + 8004b98: cfff69f3 .word 0xcfff69f3 + 8004b9c: 40013800 .word 0x40013800 + 8004ba0: 40021000 .word 0x40021000 + 8004ba4: 40004400 .word 0x40004400 + 8004ba8: 40004800 .word 0x40004800 + 8004bac: 00f42400 .word 0x00f42400 + 8004bb0: 2210 movs r2, #16 + 8004bb2: e70a b.n 80049ca + 8004bb4: 2220 movs r2, #32 + 8004bb6: e708 b.n 80049ca + 8004bb8: 2240 movs r2, #64 ; 0x40 + 8004bba: e706 b.n 80049ca + 8004bbc: 2280 movs r2, #128 ; 0x80 + 8004bbe: e704 b.n 80049ca + while ((__HAL_USART_GET_FLAG(husart, Flag) ? SET : RESET) == Status) + 8004bc0: 6823 ldr r3, [r4, #0] + 8004bc2: 69de ldr r6, [r3, #28] + 8004bc4: f416 1600 ands.w r6, r6, #2097152 ; 0x200000 + 8004bc8: f47f af75 bne.w 8004ab6 + if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U)) + 8004bcc: f002 fa8e bl 80070ec + 8004bd0: 1bc0 subs r0, r0, r7 + 8004bd2: f5b0 7f7a cmp.w r0, #1000 ; 0x3e8 + 8004bd6: d9f3 bls.n 8004bc0 + husart->State = HAL_USART_STATE_READY; + 8004bd8: 2301 movs r3, #1 + 8004bda: f884 3059 strb.w r3, [r4, #89] ; 0x59 + __HAL_UNLOCK(husart); + 8004bde: f884 6058 strb.w r6, [r4, #88] ; 0x58 + return HAL_TIMEOUT; + 8004be2: 2503 movs r5, #3 + 8004be4: e670 b.n 80048c8 + if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U)) + 8004be6: f002 fa81 bl 80070ec + 8004bea: 1bc0 subs r0, r0, r7 + 8004bec: f5b0 7f7a cmp.w r0, #1000 ; 0x3e8 + 8004bf0: f67f af65 bls.w 8004abe + 8004bf4: e7f0 b.n 8004bd8 + 8004bf6: bf00 nop + +08004bf8 : + __HAL_RCC_USART1_CONFIG(RCC_USART1CLKSOURCE_SYSCLK); + 8004bf8: 4b14 ldr r3, [pc, #80] ; (8004c4c ) + 8004bfa: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 8004bfe: f022 0203 bic.w r2, r2, #3 + 8004c02: f042 0201 orr.w r2, r2, #1 +{ + 8004c06: b513 push {r0, r1, r4, lr} + __HAL_RCC_USART1_CONFIG(RCC_USART1CLKSOURCE_SYSCLK); + 8004c08: f8c3 2088 str.w r2, [r3, #136] ; 0x88 + __HAL_RCC_USART1_CLK_ENABLE(); + 8004c0c: 6e1a ldr r2, [r3, #96] ; 0x60 + memset(&con, 0, sizeof(con)); + 8004c0e: 4c10 ldr r4, [pc, #64] ; (8004c50 ) + __HAL_RCC_USART1_CLK_ENABLE(); + 8004c10: f442 4280 orr.w r2, r2, #16384 ; 0x4000 + 8004c14: 661a str r2, [r3, #96] ; 0x60 + 8004c16: 6e1b ldr r3, [r3, #96] ; 0x60 + 8004c18: f403 4380 and.w r3, r3, #16384 ; 0x4000 + 8004c1c: 9301 str r3, [sp, #4] + memset(&con, 0, sizeof(con)); + 8004c1e: 2258 movs r2, #88 ; 0x58 + 8004c20: 2100 movs r1, #0 + 8004c22: f104 0008 add.w r0, r4, #8 + __HAL_RCC_USART1_CLK_ENABLE(); + 8004c26: 9b01 ldr r3, [sp, #4] + memset(&con, 0, sizeof(con)); + 8004c28: f008 fd24 bl 800d674 + con.Init.BaudRate = 115200; + 8004c2c: 4a09 ldr r2, [pc, #36] ; (8004c54 ) + 8004c2e: f44f 33e1 mov.w r3, #115200 ; 0x1c200 + 8004c32: e9c4 2300 strd r2, r3, [r4] + HAL_StatusTypeDef rv = HAL_USART_Init(&con); + 8004c36: 4620 mov r0, r4 + con.Init.Mode = USART_MODE_TX_RX; + 8004c38: 230c movs r3, #12 + 8004c3a: 6163 str r3, [r4, #20] + HAL_StatusTypeDef rv = HAL_USART_Init(&con); + 8004c3c: f7ff fe40 bl 80048c0 + ASSERT(rv == HAL_OK); + 8004c40: b110 cbz r0, 8004c48 + 8004c42: 4805 ldr r0, [pc, #20] ; (8004c58 ) + 8004c44: f7fb ff00 bl 8000a48 +} + 8004c48: b002 add sp, #8 + 8004c4a: bd10 pop {r4, pc} + 8004c4c: 40021000 .word 0x40021000 + 8004c50: 2009e1c0 .word 0x2009e1c0 + 8004c54: 40013800 .word 0x40013800 + 8004c58: 0800e3e0 .word 0x0800e3e0 + +08004c5c : + * @param Timeout Timeout duration. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_USART_Transmit(USART_HandleTypeDef *husart, uint8_t *pTxData, uint16_t Size, uint32_t Timeout) +{ + while(Size > 0U) { + 8004c5c: 4b0b ldr r3, [pc, #44] ; (8004c8c ) + 8004c5e: 440a add r2, r1 + 8004c60: 4291 cmp r1, r2 + 8004c62: d10b bne.n 8004c7c + MY_UART->TDR = *pTxData; + pTxData++; + Size --; + } + + while(!(MY_UART->ISR & UART_FLAG_TC)) { + 8004c64: 69da ldr r2, [r3, #28] + 8004c66: 0652 lsls r2, r2, #25 + 8004c68: d5fc bpl.n 8004c64 + // wait for final byte to be sent + } + + // Clear Transmission Complete Flag + MY_UART->ICR = USART_CLEAR_TCF; + 8004c6a: 2240 movs r2, #64 ; 0x40 + 8004c6c: 621a str r2, [r3, #32] + + // Clear overrun flag and discard the received data + MY_UART->ICR = USART_CLEAR_OREF; + 8004c6e: 2208 movs r2, #8 + 8004c70: 621a str r2, [r3, #32] + MY_UART->RQR = USART_RXDATA_FLUSH_REQUEST; + 8004c72: 831a strh r2, [r3, #24] + MY_UART->RQR = USART_TXDATA_FLUSH_REQUEST; + 8004c74: 2210 movs r2, #16 + 8004c76: 831a strh r2, [r3, #24] + + return HAL_OK; +} + 8004c78: 2000 movs r0, #0 + 8004c7a: 4770 bx lr + while(!(MY_UART->ISR & UART_FLAG_TXE)) { + 8004c7c: 69d8 ldr r0, [r3, #28] + 8004c7e: 0600 lsls r0, r0, #24 + 8004c80: d5fc bpl.n 8004c7c + MY_UART->TDR = *pTxData; + 8004c82: f811 0b01 ldrb.w r0, [r1], #1 + 8004c86: 8518 strh r0, [r3, #40] ; 0x28 + Size --; + 8004c88: e7ea b.n 8004c60 + 8004c8a: bf00 nop + 8004c8c: 40013800 .word 0x40013800 + +08004c90 : +{ + 8004c90: b510 push {r4, lr} + 8004c92: 4604 mov r4, r0 + rng_delay(); + 8004c94: f7fd fd72 bl 800277c + HAL_USART_Transmit(&con, (uint8_t *)msg, strlen(msg), HAL_MAX_DELAY); + 8004c98: 4620 mov r0, r4 + 8004c9a: f008 fd1e bl 800d6da + 8004c9e: 4621 mov r1, r4 + 8004ca0: b282 uxth r2, r0 + 8004ca2: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 8004ca6: 4803 ldr r0, [pc, #12] ; (8004cb4 ) + 8004ca8: f7ff ffd8 bl 8004c5c +} + 8004cac: e8bd 4010 ldmia.w sp!, {r4, lr} + rng_delay(); + 8004cb0: f7fd bd64 b.w 800277c + 8004cb4: 2009e1c0 .word 0x2009e1c0 + +08004cb8 : +{ + 8004cb8: b513 push {r0, r1, r4, lr} + 8004cba: 4604 mov r4, r0 + uint8_t cb = c; + 8004cbc: f88d 0007 strb.w r0, [sp, #7] + rng_delay(); + 8004cc0: f7fd fd5c bl 800277c + if(cb != '\n') { + 8004cc4: f89d 3007 ldrb.w r3, [sp, #7] + HAL_USART_Transmit(&con, (uint8_t *)CRLF, 2, HAL_MAX_DELAY); + 8004cc8: 4808 ldr r0, [pc, #32] ; (8004cec ) + if(cb != '\n') { + 8004cca: 2b0a cmp r3, #10 + HAL_USART_Transmit(&con, (uint8_t *)CRLF, 2, HAL_MAX_DELAY); + 8004ccc: bf08 it eq + 8004cce: 4908 ldreq r1, [pc, #32] ; (8004cf0 ) + HAL_USART_Transmit(&con, &cb, 1, HAL_MAX_DELAY); + 8004cd0: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 8004cd4: bf1a itte ne + 8004cd6: 2201 movne r2, #1 + 8004cd8: f10d 0107 addne.w r1, sp, #7 + HAL_USART_Transmit(&con, (uint8_t *)CRLF, 2, HAL_MAX_DELAY); + 8004cdc: 2202 moveq r2, #2 + 8004cde: f7ff ffbd bl 8004c5c + rng_delay(); + 8004ce2: f7fd fd4b bl 800277c +} + 8004ce6: 4620 mov r0, r4 + 8004ce8: b002 add sp, #8 + 8004cea: bd10 pop {r4, pc} + 8004cec: 2009e1c0 .word 0x2009e1c0 + 8004cf0: 0800e74f .word 0x0800e74f + +08004cf4 : +{ + 8004cf4: b538 push {r3, r4, r5, lr} + putchar(hexmap[(b>>4) & 0xf]); + 8004cf6: 4d06 ldr r5, [pc, #24] ; (8004d10 ) + 8004cf8: 0903 lsrs r3, r0, #4 +{ + 8004cfa: 4604 mov r4, r0 + putchar(hexmap[(b>>0) & 0xf]); + 8004cfc: f004 040f and.w r4, r4, #15 + putchar(hexmap[(b>>4) & 0xf]); + 8004d00: 5ce8 ldrb r0, [r5, r3] + 8004d02: f7ff ffd9 bl 8004cb8 + putchar(hexmap[(b>>0) & 0xf]); + 8004d06: 5d28 ldrb r0, [r5, r4] +} + 8004d08: e8bd 4038 ldmia.w sp!, {r3, r4, r5, lr} + putchar(hexmap[(b>>0) & 0xf]); + 8004d0c: f7ff bfd4 b.w 8004cb8 + 8004d10: 0800e752 .word 0x0800e752 + +08004d14 : +{ + 8004d14: b538 push {r3, r4, r5, lr} + putchar(hexmap[(w>>12) & 0xf]); + 8004d16: 4d0b ldr r5, [pc, #44] ; (8004d44 ) + 8004d18: 0b03 lsrs r3, r0, #12 +{ + 8004d1a: 4604 mov r4, r0 + putchar(hexmap[(w>>12) & 0xf]); + 8004d1c: 5ce8 ldrb r0, [r5, r3] + 8004d1e: f7ff ffcb bl 8004cb8 + putchar(hexmap[(w>>8) & 0xf]); + 8004d22: f3c4 2303 ubfx r3, r4, #8, #4 + 8004d26: 5ce8 ldrb r0, [r5, r3] + 8004d28: f7ff ffc6 bl 8004cb8 + putchar(hexmap[(w>>4) & 0xf]); + 8004d2c: f3c4 1303 ubfx r3, r4, #4, #4 + putchar(hexmap[(w>>0) & 0xf]); + 8004d30: f004 040f and.w r4, r4, #15 + putchar(hexmap[(w>>4) & 0xf]); + 8004d34: 5ce8 ldrb r0, [r5, r3] + 8004d36: f7ff ffbf bl 8004cb8 + putchar(hexmap[(w>>0) & 0xf]); + 8004d3a: 5d28 ldrb r0, [r5, r4] +} + 8004d3c: e8bd 4038 ldmia.w sp!, {r3, r4, r5, lr} + putchar(hexmap[(w>>0) & 0xf]); + 8004d40: f7ff bfba b.w 8004cb8 + 8004d44: 0800e752 .word 0x0800e752 + +08004d48 : +{ + 8004d48: b510 push {r4, lr} + 8004d4a: 4604 mov r4, r0 + puthex4(w >> 16); + 8004d4c: 0c00 lsrs r0, r0, #16 + 8004d4e: f7ff ffe1 bl 8004d14 + puthex4(w & 0xffff); + 8004d52: b2a0 uxth r0, r4 +} + 8004d54: e8bd 4010 ldmia.w sp!, {r4, lr} + puthex4(w & 0xffff); + 8004d58: f7ff bfdc b.w 8004d14 + +08004d5c : +{ + 8004d5c: b5f8 push {r3, r4, r5, r6, r7, lr} + 8004d5e: 4605 mov r5, r0 + 8004d60: 2604 movs r6, #4 + for(int m=1000; m; m /= 10) { + 8004d62: f44f 747a mov.w r4, #1000 ; 0x3e8 + char n = '0' + ((w / m) % 10); + 8004d66: 270a movs r7, #10 + if(w >= m) { + 8004d68: 42a5 cmp r5, r4 + 8004d6a: db09 blt.n 8004d80 + char n = '0' + ((w / m) % 10); + 8004d6c: fb95 f3f4 sdiv r3, r5, r4 + 8004d70: fb93 f0f7 sdiv r0, r3, r7 + 8004d74: fb07 3310 mls r3, r7, r0, r3 + 8004d78: 3330 adds r3, #48 ; 0x30 + putchar(n); + 8004d7a: b2d8 uxtb r0, r3 + 8004d7c: f7ff ff9c bl 8004cb8 + for(int m=1000; m; m /= 10) { + 8004d80: fb94 f4f7 sdiv r4, r4, r7 + 8004d84: 3e01 subs r6, #1 + 8004d86: d1ef bne.n 8004d68 +} + 8004d88: bdf8 pop {r3, r4, r5, r6, r7, pc} + +08004d8a : +{ + 8004d8a: b570 push {r4, r5, r6, lr} + 8004d8c: 4606 mov r6, r0 + 8004d8e: 460d mov r5, r1 + for(int i=0; i +} + 8004d96: e8bd 4070 ldmia.w sp!, {r4, r5, r6, lr} + putchar('\n'); + 8004d9a: 200a movs r0, #10 + 8004d9c: f7ff bf8c b.w 8004cb8 + puthex2(data[i]); + 8004da0: 5d30 ldrb r0, [r6, r4] + 8004da2: f7ff ffa7 bl 8004cf4 + for(int i=0; i + ... + +08004dac : +{ + 8004dac: b513 push {r0, r1, r4, lr} + 8004dae: 9001 str r0, [sp, #4] + int ln = strlen(msg); + 8004db0: f008 fc93 bl 800d6da + 8004db4: 4604 mov r4, r0 + rng_delay(); + 8004db6: f7fd fce1 bl 800277c + if(ln) HAL_USART_Transmit(&con, (uint8_t *)msg, ln, HAL_MAX_DELAY); + 8004dba: 9901 ldr r1, [sp, #4] + 8004dbc: b12c cbz r4, 8004dca + 8004dbe: 4809 ldr r0, [pc, #36] ; (8004de4 ) + 8004dc0: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 8004dc4: b2a2 uxth r2, r4 + 8004dc6: f7ff ff49 bl 8004c5c + HAL_USART_Transmit(&con, (uint8_t *)CRLF, 2, HAL_MAX_DELAY); + 8004dca: 4907 ldr r1, [pc, #28] ; (8004de8 ) + 8004dcc: 4805 ldr r0, [pc, #20] ; (8004de4 ) + 8004dce: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 8004dd2: 2202 movs r2, #2 + 8004dd4: f7ff ff42 bl 8004c5c + rng_delay(); + 8004dd8: f7fd fcd0 bl 800277c +} + 8004ddc: 2001 movs r0, #1 + 8004dde: b002 add sp, #8 + 8004de0: bd10 pop {r4, pc} + 8004de2: bf00 nop + 8004de4: 2009e1c0 .word 0x2009e1c0 + 8004de8: 0800e74f .word 0x0800e74f + +08004dec : + +// psram_send_byte() +// + void +psram_send_byte(OSPI_HandleTypeDef *qh, uint8_t cmd_byte, bool is_quad) +{ + 8004dec: b570 push {r4, r5, r6, lr} + 8004dee: b094 sub sp, #80 ; 0x50 + 8004df0: 4604 mov r4, r0 + 8004df2: 460e mov r6, r1 + 8004df4: 4615 mov r5, r2 + // Send single-byte commands to the PSRAM chip. Quad mode or normal SPI. + + OSPI_RegularCmdTypeDef cmd = { + 8004df6: 2100 movs r1, #0 + 8004df8: 2250 movs r2, #80 ; 0x50 + 8004dfa: 4668 mov r0, sp + 8004dfc: f008 fc3a bl 800d674 + .OperationType = HAL_OSPI_OPTYPE_COMMON_CFG, + .Instruction = cmd_byte, // Exit Quad Mode + .InstructionMode = is_quad ? HAL_OSPI_INSTRUCTION_4_LINES : HAL_OSPI_INSTRUCTION_1_LINE, + 8004e00: 2d00 cmp r5, #0 + 8004e02: bf14 ite ne + 8004e04: 2303 movne r3, #3 + 8004e06: 2301 moveq r3, #1 + .DataMode = HAL_OSPI_DATA_NONE, + .NbData = 0, // how much to read in bytes + }; + + // Start and finish a "Indirection functional mode" request + HAL_OSPI_Command(qh, &cmd, HAL_MAX_DELAY); + 8004e08: f04f 32ff mov.w r2, #4294967295 ; 0xffffffff + 8004e0c: 4669 mov r1, sp + 8004e0e: 4620 mov r0, r4 + OSPI_RegularCmdTypeDef cmd = { + 8004e10: 9602 str r6, [sp, #8] + 8004e12: 9303 str r3, [sp, #12] + HAL_OSPI_Command(qh, &cmd, HAL_MAX_DELAY); + 8004e14: f006 f884 bl 800af20 +} + 8004e18: b014 add sp, #80 ; 0x50 + 8004e1a: bd70 pop {r4, r5, r6, pc} + +08004e1c : + +// psram_setup() +// + void +psram_setup(void) +{ + 8004e1c: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + 8004e20: b0c6 sub sp, #280 ; 0x118 + // Using OSPI1 block + OSPI_HandleTypeDef qh = { 0 }; + 8004e22: 2250 movs r2, #80 ; 0x50 + 8004e24: 2100 movs r1, #0 + 8004e26: a80a add r0, sp, #40 ; 0x28 + 8004e28: f008 fc24 bl 800d674 + + // enable clocks + __HAL_RCC_OSPI1_CLK_ENABLE(); + 8004e2c: 4b6a ldr r3, [pc, #424] ; (8004fd8 ) + // reset module + __HAL_RCC_OSPI1_FORCE_RESET(); + __HAL_RCC_OSPI1_RELEASE_RESET(); + + // configure pins: Port E PE10-PE15 + GPIO_InitTypeDef setup = { + 8004e2e: 4c6b ldr r4, [pc, #428] ; (8004fdc ) + __HAL_RCC_OSPI1_CLK_ENABLE(); + 8004e30: 6d1a ldr r2, [r3, #80] ; 0x50 + 8004e32: f442 7280 orr.w r2, r2, #256 ; 0x100 + 8004e36: 651a str r2, [r3, #80] ; 0x50 + 8004e38: 6d1a ldr r2, [r3, #80] ; 0x50 + 8004e3a: f402 7280 and.w r2, r2, #256 ; 0x100 + 8004e3e: 9201 str r2, [sp, #4] + 8004e40: 9a01 ldr r2, [sp, #4] + __HAL_RCC_GPIOE_CLK_ENABLE(); + 8004e42: 6cda ldr r2, [r3, #76] ; 0x4c + 8004e44: f042 0210 orr.w r2, r2, #16 + 8004e48: 64da str r2, [r3, #76] ; 0x4c + 8004e4a: 6cda ldr r2, [r3, #76] ; 0x4c + 8004e4c: f002 0210 and.w r2, r2, #16 + 8004e50: 9202 str r2, [sp, #8] + 8004e52: 9a02 ldr r2, [sp, #8] + __HAL_RCC_OSPI1_FORCE_RESET(); + 8004e54: 6b1a ldr r2, [r3, #48] ; 0x30 + 8004e56: f442 7280 orr.w r2, r2, #256 ; 0x100 + 8004e5a: 631a str r2, [r3, #48] ; 0x30 + __HAL_RCC_OSPI1_RELEASE_RESET(); + 8004e5c: 6b1a ldr r2, [r3, #48] ; 0x30 + 8004e5e: f422 7280 bic.w r2, r2, #256 ; 0x100 + 8004e62: 631a str r2, [r3, #48] ; 0x30 + GPIO_InitTypeDef setup = { + 8004e64: cc0f ldmia r4!, {r0, r1, r2, r3} + 8004e66: ad05 add r5, sp, #20 + 8004e68: c50f stmia r5!, {r0, r1, r2, r3} + 8004e6a: 6823 ldr r3, [r4, #0] + .Mode = GPIO_MODE_AF_PP, // not sure + .Pull = GPIO_NOPULL, // not sure + .Speed = GPIO_SPEED_FREQ_VERY_HIGH, + .Alternate = GPIO_AF10_OCTOSPIM_P1, + }; + HAL_GPIO_Init(GPIOE, &setup); + 8004e6c: 485c ldr r0, [pc, #368] ; (8004fe0 ) + GPIO_InitTypeDef setup = { + 8004e6e: 602b str r3, [r5, #0] + HAL_GPIO_Init(GPIOE, &setup); + 8004e70: a905 add r1, sp, #20 + 8004e72: f7fc f8cd bl 8001010 + + + // Config operational values + qh.Instance = OCTOSPI1; + qh.Init.FifoThreshold = 1; // ?? unused + 8004e76: 4b5b ldr r3, [pc, #364] ; (8004fe4 ) + 8004e78: 2701 movs r7, #1 + qh.Init.DualQuad = HAL_OSPI_DUALQUAD_DISABLE; + qh.Init.MemoryType = HAL_OSPI_MEMTYPE_MICRON; // want standard mode (but octo only?) + qh.Init.DeviceSize = 24; // assume max size, actual is 8Mbyte + 8004e7a: 2218 movs r2, #24 + qh.Init.FifoThreshold = 1; // ?? unused + 8004e7c: e9cd 370a strd r3, r7, [sp, #40] ; 0x28 + qh.Init.ChipSelectHighTime = 1; // 1, maxed out, seems to work + 8004e80: e9cd 270e strd r2, r7, [sp, #56] ; 0x38 + qh.Init.DualQuad = HAL_OSPI_DUALQUAD_DISABLE; + 8004e84: 2300 movs r3, #0 + qh.Init.DelayHoldQuarterCycle = HAL_OSPI_DHQC_ENABLE; // maybe? + 8004e86: f04f 5280 mov.w r2, #268435456 ; 0x10000000 + qh.Init.FreeRunningClock = HAL_OSPI_FREERUNCLK_DISABLE; // required! + qh.Init.ClockMode = HAL_OSPI_CLOCK_MODE_0; // low clock between ops (required, see errata) +#if HCLK_FREQUENCY == 80000000 + qh.Init.ClockPrescaler = 1; // prescaler (1=>80Mhz, 2=>40Mhz, etc) +#elif HCLK_FREQUENCY == 120000000 + qh.Init.ClockPrescaler = 2; // prescaler (1=>120Mhz, 2=>60Mhz, etc) + 8004e8a: f04f 0802 mov.w r8, #2 +#else +# error "testing needed" +#endif + qh.Init.DelayBlockBypass = HAL_OSPI_DELAY_BLOCK_BYPASSED; // dont need it? + 8004e8e: f04f 0908 mov.w r9, #8 + // - (during reads) 3 => 400ns 4 => 660ns 5+ => 1us + // - LATER: Errata 2.8.1 => says shall not use + qh.Init.ChipSelectBoundary = 0; + + // module init + HAL_StatusTypeDef rv = HAL_OSPI_Init(&qh); + 8004e92: a80a add r0, sp, #40 ; 0x28 + qh.Init.MemoryType = HAL_OSPI_MEMTYPE_MICRON; // want standard mode (but octo only?) + 8004e94: e9cd 330c strd r3, r3, [sp, #48] ; 0x30 + qh.Init.ClockMode = HAL_OSPI_CLOCK_MODE_0; // low clock between ops (required, see errata) + 8004e98: e9cd 3310 strd r3, r3, [sp, #64] ; 0x40 + qh.Init.ChipSelectBoundary = 0; + 8004e9c: e9cd 3915 strd r3, r9, [sp, #84] ; 0x54 + qh.Init.DelayHoldQuarterCycle = HAL_OSPI_DHQC_ENABLE; // maybe? + 8004ea0: 9214 str r2, [sp, #80] ; 0x50 + qh.Init.ClockPrescaler = 2; // prescaler (1=>120Mhz, 2=>60Mhz, etc) + 8004ea2: f8cd 8048 str.w r8, [sp, #72] ; 0x48 + HAL_StatusTypeDef rv = HAL_OSPI_Init(&qh); + 8004ea6: f005 ffd1 bl 800ae4c + ASSERT(rv == HAL_OK); + 8004eaa: 4606 mov r6, r0 + 8004eac: b110 cbz r0, 8004eb4 + 8004eae: 484e ldr r0, [pc, #312] ; (8004fe8 ) + 8004eb0: f7fb fdca bl 8000a48 + + // do some SPI commands first + + // Exit Quad mode, to get to a known state, after first power-up + psram_send_byte(&qh, 0xf5, true); + 8004eb4: 463a mov r2, r7 + 8004eb6: 21f5 movs r1, #245 ; 0xf5 + 8004eb8: a80a add r0, sp, #40 ; 0x28 + 8004eba: f7ff ff97 bl 8004dec + + // Chip Reset sequence + psram_send_byte(&qh, 0x66, false); // reset enable + 8004ebe: 4632 mov r2, r6 + 8004ec0: 2166 movs r1, #102 ; 0x66 + 8004ec2: a80a add r0, sp, #40 ; 0x28 + 8004ec4: f7ff ff92 bl 8004dec + + // Read Electronic ID + // - length not clear from datasheet, but repeats after 8 bytes + uint8_t psram_chip_eid[8]; + + { OSPI_RegularCmdTypeDef cmd = { + 8004ec8: ad32 add r5, sp, #200 ; 0xc8 + psram_send_byte(&qh, 0x99, false); // reset + 8004eca: 4632 mov r2, r6 + 8004ecc: 2199 movs r1, #153 ; 0x99 + 8004ece: a80a add r0, sp, #40 ; 0x28 + 8004ed0: f7ff ff8c bl 8004dec + { OSPI_RegularCmdTypeDef cmd = { + 8004ed4: 2250 movs r2, #80 ; 0x50 + 8004ed6: 4631 mov r1, r6 + 8004ed8: 4628 mov r0, r5 + 8004eda: f008 fbcb bl 800d674 + 8004ede: 239f movs r3, #159 ; 0x9f + 8004ee0: e9cd 3734 strd r3, r7, [sp, #208] ; 0xd0 + 8004ee4: f44f 5a00 mov.w sl, #8192 ; 0x2000 + 8004ee8: f44f 7380 mov.w r3, #256 ; 0x100 + 8004eec: e9cd 3a39 strd r3, sl, [sp, #228] ; 0xe4 + .DataMode = HAL_OSPI_DATA_1_LINE, + .NbData = sizeof(psram_chip_eid), // how much to read in bytes + }; + + // Start a "Indirection functional mode" request + rv = HAL_OSPI_Command(&qh, &cmd, HAL_MAX_DELAY); + 8004ef0: f04f 32ff mov.w r2, #4294967295 ; 0xffffffff + { OSPI_RegularCmdTypeDef cmd = { + 8004ef4: f04f 7380 mov.w r3, #16777216 ; 0x1000000 + rv = HAL_OSPI_Command(&qh, &cmd, HAL_MAX_DELAY); + 8004ef8: 4629 mov r1, r5 + 8004efa: a80a add r0, sp, #40 ; 0x28 + { OSPI_RegularCmdTypeDef cmd = { + 8004efc: e9cd 3940 strd r3, r9, [sp, #256] ; 0x100 + rv = HAL_OSPI_Command(&qh, &cmd, HAL_MAX_DELAY); + 8004f00: f006 f80e bl 800af20 + if(rv != HAL_OK) goto fail; + 8004f04: 2800 cmp r0, #0 + 8004f06: d15d bne.n 8004fc4 + + rv = HAL_OSPI_Receive(&qh, psram_chip_eid, HAL_MAX_DELAY); + 8004f08: f04f 32ff mov.w r2, #4294967295 ; 0xffffffff + 8004f0c: a903 add r1, sp, #12 + 8004f0e: a80a add r0, sp, #40 ; 0x28 + 8004f10: f006 f938 bl 800b184 + if(rv != HAL_OK) goto fail; + 8004f14: 4606 mov r6, r0 + 8004f16: 2800 cmp r0, #0 + 8004f18: d154 bne.n 8004fc4 + } + + //puts2("PSRAM EID: "); + //hex_dump(psram_chip_eid, sizeof(psram_chip_eid)); + ASSERT(psram_chip_eid[0] == 0x0d); + 8004f1a: f89d 300c ldrb.w r3, [sp, #12] + 8004f1e: 2b0d cmp r3, #13 + 8004f20: d1c5 bne.n 8004eae + ASSERT(psram_chip_eid[1] == 0x5d); + 8004f22: f89d 300d ldrb.w r3, [sp, #13] + 8004f26: 2b5d cmp r3, #93 ; 0x5d + 8004f28: d1c1 bne.n 8004eae + // .. other bits seem pretty similar between devices, they don't claim they are UUID + + // Put into Quad mode + psram_send_byte(&qh, 0x35, false); // 0x35 = Enter Quad Mode + 8004f2a: 4602 mov r2, r0 + 8004f2c: 2135 movs r1, #53 ; 0x35 + 8004f2e: a80a add r0, sp, #40 ; 0x28 + 8004f30: f7ff ff5c bl 8004dec + + // Configure read/write cycles for mem-mapped mode + { OSPI_RegularCmdTypeDef cmd = { + 8004f34: 4631 mov r1, r6 + 8004f36: 224c movs r2, #76 ; 0x4c + 8004f38: a81f add r0, sp, #124 ; 0x7c + 8004f3a: f008 fb9b bl 800d674 + 8004f3e: f04f 0903 mov.w r9, #3 + 8004f42: f8cd 8078 str.w r8, [sp, #120] ; 0x78 + 8004f46: f8cd 8080 str.w r8, [sp, #128] ; 0x80 + .DataMode = HAL_OSPI_DATA_4_LINES, + .NbData = 0, // don't care / TBD? + }; + + // Config for write + rv = HAL_OSPI_Command(&qh, &cmd, HAL_MAX_DELAY); + 8004f4a: a91e add r1, sp, #120 ; 0x78 + { OSPI_RegularCmdTypeDef cmd = { + 8004f4c: f44f 7840 mov.w r8, #768 ; 0x300 + 8004f50: f04f 7640 mov.w r6, #50331648 ; 0x3000000 + rv = HAL_OSPI_Command(&qh, &cmd, HAL_MAX_DELAY); + 8004f54: f04f 32ff mov.w r2, #4294967295 ; 0xffffffff + 8004f58: a80a add r0, sp, #40 ; 0x28 + { OSPI_RegularCmdTypeDef cmd = { + 8004f5a: e9cd 8a25 strd r8, sl, [sp, #148] ; 0x94 + 8004f5e: f8cd 9084 str.w r9, [sp, #132] ; 0x84 + 8004f62: 962c str r6, [sp, #176] ; 0xb0 + rv = HAL_OSPI_Command(&qh, &cmd, HAL_MAX_DELAY); + 8004f64: f005 ffdc bl 800af20 + if(rv != HAL_OK) goto fail; + 8004f68: 4601 mov r1, r0 + 8004f6a: bb58 cbnz r0, 8004fc4 + + // .. for read + OSPI_RegularCmdTypeDef cmd2 = { + 8004f6c: 224c movs r2, #76 ; 0x4c + 8004f6e: a833 add r0, sp, #204 ; 0xcc + 8004f70: f008 fb80 bl 800d674 + 8004f74: 23eb movs r3, #235 ; 0xeb + 8004f76: e9cd 3934 strd r3, r9, [sp, #208] ; 0xd0 + .DataMode = HAL_OSPI_DATA_4_LINES, + .NbData = 0, // don't care / TBD? + }; + + // Config for read + rv = HAL_OSPI_Command(&qh, &cmd2, HAL_MAX_DELAY); + 8004f7a: f04f 32ff mov.w r2, #4294967295 ; 0xffffffff + OSPI_RegularCmdTypeDef cmd2 = { + 8004f7e: 2306 movs r3, #6 + rv = HAL_OSPI_Command(&qh, &cmd2, HAL_MAX_DELAY); + 8004f80: 4629 mov r1, r5 + 8004f82: a80a add r0, sp, #40 ; 0x28 + OSPI_RegularCmdTypeDef cmd2 = { + 8004f84: e9cd 8a39 strd r8, sl, [sp, #228] ; 0xe4 + 8004f88: 9732 str r7, [sp, #200] ; 0xc8 + 8004f8a: 9640 str r6, [sp, #256] ; 0x100 + 8004f8c: 9343 str r3, [sp, #268] ; 0x10c + rv = HAL_OSPI_Command(&qh, &cmd2, HAL_MAX_DELAY); + 8004f8e: f005 ffc7 bl 800af20 + if(rv != HAL_OK) goto fail; + 8004f92: b9b8 cbnz r0, 8004fc4 + } + + // config for memmap + { OSPI_MemoryMappedTypeDef mmap = { + 8004f94: e9d4 0101 ldrd r0, r1, [r4, #4] + 8004f98: e885 0003 stmia.w r5, {r0, r1} + // Need this so that CS lines returns to inactive sometimes. + .TimeOutActivation = HAL_OSPI_TIMEOUT_COUNTER_ENABLE, + .TimeOutPeriod = 16, // no idea, max value 0xffff + }; + + rv = HAL_OSPI_MemoryMapped(&qh, &mmap); + 8004f9c: 4629 mov r1, r5 + 8004f9e: a80a add r0, sp, #40 ; 0x28 + 8004fa0: f006 f9d6 bl 800b350 + if(rv != HAL_OK) goto fail; + 8004fa4: b970 cbnz r0, 8004fc4 +#else + // Only a quick operational check only here. Non-destructive. + { __IO uint32_t *ptr = (uint32_t *)(PSRAM_BASE+PSRAM_SIZE-4); + uint32_t tmp; + + tmp = *ptr; + 8004fa6: 4b11 ldr r3, [pc, #68] ; (8004fec ) + *ptr = 0x55aa1234; + 8004fa8: 4a11 ldr r2, [pc, #68] ; (8004ff0 ) + tmp = *ptr; + 8004faa: f8d3 1ffc ldr.w r1, [r3, #4092] ; 0xffc + *ptr = 0x55aa1234; + 8004fae: f8c3 2ffc str.w r2, [r3, #4092] ; 0xffc + if(*ptr != 0x55aa1234) goto fail; + 8004fb2: f8d3 0ffc ldr.w r0, [r3, #4092] ; 0xffc + 8004fb6: 4290 cmp r0, r2 + 8004fb8: d104 bne.n 8004fc4 + *ptr = tmp; + 8004fba: f8c3 1ffc str.w r1, [r3, #4092] ; 0xffc + + oled_setup(); + oled_show(screen_fatal); + + LOCKUP_FOREVER(); +} + 8004fbe: b046 add sp, #280 ; 0x118 + 8004fc0: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + puts("PSRAM fail"); + 8004fc4: 480b ldr r0, [pc, #44] ; (8004ff4 ) + 8004fc6: f7ff fef1 bl 8004dac + oled_setup(); + 8004fca: f7fb feab bl 8000d24 + oled_show(screen_fatal); + 8004fce: 480a ldr r0, [pc, #40] ; (8004ff8 ) + 8004fd0: f7fb ff38 bl 8000e44 + LOCKUP_FOREVER(); + 8004fd4: bf30 wfi + 8004fd6: e7fd b.n 8004fd4 + 8004fd8: 40021000 .word 0x40021000 + 8004fdc: 0800e790 .word 0x0800e790 + 8004fe0: 48001000 .word 0x48001000 + 8004fe4: a0001000 .word 0xa0001000 + 8004fe8: 0800e3e0 .word 0x0800e3e0 + 8004fec: 907ff000 .word 0x907ff000 + 8004ff0: 55aa1234 .word 0x55aa1234 + 8004ff4: 0800e762 .word 0x0800e762 + 8004ff8: 0800db52 .word 0x0800db52 + +08004ffc : + +// psram_wipe() +// + void +psram_wipe(void) +{ + 8004ffc: b508 push {r3, lr} + if(OCTOSPI1->CR == 0) return; // PSRAM not enabled (yet?) + 8004ffe: 4b06 ldr r3, [pc, #24] ; (8005018 ) + 8005000: 681b ldr r3, [r3, #0] + 8005002: b143 cbz r3, 8005016 + + // Fast! But real; maybe 150ms + //puts2("PSRAM Wipe: "); + memset4((uint32_t *)PSRAM_BASE, rng_sample(), PSRAM_SIZE); + 8005004: f7fd fb66 bl 80026d4 + 8005008: f04f 4310 mov.w r3, #2415919104 ; 0x90000000 + *dest = value; + 800500c: f843 0b04 str.w r0, [r3], #4 + for(; byte_len; byte_len-=4, dest++) { + 8005010: f113 4fdf cmn.w r3, #1870659584 ; 0x6f800000 + 8005014: d1fa bne.n 800500c + //puts("done"); +} + 8005016: bd08 pop {r3, pc} + 8005018: a0001000 .word 0xa0001000 + +0800501c : +// NOTE: Incoming start address is typically not aligned. +// + void +psram_do_upgrade(const uint8_t *start, uint32_t size) +{ + ASSERT(size >= FW_MIN_LENGTH); + 800501c: f5b1 2f80 cmp.w r1, #262144 ; 0x40000 +{ + 8005020: e92d 43f7 stmdb sp!, {r0, r1, r2, r4, r5, r6, r7, r8, r9, lr} + 8005024: 4606 mov r6, r0 + 8005026: 460d mov r5, r1 + ASSERT(size >= FW_MIN_LENGTH); + 8005028: d202 bcs.n 8005030 + 800502a: 481e ldr r0, [pc, #120] ; (80050a4 ) + 800502c: f7fb fd0c bl 8000a48 + + // In case of reset/crash, we can recover, so save + // what we need for that -- yes, we will re-verify signatures + volatile recovery_header_t *h = RECHDR_POS; + h->start = start; + 8005030: 4b1d ldr r3, [pc, #116] ; (80050a8 ) + h->size = size; + h->magic1 = RECHDR_MAGIC1; + 8005032: 4a1e ldr r2, [pc, #120] ; (80050ac ) + h->start = start; + 8005034: 6058 str r0, [r3, #4] + h->size = size; + 8005036: 6099 str r1, [r3, #8] + h->magic1 = RECHDR_MAGIC1; + 8005038: 601a str r2, [r3, #0] + h->magic2 = RECHDR_MAGIC2; + 800503a: 4a1d ldr r2, [pc, #116] ; (80050b0 ) + 800503c: 60da str r2, [r3, #12] + + flash_setup0(); + 800503e: f7fc ffc3 bl 8001fc8 + flash_unlock(); + 8005042: f7fc ffe5 bl 8002010 + for(uint32_t pos=0; pos < size; pos += 8) { + uint32_t dest = FIRMWARE_START+pos; + + if(dest % (4*FLASH_ERASE_SIZE) == 0) { + // show some progress + oled_show_progress(screen_upgrading, pos*100/size); + 8005046: f8df 906c ldr.w r9, [pc, #108] ; 80050b4 + for(uint32_t pos=0; pos < size; pos += 8) { + 800504a: 2400 movs r4, #0 + oled_show_progress(screen_upgrading, pos*100/size); + 800504c: f04f 0864 mov.w r8, #100 ; 0x64 + uint32_t dest = FIRMWARE_START+pos; + 8005050: f104 6700 add.w r7, r4, #134217728 ; 0x8000000 + if(dest % (4*FLASH_ERASE_SIZE) == 0) { + 8005054: f3c4 030d ubfx r3, r4, #0, #14 + 8005058: f507 3700 add.w r7, r7, #131072 ; 0x20000 + 800505c: b933 cbnz r3, 800506c + oled_show_progress(screen_upgrading, pos*100/size); + 800505e: fb08 f104 mul.w r1, r8, r4 + 8005062: 4648 mov r0, r9 + 8005064: fbb1 f1f5 udiv r1, r1, r5 + 8005068: f7fb ff2e bl 8000ec8 + } + + if(dest % FLASH_ERASE_SIZE == 0) { + 800506c: f3c7 030b ubfx r3, r7, #0, #12 + 8005070: b923 cbnz r3, 800507c + // page erase as we go + rv = flash_page_erase(dest); + 8005072: 4638 mov r0, r7 + 8005074: f008 fb40 bl 800d6f8 <__flash_page_erase_veneer> + puts2("erase rv="); + puthex2(rv); + putchar('\n'); + } +#endif + ASSERT(rv == 0); + 8005078: 2800 cmp r0, #0 + 800507a: d1d6 bne.n 800502a + } + + memcpy(&tmp, start+pos, 8); + 800507c: 1932 adds r2, r6, r4 + 800507e: 5930 ldr r0, [r6, r4] + 8005080: 6851 ldr r1, [r2, #4] + 8005082: 466b mov r3, sp + 8005084: c303 stmia r3!, {r0, r1} + rv = flash_burn(dest, tmp); + 8005086: 4638 mov r0, r7 + 8005088: e9dd 2300 ldrd r2, r3, [sp] + 800508c: f008 fb30 bl 800d6f0 <__flash_burn_veneer> + puts2(" addr="); + puthex8(dest); + putchar('\n'); + } +#endif + ASSERT(rv == 0); + 8005090: 2800 cmp r0, #0 + 8005092: d1ca bne.n 800502a + for(uint32_t pos=0; pos < size; pos += 8) { + 8005094: 3408 adds r4, #8 + 8005096: 42a5 cmp r5, r4 + 8005098: d8da bhi.n 8005050 + } + + flash_lock(); +} + 800509a: b003 add sp, #12 + 800509c: e8bd 43f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, lr} + flash_lock(); + 80050a0: f7fc bfae b.w 8002000 + 80050a4: 0800e3e0 .word 0x0800e3e0 + 80050a8: 907ff800 .word 0x907ff800 + 80050ac: dbcc8350 .word 0xdbcc8350 + 80050b0: bafcfba3 .word 0xbafcfba3 + 80050b4: 0800e18b .word 0x0800e18b + +080050b8 : +{ + 80050b8: b510 push {r4, lr} + if( (h->magic1 != RECHDR_MAGIC1) + 80050ba: 4c1f ldr r4, [pc, #124] ; (8005138 ) + 80050bc: 4b1f ldr r3, [pc, #124] ; (800513c ) + 80050be: 6822 ldr r2, [r4, #0] + 80050c0: 429a cmp r2, r3 +{ + 80050c2: b088 sub sp, #32 + if( (h->magic1 != RECHDR_MAGIC1) + 80050c4: d113 bne.n 80050ee + || (h->magic2 != RECHDR_MAGIC2) + 80050c6: 68e2 ldr r2, [r4, #12] + 80050c8: 4b1d ldr r3, [pc, #116] ; (8005140 ) + 80050ca: 429a cmp r2, r3 + 80050cc: d10f bne.n 80050ee + || ((uint32_t)h->start < PSRAM_BASE) + 80050ce: 6863 ldr r3, [r4, #4] + 80050d0: f1b3 4f10 cmp.w r3, #2415919104 ; 0x90000000 + 80050d4: d30b bcc.n 80050ee + || ((uint32_t)h->start >= PSRAM_BASE+(PSRAM_SIZE/2)) + 80050d6: 6862 ldr r2, [r4, #4] + 80050d8: 4b1a ldr r3, [pc, #104] ; (8005144 ) + 80050da: 429a cmp r2, r3 + 80050dc: d807 bhi.n 80050ee + || (h->size > FW_MAX_LENGTH_MK4) + 80050de: 68a3 ldr r3, [r4, #8] + 80050e0: f5b3 1ff0 cmp.w r3, #1966080 ; 0x1e0000 + 80050e4: d803 bhi.n 80050ee + || (h->size < FW_MIN_LENGTH) + 80050e6: 68a3 ldr r3, [r4, #8] + 80050e8: f5b3 2f80 cmp.w r3, #262144 ; 0x40000 + 80050ec: d205 bcs.n 80050fa + puts("PSR: nada"); + 80050ee: 4816 ldr r0, [pc, #88] ; (8005148 ) + puts("PSR: version"); + 80050f0: f7ff fe5c bl 8004dac +} + 80050f4: 2000 movs r0, #0 + 80050f6: b008 add sp, #32 + 80050f8: bd10 pop {r4, pc} + bool ok = verify_firmware_in_ram(h->start, h->size, world_check); + 80050fa: 6860 ldr r0, [r4, #4] + 80050fc: 68a1 ldr r1, [r4, #8] + 80050fe: 466a mov r2, sp + 8005100: f7fc fda8 bl 8001c54 + if(!ok) { + 8005104: b908 cbnz r0, 800510a + puts("PSR: !check"); + 8005106: 4811 ldr r0, [pc, #68] ; (800514c ) + 8005108: e7f2 b.n 80050f0 + if(!verify_world_checksum(world_check)) { + 800510a: 4668 mov r0, sp + 800510c: f7fc fdf6 bl 8001cfc + 8005110: b908 cbnz r0, 8005116 + puts("PSR: version"); + 8005112: 480f ldr r0, [pc, #60] ; (8005150 ) + 8005114: e7ec b.n 80050f0 + psram_do_upgrade(h->start, h->size); + 8005116: 6860 ldr r0, [r4, #4] + 8005118: 68a1 ldr r1, [r4, #8] + 800511a: f7ff ff7f bl 800501c + 800511e: f3bf 8f4f dsb sy + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 8005122: 490c ldr r1, [pc, #48] ; (8005154 ) + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 8005124: 4b0c ldr r3, [pc, #48] ; (8005158 ) + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 8005126: 68ca ldr r2, [r1, #12] + 8005128: f402 62e0 and.w r2, r2, #1792 ; 0x700 + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 800512c: 4313 orrs r3, r2 + 800512e: 60cb str r3, [r1, #12] + 8005130: f3bf 8f4f dsb sy + __NOP(); + 8005134: bf00 nop + for(;;) /* wait until reset */ + 8005136: e7fd b.n 8005134 + 8005138: 907ff800 .word 0x907ff800 + 800513c: dbcc8350 .word 0xdbcc8350 + 8005140: bafcfba3 .word 0xbafcfba3 + 8005144: 903fffff .word 0x903fffff + 8005148: 0800e76d .word 0x0800e76d + 800514c: 0800e777 .word 0x0800e777 + 8005150: 0800e783 .word 0x0800e783 + 8005154: e000ed00 .word 0xe000ed00 + 8005158: 05fa0004 .word 0x05fa0004 + +0800515c : + +// sdcard_light() +// + void inline +sdcard_light(bool on) +{ + 800515c: 4602 mov r2, r0 + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, !!on); // turn LED off + 800515e: 2180 movs r1, #128 ; 0x80 + 8005160: 4801 ldr r0, [pc, #4] ; (8005168 ) + 8005162: f7fc b8cf b.w 8001304 + 8005166: bf00 nop + 8005168: 48000800 .word 0x48000800 + +0800516c : + +// sdcard_is_inserted() +// + bool +sdcard_is_inserted(void) +{ + 800516c: b508 push {r3, lr} +#ifdef FOR_Q1_ONLY + return !HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_3); // PD3 - inserted when low (Q) +#else + return !!HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13); // PC13 - inserted when high (Mk4) + 800516e: f44f 5100 mov.w r1, #8192 ; 0x2000 + 8005172: 4803 ldr r0, [pc, #12] ; (8005180 ) + 8005174: f7fc f8c0 bl 80012f8 +#endif +} + 8005178: 3800 subs r0, #0 + 800517a: bf18 it ne + 800517c: 2001 movne r0, #1 + 800517e: bd08 pop {r3, pc} + 8005180: 48000800 .word 0x48000800 + +08005184 : + +// sdcard_try_file() +// + void +sdcard_try_file(uint32_t blk_pos) +{ + 8005184: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + 8005188: 4606 mov r6, r0 + 800518a: f5ad 7d0a sub.w sp, sp, #552 ; 0x228 + oled_show(screen_verify); + 800518e: 4832 ldr r0, [pc, #200] ; (8005258 ) + uint8_t *ps = (uint8_t *)PSRAM_BASE; + //uint8_t buf[512*8]; // half of all our SRAM 0x00002000 + uint8_t buf[512]; // slower, but works. + + for(uint32_t off = 0; off < FW_MAX_LENGTH_MK4; off += sizeof(buf)) { + int rv = HAL_SD_ReadBlocks(&hsd, buf, blk_pos+(off/512), sizeof(buf)/512, 60000); + 8005190: f8df 80e4 ldr.w r8, [pc, #228] ; 8005278 + oled_show(screen_verify); + 8005194: f7fb fe56 bl 8000e44 + for(uint32_t off = 0; off < FW_MAX_LENGTH_MK4; off += sizeof(buf)) { + 8005198: 2500 movs r5, #0 + int rv = HAL_SD_ReadBlocks(&hsd, buf, blk_pos+(off/512), sizeof(buf)/512, 60000); + 800519a: f64e 2760 movw r7, #60000 ; 0xea60 + 800519e: 9700 str r7, [sp, #0] + 80051a0: 2301 movs r3, #1 + 80051a2: eb06 2255 add.w r2, r6, r5, lsr #9 + 80051a6: a90a add r1, sp, #40 ; 0x28 + 80051a8: 4640 mov r0, r8 + 80051aa: f006 fe4d bl 800be48 + if(rv != HAL_OK) { + 80051ae: 4604 mov r4, r0 + 80051b0: b130 cbz r0, 80051c0 + puts("long read fail"); + 80051b2: 482a ldr r0, [pc, #168] ; (800525c ) + + // Check we have the **right** firmware, based on the world check sum + // but don't set the light at this point. + // - this includes check over bootrom (ourselves) + if(!verify_world_checksum(world_check)) { + puts("wrong world"); + 80051b4: f7ff fdfa bl 8004dac + // Do the upgrade, using PSRAM data. + psram_do_upgrade(start, len); + + // done + NVIC_SystemReset(); +} + 80051b8: f50d 7d0a add.w sp, sp, #552 ; 0x228 + 80051bc: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + memcpy(ps + off, buf, sizeof(buf)); + 80051c0: f105 4010 add.w r0, r5, #2415919104 ; 0x90000000 + 80051c4: f44f 7200 mov.w r2, #512 ; 0x200 + 80051c8: a90a add r1, sp, #40 ; 0x28 + for(uint32_t off = 0; off < FW_MAX_LENGTH_MK4; off += sizeof(buf)) { + 80051ca: f505 7500 add.w r5, r5, #512 ; 0x200 + memcpy(ps + off, buf, sizeof(buf)); + 80051ce: f008 fa29 bl 800d624 + for(uint32_t off = 0; off < FW_MAX_LENGTH_MK4; off += sizeof(buf)) { + 80051d2: f5b5 1ff0 cmp.w r5, #1966080 ; 0x1e0000 + 80051d6: d1e2 bne.n 800519e + for(int idx=0; idxtargets; idx++) { + 80051d8: f04f 4310 mov.w r3, #2415919104 ; 0x90000000 + if(elem->addr == FIRMWARE_START) { + 80051dc: 4d20 ldr r5, [pc, #128] ; (8005260 ) + for(int idx=0; idxtargets; idx++) { + 80051de: 7a99 ldrb r1, [r3, #10] + 80051e0: 4620 mov r0, r4 + ptr += sizeof(DFUFile_t); + 80051e2: 330b adds r3, #11 + for(int idx=0; idxtargets; idx++) { + 80051e4: 4288 cmp r0, r1 + 80051e6: db01 blt.n 80051ec + puts("DFU parse fail"); + 80051e8: 481e ldr r0, [pc, #120] ; (8005264 ) + 80051ea: e7e3 b.n 80051b4 + for(int ei=0; eielements; ei++) { + 80051ec: f8d3 610e ldr.w r6, [r3, #270] ; 0x10e + 80051f0: 2200 movs r2, #0 + ptr += sizeof(DFUTarget_t); + 80051f2: f503 7389 add.w r3, r3, #274 ; 0x112 + for(int ei=0; eielements; ei++) { + 80051f6: 42b2 cmp r2, r6 + 80051f8: d101 bne.n 80051fe + for(int idx=0; idxtargets; idx++) { + 80051fa: 3001 adds r0, #1 + 80051fc: e7f2 b.n 80051e4 + ptr += sizeof(DFUElement_t); + 80051fe: 461c mov r4, r3 + if(elem->addr == FIRMWARE_START) { + 8005200: f854 7b08 ldr.w r7, [r4], #8 + 8005204: 42af cmp r7, r5 + 8005206: d110 bne.n 800522a + *target_size = elem->size; + 8005208: 685d ldr r5, [r3, #4] + bool ok = verify_firmware_in_ram(start, len, world_check); + 800520a: aa02 add r2, sp, #8 + 800520c: 4629 mov r1, r5 + 800520e: 4620 mov r0, r4 + 8005210: f7fc fd20 bl 8001c54 + if(!ok) return; + 8005214: 2800 cmp r0, #0 + 8005216: d0cf beq.n 80051b8 + puts("good firmware"); + 8005218: 4813 ldr r0, [pc, #76] ; (8005268 ) + 800521a: f7ff fdc7 bl 8004dac + if(!verify_world_checksum(world_check)) { + 800521e: a802 add r0, sp, #8 + 8005220: f7fc fd6c bl 8001cfc + 8005224: b920 cbnz r0, 8005230 + puts("wrong world"); + 8005226: 4811 ldr r0, [pc, #68] ; (800526c ) + 8005228: e7c4 b.n 80051b4 + for(int ei=0; eielements; ei++) { + 800522a: 3201 adds r2, #1 + ptr += sizeof(DFUElement_t); + 800522c: 4623 mov r3, r4 + 800522e: e7e2 b.n 80051f6 + sdcard_light(false); + 8005230: 2000 movs r0, #0 + 8005232: f7ff ff93 bl 800515c + psram_do_upgrade(start, len); + 8005236: 4629 mov r1, r5 + 8005238: 4620 mov r0, r4 + 800523a: f7ff feef bl 800501c + 800523e: f3bf 8f4f dsb sy + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 8005242: 490b ldr r1, [pc, #44] ; (8005270 ) + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 8005244: 4b0b ldr r3, [pc, #44] ; (8005274 ) + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 8005246: 68ca ldr r2, [r1, #12] + 8005248: f402 62e0 and.w r2, r2, #1792 ; 0x700 + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 800524c: 4313 orrs r3, r2 + 800524e: 60cb str r3, [r1, #12] + 8005250: f3bf 8f4f dsb sy + __NOP(); + 8005254: bf00 nop + for(;;) /* wait until reset */ + 8005256: e7fd b.n 8005254 + 8005258: 0800e242 .word 0x0800e242 + 800525c: 0800e7ac .word 0x0800e7ac + 8005260: 08020000 .word 0x08020000 + 8005264: 0800e7bb .word 0x0800e7bb + 8005268: 0800e7ca .word 0x0800e7ca + 800526c: 0800e7d8 .word 0x0800e7d8 + 8005270: e000ed00 .word 0xe000ed00 + 8005274: 05fa0004 .word 0x05fa0004 + 8005278: 2009e220 .word 0x2009e220 + +0800527c : + +// sdcard_search() +// + void +sdcard_search(void) +{ + 800527c: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + oled_show(screen_search); + 8005280: 4854 ldr r0, [pc, #336] ; (80053d4 ) +{ + 8005282: f5ad 7d04 sub.w sp, sp, #528 ; 0x210 + oled_show(screen_search); + 8005286: f7fb fddd bl 8000e44 + + if(!sdcard_is_inserted()) return; + 800528a: f7ff ff6f bl 800516c + 800528e: 2800 cmp r0, #0 + 8005290: d07a beq.n 8005388 + __HAL_RCC_SDMMC1_CLK_ENABLE(); + 8005292: 4f51 ldr r7, [pc, #324] ; (80053d8 ) + + uint32_t num_blocks; + + // open card (power it) and get details, do setup + puts2("sdcard_search: "); + 8005294: 4851 ldr r0, [pc, #324] ; (80053dc ) + { GPIO_InitTypeDef setup = { + 8005296: 4c52 ldr r4, [pc, #328] ; (80053e0 ) + puts2("sdcard_search: "); + 8005298: f7ff fcfa bl 8004c90 + __HAL_RCC_SDMMC1_CLK_ENABLE(); + 800529c: 6cfb ldr r3, [r7, #76] ; 0x4c + 800529e: f443 0380 orr.w r3, r3, #4194304 ; 0x400000 + 80052a2: 64fb str r3, [r7, #76] ; 0x4c + 80052a4: 6cfb ldr r3, [r7, #76] ; 0x4c + 80052a6: f403 0380 and.w r3, r3, #4194304 ; 0x400000 + 80052aa: 9303 str r3, [sp, #12] + 80052ac: 9b03 ldr r3, [sp, #12] + { GPIO_InitTypeDef setup = { + 80052ae: cc0f ldmia r4!, {r0, r1, r2, r3} + 80052b0: ad04 add r5, sp, #16 + 80052b2: c50f stmia r5!, {r0, r1, r2, r3} + 80052b4: f854 3b04 ldr.w r3, [r4], #4 + 80052b8: 602b str r3, [r5, #0] + HAL_GPIO_Init(GPIOC, &setup); + 80052ba: 484a ldr r0, [pc, #296] ; (80053e4 ) + 80052bc: a904 add r1, sp, #16 + 80052be: f7fb fea7 bl 8001010 + { GPIO_InitTypeDef setup = { + 80052c2: cc0f ldmia r4!, {r0, r1, r2, r3} + 80052c4: ae04 add r6, sp, #16 + 80052c6: c60f stmia r6!, {r0, r1, r2, r3} + 80052c8: 6823 ldr r3, [r4, #0] + 80052ca: 602b str r3, [r5, #0] + HAL_GPIO_Init(GPIOD, &setup); + 80052cc: a904 add r1, sp, #16 + 80052ce: 4846 ldr r0, [pc, #280] ; (80053e8 ) + memset(&hsd, 0, sizeof(SD_HandleTypeDef)); + 80052d0: 4d46 ldr r5, [pc, #280] ; (80053ec ) + HAL_GPIO_Init(GPIOD, &setup); + 80052d2: f7fb fe9d bl 8001010 + __HAL_RCC_SDMMC1_FORCE_RESET(); + 80052d6: 6afb ldr r3, [r7, #44] ; 0x2c + 80052d8: f443 0380 orr.w r3, r3, #4194304 ; 0x400000 + 80052dc: 62fb str r3, [r7, #44] ; 0x2c + __HAL_RCC_SDMMC1_RELEASE_RESET(); + 80052de: 6afb ldr r3, [r7, #44] ; 0x2c + 80052e0: f423 0380 bic.w r3, r3, #4194304 ; 0x400000 + 80052e4: 62fb str r3, [r7, #44] ; 0x2c + sdcard_setup(); + delay_ms(100); + 80052e6: 2064 movs r0, #100 ; 0x64 + 80052e8: f7fe fb06 bl 80038f8 + memset(&hsd, 0, sizeof(SD_HandleTypeDef)); + 80052ec: 2280 movs r2, #128 ; 0x80 + 80052ee: 2100 movs r1, #0 + 80052f0: 4628 mov r0, r5 + 80052f2: f008 f9bf bl 800d674 + puts2("sdcard_probe: "); + 80052f6: 483e ldr r0, [pc, #248] ; (80053f0 ) + 80052f8: f7ff fcca bl 8004c90 + hsd.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING; + 80052fc: 4a3d ldr r2, [pc, #244] ; (80053f4 ) + 80052fe: 2300 movs r3, #0 + 8005300: e9c5 2300 strd r2, r3, [r5] + hsd.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_ENABLE; + 8005304: f44f 5280 mov.w r2, #4096 ; 0x1000 + hsd.Init.BusWide = SDMMC_BUS_WIDE_1B; + 8005308: e9c5 2302 strd r2, r3, [r5, #8] + hsd.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; + 800530c: 612b str r3, [r5, #16] + int rv = HAL_SD_Init(&hsd); + 800530e: 4628 mov r0, r5 + hsd.Init.ClockDiv = SDMMC_TRANSFER_CLK_DIV; + 8005310: 2303 movs r3, #3 + 8005312: 616b str r3, [r5, #20] + int rv = HAL_SD_Init(&hsd); + 8005314: f007 fb12 bl 800c93c + if(rv != HAL_OK) { + 8005318: 4604 mov r4, r0 + 800531a: b130 cbz r0, 800532a + puts("init fail"); + 800531c: 4836 ldr r0, [pc, #216] ; (80053f8 ) + oled_show_progress(screen_search, pos*100 / num_blocks); + sdcard_light(true); + } + } + +} + 800531e: f50d 7d04 add.w sp, sp, #528 ; 0x210 + 8005322: e8bd 41f0 ldmia.w sp!, {r4, r5, r6, r7, r8, lr} + puts("bsize?"); + 8005326: f7ff bd41 b.w 8004dac + sdcard_light(true); + 800532a: 2001 movs r0, #1 + 800532c: f7ff ff16 bl 800515c + rv = HAL_SD_ConfigSpeedBusOperation(&hsd, SDMMC_SPEED_MODE_AUTO); + 8005330: 4621 mov r1, r4 + 8005332: 4628 mov r0, r5 + 8005334: f007 fbda bl 800caec + if(rv != HAL_OK) { + 8005338: b108 cbz r0, 800533e + puts("speed"); + 800533a: 4830 ldr r0, [pc, #192] ; (80053fc ) + 800533c: e7ef b.n 800531e + rv = HAL_SD_ConfigWideBusOperation(&hsd, SDMMC_BUS_WIDE_4B); + 800533e: f44f 4180 mov.w r1, #16384 ; 0x4000 + 8005342: 4628 mov r0, r5 + 8005344: f007 fa24 bl 800c790 + if(rv != HAL_OK) { + 8005348: 4604 mov r4, r0 + 800534a: b108 cbz r0, 8005350 + puts("wide"); + 800534c: 482c ldr r0, [pc, #176] ; (8005400 ) + 800534e: e7e6 b.n 800531e + if(hsd.SdCard.BlockSize != 512) { + 8005350: 6d2b ldr r3, [r5, #80] ; 0x50 + 8005352: f5b3 7f00 cmp.w r3, #512 ; 0x200 + 8005356: d001 beq.n 800535c + puts("bsize?"); + 8005358: 482a ldr r0, [pc, #168] ; (8005404 ) + 800535a: e7e0 b.n 800531e + puts("ok"); + 800535c: 482a ldr r0, [pc, #168] ; (8005408 ) + *num_blocks = hsd.SdCard.BlockNbr; + 800535e: 6cee ldr r6, [r5, #76] ; 0x4c + if(memcmp(blk, "DfuSe", 5) == 0) { + 8005360: 4f2a ldr r7, [pc, #168] ; (800540c ) + oled_show_progress(screen_search, pos*100 / num_blocks); + 8005362: f8df 8070 ldr.w r8, [pc, #112] ; 80053d4 + puts("ok"); + 8005366: f7ff fd21 bl 8004dac + for(int pos=0; pos + int rv = HAL_SD_ReadBlocks(&hsd, blk, pos, 1, 60000); + 800536e: f64e 2360 movw r3, #60000 ; 0xea60 + 8005372: 9300 str r3, [sp, #0] + 8005374: 4622 mov r2, r4 + 8005376: 2301 movs r3, #1 + 8005378: a904 add r1, sp, #16 + 800537a: 4628 mov r0, r5 + 800537c: f006 fd64 bl 800be48 + if(rv != HAL_OK) { + 8005380: b130 cbz r0, 8005390 + puts("fail read"); + 8005382: 4823 ldr r0, [pc, #140] ; (8005410 ) + 8005384: f7ff fd12 bl 8004dac +} + 8005388: f50d 7d04 add.w sp, sp, #528 ; 0x210 + 800538c: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + if(memcmp(blk, "DfuSe", 5) == 0) { + 8005390: 2205 movs r2, #5 + 8005392: 4639 mov r1, r7 + 8005394: a804 add r0, sp, #16 + 8005396: f008 f935 bl 800d604 + 800539a: b9b0 cbnz r0, 80053ca + puts2("found @ "); + 800539c: 481d ldr r0, [pc, #116] ; (8005414 ) + 800539e: f7ff fc77 bl 8004c90 + puthex8(pos); + 80053a2: 4620 mov r0, r4 + 80053a4: f7ff fcd0 bl 8004d48 + putchar('\n'); + 80053a8: 200a movs r0, #10 + 80053aa: f7ff fc85 bl 8004cb8 + sdcard_try_file(pos); + 80053ae: 4620 mov r0, r4 + 80053b0: f7ff fee8 bl 8005184 + oled_show_progress(screen_search, pos*100 / num_blocks); + 80053b4: 2164 movs r1, #100 ; 0x64 + 80053b6: 4640 mov r0, r8 + 80053b8: 4361 muls r1, r4 + 80053ba: fbb1 f1f6 udiv r1, r1, r6 + 80053be: f7fb fd83 bl 8000ec8 + sdcard_light(true); + 80053c2: 2001 movs r0, #1 + 80053c4: f7ff feca bl 800515c + 80053c8: e001 b.n 80053ce + if(pos % 128 == 0) { + 80053ca: 0663 lsls r3, r4, #25 + 80053cc: d0f2 beq.n 80053b4 + for(int pos=0; pos + 80053d2: bf00 nop + 80053d4: 0800e079 .word 0x0800e079 + 80053d8: 40021000 .word 0x40021000 + 80053dc: 0800e7e4 .word 0x0800e7e4 + 80053e0: 0800e84c .word 0x0800e84c + 80053e4: 48000800 .word 0x48000800 + 80053e8: 48000c00 .word 0x48000c00 + 80053ec: 2009e220 .word 0x2009e220 + 80053f0: 0800e7f4 .word 0x0800e7f4 + 80053f4: 50062400 .word 0x50062400 + 80053f8: 0800e803 .word 0x0800e803 + 80053fc: 0800e80d .word 0x0800e80d + 8005400: 0800e813 .word 0x0800e813 + 8005404: 0800e818 .word 0x0800e818 + 8005408: 0800e81f .word 0x0800e81f + 800540c: 0800e82c .word 0x0800e82c + 8005410: 0800e822 .word 0x0800e822 + 8005414: 0800e832 .word 0x0800e832 + +08005418 : + +// sdcard_recovery() +// + void +sdcard_recovery(void) +{ + 8005418: b508 push {r3, lr} + // Use SDCard to recover. Must be precise version they tried to + // install before, and will be slow AF. + + puts("Recovery mode."); + 800541a: 480b ldr r0, [pc, #44] ; (8005448 ) + while(1) { + // .. need them to insert a card + + sdcard_light(false); + while(!sdcard_is_inserted()) { + oled_show(screen_recovery); + 800541c: 4c0b ldr r4, [pc, #44] ; (800544c ) + puts("Recovery mode."); + 800541e: f7ff fcc5 bl 8004dac + sdcard_light(false); + 8005422: 2000 movs r0, #0 + 8005424: f7ff fe9a bl 800515c + while(!sdcard_is_inserted()) { + 8005428: f7ff fea0 bl 800516c + 800542c: b128 cbz r0, 800543a + delay_ms(200); + } + + // look for binary, will reset system if successful + sdcard_light(true); + 800542e: 2001 movs r0, #1 + 8005430: f7ff fe94 bl 800515c + sdcard_search(); + 8005434: f7ff ff22 bl 800527c + sdcard_light(false); + 8005438: e7f3 b.n 8005422 + oled_show(screen_recovery); + 800543a: 4620 mov r0, r4 + 800543c: f7fb fd02 bl 8000e44 + delay_ms(200); + 8005440: 20c8 movs r0, #200 ; 0xc8 + 8005442: f7fe fa59 bl 80038f8 + 8005446: e7ef b.n 8005428 + 8005448: 0800e83b .word 0x0800e83b + 800544c: 0800dc78 .word 0x0800dc78 + +08005450 : +#include + +// so we don't need stm32l4xx_hal_hash_ex.c +HAL_StatusTypeDef HAL_HASHEx_SHA256_Accmlt(HASH_HandleTypeDef *hhash, uint8_t *pInBuffer, uint32_t Size) +{ + return HASH_Accumulate(hhash, pInBuffer, Size,HASH_ALGOSELECTION_SHA256); + 8005450: 4b01 ldr r3, [pc, #4] ; (8005458 ) + 8005452: f005 ba41 b.w 800a8d8 + 8005456: bf00 nop + 8005458: 00040080 .word 0x00040080 + +0800545c : +} + +HAL_StatusTypeDef HAL_HASHEx_SHA256_Start(HASH_HandleTypeDef *hhash, uint8_t *pInBuffer, uint32_t Size, uint8_t* pOutBuffer, uint32_t Timeout) +{ + 800545c: b513 push {r0, r1, r4, lr} + return HASH_Start(hhash, pInBuffer, Size, pOutBuffer, Timeout, HASH_ALGOSELECTION_SHA256); + 800545e: 4c04 ldr r4, [pc, #16] ; (8005470 ) + 8005460: 9401 str r4, [sp, #4] + 8005462: 9c04 ldr r4, [sp, #16] + 8005464: 9400 str r4, [sp, #0] + 8005466: f005 f993 bl 800a790 +} + 800546a: b002 add sp, #8 + 800546c: bd10 pop {r4, pc} + 800546e: bf00 nop + 8005470: 00040080 .word 0x00040080 + +08005474 : + +HAL_StatusTypeDef HAL_HMACEx_SHA256_Start(HASH_HandleTypeDef *hhash, uint8_t *pInBuffer, uint32_t Size, uint8_t* pOutBuffer, uint32_t Timeout) +{ + 8005474: b513 push {r0, r1, r4, lr} + return HMAC_Start(hhash, pInBuffer, Size, pOutBuffer, Timeout, HASH_ALGOSELECTION_SHA256); + 8005476: 4c04 ldr r4, [pc, #16] ; (8005488 ) + 8005478: 9401 str r4, [sp, #4] + 800547a: 9c04 ldr r4, [sp, #16] + 800547c: 9400 str r4, [sp, #0] + 800547e: f005 fbc9 bl 800ac14 +} + 8005482: b002 add sp, #8 + 8005484: bd10 pop {r4, pc} + 8005486: bf00 nop + 8005488: 00040080 .word 0x00040080 + +0800548c : + +void sha256_init(SHA256_CTX *ctx) +{ + 800548c: b510 push {r4, lr} + memset(ctx, 0, sizeof(SHA256_CTX)); + 800548e: 2248 movs r2, #72 ; 0x48 +{ + 8005490: 4604 mov r4, r0 + memset(ctx, 0, sizeof(SHA256_CTX)); + 8005492: 2100 movs r1, #0 + 8005494: 3004 adds r0, #4 + 8005496: f008 f8ed bl 800d674 + +#if 1 + ctx->num_pending = 0; + ctx->hh.Init.DataType = HASH_DATATYPE_8B; + 800549a: 2320 movs r3, #32 + 800549c: 6023 str r3, [r4, #0] + HAL_HASH_Init(&ctx->hh); + 800549e: 4620 mov r0, r4 + __HAL_HASH_RESET_MDMAT(); + + MODIFY_REG(HASH->CR, HASH_CR_LKEY|HASH_CR_ALGO|HASH_CR_MODE|HASH_CR_INIT, + HASH_ALGOSELECTION_SHA256 | HASH_CR_INIT); +#endif +} + 80054a0: e8bd 4010 ldmia.w sp!, {r4, lr} + HAL_HASH_Init(&ctx->hh); + 80054a4: f005 b802 b.w 800a4ac + +080054a8 : + +void sha256_update(SHA256_CTX *ctx, const uint8_t data[], uint32_t len) +{ + 80054a8: b5f8 push {r3, r4, r5, r6, r7, lr} + HAL_StatusTypeDef rv; + + // clear out any pending bytes + if(ctx->num_pending + len >= 4) { + 80054aa: f890 3048 ldrb.w r3, [r0, #72] ; 0x48 + 80054ae: 4413 add r3, r2 + 80054b0: 2b03 cmp r3, #3 +{ + 80054b2: 4605 mov r5, r0 + 80054b4: 460e mov r6, r1 + 80054b6: 4614 mov r4, r2 + if(ctx->num_pending + len >= 4) { + 80054b8: d818 bhi.n 80054ec + } + } + + // write full blocks + uint32_t blocks = len / 4; + if(blocks) { + 80054ba: 2c03 cmp r4, #3 + 80054bc: d926 bls.n 800550c +#if 1 + rv = HAL_HASHEx_SHA256_Accumulate(&ctx->hh, (uint8_t *)data, blocks*4); + 80054be: f024 0703 bic.w r7, r4, #3 + 80054c2: 463a mov r2, r7 + 80054c4: 4631 mov r1, r6 + 80054c6: 4628 mov r0, r5 + 80054c8: f7ff ffc2 bl 8005450 + ASSERT(rv == HAL_OK); + 80054cc: b9c8 cbnz r0, 8005502 + uint32_t tmp; + memcpy(&tmp, data, 4); + HASH->DIN = tmp; + } +#endif + len -= blocks*4; + 80054ce: f004 0403 and.w r4, r4, #3 + data += blocks*4; + 80054d2: 443e add r6, r7 + 80054d4: e01a b.n 800550c + ctx->pending[ctx->num_pending++] = *data; + 80054d6: 1c5a adds r2, r3, #1 + 80054d8: b2d2 uxtb r2, r2 + 80054da: f885 2048 strb.w r2, [r5, #72] ; 0x48 + 80054de: 442b add r3, r5 + 80054e0: f816 1b01 ldrb.w r1, [r6], #1 + 80054e4: f883 1044 strb.w r1, [r3, #68] ; 0x44 + if(!len) break; + 80054e8: 3c01 subs r4, #1 + 80054ea: d00d beq.n 8005508 + while(ctx->num_pending != 4) { + 80054ec: f895 3048 ldrb.w r3, [r5, #72] ; 0x48 + 80054f0: 2b04 cmp r3, #4 + 80054f2: d1f0 bne.n 80054d6 + rv = HAL_HASHEx_SHA256_Accumulate(&ctx->hh, ctx->pending, 4); + 80054f4: 2204 movs r2, #4 + 80054f6: f105 0144 add.w r1, r5, #68 ; 0x44 + 80054fa: 4628 mov r0, r5 + 80054fc: f7ff ffa8 bl 8005450 + ASSERT(rv == HAL_OK); + 8005500: b140 cbz r0, 8005514 + 8005502: 480b ldr r0, [pc, #44] ; (8005530 ) + 8005504: f7fb faa0 bl 8000a48 + if(ctx->num_pending == 4) { + 8005508: 2a04 cmp r2, #4 + 800550a: d0f3 beq.n 80054f4 + 800550c: 4434 add r4, r6 + } + + // save runt for later + ASSERT(len <= 3); + while(len) { + 800550e: 42b4 cmp r4, r6 + 8005510: d103 bne.n 800551a + ctx->pending[ctx->num_pending++] = *data; + data++; + len--; + } +} + 8005512: bdf8 pop {r3, r4, r5, r6, r7, pc} + ctx->num_pending = 0; + 8005514: f885 0048 strb.w r0, [r5, #72] ; 0x48 + 8005518: e7cf b.n 80054ba + ctx->pending[ctx->num_pending++] = *data; + 800551a: f895 3048 ldrb.w r3, [r5, #72] ; 0x48 + 800551e: 1c5a adds r2, r3, #1 + 8005520: f885 2048 strb.w r2, [r5, #72] ; 0x48 + 8005524: 442b add r3, r5 + 8005526: f816 2b01 ldrb.w r2, [r6], #1 + 800552a: f883 2044 strb.w r2, [r3, #68] ; 0x44 + len--; + 800552e: e7ee b.n 800550e + 8005530: 0800e3e0 .word 0x0800e3e0 + +08005534 : + +void sha256_final(SHA256_CTX *ctx, uint8_t digest[32]) +{ + 8005534: b513 push {r0, r1, r4, lr} + // Do final 0-3 bytes, pad and return digest. +#if 1 + HAL_StatusTypeDef rv = HAL_HASHEx_SHA256_Start(&ctx->hh, + 8005536: f04f 32ff mov.w r2, #4294967295 ; 0xffffffff + 800553a: 9200 str r2, [sp, #0] +{ + 800553c: 460b mov r3, r1 + HAL_StatusTypeDef rv = HAL_HASHEx_SHA256_Start(&ctx->hh, + 800553e: f890 2048 ldrb.w r2, [r0, #72] ; 0x48 + 8005542: f100 0144 add.w r1, r0, #68 ; 0x44 + 8005546: f7ff ff89 bl 800545c + ctx->pending, ctx->num_pending, digest, HAL_MAX_DELAY); + ASSERT(rv == HAL_OK); + 800554a: b110 cbz r0, 8005552 + 800554c: 4802 ldr r0, [pc, #8] ; (8005558 ) + 800554e: f7fb fa7b bl 8000a48 + tmp = __REV(HASH_DIGEST->HR[6]); + memcpy(out, &tmp, 4); out += 4; + tmp = __REV(HASH_DIGEST->HR[7]); + memcpy(out, &tmp, 4); +#endif +} + 8005552: b002 add sp, #8 + 8005554: bd10 pop {r4, pc} + 8005556: bf00 nop + 8005558: 0800e3e0 .word 0x0800e3e0 + +0800555c : +// +// single-shot version (best) +// + void +sha256_single(const uint8_t data[], uint32_t len, uint8_t digest[32]) +{ + 800555c: b530 push {r4, r5, lr} + 800555e: b097 sub sp, #92 ; 0x5c + 8005560: 4604 mov r4, r0 + 8005562: 460d mov r5, r1 + 8005564: 9203 str r2, [sp, #12] + HASH_HandleTypeDef hh = {0}; + 8005566: 2100 movs r1, #0 + 8005568: 2240 movs r2, #64 ; 0x40 + 800556a: a806 add r0, sp, #24 + 800556c: f008 f882 bl 800d674 + + hh.Init.DataType = HASH_DATATYPE_8B; + 8005570: 2220 movs r2, #32 + + HAL_HASH_Init(&hh); + 8005572: a805 add r0, sp, #20 + hh.Init.DataType = HASH_DATATYPE_8B; + 8005574: 9205 str r2, [sp, #20] + HAL_HASH_Init(&hh); + 8005576: f004 ff99 bl 800a4ac + + // It's called "Start" but it handles the runt packet, so really can only + // be used once at end of message, or for whole message. + HAL_StatusTypeDef rv = HAL_HASHEx_SHA256_Start(&hh, (uint8_t *)data, len, + 800557a: f04f 32ff mov.w r2, #4294967295 ; 0xffffffff + 800557e: 9200 str r2, [sp, #0] + 8005580: 9b03 ldr r3, [sp, #12] + 8005582: 462a mov r2, r5 + 8005584: 4621 mov r1, r4 + 8005586: a805 add r0, sp, #20 + 8005588: f7ff ff68 bl 800545c + digest, HAL_MAX_DELAY); + ASSERT(rv == HAL_OK); + 800558c: b110 cbz r0, 8005594 + 800558e: 4802 ldr r0, [pc, #8] ; (8005598 ) + 8005590: f7fb fa5a bl 8000a48 +} + 8005594: b017 add sp, #92 ; 0x5c + 8005596: bd30 pop {r4, r5, pc} + 8005598: 0800e3e0 .word 0x0800e3e0 + +0800559c : +// hmac_sha256_init() +// + void +hmac_sha256_init(HMAC_CTX *ctx) +{ + memset(ctx, 0, sizeof(HMAC_CTX)); + 800559c: f44f 7282 mov.w r2, #260 ; 0x104 + 80055a0: 2100 movs r1, #0 + 80055a2: f008 b867 b.w 800d674 + ... + +080055a8 : + +// hmac_sha256_update() +// + void +hmac_sha256_update(HMAC_CTX *ctx, const uint8_t data[], uint32_t len) +{ + 80055a8: b538 push {r3, r4, r5, lr} + 80055aa: 4604 mov r4, r0 + // simple append + ASSERT(ctx->num_pending + len < sizeof(ctx->pending)); + 80055ac: f8d0 0100 ldr.w r0, [r0, #256] ; 0x100 + 80055b0: 1883 adds r3, r0, r2 + 80055b2: 2bff cmp r3, #255 ; 0xff +{ + 80055b4: 4615 mov r5, r2 + ASSERT(ctx->num_pending + len < sizeof(ctx->pending)); + 80055b6: d902 bls.n 80055be + 80055b8: 4805 ldr r0, [pc, #20] ; (80055d0 ) + 80055ba: f7fb fa45 bl 8000a48 + + memcpy(ctx->pending+ctx->num_pending, data, len); + 80055be: 4420 add r0, r4 + 80055c0: f008 f830 bl 800d624 + + ctx->num_pending += len; + 80055c4: f8d4 2100 ldr.w r2, [r4, #256] ; 0x100 + 80055c8: 442a add r2, r5 + 80055ca: f8c4 2100 str.w r2, [r4, #256] ; 0x100 +} + 80055ce: bd38 pop {r3, r4, r5, pc} + 80055d0: 0800e3e0 .word 0x0800e3e0 + +080055d4 : + +// hmac_sha256_final() +// + void +hmac_sha256_final(HMAC_CTX *ctx, const uint8_t key[32], uint8_t digest[32]) +{ + 80055d4: b530 push {r4, r5, lr} + 80055d6: b097 sub sp, #92 ; 0x5c + 80055d8: 4604 mov r4, r0 + 80055da: 460d mov r5, r1 + 80055dc: 9203 str r2, [sp, #12] + HASH_HandleTypeDef hh = {0}; + 80055de: 2100 movs r1, #0 + 80055e0: 2238 movs r2, #56 ; 0x38 + 80055e2: a808 add r0, sp, #32 + 80055e4: f008 f846 bl 800d674 + + hh.Init.DataType = HASH_DATATYPE_8B; + 80055e8: 2220 movs r2, #32 + hh.Init.pKey = (uint8_t *)key; // const viol due to API dumbness + hh.Init.KeySize = 32; + + HAL_HASH_Init(&hh); + 80055ea: a805 add r0, sp, #20 + hh.Init.KeySize = 32; + 80055ec: e9cd 2506 strd r2, r5, [sp, #24] + hh.Init.DataType = HASH_DATATYPE_8B; + 80055f0: 9205 str r2, [sp, #20] + HAL_HASH_Init(&hh); + 80055f2: f004 ff5b bl 800a4ac + + HAL_StatusTypeDef rv = HAL_HMACEx_SHA256_Start(&hh, + 80055f6: f04f 32ff mov.w r2, #4294967295 ; 0xffffffff + 80055fa: 9200 str r2, [sp, #0] + 80055fc: 9b03 ldr r3, [sp, #12] + 80055fe: f8d4 2100 ldr.w r2, [r4, #256] ; 0x100 + 8005602: 4621 mov r1, r4 + 8005604: a805 add r0, sp, #20 + 8005606: f7ff ff35 bl 8005474 + ctx->pending, ctx->num_pending, digest, HAL_MAX_DELAY); + ASSERT(rv == HAL_OK); + 800560a: b110 cbz r0, 8005612 + 800560c: 4802 ldr r0, [pc, #8] ; (8005618 ) + 800560e: f7fb fa1b bl 8000a48 +} + 8005612: b017 add sp, #92 ; 0x5c + 8005614: bd30 pop {r4, r5, pc} + 8005616: bf00 nop + 8005618: 0800e3e0 .word 0x0800e3e0 + +0800561c : + +#if !asm_mult +uECC_VLI_API void uECC_vli_mult(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + wordcount_t num_words) { + 800561c: e92d 43f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, lr} + ); + +#else /* Thumb-1 */ + uint32_t r4, r5, r6, r7; + + __asm__ volatile ( + 8005620: 3b01 subs r3, #1 + 8005622: 009b lsls r3, r3, #2 + 8005624: 4698 mov r8, r3 + 8005626: 005b lsls r3, r3, #1 + 8005628: 4699 mov r9, r3 + 800562a: 2300 movs r3, #0 + 800562c: 2400 movs r4, #0 + 800562e: 2500 movs r5, #0 + 8005630: 2600 movs r6, #0 + 8005632: b401 push {r0} + 8005634: 2700 movs r7, #0 + 8005636: e002 b.n 800563e + 8005638: 0037 movs r7, r6 + 800563a: 4640 mov r0, r8 + 800563c: 1a3f subs r7, r7, r0 + 800563e: b478 push {r3, r4, r5, r6} + 8005640: 1bf0 subs r0, r6, r7 + 8005642: 5814 ldr r4, [r2, r0] + 8005644: 59c8 ldr r0, [r1, r7] + 8005646: 0c03 lsrs r3, r0, #16 + 8005648: b280 uxth r0, r0 + 800564a: 0c25 lsrs r5, r4, #16 + 800564c: b2a4 uxth r4, r4 + 800564e: 001e movs r6, r3 + 8005650: 436e muls r6, r5 + 8005652: 4363 muls r3, r4 + 8005654: 4345 muls r5, r0 + 8005656: 4360 muls r0, r4 + 8005658: 2400 movs r4, #0 + 800565a: 195b adds r3, r3, r5 + 800565c: 4164 adcs r4, r4 + 800565e: 0424 lsls r4, r4, #16 + 8005660: 1936 adds r6, r6, r4 + 8005662: 041c lsls r4, r3, #16 + 8005664: 0c1b lsrs r3, r3, #16 + 8005666: 1900 adds r0, r0, r4 + 8005668: 415e adcs r6, r3 + 800566a: bc38 pop {r3, r4, r5} + 800566c: 181b adds r3, r3, r0 + 800566e: 4174 adcs r4, r6 + 8005670: 2000 movs r0, #0 + 8005672: 4145 adcs r5, r0 + 8005674: bc40 pop {r6} + 8005676: 3704 adds r7, #4 + 8005678: 4547 cmp r7, r8 + 800567a: dc01 bgt.n 8005680 + 800567c: 42b7 cmp r7, r6 + 800567e: ddde ble.n 800563e + 8005680: 9800 ldr r0, [sp, #0] + 8005682: 5183 str r3, [r0, r6] + 8005684: 4623 mov r3, r4 + 8005686: 462c mov r4, r5 + 8005688: 2500 movs r5, #0 + 800568a: 3604 adds r6, #4 + 800568c: 4546 cmp r6, r8 + 800568e: ddd1 ble.n 8005634 + 8005690: 454e cmp r6, r9 + 8005692: ddd1 ble.n 8005638 + 8005694: 5183 str r3, [r0, r6] + 8005696: bc01 pop {r0} + [r5] "=&l" (r5), [r6] "=&l" (r6), [r7] "=&l" (r7) + : [r0] "l" (result), [r1] "l" (left), [r2] "l" (right) + : "r8", "r9", "cc", "memory" + ); +#endif +} + 8005698: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + +0800569c : + +#if !asm_clear +uECC_VLI_API void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words) { + wordcount_t i; + for (i = 0; i < num_words; ++i) { + vli[i] = 0; + 800569c: ea21 71e1 bic.w r1, r1, r1, asr #31 + 80056a0: 008a lsls r2, r1, #2 + 80056a2: 2100 movs r1, #0 + 80056a4: f007 bfe6 b.w 800d674 + +080056a8 : +} +#endif /* !asm_clear */ + +/* Constant-time comparison to zero - secure way to compare long integers */ +/* Returns 1 if vli == 0, 0 otherwise. */ +uECC_VLI_API uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words) { + 80056a8: b510 push {r4, lr} + uECC_word_t bits = 0; + wordcount_t i; + for (i = 0; i < num_words; ++i) { + 80056aa: 2300 movs r3, #0 + uECC_word_t bits = 0; + 80056ac: 461a mov r2, r3 + for (i = 0; i < num_words; ++i) { + 80056ae: b25c sxtb r4, r3 + 80056b0: 42a1 cmp r1, r4 + 80056b2: dc03 bgt.n 80056bc + bits |= vli[i]; + } + return (bits == 0); +} + 80056b4: fab2 f082 clz r0, r2 + 80056b8: 0940 lsrs r0, r0, #5 + 80056ba: bd10 pop {r4, pc} + bits |= vli[i]; + 80056bc: f850 4023 ldr.w r4, [r0, r3, lsl #2] + 80056c0: 3301 adds r3, #1 + 80056c2: 4322 orrs r2, r4 + for (i = 0; i < num_words; ++i) { + 80056c4: e7f3 b.n 80056ae + +080056c6 : + +/* Returns nonzero if bit 'bit' of vli is set. */ +uECC_VLI_API uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit) { + return (vli[bit >> uECC_WORD_BITS_SHIFT] & ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK))); + 80056c6: 114a asrs r2, r1, #5 + 80056c8: 2301 movs r3, #1 + 80056ca: f850 0022 ldr.w r0, [r0, r2, lsl #2] + 80056ce: f001 011f and.w r1, r1, #31 + 80056d2: fa03 f101 lsl.w r1, r3, r1 +} + 80056d6: 4008 ands r0, r1 + 80056d8: 4770 bx lr + +080056da : +/* Counts the number of words in vli. */ +static wordcount_t vli_numDigits(const uECC_word_t *vli, const wordcount_t max_words) { + wordcount_t i; + /* Search from the end until we find a non-zero digit. + We do it in reverse because we expect that most digits will be nonzero. */ + for (i = max_words - 1; i >= 0 && vli[i] == 0; --i) { + 80056da: 3901 subs r1, #1 + + return (i + 1); +} + +/* Counts the number of bits required to represent vli. */ +uECC_VLI_API bitcount_t uECC_vli_numBits(const uECC_word_t *vli, const wordcount_t max_words) { + 80056dc: b510 push {r4, lr} + 80056de: b249 sxtb r1, r1 + for (i = max_words - 1; i >= 0 && vli[i] == 0; --i) { + 80056e0: 1d04 adds r4, r0, #4 + 80056e2: 060a lsls r2, r1, #24 + 80056e4: b2cb uxtb r3, r1 + 80056e6: d404 bmi.n 80056f2 + 80056e8: 3901 subs r1, #1 + 80056ea: f854 2021 ldr.w r2, [r4, r1, lsl #2] + 80056ee: 2a00 cmp r2, #0 + 80056f0: d0f7 beq.n 80056e2 + return (i + 1); + 80056f2: 3301 adds r3, #1 + 80056f4: b25b sxtb r3, r3 + uECC_word_t i; + uECC_word_t digit; + + wordcount_t num_digits = vli_numDigits(vli, max_words); + if (num_digits == 0) { + 80056f6: b173 cbz r3, 8005716 + return 0; + } + + digit = vli[num_digits - 1]; + 80056f8: f103 4280 add.w r2, r3, #1073741824 ; 0x40000000 + 80056fc: 3a01 subs r2, #1 + 80056fe: f850 2022 ldr.w r2, [r0, r2, lsl #2] + for (i = 0; digit; ++i) { + 8005702: 2000 movs r0, #0 + 8005704: b922 cbnz r2, 8005710 + digit >>= 1; + } + + return (((bitcount_t)(num_digits - 1) << uECC_WORD_BITS_SHIFT) + i); + 8005706: 3b01 subs r3, #1 + 8005708: eb00 1343 add.w r3, r0, r3, lsl #5 + 800570c: b218 sxth r0, r3 +} + 800570e: bd10 pop {r4, pc} + digit >>= 1; + 8005710: 0852 lsrs r2, r2, #1 + for (i = 0; digit; ++i) { + 8005712: 3001 adds r0, #1 + 8005714: e7f6 b.n 8005704 + return 0; + 8005716: 4618 mov r0, r3 + 8005718: e7f9 b.n 800570e + +0800571a : + +/* Sets dest = src. */ +#if !asm_set +uECC_VLI_API void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src, wordcount_t num_words) { + 800571a: b510 push {r4, lr} + wordcount_t i; + for (i = 0; i < num_words; ++i) { + 800571c: 2300 movs r3, #0 + 800571e: b25c sxtb r4, r3 + 8005720: 42a2 cmp r2, r4 + 8005722: dc00 bgt.n 8005726 + dest[i] = src[i]; + } +} + 8005724: bd10 pop {r4, pc} + dest[i] = src[i]; + 8005726: f851 4023 ldr.w r4, [r1, r3, lsl #2] + 800572a: f840 4023 str.w r4, [r0, r3, lsl #2] + for (i = 0; i < num_words; ++i) { + 800572e: 3301 adds r3, #1 + 8005730: e7f5 b.n 800571e + +08005732 : +#endif /* !asm_set */ + +/* Returns sign of left - right. */ +static cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left, + const uECC_word_t *right, + wordcount_t num_words) { + 8005732: b510 push {r4, lr} + wordcount_t i; + for (i = num_words - 1; i >= 0; --i) { + 8005734: 3a01 subs r2, #1 + 8005736: b252 sxtb r2, r2 + 8005738: 0613 lsls r3, r2, #24 + 800573a: d501 bpl.n 8005740 + return 1; + } else if (left[i] < right[i]) { + return -1; + } + } + return 0; + 800573c: 2000 movs r0, #0 +} + 800573e: bd10 pop {r4, pc} + if (left[i] > right[i]) { + 8005740: f850 4022 ldr.w r4, [r0, r2, lsl #2] + 8005744: f851 3022 ldr.w r3, [r1, r2, lsl #2] + 8005748: 429c cmp r4, r3 + 800574a: d805 bhi.n 8005758 + } else if (left[i] < right[i]) { + 800574c: f102 32ff add.w r2, r2, #4294967295 ; 0xffffffff + 8005750: d2f2 bcs.n 8005738 + return -1; + 8005752: f04f 30ff mov.w r0, #4294967295 ; 0xffffffff + 8005756: e7f2 b.n 800573e + return 1; + 8005758: 2001 movs r0, #1 + 800575a: e7f0 b.n 800573e + +0800575c : +#if !asm_rshift1 +uECC_VLI_API void uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words) { + uECC_word_t *end = vli; + uECC_word_t carry = 0; + + vli += num_words; + 800575c: eb00 0181 add.w r1, r0, r1, lsl #2 + uECC_word_t carry = 0; + 8005760: 2300 movs r3, #0 + while (vli-- > end) { + 8005762: 4288 cmp r0, r1 + 8005764: d300 bcc.n 8005768 + uECC_word_t temp = *vli; + *vli = (temp >> 1) | carry; + carry = temp << (uECC_WORD_BITS - 1); + } +} + 8005766: 4770 bx lr + uECC_word_t temp = *vli; + 8005768: f851 2d04 ldr.w r2, [r1, #-4]! + *vli = (temp >> 1) | carry; + 800576c: ea43 0352 orr.w r3, r3, r2, lsr #1 + 8005770: 600b str r3, [r1, #0] + carry = temp << (uECC_WORD_BITS - 1); + 8005772: 07d3 lsls r3, r2, #31 + 8005774: e7f5 b.n 8005762 + +08005776 : +/* Computes result = (left * right) % mod. */ +uECC_VLI_API void uECC_vli_modMult(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + const uECC_word_t *mod, + wordcount_t num_words) { + 8005776: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + 800577a: b0b5 sub sp, #212 ; 0xd4 + 800577c: 461f mov r7, r3 + 800577e: f99d 50f8 ldrsb.w r5, [sp, #248] ; 0xf8 + 8005782: 4680 mov r8, r0 + uECC_word_t product[2 * uECC_MAX_WORDS]; + uECC_vli_mult(product, left, right, num_words); + 8005784: 462b mov r3, r5 + 8005786: a804 add r0, sp, #16 + 8005788: f7ff ff48 bl 800561c + uECC_word_t *v[2] = {tmp, product}; + 800578c: ab24 add r3, sp, #144 ; 0x90 + 800578e: e9cd 3002 strd r3, r0, [sp, #8] + bitcount_t shift = (num_words * 2 * uECC_WORD_BITS) - uECC_vli_numBits(mod, num_words); + 8005792: 4629 mov r1, r5 + 8005794: 4638 mov r0, r7 + 8005796: f7ff ffa0 bl 80056da + 800579a: ebc0 1085 rsb r0, r0, r5, lsl #6 + 800579e: b204 sxth r4, r0 + wordcount_t word_shift = shift / uECC_WORD_BITS; + 80057a0: 2c00 cmp r4, #0 + 80057a2: 4626 mov r6, r4 + 80057a4: bfb8 it lt + 80057a6: f104 061f addlt.w r6, r4, #31 + wordcount_t bit_shift = shift % uECC_WORD_BITS; + 80057aa: 4263 negs r3, r4 + wordcount_t word_shift = shift / uECC_WORD_BITS; + 80057ac: f346 1647 sbfx r6, r6, #5, #8 + wordcount_t bit_shift = shift % uECC_WORD_BITS; + 80057b0: f003 031f and.w r3, r3, #31 + 80057b4: f004 091f and.w r9, r4, #31 + uECC_vli_clear(mod_multiple, word_shift); + 80057b8: 4631 mov r1, r6 + wordcount_t bit_shift = shift % uECC_WORD_BITS; + 80057ba: bf58 it pl + 80057bc: f1c3 0900 rsbpl r9, r3, #0 + uECC_vli_clear(mod_multiple, word_shift); + 80057c0: a814 add r0, sp, #80 ; 0x50 + 80057c2: f7ff ff6b bl 800569c + if (bit_shift > 0) { + 80057c6: f1b9 0f00 cmp.w r9, #0 + 80057ca: b236 sxth r6, r6 + 80057cc: dd2b ble.n 8005826 + 80057ce: ab14 add r3, sp, #80 ; 0x50 + uECC_word_t carry = 0; + 80057d0: 2200 movs r2, #0 + 80057d2: eb03 0686 add.w r6, r3, r6, lsl #2 + carry = mod[index] >> (uECC_WORD_BITS - bit_shift); + 80057d6: f1c9 0c20 rsb ip, r9, #32 + for(index = 0; index < (uECC_word_t)num_words; ++index) { + 80057da: 4613 mov r3, r2 + 80057dc: 42ab cmp r3, r5 + 80057de: d317 bcc.n 8005810 + for (i = 0; i < num_words * 2; ++i) { + 80057e0: 006b lsls r3, r5, #1 + 80057e2: 9301 str r3, [sp, #4] + uECC_vli_rshift1(mod_multiple + num_words, num_words); + 80057e4: ab14 add r3, sp, #80 ; 0x50 + 80057e6: eb03 0985 add.w r9, r3, r5, lsl #2 + mod_multiple[num_words - 1] |= mod_multiple[num_words] << (uECC_WORD_BITS - 1); + 80057ea: 1e6f subs r7, r5, #1 + 80057ec: ab34 add r3, sp, #208 ; 0xd0 + uECC_vli_rshift1(mod_multiple + num_words, num_words); + 80057ee: 2601 movs r6, #1 + mod_multiple[num_words - 1] |= mod_multiple[num_words] << (uECC_WORD_BITS - 1); + 80057f0: eb03 0787 add.w r7, r3, r7, lsl #2 + for (index = 1; shift >= 0; --shift) { + 80057f4: 2c00 cmp r4, #0 + 80057f6: da54 bge.n 80058a2 + uECC_vli_set(result, v[index], num_words); + 80057f8: ab34 add r3, sp, #208 ; 0xd0 + 80057fa: eb03 0686 add.w r6, r3, r6, lsl #2 + 80057fe: 462a mov r2, r5 + 8005800: f856 1cc8 ldr.w r1, [r6, #-200] + 8005804: 4640 mov r0, r8 + 8005806: f7ff ff88 bl 800571a + uECC_vli_mmod(result, product, mod, num_words); +} + 800580a: b035 add sp, #212 ; 0xd4 + 800580c: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + mod_multiple[word_shift + index] = (mod[index] << bit_shift) | carry; + 8005810: f857 0023 ldr.w r0, [r7, r3, lsl #2] + 8005814: fa00 f109 lsl.w r1, r0, r9 + 8005818: 430a orrs r2, r1 + 800581a: f846 2b04 str.w r2, [r6], #4 + for(index = 0; index < (uECC_word_t)num_words; ++index) { + 800581e: 3301 adds r3, #1 + carry = mod[index] >> (uECC_WORD_BITS - bit_shift); + 8005820: fa20 f20c lsr.w r2, r0, ip + for(index = 0; index < (uECC_word_t)num_words; ++index) { + 8005824: e7da b.n 80057dc + uECC_vli_set(mod_multiple + word_shift, mod, num_words); + 8005826: ab14 add r3, sp, #80 ; 0x50 + 8005828: 462a mov r2, r5 + 800582a: 4639 mov r1, r7 + 800582c: eb03 0086 add.w r0, r3, r6, lsl #2 + 8005830: f7ff ff73 bl 800571a + 8005834: e7d4 b.n 80057e0 + uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow; + 8005836: fa0f fe82 sxth.w lr, r2 + 800583a: f85a 3cc8 ldr.w r3, [sl, #-200] + 800583e: f853 b02e ldr.w fp, [r3, lr, lsl #2] + 8005842: ab34 add r3, sp, #208 ; 0xd0 + 8005844: eb03 0282 add.w r2, r3, r2, lsl #2 + 8005848: 3001 adds r0, #1 + 800584a: f852 3c80 ldr.w r3, [r2, #-128] + 800584e: 440b add r3, r1 + 8005850: ebbb 0303 subs.w r3, fp, r3 + 8005854: bf34 ite cc + 8005856: 2201 movcc r2, #1 + 8005858: 2200 movcs r2, #0 + if (diff != v[index][i]) { + 800585a: 459b cmp fp, r3 + borrow = (diff > v[index][i]); + 800585c: bf18 it ne + 800585e: 4611 movne r1, r2 + v[1 - index][i] = diff; + 8005860: f85c 2cc8 ldr.w r2, [ip, #-200] + 8005864: f842 302e str.w r3, [r2, lr, lsl #2] + for (i = 0; i < num_words * 2; ++i) { + 8005868: 9b01 ldr r3, [sp, #4] + 800586a: b242 sxtb r2, r0 + 800586c: 429a cmp r2, r3 + 800586e: dbe2 blt.n 8005836 + index = !(index ^ borrow); /* Swap the index if there was no borrow */ + 8005870: 1a73 subs r3, r6, r1 + 8005872: 425e negs r6, r3 + uECC_vli_rshift1(mod_multiple, num_words); + 8005874: 4629 mov r1, r5 + 8005876: a814 add r0, sp, #80 ; 0x50 + index = !(index ^ borrow); /* Swap the index if there was no borrow */ + 8005878: 415e adcs r6, r3 + uECC_vli_rshift1(mod_multiple, num_words); + 800587a: f7ff ff6f bl 800575c + mod_multiple[num_words - 1] |= mod_multiple[num_words] << (uECC_WORD_BITS - 1); + 800587e: ab34 add r3, sp, #208 ; 0xd0 + 8005880: eb03 0385 add.w r3, r3, r5, lsl #2 + uECC_vli_rshift1(mod_multiple + num_words, num_words); + 8005884: 4629 mov r1, r5 + mod_multiple[num_words - 1] |= mod_multiple[num_words] << (uECC_WORD_BITS - 1); + 8005886: f853 2c80 ldr.w r2, [r3, #-128] + 800588a: f857 3c80 ldr.w r3, [r7, #-128] + 800588e: ea43 73c2 orr.w r3, r3, r2, lsl #31 + 8005892: f847 3c80 str.w r3, [r7, #-128] + uECC_vli_rshift1(mod_multiple + num_words, num_words); + 8005896: 4648 mov r0, r9 + 8005898: 3c01 subs r4, #1 + 800589a: f7ff ff5f bl 800575c + for (index = 1; shift >= 0; --shift) { + 800589e: b224 sxth r4, r4 + 80058a0: e7a8 b.n 80057f4 + uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow; + 80058a2: ab34 add r3, sp, #208 ; 0xd0 + 80058a4: 2000 movs r0, #0 + v[1 - index][i] = diff; + 80058a6: f1c6 0c01 rsb ip, r6, #1 + uECC_word_t borrow = 0; + 80058aa: 4601 mov r1, r0 + uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow; + 80058ac: eb03 0a86 add.w sl, r3, r6, lsl #2 + v[1 - index][i] = diff; + 80058b0: eb03 0c8c add.w ip, r3, ip, lsl #2 + 80058b4: e7d8 b.n 8005868 + +080058b6 : + +uECC_VLI_API void uECC_vli_modMult_fast(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + uECC_Curve curve) { + 80058b6: b530 push {r4, r5, lr} + 80058b8: 461c mov r4, r3 + 80058ba: b091 sub sp, #68 ; 0x44 + 80058bc: 4605 mov r5, r0 + uECC_word_t product[2 * uECC_MAX_WORDS]; + uECC_vli_mult(product, left, right, curve->num_words); + 80058be: f993 3000 ldrsb.w r3, [r3] + 80058c2: 4668 mov r0, sp + 80058c4: f7ff feaa bl 800561c +#if (uECC_OPTIMIZATION_LEVEL > 0) + curve->mmod_fast(result, product); + 80058c8: 4601 mov r1, r0 + 80058ca: f8d4 30b0 ldr.w r3, [r4, #176] ; 0xb0 + 80058ce: 4628 mov r0, r5 + 80058d0: 4798 blx r3 +#else + uECC_vli_mmod(result, product, curve->p, curve->num_words); +#endif +} + 80058d2: b011 add sp, #68 ; 0x44 + 80058d4: bd30 pop {r4, r5, pc} + +080058d6 : +} +#endif /* uECC_ENABLE_VLI_API */ + +uECC_VLI_API void uECC_vli_modSquare_fast(uECC_word_t *result, + const uECC_word_t *left, + uECC_Curve curve) { + 80058d6: 4613 mov r3, r2 + uECC_vli_modMult_fast(result, left, left, curve); + 80058d8: 460a mov r2, r1 + 80058da: f7ff bfec b.w 80058b6 + +080058de : + +/* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */ +static void apply_z(uECC_word_t * X1, + uECC_word_t * Y1, + const uECC_word_t * const Z, + uECC_Curve curve) { + 80058de: b570 push {r4, r5, r6, lr} + 80058e0: 4614 mov r4, r2 + 80058e2: b08a sub sp, #40 ; 0x28 + 80058e4: 4606 mov r6, r0 + 80058e6: 460d mov r5, r1 + uECC_word_t t1[uECC_MAX_WORDS]; + + uECC_vli_modSquare_fast(t1, Z, curve); /* z^2 */ + 80058e8: 461a mov r2, r3 + 80058ea: 4621 mov r1, r4 + 80058ec: a802 add r0, sp, #8 + 80058ee: 9301 str r3, [sp, #4] + 80058f0: f7ff fff1 bl 80058d6 + uECC_vli_modMult_fast(X1, X1, t1, curve); /* x1 * z^2 */ + 80058f4: 9b01 ldr r3, [sp, #4] + 80058f6: aa02 add r2, sp, #8 + 80058f8: 4631 mov r1, r6 + 80058fa: 4630 mov r0, r6 + 80058fc: f7ff ffdb bl 80058b6 + uECC_vli_modMult_fast(t1, t1, Z, curve); /* z^3 */ + 8005900: a902 add r1, sp, #8 + 8005902: 9b01 ldr r3, [sp, #4] + 8005904: 4622 mov r2, r4 + 8005906: 4608 mov r0, r1 + 8005908: f7ff ffd5 bl 80058b6 + uECC_vli_modMult_fast(Y1, Y1, t1, curve); /* y1 * z^3 */ + 800590c: 9b01 ldr r3, [sp, #4] + 800590e: aa02 add r2, sp, #8 + 8005910: 4629 mov r1, r5 + 8005912: 4628 mov r0, r5 + 8005914: f7ff ffcf bl 80058b6 +} + 8005918: b00a add sp, #40 ; 0x28 + 800591a: bd70 pop {r4, r5, r6, pc} + +0800591c : + +#else + +uECC_VLI_API void uECC_vli_nativeToBytes(uint8_t *bytes, + int num_bytes, + const uECC_word_t *native) { + 800591c: b5f0 push {r4, r5, r6, r7, lr} + wordcount_t i; + for (i = 0; i < num_bytes; ++i) { + 800591e: 2500 movs r5, #0 + unsigned b = num_bytes - 1 - i; + 8005920: 1e4f subs r7, r1, #1 + 8005922: b26c sxtb r4, r5 + for (i = 0; i < num_bytes; ++i) { + 8005924: 428c cmp r4, r1 + 8005926: f105 0501 add.w r5, r5, #1 + 800592a: db00 blt.n 800592e + bytes[i] = native[b / uECC_WORD_SIZE] >> (8 * (b % uECC_WORD_SIZE)); + } +} + 800592c: bdf0 pop {r4, r5, r6, r7, pc} + unsigned b = num_bytes - 1 - i; + 800592e: 1b3b subs r3, r7, r4 + bytes[i] = native[b / uECC_WORD_SIZE] >> (8 * (b % uECC_WORD_SIZE)); + 8005930: f023 0603 bic.w r6, r3, #3 + 8005934: f003 0303 and.w r3, r3, #3 + 8005938: 5996 ldr r6, [r2, r6] + 800593a: 00db lsls r3, r3, #3 + 800593c: fa26 f303 lsr.w r3, r6, r3 + 8005940: 5503 strb r3, [r0, r4] + for (i = 0; i < num_bytes; ++i) { + 8005942: e7ee b.n 8005922 + +08005944 : + +uECC_VLI_API void uECC_vli_bytesToNative(uECC_word_t *native, + const uint8_t *bytes, + int num_bytes) { + 8005944: b5f8 push {r3, r4, r5, r6, r7, lr} + 8005946: 460e mov r6, r1 + wordcount_t i; + uECC_vli_clear(native, (num_bytes + (uECC_WORD_SIZE - 1)) / uECC_WORD_SIZE); + 8005948: 1cd1 adds r1, r2, #3 + 800594a: bf48 it mi + 800594c: 1d91 addmi r1, r2, #6 + int num_bytes) { + 800594e: 4614 mov r4, r2 + uECC_vli_clear(native, (num_bytes + (uECC_WORD_SIZE - 1)) / uECC_WORD_SIZE); + 8005950: f341 0187 sbfx r1, r1, #2, #8 + int num_bytes) { + 8005954: 4605 mov r5, r0 + for (i = 0; i < num_bytes; ++i) { + unsigned b = num_bytes - 1 - i; + 8005956: 1e67 subs r7, r4, #1 + uECC_vli_clear(native, (num_bytes + (uECC_WORD_SIZE - 1)) / uECC_WORD_SIZE); + 8005958: f7ff fea0 bl 800569c + for (i = 0; i < num_bytes; ++i) { + 800595c: 2000 movs r0, #0 + 800595e: b242 sxtb r2, r0 + 8005960: 42a2 cmp r2, r4 + 8005962: f100 0001 add.w r0, r0, #1 + 8005966: db00 blt.n 800596a + native[b / uECC_WORD_SIZE] |= + (uECC_word_t)bytes[i] << (8 * (b % uECC_WORD_SIZE)); + } +} + 8005968: bdf8 pop {r3, r4, r5, r6, r7, pc} + unsigned b = num_bytes - 1 - i; + 800596a: 1abb subs r3, r7, r2 + native[b / uECC_WORD_SIZE] |= + 800596c: f023 0103 bic.w r1, r3, #3 + (uECC_word_t)bytes[i] << (8 * (b % uECC_WORD_SIZE)); + 8005970: 5cb2 ldrb r2, [r6, r2] + 8005972: f003 0303 and.w r3, r3, #3 + 8005976: 00db lsls r3, r3, #3 + 8005978: fa02 f303 lsl.w r3, r2, r3 + native[b / uECC_WORD_SIZE] |= + 800597c: 586a ldr r2, [r5, r1] + 800597e: 431a orrs r2, r3 + 8005980: 506a str r2, [r5, r1] + for (i = 0; i < num_bytes; ++i) { + 8005982: e7ec b.n 800595e + +08005984 : + return 0; +} + +/* Compute an HMAC using K as a key (as in RFC 6979). Note that K is always + the same size as the hash result size. */ +static void HMAC_init(uECC_HashContext *hash_context, const uint8_t *K) { + 8005984: b570 push {r4, r5, r6, lr} + uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size; + 8005986: e9d0 3504 ldrd r3, r5, [r0, #16] +static void HMAC_init(uECC_HashContext *hash_context, const uint8_t *K) { + 800598a: 4604 mov r4, r0 + uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size; + 800598c: eb05 0543 add.w r5, r5, r3, lsl #1 + unsigned i; + for (i = 0; i < hash_context->result_size; ++i) + 8005990: 2300 movs r3, #0 + 8005992: 6922 ldr r2, [r4, #16] + 8005994: 429a cmp r2, r3 + 8005996: d80d bhi.n 80059b4 + pad[i] = K[i] ^ 0x36; + for (; i < hash_context->block_size; ++i) + pad[i] = 0x36; + 8005998: 2136 movs r1, #54 ; 0x36 + for (; i < hash_context->block_size; ++i) + 800599a: 68e2 ldr r2, [r4, #12] + 800599c: 429a cmp r2, r3 + 800599e: d80f bhi.n 80059c0 + + hash_context->init_hash(hash_context); + 80059a0: 6823 ldr r3, [r4, #0] + 80059a2: 4620 mov r0, r4 + 80059a4: 4798 blx r3 + hash_context->update_hash(hash_context, pad, hash_context->block_size); + 80059a6: 6863 ldr r3, [r4, #4] + 80059a8: 68e2 ldr r2, [r4, #12] + 80059aa: 4629 mov r1, r5 + 80059ac: 4620 mov r0, r4 +} + 80059ae: e8bd 4070 ldmia.w sp!, {r4, r5, r6, lr} + hash_context->update_hash(hash_context, pad, hash_context->block_size); + 80059b2: 4718 bx r3 + pad[i] = K[i] ^ 0x36; + 80059b4: 5cca ldrb r2, [r1, r3] + 80059b6: f082 0236 eor.w r2, r2, #54 ; 0x36 + 80059ba: 54ea strb r2, [r5, r3] + for (i = 0; i < hash_context->result_size; ++i) + 80059bc: 3301 adds r3, #1 + 80059be: e7e8 b.n 8005992 + pad[i] = 0x36; + 80059c0: 54e9 strb r1, [r5, r3] + for (; i < hash_context->block_size; ++i) + 80059c2: 3301 adds r3, #1 + 80059c4: e7e9 b.n 800599a + +080059c6 : + +static void HMAC_update(uECC_HashContext *hash_context, + const uint8_t *message, + unsigned message_size) { + hash_context->update_hash(hash_context, message, message_size); + 80059c6: 6843 ldr r3, [r0, #4] + 80059c8: 4718 bx r3 + +080059ca : +} + +static void HMAC_finish(uECC_HashContext *hash_context, const uint8_t *K, uint8_t *result) { + 80059ca: b570 push {r4, r5, r6, lr} + uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size; + 80059cc: e9d0 3604 ldrd r3, r6, [r0, #16] +static void HMAC_finish(uECC_HashContext *hash_context, const uint8_t *K, uint8_t *result) { + 80059d0: 4604 mov r4, r0 + uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size; + 80059d2: eb06 0643 add.w r6, r6, r3, lsl #1 +static void HMAC_finish(uECC_HashContext *hash_context, const uint8_t *K, uint8_t *result) { + 80059d6: 4615 mov r5, r2 + unsigned i; + for (i = 0; i < hash_context->result_size; ++i) + 80059d8: 2300 movs r3, #0 + 80059da: 6922 ldr r2, [r4, #16] + 80059dc: 429a cmp r2, r3 + 80059de: d81a bhi.n 8005a16 + pad[i] = K[i] ^ 0x5c; + for (; i < hash_context->block_size; ++i) + pad[i] = 0x5c; + 80059e0: 215c movs r1, #92 ; 0x5c + for (; i < hash_context->block_size; ++i) + 80059e2: 68e2 ldr r2, [r4, #12] + 80059e4: 429a cmp r2, r3 + 80059e6: d81c bhi.n 8005a22 + + hash_context->finish_hash(hash_context, result); + 80059e8: 4629 mov r1, r5 + 80059ea: 68a3 ldr r3, [r4, #8] + 80059ec: 4620 mov r0, r4 + 80059ee: 4798 blx r3 + + hash_context->init_hash(hash_context); + 80059f0: 6823 ldr r3, [r4, #0] + 80059f2: 4620 mov r0, r4 + 80059f4: 4798 blx r3 + hash_context->update_hash(hash_context, pad, hash_context->block_size); + 80059f6: 6863 ldr r3, [r4, #4] + 80059f8: 68e2 ldr r2, [r4, #12] + 80059fa: 4631 mov r1, r6 + 80059fc: 4620 mov r0, r4 + 80059fe: 4798 blx r3 + hash_context->update_hash(hash_context, result, hash_context->result_size); + 8005a00: 6863 ldr r3, [r4, #4] + 8005a02: 6922 ldr r2, [r4, #16] + 8005a04: 4629 mov r1, r5 + 8005a06: 4620 mov r0, r4 + 8005a08: 4798 blx r3 + hash_context->finish_hash(hash_context, result); + 8005a0a: 68a3 ldr r3, [r4, #8] + 8005a0c: 4629 mov r1, r5 + 8005a0e: 4620 mov r0, r4 +} + 8005a10: e8bd 4070 ldmia.w sp!, {r4, r5, r6, lr} + hash_context->finish_hash(hash_context, result); + 8005a14: 4718 bx r3 + pad[i] = K[i] ^ 0x5c; + 8005a16: 5cca ldrb r2, [r1, r3] + 8005a18: f082 025c eor.w r2, r2, #92 ; 0x5c + 8005a1c: 54f2 strb r2, [r6, r3] + for (i = 0; i < hash_context->result_size; ++i) + 8005a1e: 3301 adds r3, #1 + 8005a20: e7db b.n 80059da + pad[i] = 0x5c; + 8005a22: 54f1 strb r1, [r6, r3] + for (; i < hash_context->block_size; ++i) + 8005a24: 3301 adds r3, #1 + 8005a26: e7dc b.n 80059e2 + +08005a28 : + +/* V = HMAC_K(V) */ +static void update_V(uECC_HashContext *hash_context, uint8_t *K, uint8_t *V) { + 8005a28: b570 push {r4, r5, r6, lr} + 8005a2a: 4604 mov r4, r0 + 8005a2c: 4615 mov r5, r2 + 8005a2e: 460e mov r6, r1 + HMAC_init(hash_context, K); + 8005a30: f7ff ffa8 bl 8005984 + HMAC_update(hash_context, V, hash_context->result_size); + 8005a34: 6922 ldr r2, [r4, #16] + 8005a36: 4629 mov r1, r5 + 8005a38: 4620 mov r0, r4 + 8005a3a: f7ff ffc4 bl 80059c6 + HMAC_finish(hash_context, K, V); + 8005a3e: 462a mov r2, r5 + 8005a40: 4631 mov r1, r6 + 8005a42: 4620 mov r0, r4 +} + 8005a44: e8bd 4070 ldmia.w sp!, {r4, r5, r6, lr} + HMAC_finish(hash_context, K, V); + 8005a48: f7ff bfbf b.w 80059ca + +08005a4c : +uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result, + 8005a4c: b530 push {r4, r5, lr} + __asm__ volatile ( + 8005a4e: 2300 movs r3, #0 + 8005a50: c910 ldmia r1!, {r4} + 8005a52: ca20 ldmia r2!, {r5} + 8005a54: 1b64 subs r4, r4, r5 + 8005a56: c010 stmia r0!, {r4} + 8005a58: c910 ldmia r1!, {r4} + 8005a5a: ca20 ldmia r2!, {r5} + 8005a5c: 41ac sbcs r4, r5 + 8005a5e: c010 stmia r0!, {r4} + 8005a60: c910 ldmia r1!, {r4} + 8005a62: ca20 ldmia r2!, {r5} + 8005a64: 41ac sbcs r4, r5 + 8005a66: c010 stmia r0!, {r4} + 8005a68: c910 ldmia r1!, {r4} + 8005a6a: ca20 ldmia r2!, {r5} + 8005a6c: 41ac sbcs r4, r5 + 8005a6e: c010 stmia r0!, {r4} + 8005a70: c910 ldmia r1!, {r4} + 8005a72: ca20 ldmia r2!, {r5} + 8005a74: 41ac sbcs r4, r5 + 8005a76: c010 stmia r0!, {r4} + 8005a78: c910 ldmia r1!, {r4} + 8005a7a: ca20 ldmia r2!, {r5} + 8005a7c: 41ac sbcs r4, r5 + 8005a7e: c010 stmia r0!, {r4} + 8005a80: c910 ldmia r1!, {r4} + 8005a82: ca20 ldmia r2!, {r5} + 8005a84: 41ac sbcs r4, r5 + 8005a86: c010 stmia r0!, {r4} + 8005a88: c910 ldmia r1!, {r4} + 8005a8a: ca20 ldmia r2!, {r5} + 8005a8c: 41ac sbcs r4, r5 + 8005a8e: c010 stmia r0!, {r4} + 8005a90: 415b adcs r3, r3 +} + 8005a92: fab3 f083 clz r0, r3 + 8005a96: 0940 lsrs r0, r0, #5 + 8005a98: bd30 pop {r4, r5, pc} + +08005a9a : + uECC_Curve curve) { + 8005a9a: e92d 43f8 stmdb sp!, {r3, r4, r5, r6, r7, r8, r9, lr} + 8005a9e: 4698 mov r8, r3 + unsigned num_n_bytes = BITS_TO_BYTES(curve->num_n_bits); + 8005aa0: f9b3 3002 ldrsh.w r3, [r3, #2] + unsigned num_n_words = BITS_TO_WORDS(curve->num_n_bits); + 8005aa4: f113 041f adds.w r4, r3, #31 + 8005aa8: bf48 it mi + 8005aaa: f103 043e addmi.w r4, r3, #62 ; 0x3e + unsigned num_n_bytes = BITS_TO_BYTES(curve->num_n_bits); + 8005aae: 1ddd adds r5, r3, #7 + 8005ab0: bf48 it mi + 8005ab2: f103 050e addmi.w r5, r3, #14 + unsigned num_n_words = BITS_TO_WORDS(curve->num_n_bits); + 8005ab6: 1166 asrs r6, r4, #5 + unsigned num_n_bytes = BITS_TO_BYTES(curve->num_n_bits); + 8005ab8: 10ec asrs r4, r5, #3 + 8005aba: 4294 cmp r4, r2 + uECC_vli_clear(native, num_n_words); + 8005abc: b275 sxtb r5, r6 + 8005abe: bf28 it cs + 8005ac0: 4614 movcs r4, r2 + uECC_Curve curve) { + 8005ac2: 4607 mov r7, r0 + 8005ac4: 4689 mov r9, r1 + uECC_vli_clear(native, num_n_words); + 8005ac6: 4629 mov r1, r5 + 8005ac8: f7ff fde8 bl 800569c + uECC_vli_bytesToNative(native, bits, bits_size); + 8005acc: 4622 mov r2, r4 + 8005ace: 4649 mov r1, r9 + 8005ad0: 4638 mov r0, r7 + 8005ad2: f7ff ff37 bl 8005944 + if (bits_size * 8 <= (unsigned)curve->num_n_bits) { + 8005ad6: f9b8 2002 ldrsh.w r2, [r8, #2] + 8005ada: ebb2 0fc4 cmp.w r2, r4, lsl #3 + 8005ade: ea4f 03c4 mov.w r3, r4, lsl #3 + 8005ae2: d21f bcs.n 8005b24 + int shift = bits_size * 8 - curve->num_n_bits; + 8005ae4: 1a9b subs r3, r3, r2 + uECC_word_t *ptr = native + num_n_words; + 8005ae6: eb07 0486 add.w r4, r7, r6, lsl #2 + uECC_word_t carry = 0; + 8005aea: 2100 movs r1, #0 + carry = temp << (uECC_WORD_BITS - shift); + 8005aec: f1c3 0620 rsb r6, r3, #32 + while (ptr-- > native) { + 8005af0: 42a7 cmp r7, r4 + 8005af2: d30e bcc.n 8005b12 + if (uECC_vli_cmp_unsafe(curve->n, native, num_n_words) != 1) { + 8005af4: f108 0824 add.w r8, r8, #36 ; 0x24 + 8005af8: 462a mov r2, r5 + 8005afa: 4639 mov r1, r7 + 8005afc: 4640 mov r0, r8 + 8005afe: f7ff fe18 bl 8005732 + 8005b02: 2801 cmp r0, #1 + 8005b04: d00e beq.n 8005b24 + uECC_vli_sub(native, native, curve->n, num_n_words); + 8005b06: 4642 mov r2, r8 + 8005b08: 4638 mov r0, r7 +} + 8005b0a: e8bd 43f8 ldmia.w sp!, {r3, r4, r5, r6, r7, r8, r9, lr} + uECC_vli_sub(native, native, curve->n, num_n_words); + 8005b0e: f7ff bf9d b.w 8005a4c + uECC_word_t temp = *ptr; + 8005b12: f854 0d04 ldr.w r0, [r4, #-4]! + *ptr = (temp >> shift) | carry; + 8005b16: fa20 f203 lsr.w r2, r0, r3 + 8005b1a: 430a orrs r2, r1 + 8005b1c: 6022 str r2, [r4, #0] + carry = temp << (uECC_WORD_BITS - shift); + 8005b1e: fa00 f106 lsl.w r1, r0, r6 + 8005b22: e7e5 b.n 8005af0 +} + 8005b24: e8bd 83f8 ldmia.w sp!, {r3, r4, r5, r6, r7, r8, r9, pc} + +08005b28 : + wordcount_t num_words) { + 8005b28: b530 push {r4, r5, lr} + 8005b2a: b089 sub sp, #36 ; 0x24 + 8005b2c: 4615 mov r5, r2 + uECC_word_t neg = !!uECC_vli_sub(tmp, left, right, num_words); + 8005b2e: 460a mov r2, r1 + 8005b30: 4601 mov r1, r0 + 8005b32: 4668 mov r0, sp + 8005b34: f7ff ff8a bl 8005a4c + uECC_word_t equal = uECC_vli_isZero(tmp, num_words); + 8005b38: 4629 mov r1, r5 + uECC_word_t neg = !!uECC_vli_sub(tmp, left, right, num_words); + 8005b3a: 4604 mov r4, r0 + uECC_word_t equal = uECC_vli_isZero(tmp, num_words); + 8005b3c: 4668 mov r0, sp + 8005b3e: f7ff fdb3 bl 80056a8 + uECC_word_t neg = !!uECC_vli_sub(tmp, left, right, num_words); + 8005b42: 3c00 subs r4, #0 + 8005b44: bf18 it ne + 8005b46: 2401 movne r4, #1 + return (!equal - 2 * neg); + 8005b48: 0064 lsls r4, r4, #1 +} + 8005b4a: 2800 cmp r0, #0 + 8005b4c: bf14 ite ne + 8005b4e: 4260 negne r0, r4 + 8005b50: f1c4 0001 rsbeq r0, r4, #1 + 8005b54: b009 add sp, #36 ; 0x24 + 8005b56: bd30 pop {r4, r5, pc} + +08005b58 : + wordcount_t num_words) { + 8005b58: e92d 4ff8 stmdb sp!, {r3, r4, r5, r6, r7, r8, r9, sl, fp, lr} + 8005b5c: 460f mov r7, r1 + if (!g_rng_function) { + 8005b5e: f8df a06c ldr.w sl, [pc, #108] ; 8005bcc + wordcount_t num_words) { + 8005b62: 4606 mov r6, r0 + bitcount_t num_bits = uECC_vli_numBits(top, num_words); + 8005b64: 4611 mov r1, r2 + 8005b66: 4638 mov r0, r7 + wordcount_t num_words) { + 8005b68: 4614 mov r4, r2 + bitcount_t num_bits = uECC_vli_numBits(top, num_words); + 8005b6a: f7ff fdb6 bl 80056da + if (!g_rng_function) { + 8005b6e: f8da 3000 ldr.w r3, [sl] + 8005b72: b303 cbz r3, 8005bb6 + if (!g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE)) { + 8005b74: 2504 movs r5, #4 + random[num_words - 1] &= mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits)); + 8005b76: ebc0 1044 rsb r0, r0, r4, lsl #5 + if (!g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE)) { + 8005b7a: fb14 fb05 smulbb fp, r4, r5 + random[num_words - 1] &= mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits)); + 8005b7e: b200 sxth r0, r0 + 8005b80: fb05 6504 mla r5, r5, r4, r6 + 8005b84: f04f 38ff mov.w r8, #4294967295 ; 0xffffffff + 8005b88: 3d04 subs r5, #4 + 8005b8a: fa28 f800 lsr.w r8, r8, r0 + 8005b8e: f04f 0940 mov.w r9, #64 ; 0x40 + if (!g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE)) { + 8005b92: f8da 3000 ldr.w r3, [sl] + 8005b96: 4659 mov r1, fp + 8005b98: 4630 mov r0, r6 + 8005b9a: 4798 blx r3 + 8005b9c: b158 cbz r0, 8005bb6 + random[num_words - 1] &= mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits)); + 8005b9e: 682b ldr r3, [r5, #0] + 8005ba0: ea03 0308 and.w r3, r3, r8 + 8005ba4: 602b str r3, [r5, #0] + if (!uECC_vli_isZero(random, num_words) && + 8005ba6: 4621 mov r1, r4 + 8005ba8: 4630 mov r0, r6 + 8005baa: f7ff fd7d bl 80056a8 + 8005bae: b120 cbz r0, 8005bba + for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { + 8005bb0: f1b9 0901 subs.w r9, r9, #1 + 8005bb4: d1ed bne.n 8005b92 + return 0; + 8005bb6: 2000 movs r0, #0 + 8005bb8: e006 b.n 8005bc8 + uECC_vli_cmp(top, random, num_words) == 1) { + 8005bba: 4622 mov r2, r4 + 8005bbc: 4631 mov r1, r6 + 8005bbe: 4638 mov r0, r7 + 8005bc0: f7ff ffb2 bl 8005b28 + if (!uECC_vli_isZero(random, num_words) && + 8005bc4: 2801 cmp r0, #1 + 8005bc6: d1f3 bne.n 8005bb0 +} + 8005bc8: e8bd 8ff8 ldmia.w sp!, {r3, r4, r5, r6, r7, r8, r9, sl, fp, pc} + 8005bcc: 2009e2a0 .word 0x2009e2a0 + +08005bd0 : +uECC_VLI_API uECC_word_t uECC_vli_add(uECC_word_t *result, + 8005bd0: b530 push {r4, r5, lr} + __asm__ volatile ( + 8005bd2: 4603 mov r3, r0 + 8005bd4: 2000 movs r0, #0 + 8005bd6: c910 ldmia r1!, {r4} + 8005bd8: ca20 ldmia r2!, {r5} + 8005bda: 1964 adds r4, r4, r5 + 8005bdc: c310 stmia r3!, {r4} + 8005bde: c910 ldmia r1!, {r4} + 8005be0: ca20 ldmia r2!, {r5} + 8005be2: 416c adcs r4, r5 + 8005be4: c310 stmia r3!, {r4} + 8005be6: c910 ldmia r1!, {r4} + 8005be8: ca20 ldmia r2!, {r5} + 8005bea: 416c adcs r4, r5 + 8005bec: c310 stmia r3!, {r4} + 8005bee: c910 ldmia r1!, {r4} + 8005bf0: ca20 ldmia r2!, {r5} + 8005bf2: 416c adcs r4, r5 + 8005bf4: c310 stmia r3!, {r4} + 8005bf6: c910 ldmia r1!, {r4} + 8005bf8: ca20 ldmia r2!, {r5} + 8005bfa: 416c adcs r4, r5 + 8005bfc: c310 stmia r3!, {r4} + 8005bfe: c910 ldmia r1!, {r4} + 8005c00: ca20 ldmia r2!, {r5} + 8005c02: 416c adcs r4, r5 + 8005c04: c310 stmia r3!, {r4} + 8005c06: c910 ldmia r1!, {r4} + 8005c08: ca20 ldmia r2!, {r5} + 8005c0a: 416c adcs r4, r5 + 8005c0c: c310 stmia r3!, {r4} + 8005c0e: c910 ldmia r1!, {r4} + 8005c10: ca20 ldmia r2!, {r5} + 8005c12: 416c adcs r4, r5 + 8005c14: c310 stmia r3!, {r4} + 8005c16: 4140 adcs r0, r0 +} + 8005c18: bd30 pop {r4, r5, pc} + +08005c1a : + uECC_Curve curve) { + 8005c1a: b573 push {r0, r1, r4, r5, r6, lr} + 8005c1c: 460d mov r5, r1 + 8005c1e: 4616 mov r6, r2 + uECC_word_t carry = uECC_vli_add(k0, k, curve->n, num_n_words) || + 8005c20: 4601 mov r1, r0 + 8005c22: f103 0224 add.w r2, r3, #36 ; 0x24 + 8005c26: 4628 mov r0, r5 + 8005c28: 9201 str r2, [sp, #4] + wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); + 8005c2a: f9b3 4002 ldrsh.w r4, [r3, #2] + uECC_word_t carry = uECC_vli_add(k0, k, curve->n, num_n_words) || + 8005c2e: f7ff ffcf bl 8005bd0 + 8005c32: 9a01 ldr r2, [sp, #4] + 8005c34: b9c8 cbnz r0, 8005c6a + wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); + 8005c36: f114 031f adds.w r3, r4, #31 + 8005c3a: bf48 it mi + 8005c3c: f104 033e addmi.w r3, r4, #62 ; 0x3e + (num_n_bits < ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8) && + 8005c40: f343 1347 sbfx r3, r3, #5, #8 + uECC_word_t carry = uECC_vli_add(k0, k, curve->n, num_n_words) || + 8005c44: ebb4 1f43 cmp.w r4, r3, lsl #5 + 8005c48: da11 bge.n 8005c6e + uECC_vli_testBit(k0, num_n_bits)); + 8005c4a: 4621 mov r1, r4 + 8005c4c: 4628 mov r0, r5 + 8005c4e: 9201 str r2, [sp, #4] + 8005c50: f7ff fd39 bl 80056c6 + 8005c54: 9a01 ldr r2, [sp, #4] + (num_n_bits < ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8) && + 8005c56: 1e04 subs r4, r0, #0 + 8005c58: bf18 it ne + 8005c5a: 2401 movne r4, #1 + uECC_vli_add(k1, k0, curve->n, num_n_words); + 8005c5c: 4629 mov r1, r5 + 8005c5e: 4630 mov r0, r6 + 8005c60: f7ff ffb6 bl 8005bd0 +} + 8005c64: 4620 mov r0, r4 + 8005c66: b002 add sp, #8 + 8005c68: bd70 pop {r4, r5, r6, pc} + uECC_word_t carry = uECC_vli_add(k0, k, curve->n, num_n_words) || + 8005c6a: 2401 movs r4, #1 + 8005c6c: e7f6 b.n 8005c5c + 8005c6e: 2400 movs r4, #0 + 8005c70: e7f4 b.n 8005c5c + +08005c72 : + /* add the 2^32 multiple */ + result[4 + num_words_secp256k1] = + uECC_vli_add(result + 4, result + 4, right, num_words_secp256k1); +} +#elif uECC_WORD_SIZE == 4 +static void omega_mult_secp256k1(uint32_t * result, const uint32_t * right) { + 8005c72: b5f8 push {r3, r4, r5, r6, r7, lr} + 8005c74: 460a mov r2, r1 + /* Multiply by (2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */ + uint32_t carry = 0; + 8005c76: 2300 movs r3, #0 +static void omega_mult_secp256k1(uint32_t * result, const uint32_t * right) { + 8005c78: 4604 mov r4, r0 + 8005c7a: 3904 subs r1, #4 + 8005c7c: 3804 subs r0, #4 + 8005c7e: f102 071c add.w r7, r2, #28 + wordcount_t k; + + for (k = 0; k < num_words_secp256k1; ++k) { + uint64_t p = (uint64_t)0x3D1 * right[k] + carry; + 8005c82: 469e mov lr, r3 + 8005c84: f240 35d1 movw r5, #977 ; 0x3d1 + 8005c88: f851 6f04 ldr.w r6, [r1, #4]! + 8005c8c: 46f4 mov ip, lr + 8005c8e: fbe6 3c05 umlal r3, ip, r6, r5 + for (k = 0; k < num_words_secp256k1; ++k) { + 8005c92: 428f cmp r7, r1 + result[k] = p; + 8005c94: f840 3f04 str.w r3, [r0, #4]! + carry = p >> 32; + 8005c98: 4663 mov r3, ip + for (k = 0; k < num_words_secp256k1; ++k) { + 8005c9a: d1f5 bne.n 8005c88 + } + result[num_words_secp256k1] = carry; + /* add the 2^32 multiple */ + result[1 + num_words_secp256k1] = + uECC_vli_add(result + 1, result + 1, right, num_words_secp256k1); + 8005c9c: 1d21 adds r1, r4, #4 + result[num_words_secp256k1] = carry; + 8005c9e: f8c4 c020 str.w ip, [r4, #32] + uECC_vli_add(result + 1, result + 1, right, num_words_secp256k1); + 8005ca2: 4608 mov r0, r1 + 8005ca4: f7ff ff94 bl 8005bd0 + result[1 + num_words_secp256k1] = + 8005ca8: 6260 str r0, [r4, #36] ; 0x24 +} + 8005caa: bdf8 pop {r3, r4, r5, r6, r7, pc} + +08005cac : +static void vli_mmod_fast_secp256k1(uECC_word_t *result, uECC_word_t *product) { + 8005cac: b570 push {r4, r5, r6, lr} + 8005cae: b090 sub sp, #64 ; 0x40 + 8005cb0: 460e mov r6, r1 + 8005cb2: 4604 mov r4, r0 + uECC_vli_clear(tmp, num_words_secp256k1); + 8005cb4: 2108 movs r1, #8 + 8005cb6: 4668 mov r0, sp + 8005cb8: f7ff fcf0 bl 800569c + uECC_vli_clear(tmp + num_words_secp256k1, num_words_secp256k1); + 8005cbc: 2108 movs r1, #8 + 8005cbe: a808 add r0, sp, #32 + 8005cc0: f7ff fcec bl 800569c + omega_mult_secp256k1(tmp, product + num_words_secp256k1); /* (Rq, q) = q * c */ + 8005cc4: f106 0120 add.w r1, r6, #32 + 8005cc8: 4668 mov r0, sp + 8005cca: f7ff ffd2 bl 8005c72 + carry = uECC_vli_add(result, product, tmp, num_words_secp256k1); /* (C, r) = r + q */ + 8005cce: 466a mov r2, sp + 8005cd0: 4631 mov r1, r6 + 8005cd2: 4620 mov r0, r4 + 8005cd4: f7ff ff7c bl 8005bd0 + uECC_vli_clear(product, num_words_secp256k1); + 8005cd8: 2108 movs r1, #8 + carry = uECC_vli_add(result, product, tmp, num_words_secp256k1); /* (C, r) = r + q */ + 8005cda: 4605 mov r5, r0 + uECC_vli_clear(product, num_words_secp256k1); + 8005cdc: 4630 mov r0, r6 + 8005cde: f7ff fcdd bl 800569c + omega_mult_secp256k1(product, tmp + num_words_secp256k1); /* Rq*c */ + 8005ce2: 4630 mov r0, r6 + 8005ce4: a908 add r1, sp, #32 + 8005ce6: f7ff ffc4 bl 8005c72 + carry += uECC_vli_add(result, result, product, num_words_secp256k1); /* (C1, r) = r + Rq*c */ + 8005cea: 4632 mov r2, r6 + 8005cec: 4621 mov r1, r4 + 8005cee: 4620 mov r0, r4 + 8005cf0: f7ff ff6e bl 8005bd0 + uECC_vli_sub(result, result, curve_secp256k1.p, num_words_secp256k1); + 8005cf4: 4e0b ldr r6, [pc, #44] ; (8005d24 ) + carry += uECC_vli_add(result, result, product, num_words_secp256k1); /* (C1, r) = r + Rq*c */ + 8005cf6: 4405 add r5, r0 + while (carry > 0) { + 8005cf8: b96d cbnz r5, 8005d16 + if (uECC_vli_cmp_unsafe(result, curve_secp256k1.p, num_words_secp256k1) > 0) { + 8005cfa: 490a ldr r1, [pc, #40] ; (8005d24 ) + 8005cfc: 2208 movs r2, #8 + 8005cfe: 4620 mov r0, r4 + 8005d00: f7ff fd17 bl 8005732 + 8005d04: 2800 cmp r0, #0 + 8005d06: dd04 ble.n 8005d12 + uECC_vli_sub(result, result, curve_secp256k1.p, num_words_secp256k1); + 8005d08: 460a mov r2, r1 + 8005d0a: 4620 mov r0, r4 + 8005d0c: 4621 mov r1, r4 + 8005d0e: f7ff fe9d bl 8005a4c +} + 8005d12: b010 add sp, #64 ; 0x40 + 8005d14: bd70 pop {r4, r5, r6, pc} + uECC_vli_sub(result, result, curve_secp256k1.p, num_words_secp256k1); + 8005d16: 4632 mov r2, r6 + 8005d18: 4621 mov r1, r4 + 8005d1a: 4620 mov r0, r4 + --carry; + 8005d1c: 3d01 subs r5, #1 + uECC_vli_sub(result, result, curve_secp256k1.p, num_words_secp256k1); + 8005d1e: f7ff fe95 bl 8005a4c + 8005d22: e7e9 b.n 8005cf8 + 8005d24: 0800e878 .word 0x0800e878 + +08005d28 : +static void vli_mmod_fast_secp256r1(uint32_t *result, uint32_t *product) { + 8005d28: e92d 44f0 stmdb sp!, {r4, r5, r6, r7, sl, lr} + uECC_vli_set(result, product, num_words_secp256r1); + 8005d2c: 2208 movs r2, #8 +static void vli_mmod_fast_secp256r1(uint32_t *result, uint32_t *product) { + 8005d2e: b088 sub sp, #32 + uECC_vli_set(result, product, num_words_secp256r1); + 8005d30: f7ff fcf3 bl 800571a + tmp[3] = product[11]; + 8005d34: 6acb ldr r3, [r1, #44] ; 0x2c + 8005d36: 9303 str r3, [sp, #12] + tmp[4] = product[12]; + 8005d38: 6b0b ldr r3, [r1, #48] ; 0x30 + 8005d3a: 9304 str r3, [sp, #16] + tmp[5] = product[13]; + 8005d3c: 6b4b ldr r3, [r1, #52] ; 0x34 + 8005d3e: 9305 str r3, [sp, #20] + tmp[6] = product[14]; + 8005d40: 6b8b ldr r3, [r1, #56] ; 0x38 + 8005d42: 9306 str r3, [sp, #24] +static void vli_mmod_fast_secp256r1(uint32_t *result, uint32_t *product) { + 8005d44: 460c mov r4, r1 + 8005d46: 4682 mov sl, r0 + tmp[0] = tmp[1] = tmp[2] = 0; + 8005d48: 2700 movs r7, #0 + tmp[7] = product[15]; + 8005d4a: 6bcb ldr r3, [r1, #60] ; 0x3c + 8005d4c: 9307 str r3, [sp, #28] + carry = uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); + 8005d4e: 466a mov r2, sp + 8005d50: 4669 mov r1, sp + 8005d52: 4668 mov r0, sp + tmp[0] = tmp[1] = tmp[2] = 0; + 8005d54: e9cd 7701 strd r7, r7, [sp, #4] + 8005d58: 9700 str r7, [sp, #0] + carry = uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); + 8005d5a: f7ff ff39 bl 8005bd0 + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + 8005d5e: 466a mov r2, sp + carry = uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); + 8005d60: 4605 mov r5, r0 + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + 8005d62: 4651 mov r1, sl + 8005d64: 4650 mov r0, sl + 8005d66: f7ff ff33 bl 8005bd0 + tmp[3] = product[12]; + 8005d6a: 6b23 ldr r3, [r4, #48] ; 0x30 + 8005d6c: 9303 str r3, [sp, #12] + tmp[4] = product[13]; + 8005d6e: 6b63 ldr r3, [r4, #52] ; 0x34 + 8005d70: 9304 str r3, [sp, #16] + tmp[5] = product[14]; + 8005d72: 6ba3 ldr r3, [r4, #56] ; 0x38 + 8005d74: 9305 str r3, [sp, #20] + tmp[6] = product[15]; + 8005d76: 6be3 ldr r3, [r4, #60] ; 0x3c + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + 8005d78: 4405 add r5, r0 + carry += uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); + 8005d7a: 466a mov r2, sp + 8005d7c: 4669 mov r1, sp + 8005d7e: 4668 mov r0, sp + tmp[7] = 0; + 8005d80: e9cd 3706 strd r3, r7, [sp, #24] + carry += uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); + 8005d84: f7ff ff24 bl 8005bd0 + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + 8005d88: 466a mov r2, sp + carry += uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); + 8005d8a: 4405 add r5, r0 + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + 8005d8c: 4651 mov r1, sl + 8005d8e: 4650 mov r0, sl + 8005d90: f7ff ff1e bl 8005bd0 + tmp[0] = product[8]; + 8005d94: 6a23 ldr r3, [r4, #32] + 8005d96: 9300 str r3, [sp, #0] + tmp[1] = product[9]; + 8005d98: 6a63 ldr r3, [r4, #36] ; 0x24 + 8005d9a: 9301 str r3, [sp, #4] + tmp[2] = product[10]; + 8005d9c: 6aa3 ldr r3, [r4, #40] ; 0x28 + 8005d9e: 9302 str r3, [sp, #8] + tmp[6] = product[14]; + 8005da0: 6ba3 ldr r3, [r4, #56] ; 0x38 + 8005da2: 9306 str r3, [sp, #24] + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + 8005da4: 4405 add r5, r0 + tmp[7] = product[15]; + 8005da6: 6be3 ldr r3, [r4, #60] ; 0x3c + 8005da8: 9307 str r3, [sp, #28] + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + 8005daa: 466a mov r2, sp + 8005dac: 4651 mov r1, sl + 8005dae: 4650 mov r0, sl + tmp[3] = tmp[4] = tmp[5] = 0; + 8005db0: e9cd 7704 strd r7, r7, [sp, #16] + 8005db4: 9703 str r7, [sp, #12] + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + 8005db6: f7ff ff0b bl 8005bd0 + tmp[0] = product[9]; + 8005dba: 6a63 ldr r3, [r4, #36] ; 0x24 + 8005dbc: 9300 str r3, [sp, #0] + tmp[1] = product[10]; + 8005dbe: 6aa3 ldr r3, [r4, #40] ; 0x28 + tmp[4] = product[14]; + 8005dc0: 6ba2 ldr r2, [r4, #56] ; 0x38 + tmp[1] = product[10]; + 8005dc2: 9301 str r3, [sp, #4] + tmp[2] = product[11]; + 8005dc4: 6ae3 ldr r3, [r4, #44] ; 0x2c + 8005dc6: 9302 str r3, [sp, #8] + tmp[4] = product[14]; + 8005dc8: 9204 str r2, [sp, #16] + tmp[3] = product[13]; + 8005dca: 6b63 ldr r3, [r4, #52] ; 0x34 + tmp[5] = product[15]; + 8005dcc: 6be2 ldr r2, [r4, #60] ; 0x3c + tmp[3] = product[13]; + 8005dce: 9303 str r3, [sp, #12] + tmp[6] = product[13]; + 8005dd0: e9cd 2305 strd r2, r3, [sp, #20] + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + 8005dd4: 182e adds r6, r5, r0 + tmp[7] = product[8]; + 8005dd6: 6a23 ldr r3, [r4, #32] + 8005dd8: 9307 str r3, [sp, #28] + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + 8005dda: 466a mov r2, sp + 8005ddc: 4651 mov r1, sl + 8005dde: 4650 mov r0, sl + 8005de0: f7ff fef6 bl 8005bd0 + tmp[0] = product[11]; + 8005de4: 6ae3 ldr r3, [r4, #44] ; 0x2c + 8005de6: 9300 str r3, [sp, #0] + tmp[1] = product[12]; + 8005de8: 6b23 ldr r3, [r4, #48] ; 0x30 + 8005dea: 9301 str r3, [sp, #4] + tmp[2] = product[13]; + 8005dec: 6b63 ldr r3, [r4, #52] ; 0x34 + 8005dee: 9302 str r3, [sp, #8] + tmp[6] = product[8]; + 8005df0: 6a23 ldr r3, [r4, #32] + 8005df2: 9306 str r3, [sp, #24] + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + 8005df4: 1835 adds r5, r6, r0 + tmp[7] = product[10]; + 8005df6: 6aa3 ldr r3, [r4, #40] ; 0x28 + 8005df8: 9307 str r3, [sp, #28] + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + 8005dfa: 466a mov r2, sp + 8005dfc: 4651 mov r1, sl + 8005dfe: 4650 mov r0, sl + tmp[3] = tmp[4] = tmp[5] = 0; + 8005e00: e9cd 7704 strd r7, r7, [sp, #16] + 8005e04: 9703 str r7, [sp, #12] + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + 8005e06: f7ff fe21 bl 8005a4c + tmp[0] = product[12]; + 8005e0a: 6b23 ldr r3, [r4, #48] ; 0x30 + 8005e0c: 9300 str r3, [sp, #0] + tmp[1] = product[13]; + 8005e0e: 6b63 ldr r3, [r4, #52] ; 0x34 + 8005e10: 9301 str r3, [sp, #4] + tmp[2] = product[14]; + 8005e12: 6ba3 ldr r3, [r4, #56] ; 0x38 + 8005e14: 9302 str r3, [sp, #8] + tmp[3] = product[15]; + 8005e16: 6be3 ldr r3, [r4, #60] ; 0x3c + 8005e18: 9303 str r3, [sp, #12] + tmp[6] = product[9]; + 8005e1a: 6a63 ldr r3, [r4, #36] ; 0x24 + 8005e1c: 9306 str r3, [sp, #24] + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + 8005e1e: 1a2e subs r6, r5, r0 + tmp[7] = product[11]; + 8005e20: 6ae3 ldr r3, [r4, #44] ; 0x2c + 8005e22: 9307 str r3, [sp, #28] + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + 8005e24: 466a mov r2, sp + 8005e26: 4651 mov r1, sl + 8005e28: 4650 mov r0, sl + tmp[4] = tmp[5] = 0; + 8005e2a: e9cd 7704 strd r7, r7, [sp, #16] + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + 8005e2e: f7ff fe0d bl 8005a4c + tmp[0] = product[13]; + 8005e32: 6b63 ldr r3, [r4, #52] ; 0x34 + 8005e34: 9300 str r3, [sp, #0] + tmp[1] = product[14]; + 8005e36: 6ba3 ldr r3, [r4, #56] ; 0x38 + 8005e38: 9301 str r3, [sp, #4] + tmp[2] = product[15]; + 8005e3a: 6be3 ldr r3, [r4, #60] ; 0x3c + 8005e3c: 9302 str r3, [sp, #8] + tmp[3] = product[8]; + 8005e3e: 6a23 ldr r3, [r4, #32] + 8005e40: 9303 str r3, [sp, #12] + tmp[4] = product[9]; + 8005e42: 6a63 ldr r3, [r4, #36] ; 0x24 + 8005e44: 9304 str r3, [sp, #16] + tmp[5] = product[10]; + 8005e46: 6aa3 ldr r3, [r4, #40] ; 0x28 + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + 8005e48: 1a36 subs r6, r6, r0 + tmp[6] = 0; + 8005e4a: e9cd 3705 strd r3, r7, [sp, #20] + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + 8005e4e: 466a mov r2, sp + tmp[7] = product[12]; + 8005e50: 6b23 ldr r3, [r4, #48] ; 0x30 + 8005e52: 9307 str r3, [sp, #28] + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + 8005e54: 4651 mov r1, sl + 8005e56: 4650 mov r0, sl + 8005e58: f7ff fdf8 bl 8005a4c + tmp[0] = product[14]; + 8005e5c: 6ba3 ldr r3, [r4, #56] ; 0x38 + 8005e5e: 9300 str r3, [sp, #0] + tmp[1] = product[15]; + 8005e60: 6be3 ldr r3, [r4, #60] ; 0x3c + tmp[2] = 0; + 8005e62: e9cd 3701 strd r3, r7, [sp, #4] + tmp[3] = product[9]; + 8005e66: 6a63 ldr r3, [r4, #36] ; 0x24 + 8005e68: 9303 str r3, [sp, #12] + tmp[4] = product[10]; + 8005e6a: 6aa3 ldr r3, [r4, #40] ; 0x28 + 8005e6c: 9304 str r3, [sp, #16] + tmp[5] = product[11]; + 8005e6e: 6ae3 ldr r3, [r4, #44] ; 0x2c + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + 8005e70: 1a36 subs r6, r6, r0 + tmp[6] = 0; + 8005e72: e9cd 3705 strd r3, r7, [sp, #20] + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + 8005e76: 466a mov r2, sp + tmp[7] = product[13]; + 8005e78: 6b63 ldr r3, [r4, #52] ; 0x34 + 8005e7a: 9307 str r3, [sp, #28] + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + 8005e7c: 4651 mov r1, sl + 8005e7e: 4650 mov r0, sl + 8005e80: f7ff fde4 bl 8005a4c + if (carry < 0) { + 8005e84: 1a36 subs r6, r6, r0 + carry += uECC_vli_add(result, result, curve_secp256r1.p, num_words_secp256r1); + 8005e86: 4c0d ldr r4, [pc, #52] ; (8005ebc ) + if (carry < 0) { + 8005e88: d40e bmi.n 8005ea8 + while (carry || uECC_vli_cmp_unsafe(curve_secp256r1.p, result, num_words_secp256r1) != 1) { + 8005e8a: b936 cbnz r6, 8005e9a + 8005e8c: 2208 movs r2, #8 + 8005e8e: 4651 mov r1, sl + 8005e90: 4620 mov r0, r4 + 8005e92: f7ff fc4e bl 8005732 + 8005e96: 2801 cmp r0, #1 + 8005e98: d00d beq.n 8005eb6 + carry -= uECC_vli_sub(result, result, curve_secp256r1.p, num_words_secp256r1); + 8005e9a: 4622 mov r2, r4 + 8005e9c: 4651 mov r1, sl + 8005e9e: 4650 mov r0, sl + 8005ea0: f7ff fdd4 bl 8005a4c + 8005ea4: 1a36 subs r6, r6, r0 + 8005ea6: e7f0 b.n 8005e8a + carry += uECC_vli_add(result, result, curve_secp256r1.p, num_words_secp256r1); + 8005ea8: 4622 mov r2, r4 + 8005eaa: 4651 mov r1, sl + 8005eac: 4650 mov r0, sl + 8005eae: f7ff fe8f bl 8005bd0 + } while (carry < 0); + 8005eb2: 1836 adds r6, r6, r0 + 8005eb4: d4f8 bmi.n 8005ea8 +} + 8005eb6: b008 add sp, #32 + 8005eb8: e8bd 84f0 ldmia.w sp!, {r4, r5, r6, r7, sl, pc} + 8005ebc: 0800e92c .word 0x0800e92c + +08005ec0 : +static void mod_sqrt_default(uECC_word_t *a, uECC_Curve curve) { + 8005ec0: b5f0 push {r4, r5, r6, r7, lr} + 8005ec2: b091 sub sp, #68 ; 0x44 + 8005ec4: 460d mov r5, r1 + uECC_word_t p1[uECC_MAX_WORDS] = {1}; + 8005ec6: 221c movs r2, #28 + 8005ec8: 2100 movs r1, #0 +static void mod_sqrt_default(uECC_word_t *a, uECC_Curve curve) { + 8005eca: 4606 mov r6, r0 + uECC_word_t p1[uECC_MAX_WORDS] = {1}; + 8005ecc: a801 add r0, sp, #4 + 8005ece: f007 fbd1 bl 800d674 + 8005ed2: 2401 movs r4, #1 + uECC_word_t l_result[uECC_MAX_WORDS] = {1}; + 8005ed4: 221c movs r2, #28 + 8005ed6: 2100 movs r1, #0 + 8005ed8: a809 add r0, sp, #36 ; 0x24 + uECC_word_t p1[uECC_MAX_WORDS] = {1}; + 8005eda: 9400 str r4, [sp, #0] + uECC_word_t l_result[uECC_MAX_WORDS] = {1}; + 8005edc: f007 fbca bl 800d674 + wordcount_t num_words = curve->num_words; + 8005ee0: 4629 mov r1, r5 + uECC_vli_add(p1, curve->p, p1, num_words); /* p1 = curve_p + 1 */ + 8005ee2: 466a mov r2, sp + wordcount_t num_words = curve->num_words; + 8005ee4: f911 7b04 ldrsb.w r7, [r1], #4 + uECC_word_t l_result[uECC_MAX_WORDS] = {1}; + 8005ee8: 9408 str r4, [sp, #32] + uECC_vli_add(p1, curve->p, p1, num_words); /* p1 = curve_p + 1 */ + 8005eea: 4668 mov r0, sp + 8005eec: f7ff fe70 bl 8005bd0 + for (i = uECC_vli_numBits(p1, num_words) - 1; i > 1; --i) { + 8005ef0: 4639 mov r1, r7 + 8005ef2: 4668 mov r0, sp + 8005ef4: f7ff fbf1 bl 80056da + 8005ef8: 1e44 subs r4, r0, #1 + 8005efa: b224 sxth r4, r4 + 8005efc: 2c01 cmp r4, #1 + 8005efe: dc06 bgt.n 8005f0e + uECC_vli_set(a, l_result, num_words); + 8005f00: 463a mov r2, r7 + 8005f02: a908 add r1, sp, #32 + 8005f04: 4630 mov r0, r6 + 8005f06: f7ff fc08 bl 800571a +} + 8005f0a: b011 add sp, #68 ; 0x44 + 8005f0c: bdf0 pop {r4, r5, r6, r7, pc} + uECC_vli_modSquare_fast(l_result, l_result, curve); + 8005f0e: a908 add r1, sp, #32 + 8005f10: 4608 mov r0, r1 + 8005f12: 462a mov r2, r5 + 8005f14: f7ff fcdf bl 80058d6 + if (uECC_vli_testBit(p1, i)) { + 8005f18: 4621 mov r1, r4 + 8005f1a: 4668 mov r0, sp + 8005f1c: f7ff fbd3 bl 80056c6 + 8005f20: b128 cbz r0, 8005f2e + uECC_vli_modMult_fast(l_result, l_result, a, curve); + 8005f22: a908 add r1, sp, #32 + 8005f24: 462b mov r3, r5 + 8005f26: 4632 mov r2, r6 + 8005f28: 4608 mov r0, r1 + 8005f2a: f7ff fcc4 bl 80058b6 + for (i = uECC_vli_numBits(p1, num_words) - 1; i > 1; --i) { + 8005f2e: 3c01 subs r4, #1 + 8005f30: e7e3 b.n 8005efa + +08005f32 : + if (!EVEN(uv)) { + 8005f32: 6803 ldr r3, [r0, #0] + wordcount_t num_words) { + 8005f34: b570 push {r4, r5, r6, lr} + if (!EVEN(uv)) { + 8005f36: f013 0601 ands.w r6, r3, #1 + wordcount_t num_words) { + 8005f3a: 4605 mov r5, r0 + 8005f3c: 4614 mov r4, r2 + if (!EVEN(uv)) { + 8005f3e: d004 beq.n 8005f4a + carry = uECC_vli_add(uv, uv, mod, num_words); + 8005f40: 460a mov r2, r1 + 8005f42: 4601 mov r1, r0 + 8005f44: f7ff fe44 bl 8005bd0 + 8005f48: 4606 mov r6, r0 + uECC_vli_rshift1(uv, num_words); + 8005f4a: 4621 mov r1, r4 + 8005f4c: 4628 mov r0, r5 + 8005f4e: f7ff fc05 bl 800575c + if (carry) { + 8005f52: b146 cbz r6, 8005f66 + uv[num_words - 1] |= HIGH_BIT_SET; + 8005f54: f104 4280 add.w r2, r4, #1073741824 ; 0x40000000 + 8005f58: 3a01 subs r2, #1 + 8005f5a: f855 3022 ldr.w r3, [r5, r2, lsl #2] + 8005f5e: f043 4300 orr.w r3, r3, #2147483648 ; 0x80000000 + 8005f62: f845 3022 str.w r3, [r5, r2, lsl #2] +} + 8005f66: bd70 pop {r4, r5, r6, pc} + +08005f68 : + wordcount_t num_words) { + 8005f68: b5f0 push {r4, r5, r6, r7, lr} + 8005f6a: 460f mov r7, r1 + 8005f6c: b0a1 sub sp, #132 ; 0x84 + 8005f6e: 4606 mov r6, r0 + if (uECC_vli_isZero(input, num_words)) { + 8005f70: 4619 mov r1, r3 + 8005f72: 4638 mov r0, r7 + wordcount_t num_words) { + 8005f74: 4615 mov r5, r2 + 8005f76: 461c mov r4, r3 + if (uECC_vli_isZero(input, num_words)) { + 8005f78: f7ff fb96 bl 80056a8 + 8005f7c: b128 cbz r0, 8005f8a + uECC_vli_clear(result, num_words); + 8005f7e: 4630 mov r0, r6 +} + 8005f80: b021 add sp, #132 ; 0x84 + 8005f82: e8bd 40f0 ldmia.w sp!, {r4, r5, r6, r7, lr} + uECC_vli_clear(result, num_words); + 8005f86: f7ff bb89 b.w 800569c + uECC_vli_set(a, input, num_words); + 8005f8a: 4622 mov r2, r4 + 8005f8c: 4639 mov r1, r7 + 8005f8e: 4668 mov r0, sp + 8005f90: f7ff fbc3 bl 800571a + uECC_vli_set(b, mod, num_words); + 8005f94: 4629 mov r1, r5 + 8005f96: a808 add r0, sp, #32 + 8005f98: f7ff fbbf bl 800571a + uECC_vli_clear(u, num_words); + 8005f9c: 4621 mov r1, r4 + 8005f9e: a810 add r0, sp, #64 ; 0x40 + 8005fa0: f7ff fb7c bl 800569c + u[0] = 1; + 8005fa4: 2301 movs r3, #1 + uECC_vli_clear(v, num_words); + 8005fa6: 4621 mov r1, r4 + 8005fa8: a818 add r0, sp, #96 ; 0x60 + u[0] = 1; + 8005faa: 9310 str r3, [sp, #64] ; 0x40 + uECC_vli_clear(v, num_words); + 8005fac: f7ff fb76 bl 800569c + while ((cmpResult = uECC_vli_cmp_unsafe(a, b, num_words)) != 0) { + 8005fb0: 4622 mov r2, r4 + 8005fb2: a908 add r1, sp, #32 + 8005fb4: 4668 mov r0, sp + 8005fb6: f7ff fbbc bl 8005732 + 8005fba: b930 cbnz r0, 8005fca + uECC_vli_set(result, u, num_words); + 8005fbc: 4622 mov r2, r4 + 8005fbe: a910 add r1, sp, #64 ; 0x40 + 8005fc0: 4630 mov r0, r6 + 8005fc2: f7ff fbaa bl 800571a +} + 8005fc6: b021 add sp, #132 ; 0x84 + 8005fc8: bdf0 pop {r4, r5, r6, r7, pc} + if (EVEN(a)) { + 8005fca: 9b00 ldr r3, [sp, #0] + 8005fcc: 07da lsls r2, r3, #31 + 8005fce: d409 bmi.n 8005fe4 + uECC_vli_rshift1(a, num_words); + 8005fd0: 4621 mov r1, r4 + 8005fd2: 4668 mov r0, sp + 8005fd4: f7ff fbc2 bl 800575c + vli_modInv_update(u, mod, num_words); + 8005fd8: 4622 mov r2, r4 + 8005fda: 4629 mov r1, r5 + 8005fdc: a810 add r0, sp, #64 ; 0x40 + vli_modInv_update(v, mod, num_words); + 8005fde: f7ff ffa8 bl 8005f32 + 8005fe2: e7e5 b.n 8005fb0 + } else if (EVEN(b)) { + 8005fe4: 9b08 ldr r3, [sp, #32] + 8005fe6: 07db lsls r3, r3, #31 + 8005fe8: d407 bmi.n 8005ffa + uECC_vli_rshift1(b, num_words); + 8005fea: 4621 mov r1, r4 + 8005fec: a808 add r0, sp, #32 + 8005fee: f7ff fbb5 bl 800575c + vli_modInv_update(v, mod, num_words); + 8005ff2: 4622 mov r2, r4 + 8005ff4: 4629 mov r1, r5 + 8005ff6: a818 add r0, sp, #96 ; 0x60 + 8005ff8: e7f1 b.n 8005fde + } else if (cmpResult > 0) { + 8005ffa: 2800 cmp r0, #0 + 8005ffc: dd1a ble.n 8006034 + uECC_vli_sub(a, a, b, num_words); + 8005ffe: aa08 add r2, sp, #32 + 8006000: 4669 mov r1, sp + 8006002: 4668 mov r0, sp + 8006004: f7ff fd22 bl 8005a4c + uECC_vli_rshift1(a, num_words); + 8006008: 4621 mov r1, r4 + 800600a: 4668 mov r0, sp + 800600c: f7ff fba6 bl 800575c + if (uECC_vli_cmp_unsafe(u, v, num_words) < 0) { + 8006010: 4622 mov r2, r4 + 8006012: a918 add r1, sp, #96 ; 0x60 + 8006014: a810 add r0, sp, #64 ; 0x40 + 8006016: f7ff fb8c bl 8005732 + 800601a: 2800 cmp r0, #0 + 800601c: da04 bge.n 8006028 + uECC_vli_add(u, u, mod, num_words); + 800601e: a910 add r1, sp, #64 ; 0x40 + 8006020: 462a mov r2, r5 + 8006022: 4608 mov r0, r1 + 8006024: f7ff fdd4 bl 8005bd0 + uECC_vli_sub(u, u, v, num_words); + 8006028: a910 add r1, sp, #64 ; 0x40 + 800602a: aa18 add r2, sp, #96 ; 0x60 + 800602c: 4608 mov r0, r1 + 800602e: f7ff fd0d bl 8005a4c + 8006032: e7d1 b.n 8005fd8 + uECC_vli_sub(b, b, a, num_words); + 8006034: 466a mov r2, sp + 8006036: a808 add r0, sp, #32 + 8006038: f7ff fd08 bl 8005a4c + uECC_vli_rshift1(b, num_words); + 800603c: 4621 mov r1, r4 + 800603e: a808 add r0, sp, #32 + 8006040: f7ff fb8c bl 800575c + if (uECC_vli_cmp_unsafe(v, u, num_words) < 0) { + 8006044: 4622 mov r2, r4 + 8006046: a910 add r1, sp, #64 ; 0x40 + 8006048: a818 add r0, sp, #96 ; 0x60 + 800604a: f7ff fb72 bl 8005732 + 800604e: 2800 cmp r0, #0 + 8006050: da04 bge.n 800605c + uECC_vli_add(v, v, mod, num_words); + 8006052: a918 add r1, sp, #96 ; 0x60 + 8006054: 462a mov r2, r5 + 8006056: 4608 mov r0, r1 + 8006058: f7ff fdba bl 8005bd0 + uECC_vli_sub(v, v, u, num_words); + 800605c: a918 add r1, sp, #96 ; 0x60 + 800605e: aa10 add r2, sp, #64 ; 0x40 + 8006060: 4608 mov r0, r1 + 8006062: f7ff fcf3 bl 8005a4c + 8006066: e7c4 b.n 8005ff2 + +08006068 : + wordcount_t num_words) { + 8006068: b570 push {r4, r5, r6, lr} + 800606a: 4604 mov r4, r0 + 800606c: f99d 6010 ldrsb.w r6, [sp, #16] + 8006070: 461d mov r5, r3 + uECC_word_t carry = uECC_vli_add(result, left, right, num_words); + 8006072: f7ff fdad bl 8005bd0 + if (carry || uECC_vli_cmp_unsafe(mod, result, num_words) != 1) { + 8006076: b930 cbnz r0, 8006086 + 8006078: 4632 mov r2, r6 + 800607a: 4621 mov r1, r4 + 800607c: 4628 mov r0, r5 + 800607e: f7ff fb58 bl 8005732 + 8006082: 2801 cmp r0, #1 + 8006084: d006 beq.n 8006094 + uECC_vli_sub(result, result, mod, num_words); + 8006086: 462a mov r2, r5 + 8006088: 4621 mov r1, r4 + 800608a: 4620 mov r0, r4 +} + 800608c: e8bd 4070 ldmia.w sp!, {r4, r5, r6, lr} + uECC_vli_sub(result, result, mod, num_words); + 8006090: f7ff bcdc b.w 8005a4c +} + 8006094: bd70 pop {r4, r5, r6, pc} + +08006096 : +static void x_side_secp256k1(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve) { + 8006096: b573 push {r0, r1, r4, r5, r6, lr} + 8006098: 4604 mov r4, r0 + 800609a: 4615 mov r5, r2 + 800609c: 460e mov r6, r1 + uECC_vli_modSquare_fast(result, x, curve); /* r = x^2 */ + 800609e: f7ff fc1a bl 80058d6 + uECC_vli_modMult_fast(result, result, x, curve); /* r = x^3 */ + 80060a2: 462b mov r3, r5 + 80060a4: 4632 mov r2, r6 + 80060a6: 4621 mov r1, r4 + 80060a8: 4620 mov r0, r4 + 80060aa: f7ff fc04 bl 80058b6 + uECC_vli_modAdd(result, result, curve->b, curve->p, num_words_secp256k1); /* r = x^3 + b */ + 80060ae: 2308 movs r3, #8 + 80060b0: 9300 str r3, [sp, #0] + 80060b2: f105 0284 add.w r2, r5, #132 ; 0x84 + 80060b6: 1d2b adds r3, r5, #4 + 80060b8: 4621 mov r1, r4 + 80060ba: 4620 mov r0, r4 + 80060bc: f7ff ffd4 bl 8006068 +} + 80060c0: b002 add sp, #8 + 80060c2: bd70 pop {r4, r5, r6, pc} + +080060c4 : +uECC_VLI_API void uECC_vli_modSub(uECC_word_t *result, + 80060c4: b538 push {r3, r4, r5, lr} + 80060c6: 4604 mov r4, r0 + 80060c8: 461d mov r5, r3 + uECC_word_t l_borrow = uECC_vli_sub(result, left, right, num_words); + 80060ca: f7ff fcbf bl 8005a4c + if (l_borrow) { + 80060ce: b130 cbz r0, 80060de + uECC_vli_add(result, result, mod, num_words); + 80060d0: 462a mov r2, r5 + 80060d2: 4621 mov r1, r4 + 80060d4: 4620 mov r0, r4 +} + 80060d6: e8bd 4038 ldmia.w sp!, {r3, r4, r5, lr} + uECC_vli_add(result, result, mod, num_words); + 80060da: f7ff bd79 b.w 8005bd0 +} + 80060de: bd38 pop {r3, r4, r5, pc} + +080060e0 : + uECC_Curve curve) { + 80060e0: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + 80060e4: b09a sub sp, #104 ; 0x68 + 80060e6: 4615 mov r5, r2 + 80060e8: 9f22 ldr r7, [sp, #136] ; 0x88 + wordcount_t num_words = curve->num_words; + 80060ea: 463c mov r4, r7 + uECC_Curve curve) { + 80060ec: 4698 mov r8, r3 + wordcount_t num_words = curve->num_words; + 80060ee: f914 ab04 ldrsb.w sl, [r4], #4 + uECC_Curve curve) { + 80060f2: 4606 mov r6, r0 + 80060f4: 4689 mov r9, r1 + uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */ + 80060f6: 4623 mov r3, r4 + 80060f8: 4602 mov r2, r0 + 80060fa: 4629 mov r1, r5 + 80060fc: a802 add r0, sp, #8 + 80060fe: f7ff ffe1 bl 80060c4 + uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */ + 8006102: a902 add r1, sp, #8 + 8006104: 463a mov r2, r7 + 8006106: 4608 mov r0, r1 + 8006108: f7ff fbe5 bl 80058d6 + uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */ + 800610c: 463b mov r3, r7 + 800610e: aa02 add r2, sp, #8 + 8006110: 4631 mov r1, r6 + 8006112: 4630 mov r0, r6 + 8006114: f7ff fbcf bl 80058b6 + uECC_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */ + 8006118: 463b mov r3, r7 + 800611a: aa02 add r2, sp, #8 + 800611c: 4629 mov r1, r5 + 800611e: 4628 mov r0, r5 + 8006120: f7ff fbc9 bl 80058b6 + uECC_vli_modAdd(t5, Y2, Y1, curve->p, num_words); /* t5 = y2 + y1 */ + 8006124: 4623 mov r3, r4 + 8006126: 464a mov r2, r9 + 8006128: 4641 mov r1, r8 + 800612a: a802 add r0, sp, #8 + 800612c: f8cd a000 str.w sl, [sp] + 8006130: f7ff ff9a bl 8006068 + uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */ + 8006134: 4623 mov r3, r4 + 8006136: 464a mov r2, r9 + 8006138: 4641 mov r1, r8 + 800613a: 4640 mov r0, r8 + 800613c: f7ff ffc2 bl 80060c4 + uECC_vli_modSub(t6, X2, X1, curve->p, num_words); /* t6 = C - B */ + 8006140: 4623 mov r3, r4 + 8006142: 4632 mov r2, r6 + 8006144: 4629 mov r1, r5 + 8006146: a80a add r0, sp, #40 ; 0x28 + 8006148: f7ff ffbc bl 80060c4 + uECC_vli_modMult_fast(Y1, Y1, t6, curve); /* t2 = y1 * (C - B) = E */ + 800614c: 463b mov r3, r7 + 800614e: aa0a add r2, sp, #40 ; 0x28 + 8006150: 4649 mov r1, r9 + 8006152: 4648 mov r0, r9 + 8006154: f7ff fbaf bl 80058b6 + uECC_vli_modAdd(t6, X1, X2, curve->p, num_words); /* t6 = B + C */ + 8006158: 4623 mov r3, r4 + 800615a: 462a mov r2, r5 + 800615c: 4631 mov r1, r6 + 800615e: a80a add r0, sp, #40 ; 0x28 + 8006160: f8cd a000 str.w sl, [sp] + 8006164: f7ff ff80 bl 8006068 + uECC_vli_modSquare_fast(X2, Y2, curve); /* t3 = (y2 - y1)^2 = D */ + 8006168: 463a mov r2, r7 + 800616a: 4641 mov r1, r8 + 800616c: 4628 mov r0, r5 + 800616e: f7ff fbb2 bl 80058d6 + uECC_vli_modSub(X2, X2, t6, curve->p, num_words); /* t3 = D - (B + C) = x3 */ + 8006172: 4623 mov r3, r4 + 8006174: aa0a add r2, sp, #40 ; 0x28 + 8006176: 4629 mov r1, r5 + 8006178: 4628 mov r0, r5 + 800617a: f7ff ffa3 bl 80060c4 + uECC_vli_modSub(t7, X1, X2, curve->p, num_words); /* t7 = B - x3 */ + 800617e: 4623 mov r3, r4 + 8006180: 462a mov r2, r5 + 8006182: 4631 mov r1, r6 + 8006184: a812 add r0, sp, #72 ; 0x48 + 8006186: f7ff ff9d bl 80060c4 + uECC_vli_modMult_fast(Y2, Y2, t7, curve); /* t4 = (y2 - y1)*(B - x3) */ + 800618a: 463b mov r3, r7 + 800618c: aa12 add r2, sp, #72 ; 0x48 + 800618e: 4641 mov r1, r8 + 8006190: 4640 mov r0, r8 + 8006192: f7ff fb90 bl 80058b6 + uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = (y2 - y1)*(B - x3) - E = y3 */ + 8006196: 4623 mov r3, r4 + 8006198: 464a mov r2, r9 + 800619a: 4641 mov r1, r8 + 800619c: 4640 mov r0, r8 + 800619e: f7ff ff91 bl 80060c4 + uECC_vli_modSquare_fast(t7, t5, curve); /* t7 = (y2 + y1)^2 = F */ + 80061a2: 463a mov r2, r7 + 80061a4: a902 add r1, sp, #8 + 80061a6: a812 add r0, sp, #72 ; 0x48 + 80061a8: f7ff fb95 bl 80058d6 + uECC_vli_modSub(t7, t7, t6, curve->p, num_words); /* t7 = F - (B + C) = x3' */ + 80061ac: a912 add r1, sp, #72 ; 0x48 + 80061ae: 4623 mov r3, r4 + 80061b0: aa0a add r2, sp, #40 ; 0x28 + 80061b2: 4608 mov r0, r1 + 80061b4: f7ff ff86 bl 80060c4 + uECC_vli_modSub(t6, t7, X1, curve->p, num_words); /* t6 = x3' - B */ + 80061b8: 4623 mov r3, r4 + 80061ba: 4632 mov r2, r6 + 80061bc: a912 add r1, sp, #72 ; 0x48 + 80061be: a80a add r0, sp, #40 ; 0x28 + 80061c0: f7ff ff80 bl 80060c4 + uECC_vli_modMult_fast(t6, t6, t5, curve); /* t6 = (y2+y1)*(x3' - B) */ + 80061c4: a90a add r1, sp, #40 ; 0x28 + 80061c6: 463b mov r3, r7 + 80061c8: aa02 add r2, sp, #8 + 80061ca: 4608 mov r0, r1 + 80061cc: f7ff fb73 bl 80058b6 + uECC_vli_modSub(Y1, t6, Y1, curve->p, num_words); /* t2 = (y2+y1)*(x3' - B) - E = y3' */ + 80061d0: 4623 mov r3, r4 + 80061d2: 464a mov r2, r9 + 80061d4: a90a add r1, sp, #40 ; 0x28 + 80061d6: 4648 mov r0, r9 + 80061d8: f7ff ff74 bl 80060c4 + uECC_vli_set(X1, t7, num_words); + 80061dc: 4652 mov r2, sl + 80061de: a912 add r1, sp, #72 ; 0x48 + 80061e0: 4630 mov r0, r6 + 80061e2: f7ff fa9a bl 800571a +} + 80061e6: b01a add sp, #104 ; 0x68 + 80061e8: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + +080061ec : + uECC_Curve curve) { + 80061ec: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + 80061f0: b088 sub sp, #32 + 80061f2: 4614 mov r4, r2 + 80061f4: f8dd 8040 ldr.w r8, [sp, #64] ; 0x40 + wordcount_t num_words = curve->num_words; + 80061f8: 4645 mov r5, r8 + uECC_Curve curve) { + 80061fa: 461e mov r6, r3 + wordcount_t num_words = curve->num_words; + 80061fc: f915 ab04 ldrsb.w sl, [r5], #4 + uECC_Curve curve) { + 8006200: 4607 mov r7, r0 + 8006202: 4689 mov r9, r1 + uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */ + 8006204: 462b mov r3, r5 + 8006206: 4602 mov r2, r0 + 8006208: 4621 mov r1, r4 + 800620a: 4668 mov r0, sp + 800620c: f7ff ff5a bl 80060c4 + uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */ + 8006210: 4642 mov r2, r8 + 8006212: 4669 mov r1, sp + 8006214: 4668 mov r0, sp + 8006216: f7ff fb5e bl 80058d6 + uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */ + 800621a: 4643 mov r3, r8 + 800621c: 466a mov r2, sp + 800621e: 4639 mov r1, r7 + 8006220: 4638 mov r0, r7 + 8006222: f7ff fb48 bl 80058b6 + uECC_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */ + 8006226: 4643 mov r3, r8 + 8006228: 466a mov r2, sp + 800622a: 4621 mov r1, r4 + 800622c: 4620 mov r0, r4 + 800622e: f7ff fb42 bl 80058b6 + uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */ + 8006232: 462b mov r3, r5 + 8006234: 464a mov r2, r9 + 8006236: 4631 mov r1, r6 + 8006238: 4630 mov r0, r6 + 800623a: f7ff ff43 bl 80060c4 + uECC_vli_modSquare_fast(t5, Y2, curve); /* t5 = (y2 - y1)^2 = D */ + 800623e: 4642 mov r2, r8 + 8006240: 4631 mov r1, r6 + 8006242: 4668 mov r0, sp + 8006244: f7ff fb47 bl 80058d6 + uECC_vli_modSub(t5, t5, X1, curve->p, num_words); /* t5 = D - B */ + 8006248: 462b mov r3, r5 + 800624a: 463a mov r2, r7 + 800624c: 4669 mov r1, sp + 800624e: 4668 mov r0, sp + 8006250: f7ff ff38 bl 80060c4 + uECC_vli_modSub(t5, t5, X2, curve->p, num_words); /* t5 = D - B - C = x3 */ + 8006254: 462b mov r3, r5 + 8006256: 4622 mov r2, r4 + 8006258: 4669 mov r1, sp + 800625a: 4668 mov r0, sp + 800625c: f7ff ff32 bl 80060c4 + uECC_vli_modSub(X2, X2, X1, curve->p, num_words); /* t3 = C - B */ + 8006260: 462b mov r3, r5 + 8006262: 463a mov r2, r7 + 8006264: 4621 mov r1, r4 + 8006266: 4620 mov r0, r4 + 8006268: f7ff ff2c bl 80060c4 + uECC_vli_modMult_fast(Y1, Y1, X2, curve); /* t2 = y1*(C - B) */ + 800626c: 4643 mov r3, r8 + 800626e: 4622 mov r2, r4 + 8006270: 4649 mov r1, r9 + 8006272: 4648 mov r0, r9 + 8006274: f7ff fb1f bl 80058b6 + uECC_vli_modSub(X2, X1, t5, curve->p, num_words); /* t3 = B - x3 */ + 8006278: 462b mov r3, r5 + 800627a: 466a mov r2, sp + 800627c: 4639 mov r1, r7 + 800627e: 4620 mov r0, r4 + 8006280: f7ff ff20 bl 80060c4 + uECC_vli_modMult_fast(Y2, Y2, X2, curve); /* t4 = (y2 - y1)*(B - x3) */ + 8006284: 4643 mov r3, r8 + 8006286: 4622 mov r2, r4 + 8006288: 4631 mov r1, r6 + 800628a: 4630 mov r0, r6 + 800628c: f7ff fb13 bl 80058b6 + uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y3 */ + 8006290: 462b mov r3, r5 + 8006292: 464a mov r2, r9 + 8006294: 4631 mov r1, r6 + 8006296: 4630 mov r0, r6 + 8006298: f7ff ff14 bl 80060c4 + uECC_vli_set(X2, t5, num_words); + 800629c: 4652 mov r2, sl + 800629e: 4669 mov r1, sp + 80062a0: 4620 mov r0, r4 + 80062a2: f7ff fa3a bl 800571a +} + 80062a6: b008 add sp, #32 + 80062a8: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + +080062ac : + uECC_Curve curve) { + 80062ac: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + 80062b0: b0b1 sub sp, #196 ; 0xc4 + 80062b2: e9cd 0102 strd r0, r1, [sp, #8] + 80062b6: 9c3b ldr r4, [sp, #236] ; 0xec + 80062b8: 9204 str r2, [sp, #16] + wordcount_t num_words = curve->num_words; + 80062ba: f994 9000 ldrsb.w r9, [r4] + uECC_vli_set(Rx[1], point, num_words); + 80062be: a818 add r0, sp, #96 ; 0x60 + 80062c0: 464a mov r2, r9 + uECC_Curve curve) { + 80062c2: 461d mov r5, r3 + uECC_vli_set(Rx[1], point, num_words); + 80062c4: f7ff fa29 bl 800571a + uECC_vli_set(Ry[1], point + num_words, num_words); + 80062c8: ea4f 0389 mov.w r3, r9, lsl #2 + 80062cc: 9305 str r3, [sp, #20] + 80062ce: 9b03 ldr r3, [sp, #12] + 80062d0: eb03 0a89 add.w sl, r3, r9, lsl #2 + 80062d4: 4651 mov r1, sl + 80062d6: a828 add r0, sp, #160 ; 0xa0 + 80062d8: f7ff fa1f bl 800571a + wordcount_t num_words = curve->num_words; + 80062dc: f994 2000 ldrsb.w r2, [r4] + if (initial_Z) { + 80062e0: 2d00 cmp r5, #0 + 80062e2: f000 8082 beq.w 80063ea + uECC_vli_set(z, initial_Z, num_words); + 80062e6: 4629 mov r1, r5 + 80062e8: a808 add r0, sp, #32 + 80062ea: f7ff fa16 bl 800571a + uECC_vli_set(X2, X1, num_words); + 80062ee: af10 add r7, sp, #64 ; 0x40 + 80062f0: a918 add r1, sp, #96 ; 0x60 + 80062f2: 4638 mov r0, r7 + uECC_vli_set(Y2, Y1, num_words); + 80062f4: f10d 0880 add.w r8, sp, #128 ; 0x80 + uECC_vli_set(X2, X1, num_words); + 80062f8: f7ff fa0f bl 800571a + uECC_vli_set(Y2, Y1, num_words); + 80062fc: a928 add r1, sp, #160 ; 0xa0 + 80062fe: 4640 mov r0, r8 + 8006300: f7ff fa0b bl 800571a + apply_z(X1, Y1, z, curve); + 8006304: 4623 mov r3, r4 + 8006306: aa08 add r2, sp, #32 + 8006308: a818 add r0, sp, #96 ; 0x60 + 800630a: f7ff fae8 bl 80058de + curve->double_jacobian(X1, Y1, z, curve); + 800630e: f8d4 50a4 ldr.w r5, [r4, #164] ; 0xa4 + 8006312: 4623 mov r3, r4 + 8006314: aa08 add r2, sp, #32 + 8006316: a928 add r1, sp, #160 ; 0xa0 + 8006318: a818 add r0, sp, #96 ; 0x60 + 800631a: 47a8 blx r5 + apply_z(X2, Y2, z, curve); + 800631c: 4623 mov r3, r4 + 800631e: aa08 add r2, sp, #32 + 8006320: 4641 mov r1, r8 + 8006322: 4638 mov r0, r7 + 8006324: f7ff fadb bl 80058de + for (i = num_bits - 2; i > 0; --i) { + 8006328: f9bd 50e8 ldrsh.w r5, [sp, #232] ; 0xe8 + 800632c: 3d02 subs r5, #2 + 800632e: b22d sxth r5, r5 + 8006330: 2d00 cmp r5, #0 + 8006332: dc63 bgt.n 80063fc + return (vli[bit >> uECC_WORD_BITS_SHIFT] & ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK))); + 8006334: 9b04 ldr r3, [sp, #16] + 8006336: 681d ldr r5, [r3, #0] + XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve); + 8006338: 9400 str r4, [sp, #0] + return (vli[bit >> uECC_WORD_BITS_SHIFT] & ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK))); + 800633a: f005 0601 and.w r6, r5, #1 + XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve); + 800633e: ab10 add r3, sp, #64 ; 0x40 + 8006340: eb03 1746 add.w r7, r3, r6, lsl #5 + 8006344: 43ed mvns r5, r5 + 8006346: ab20 add r3, sp, #128 ; 0x80 + 8006348: eb03 1646 add.w r6, r3, r6, lsl #5 + 800634c: f005 0501 and.w r5, r5, #1 + 8006350: ab10 add r3, sp, #64 ; 0x40 + 8006352: eb03 1845 add.w r8, r3, r5, lsl #5 + 8006356: ab20 add r3, sp, #128 ; 0x80 + 8006358: eb03 1545 add.w r5, r3, r5, lsl #5 + 800635c: 462b mov r3, r5 + 800635e: 4642 mov r2, r8 + 8006360: 4631 mov r1, r6 + 8006362: 4638 mov r0, r7 + uECC_vli_modSub(z, Rx[1], Rx[0], curve->p, num_words); /* X1 - X0 */ + 8006364: f104 0b04 add.w fp, r4, #4 + XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve); + 8006368: f7ff feba bl 80060e0 + uECC_vli_modSub(z, Rx[1], Rx[0], curve->p, num_words); /* X1 - X0 */ + 800636c: 465b mov r3, fp + 800636e: aa10 add r2, sp, #64 ; 0x40 + 8006370: a918 add r1, sp, #96 ; 0x60 + 8006372: a808 add r0, sp, #32 + 8006374: f7ff fea6 bl 80060c4 + uECC_vli_modMult_fast(z, z, Ry[1 - nb], curve); /* Yb * (X1 - X0) */ + 8006378: a908 add r1, sp, #32 + 800637a: 4623 mov r3, r4 + 800637c: 4632 mov r2, r6 + 800637e: 4608 mov r0, r1 + 8006380: f7ff fa99 bl 80058b6 + uECC_vli_modMult_fast(z, z, point, curve); /* xP * Yb * (X1 - X0) */ + 8006384: a908 add r1, sp, #32 + 8006386: 9a03 ldr r2, [sp, #12] + 8006388: 4623 mov r3, r4 + 800638a: 4608 mov r0, r1 + 800638c: f7ff fa93 bl 80058b6 + uECC_vli_modInv(z, z, curve->p, num_words); /* 1 / (xP * Yb * (X1 - X0)) */ + 8006390: a908 add r1, sp, #32 + 8006392: 464b mov r3, r9 + 8006394: 465a mov r2, fp + 8006396: 4608 mov r0, r1 + 8006398: f7ff fde6 bl 8005f68 + uECC_vli_modMult_fast(z, z, point + num_words, curve); + 800639c: a908 add r1, sp, #32 + 800639e: 4623 mov r3, r4 + 80063a0: 4652 mov r2, sl + 80063a2: 4608 mov r0, r1 + 80063a4: f7ff fa87 bl 80058b6 + uECC_vli_modMult_fast(z, z, Rx[1 - nb], curve); /* Xb * yP / (xP * Yb * (X1 - X0)) */ + 80063a8: a908 add r1, sp, #32 + 80063aa: 4623 mov r3, r4 + 80063ac: 463a mov r2, r7 + 80063ae: 4608 mov r0, r1 + 80063b0: f7ff fa81 bl 80058b6 + XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve); + 80063b4: 4633 mov r3, r6 + 80063b6: 463a mov r2, r7 + 80063b8: 4629 mov r1, r5 + 80063ba: 4640 mov r0, r8 + 80063bc: 9400 str r4, [sp, #0] + 80063be: f7ff ff15 bl 80061ec + apply_z(Rx[0], Ry[0], z, curve); + 80063c2: 4623 mov r3, r4 + 80063c4: aa08 add r2, sp, #32 + 80063c6: a920 add r1, sp, #128 ; 0x80 + 80063c8: a810 add r0, sp, #64 ; 0x40 + 80063ca: f7ff fa88 bl 80058de + uECC_vli_set(result, Rx[0], num_words); + 80063ce: 9802 ldr r0, [sp, #8] + 80063d0: 464a mov r2, r9 + 80063d2: a910 add r1, sp, #64 ; 0x40 + 80063d4: f7ff f9a1 bl 800571a + uECC_vli_set(result + num_words, Ry[0], num_words); + 80063d8: 9802 ldr r0, [sp, #8] + 80063da: 9b05 ldr r3, [sp, #20] + 80063dc: a920 add r1, sp, #128 ; 0x80 + 80063de: 4418 add r0, r3 + 80063e0: f7ff f99b bl 800571a +} + 80063e4: b031 add sp, #196 ; 0xc4 + 80063e6: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + uECC_vli_clear(z, num_words); + 80063ea: 4611 mov r1, r2 + 80063ec: a808 add r0, sp, #32 + 80063ee: 9206 str r2, [sp, #24] + 80063f0: f7ff f954 bl 800569c + z[0] = 1; + 80063f4: 2301 movs r3, #1 + 80063f6: 9a06 ldr r2, [sp, #24] + 80063f8: 9308 str r3, [sp, #32] + 80063fa: e778 b.n 80062ee + nb = !uECC_vli_testBit(scalar, i); + 80063fc: 4629 mov r1, r5 + 80063fe: 9804 ldr r0, [sp, #16] + 8006400: f7ff f961 bl 80056c6 + 8006404: fab0 f680 clz r6, r0 + 8006408: 0976 lsrs r6, r6, #5 + XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve); + 800640a: f1c6 0101 rsb r1, r6, #1 + 800640e: eb07 1b46 add.w fp, r7, r6, lsl #5 + 8006412: eb08 1646 add.w r6, r8, r6, lsl #5 + 8006416: eb07 1041 add.w r0, r7, r1, lsl #5 + 800641a: 4633 mov r3, r6 + 800641c: eb08 1141 add.w r1, r8, r1, lsl #5 + 8006420: 465a mov r2, fp + 8006422: 9400 str r4, [sp, #0] + 8006424: e9cd 0106 strd r0, r1, [sp, #24] + 8006428: f7ff fe5a bl 80060e0 + XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve); + 800642c: 9907 ldr r1, [sp, #28] + 800642e: 9806 ldr r0, [sp, #24] + 8006430: 9400 str r4, [sp, #0] + 8006432: 460b mov r3, r1 + 8006434: 4602 mov r2, r0 + 8006436: 4631 mov r1, r6 + 8006438: 4658 mov r0, fp + 800643a: f7ff fed7 bl 80061ec + for (i = num_bits - 2; i > 0; --i) { + 800643e: 3d01 subs r5, #1 + 8006440: e775 b.n 800632e + +08006442 : + uECC_Curve curve) { + 8006442: b530 push {r4, r5, lr} + 8006444: 4614 mov r4, r2 + 8006446: b095 sub sp, #84 ; 0x54 + 8006448: 4605 mov r5, r0 + uECC_word_t *p2[2] = {tmp1, tmp2}; + 800644a: aa0c add r2, sp, #48 ; 0x30 + carry = regularize_k(private, tmp1, tmp2, curve); + 800644c: 4623 mov r3, r4 + uECC_Curve curve) { + 800644e: 4608 mov r0, r1 + uECC_word_t *p2[2] = {tmp1, tmp2}; + 8006450: a904 add r1, sp, #16 + 8006452: 9102 str r1, [sp, #8] + 8006454: 9203 str r2, [sp, #12] + carry = regularize_k(private, tmp1, tmp2, curve); + 8006456: f7ff fbe0 bl 8005c1a + EccPoint_mult(result, curve->G, p2[!carry], 0, curve->num_n_bits + 1, curve); + 800645a: fab0 f380 clz r3, r0 + 800645e: 095b lsrs r3, r3, #5 + 8006460: aa14 add r2, sp, #80 ; 0x50 + 8006462: eb02 0283 add.w r2, r2, r3, lsl #2 + 8006466: 8863 ldrh r3, [r4, #2] + 8006468: 9401 str r4, [sp, #4] + 800646a: 3301 adds r3, #1 + 800646c: b21b sxth r3, r3 + 800646e: 9300 str r3, [sp, #0] + 8006470: f852 2c48 ldr.w r2, [r2, #-72] + 8006474: 2300 movs r3, #0 + 8006476: f104 0144 add.w r1, r4, #68 ; 0x44 + 800647a: 4628 mov r0, r5 + 800647c: f7ff ff16 bl 80062ac + if (EccPoint_isZero(result, curve)) { + 8006480: 7821 ldrb r1, [r4, #0] + 8006482: 0049 lsls r1, r1, #1 + 8006484: b249 sxtb r1, r1 + 8006486: 4628 mov r0, r5 + 8006488: f7ff f90e bl 80056a8 +} + 800648c: fab0 f080 clz r0, r0 + 8006490: 0940 lsrs r0, r0, #5 + 8006492: b015 add sp, #84 ; 0x54 + 8006494: bd30 pop {r4, r5, pc} + ... + +08006498 : + uECC_Curve curve) { + 8006498: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + 800649c: ed2d 8b02 vpush {d8} + 80064a0: b0a7 sub sp, #156 ; 0x9c + 80064a2: 461e mov r6, r3 + 80064a4: 9d33 ldr r5, [sp, #204] ; 0xcc + wordcount_t num_words = curve->num_words; + 80064a6: f995 a000 ldrsb.w sl, [r5] + uECC_Curve curve) { + 80064aa: ee08 1a10 vmov s16, r1 + 80064ae: 4683 mov fp, r0 + uECC_word_t *k2[2] = {tmp, s}; + 80064b0: f10d 0918 add.w r9, sp, #24 + 80064b4: ab0e add r3, sp, #56 ; 0x38 + if (uECC_vli_isZero(k, num_words) || uECC_vli_cmp(curve->n, k, num_n_words) != 1) { + 80064b6: 4651 mov r1, sl + 80064b8: 4630 mov r0, r6 + uECC_Curve curve) { + 80064ba: ee08 2a90 vmov s17, r2 + uECC_word_t *k2[2] = {tmp, s}; + 80064be: f8cd 9010 str.w r9, [sp, #16] + 80064c2: 9305 str r3, [sp, #20] + if (uECC_vli_isZero(k, num_words) || uECC_vli_cmp(curve->n, k, num_n_words) != 1) { + 80064c4: f7ff f8f0 bl 80056a8 + 80064c8: b128 cbz r0, 80064d6 + return 0; + 80064ca: 2000 movs r0, #0 +} + 80064cc: b027 add sp, #156 ; 0x9c + 80064ce: ecbd 8b02 vpop {d8} + 80064d2: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); + 80064d6: f9b5 8002 ldrsh.w r8, [r5, #2] + 80064da: f118 041f adds.w r4, r8, #31 + 80064de: bf48 it mi + 80064e0: f108 043e addmi.w r4, r8, #62 ; 0x3e + 80064e4: f344 1447 sbfx r4, r4, #5, #8 + if (uECC_vli_isZero(k, num_words) || uECC_vli_cmp(curve->n, k, num_n_words) != 1) { + 80064e8: f105 0724 add.w r7, r5, #36 ; 0x24 + 80064ec: 4622 mov r2, r4 + 80064ee: 4631 mov r1, r6 + 80064f0: 4638 mov r0, r7 + 80064f2: f7ff fb19 bl 8005b28 + 80064f6: 2801 cmp r0, #1 + 80064f8: 9003 str r0, [sp, #12] + 80064fa: d1e6 bne.n 80064ca + carry = regularize_k(k, tmp, s, curve); + 80064fc: 462b mov r3, r5 + 80064fe: aa0e add r2, sp, #56 ; 0x38 + 8006500: 4649 mov r1, r9 + 8006502: 4630 mov r0, r6 + 8006504: f7ff fb89 bl 8005c1a + EccPoint_mult(p, curve->G, k2[!carry], 0, num_n_bits + 1, curve); + 8006508: fab0 f080 clz r0, r0 + 800650c: ab26 add r3, sp, #152 ; 0x98 + 800650e: 0940 lsrs r0, r0, #5 + 8006510: f108 0801 add.w r8, r8, #1 + 8006514: eb03 0080 add.w r0, r3, r0, lsl #2 + 8006518: fa0f f388 sxth.w r3, r8 + 800651c: 9300 str r3, [sp, #0] + 800651e: 9501 str r5, [sp, #4] + 8006520: f850 2c88 ldr.w r2, [r0, #-136] + 8006524: f105 0144 add.w r1, r5, #68 ; 0x44 + 8006528: a816 add r0, sp, #88 ; 0x58 + 800652a: 2300 movs r3, #0 + 800652c: f7ff febe bl 80062ac + if (uECC_vli_isZero(p, num_words)) { + 8006530: 4651 mov r1, sl + 8006532: a816 add r0, sp, #88 ; 0x58 + 8006534: f7ff f8b8 bl 80056a8 + 8006538: 2800 cmp r0, #0 + 800653a: d1c6 bne.n 80064ca + uECC_recid = (p[curve->num_words] & 0x01); + 800653c: f995 3000 ldrsb.w r3, [r5] + 8006540: aa26 add r2, sp, #152 ; 0x98 + 8006542: eb02 0383 add.w r3, r2, r3, lsl #2 + 8006546: 4a3b ldr r2, [pc, #236] ; (8006634 ) + 8006548: f853 3c40 ldr.w r3, [r3, #-64] + 800654c: f003 0301 and.w r3, r3, #1 + 8006550: 7013 strb r3, [r2, #0] + if (!g_rng_function) { + 8006552: 4b39 ldr r3, [pc, #228] ; (8006638 ) + 8006554: 681b ldr r3, [r3, #0] + 8006556: 2b00 cmp r3, #0 + 8006558: d163 bne.n 8006622 + uECC_vli_clear(tmp, num_n_words); + 800655a: 4621 mov r1, r4 + 800655c: 4648 mov r0, r9 + 800655e: f7ff f89d bl 800569c + tmp[0] = 1; + 8006562: 9b03 ldr r3, [sp, #12] + 8006564: 9306 str r3, [sp, #24] + uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k' = rand * k */ + 8006566: 463b mov r3, r7 + 8006568: aa06 add r2, sp, #24 + 800656a: 4631 mov r1, r6 + 800656c: 4630 mov r0, r6 + 800656e: 9400 str r4, [sp, #0] + 8006570: f7ff f901 bl 8005776 + uECC_vli_modInv(k, k, curve->n, num_n_words); /* k = 1 / k' */ + 8006574: 4623 mov r3, r4 + 8006576: 463a mov r2, r7 + 8006578: 4631 mov r1, r6 + 800657a: 4630 mov r0, r6 + 800657c: f7ff fcf4 bl 8005f68 + uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k = 1 / k */ + 8006580: 463b mov r3, r7 + 8006582: aa06 add r2, sp, #24 + 8006584: 4631 mov r1, r6 + 8006586: 4630 mov r0, r6 + 8006588: 9400 str r4, [sp, #0] + 800658a: f7ff f8f4 bl 8005776 + uECC_vli_nativeToBytes(signature, curve->num_bytes, p); /* store r */ + 800658e: f995 1001 ldrsb.w r1, [r5, #1] + 8006592: 9832 ldr r0, [sp, #200] ; 0xc8 + 8006594: aa16 add r2, sp, #88 ; 0x58 + 8006596: f7ff f9c1 bl 800591c + uECC_vli_bytesToNative(tmp, private_key, BITS_TO_BYTES(curve->num_n_bits)); /* tmp = d */ + 800659a: f9b5 3002 ldrsh.w r3, [r5, #2] + 800659e: 1dda adds r2, r3, #7 + 80065a0: bf48 it mi + 80065a2: f103 020e addmi.w r2, r3, #14 + 80065a6: 10d2 asrs r2, r2, #3 + 80065a8: 4659 mov r1, fp + 80065aa: a806 add r0, sp, #24 + 80065ac: f7ff f9ca bl 8005944 + s[num_n_words - 1] = 0; + 80065b0: aa26 add r2, sp, #152 ; 0x98 + 80065b2: 1e63 subs r3, r4, #1 + 80065b4: eb02 0383 add.w r3, r2, r3, lsl #2 + 80065b8: 2200 movs r2, #0 + uECC_vli_set(s, p, num_words); + 80065ba: a80e add r0, sp, #56 ; 0x38 + s[num_n_words - 1] = 0; + 80065bc: f843 2c60 str.w r2, [r3, #-96] + uECC_vli_set(s, p, num_words); + 80065c0: a916 add r1, sp, #88 ; 0x58 + 80065c2: 4652 mov r2, sl + 80065c4: f7ff f8a9 bl 800571a + uECC_vli_modMult(s, tmp, s, curve->n, num_n_words); /* s = r*d */ + 80065c8: 4602 mov r2, r0 + 80065ca: 463b mov r3, r7 + 80065cc: a906 add r1, sp, #24 + 80065ce: 9400 str r4, [sp, #0] + 80065d0: f7ff f8d1 bl 8005776 + bits2int(tmp, message_hash, hash_size, curve); + 80065d4: ee18 2a90 vmov r2, s17 + 80065d8: ee18 1a10 vmov r1, s16 + 80065dc: 462b mov r3, r5 + 80065de: a806 add r0, sp, #24 + 80065e0: f7ff fa5b bl 8005a9a + uECC_vli_modAdd(s, tmp, s, curve->n, num_n_words); /* s = e + r*d */ + 80065e4: aa0e add r2, sp, #56 ; 0x38 + 80065e6: 4610 mov r0, r2 + 80065e8: 463b mov r3, r7 + 80065ea: a906 add r1, sp, #24 + 80065ec: 9400 str r4, [sp, #0] + 80065ee: f7ff fd3b bl 8006068 + uECC_vli_modMult(s, s, k, curve->n, num_n_words); /* s = (e + r*d) / k */ + 80065f2: a90e add r1, sp, #56 ; 0x38 + 80065f4: 4608 mov r0, r1 + 80065f6: 463b mov r3, r7 + 80065f8: 4632 mov r2, r6 + 80065fa: 9400 str r4, [sp, #0] + 80065fc: f7ff f8bb bl 8005776 + if (uECC_vli_numBits(s, num_n_words) > (bitcount_t)curve->num_bytes * 8) { + 8006600: 4621 mov r1, r4 + 8006602: a80e add r0, sp, #56 ; 0x38 + 8006604: f7ff f869 bl 80056da + 8006608: f995 1001 ldrsb.w r1, [r5, #1] + 800660c: ebb0 0fc1 cmp.w r0, r1, lsl #3 + 8006610: f73f af5b bgt.w 80064ca + uECC_vli_nativeToBytes(signature + curve->num_bytes, curve->num_bytes, s); + 8006614: 9b32 ldr r3, [sp, #200] ; 0xc8 + 8006616: aa0e add r2, sp, #56 ; 0x38 + 8006618: 1858 adds r0, r3, r1 + 800661a: f7ff f97f bl 800591c + return 1; + 800661e: 2001 movs r0, #1 + 8006620: e754 b.n 80064cc + } else if (!uECC_generate_random_int(tmp, curve->n, num_n_words)) { + 8006622: 4622 mov r2, r4 + 8006624: 4639 mov r1, r7 + 8006626: 4648 mov r0, r9 + 8006628: f7ff fa96 bl 8005b58 + 800662c: 2800 cmp r0, #0 + 800662e: d19a bne.n 8006566 + 8006630: e74b b.n 80064ca + 8006632: bf00 nop + 8006634: 2009e2a4 .word 0x2009e2a4 + 8006638: 2009e2a0 .word 0x2009e2a0 + +0800663c : + uECC_Curve curve) { + 800663c: e92d 43f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, lr} + 8006640: 4605 mov r5, r0 + 8006642: b093 sub sp, #76 ; 0x4c + 8006644: 460c mov r4, r1 + if (uECC_vli_isZero(Z1, num_words_secp256k1)) { + 8006646: 4610 mov r0, r2 + 8006648: 2108 movs r1, #8 + uECC_Curve curve) { + 800664a: 4617 mov r7, r2 + 800664c: 461e mov r6, r3 + if (uECC_vli_isZero(Z1, num_words_secp256k1)) { + 800664e: f7ff f82b bl 80056a8 + 8006652: 2800 cmp r0, #0 + 8006654: d161 bne.n 800671a + uECC_vli_modSquare_fast(t5, Y1, curve); /* t5 = y1^2 */ + 8006656: 4632 mov r2, r6 + 8006658: 4621 mov r1, r4 + 800665a: a80a add r0, sp, #40 ; 0x28 + 800665c: f7ff f93b bl 80058d6 + uECC_vli_modMult_fast(t4, X1, t5, curve); /* t4 = x1*y1^2 = A */ + 8006660: 4633 mov r3, r6 + 8006662: aa0a add r2, sp, #40 ; 0x28 + 8006664: 4629 mov r1, r5 + 8006666: a802 add r0, sp, #8 + 8006668: f7ff f925 bl 80058b6 + uECC_vli_modSquare_fast(X1, X1, curve); /* t1 = x1^2 */ + 800666c: 4632 mov r2, r6 + 800666e: 4629 mov r1, r5 + 8006670: 4628 mov r0, r5 + 8006672: f7ff f930 bl 80058d6 + uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = y1^4 */ + 8006676: a90a add r1, sp, #40 ; 0x28 + 8006678: 4608 mov r0, r1 + 800667a: 4632 mov r2, r6 + 800667c: f7ff f92b bl 80058d6 + uECC_vli_modAdd(Y1, X1, X1, curve->p, num_words_secp256k1); /* t2 = 2*x1^2 */ + 8006680: f04f 0808 mov.w r8, #8 + uECC_vli_modMult_fast(Z1, Y1, Z1, curve); /* t3 = y1*z1 = z3 */ + 8006684: 463a mov r2, r7 + 8006686: 4638 mov r0, r7 + 8006688: 4633 mov r3, r6 + 800668a: 4621 mov r1, r4 + uECC_vli_modAdd(Y1, X1, X1, curve->p, num_words_secp256k1); /* t2 = 2*x1^2 */ + 800668c: 1d37 adds r7, r6, #4 + uECC_vli_modMult_fast(Z1, Y1, Z1, curve); /* t3 = y1*z1 = z3 */ + 800668e: f7ff f912 bl 80058b6 + uECC_vli_modAdd(Y1, X1, X1, curve->p, num_words_secp256k1); /* t2 = 2*x1^2 */ + 8006692: 463b mov r3, r7 + 8006694: 462a mov r2, r5 + 8006696: 4629 mov r1, r5 + 8006698: 4620 mov r0, r4 + 800669a: f8cd 8000 str.w r8, [sp] + 800669e: f7ff fce3 bl 8006068 + uECC_vli_modAdd(Y1, Y1, X1, curve->p, num_words_secp256k1); /* t2 = 3*x1^2 */ + 80066a2: 463b mov r3, r7 + 80066a4: f8cd 8000 str.w r8, [sp] + 80066a8: 462a mov r2, r5 + 80066aa: 4621 mov r1, r4 + 80066ac: 4620 mov r0, r4 + 80066ae: f7ff fcdb bl 8006068 + return (vli[bit >> uECC_WORD_BITS_SHIFT] & ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK))); + 80066b2: 6823 ldr r3, [r4, #0] + if (uECC_vli_testBit(Y1, 0)) { + 80066b4: 07db lsls r3, r3, #31 + 80066b6: d533 bpl.n 8006720 + uECC_word_t carry = uECC_vli_add(Y1, Y1, curve->p, num_words_secp256k1); + 80066b8: 463a mov r2, r7 + 80066ba: 4621 mov r1, r4 + 80066bc: 4620 mov r0, r4 + 80066be: f7ff fa87 bl 8005bd0 + uECC_vli_rshift1(Y1, num_words_secp256k1); + 80066c2: 4641 mov r1, r8 + uECC_word_t carry = uECC_vli_add(Y1, Y1, curve->p, num_words_secp256k1); + 80066c4: 4681 mov r9, r0 + uECC_vli_rshift1(Y1, num_words_secp256k1); + 80066c6: 4620 mov r0, r4 + 80066c8: f7ff f848 bl 800575c + Y1[num_words_secp256k1 - 1] |= carry << (uECC_WORD_BITS - 1); + 80066cc: 69e3 ldr r3, [r4, #28] + 80066ce: ea43 73c9 orr.w r3, r3, r9, lsl #31 + 80066d2: 61e3 str r3, [r4, #28] + uECC_vli_modSquare_fast(X1, Y1, curve); /* t1 = B^2 */ + 80066d4: 4632 mov r2, r6 + 80066d6: 4621 mov r1, r4 + 80066d8: 4628 mov r0, r5 + 80066da: f7ff f8fc bl 80058d6 + uECC_vli_modSub(X1, X1, t4, curve->p, num_words_secp256k1); /* t1 = B^2 - A */ + 80066de: 463b mov r3, r7 + 80066e0: aa02 add r2, sp, #8 + 80066e2: 4629 mov r1, r5 + 80066e4: 4628 mov r0, r5 + 80066e6: f7ff fced bl 80060c4 + uECC_vli_modSub(X1, X1, t4, curve->p, num_words_secp256k1); /* t1 = B^2 - 2A = x3 */ + 80066ea: 463b mov r3, r7 + 80066ec: aa02 add r2, sp, #8 + 80066ee: 4629 mov r1, r5 + 80066f0: 4628 mov r0, r5 + 80066f2: f7ff fce7 bl 80060c4 + uECC_vli_modSub(t4, t4, X1, curve->p, num_words_secp256k1); /* t4 = A - x3 */ + 80066f6: a902 add r1, sp, #8 + 80066f8: 4608 mov r0, r1 + 80066fa: 463b mov r3, r7 + 80066fc: 462a mov r2, r5 + 80066fe: f7ff fce1 bl 80060c4 + uECC_vli_modMult_fast(Y1, Y1, t4, curve); /* t2 = B * (A - x3) */ + 8006702: 4633 mov r3, r6 + 8006704: aa02 add r2, sp, #8 + 8006706: 4621 mov r1, r4 + 8006708: 4620 mov r0, r4 + 800670a: f7ff f8d4 bl 80058b6 + uECC_vli_modSub(Y1, Y1, t5, curve->p, num_words_secp256k1); /* t2 = B * (A - x3) - y1^4 = y3 */ + 800670e: 463b mov r3, r7 + 8006710: aa0a add r2, sp, #40 ; 0x28 + 8006712: 4621 mov r1, r4 + 8006714: 4620 mov r0, r4 + 8006716: f7ff fcd5 bl 80060c4 +} + 800671a: b013 add sp, #76 ; 0x4c + 800671c: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + uECC_vli_rshift1(Y1, num_words_secp256k1); + 8006720: 4641 mov r1, r8 + 8006722: 4620 mov r0, r4 + 8006724: f7ff f81a bl 800575c + 8006728: e7d4 b.n 80066d4 + +0800672a : +static void x_side_default(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve) { + 800672a: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + 800672e: b08a sub sp, #40 ; 0x28 + 8006730: 4604 mov r4, r0 + 8006732: 4615 mov r5, r2 + 8006734: 460e mov r6, r1 + uECC_word_t _3[uECC_MAX_WORDS] = {3}; /* -a = 3 */ + 8006736: 221c movs r2, #28 + 8006738: 2100 movs r1, #0 + 800673a: a803 add r0, sp, #12 + 800673c: f006 ff9a bl 800d674 + uECC_vli_modSub(result, result, _3, curve->p, num_words); /* r = x^2 - 3 */ + 8006740: 1d2f adds r7, r5, #4 + uECC_word_t _3[uECC_MAX_WORDS] = {3}; /* -a = 3 */ + 8006742: 2303 movs r3, #3 + uECC_vli_modSquare_fast(result, x, curve); /* r = x^2 */ + 8006744: 462a mov r2, r5 + 8006746: 4631 mov r1, r6 + 8006748: 4620 mov r0, r4 + wordcount_t num_words = curve->num_words; + 800674a: f995 8000 ldrsb.w r8, [r5] + uECC_word_t _3[uECC_MAX_WORDS] = {3}; /* -a = 3 */ + 800674e: 9302 str r3, [sp, #8] + uECC_vli_modSquare_fast(result, x, curve); /* r = x^2 */ + 8006750: f7ff f8c1 bl 80058d6 + uECC_vli_modSub(result, result, _3, curve->p, num_words); /* r = x^2 - 3 */ + 8006754: 463b mov r3, r7 + 8006756: aa02 add r2, sp, #8 + 8006758: 4621 mov r1, r4 + 800675a: 4620 mov r0, r4 + 800675c: f7ff fcb2 bl 80060c4 + uECC_vli_modMult_fast(result, result, x, curve); /* r = x^3 - 3x */ + 8006760: 462b mov r3, r5 + 8006762: 4632 mov r2, r6 + 8006764: 4621 mov r1, r4 + 8006766: 4620 mov r0, r4 + 8006768: f7ff f8a5 bl 80058b6 + uECC_vli_modAdd(result, result, curve->b, curve->p, num_words); /* r = x^3 - 3x + b */ + 800676c: f8cd 8000 str.w r8, [sp] + 8006770: 463b mov r3, r7 + 8006772: f105 0284 add.w r2, r5, #132 ; 0x84 + 8006776: 4621 mov r1, r4 + 8006778: 4620 mov r0, r4 + 800677a: f7ff fc75 bl 8006068 +} + 800677e: b00a add sp, #40 ; 0x28 + 8006780: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + +08006784 : + uECC_Curve curve) { + 8006784: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + wordcount_t num_words = curve->num_words; + 8006788: f993 8000 ldrsb.w r8, [r3] + uECC_Curve curve) { + 800678c: b092 sub sp, #72 ; 0x48 + 800678e: 4604 mov r4, r0 + 8006790: 4689 mov r9, r1 + if (uECC_vli_isZero(Z1, num_words)) { + 8006792: 4610 mov r0, r2 + 8006794: 4641 mov r1, r8 + uECC_Curve curve) { + 8006796: 4615 mov r5, r2 + 8006798: 461e mov r6, r3 + if (uECC_vli_isZero(Z1, num_words)) { + 800679a: f7fe ff85 bl 80056a8 + 800679e: 2800 cmp r0, #0 + 80067a0: f040 808e bne.w 80068c0 + uECC_vli_modSquare_fast(t4, Y1, curve); /* t4 = y1^2 */ + 80067a4: 4632 mov r2, r6 + 80067a6: 4649 mov r1, r9 + 80067a8: a802 add r0, sp, #8 + 80067aa: f7ff f894 bl 80058d6 + uECC_vli_modMult_fast(t5, X1, t4, curve); /* t5 = x1*y1^2 = A */ + 80067ae: 4633 mov r3, r6 + 80067b0: aa02 add r2, sp, #8 + 80067b2: 4621 mov r1, r4 + 80067b4: a80a add r0, sp, #40 ; 0x28 + 80067b6: f7ff f87e bl 80058b6 + uECC_vli_modSquare_fast(t4, t4, curve); /* t4 = y1^4 */ + 80067ba: a902 add r1, sp, #8 + 80067bc: 4608 mov r0, r1 + 80067be: 4632 mov r2, r6 + 80067c0: f7ff f889 bl 80058d6 + uECC_vli_modMult_fast(Y1, Y1, Z1, curve); /* t2 = y1*z1 = z3 */ + 80067c4: 4633 mov r3, r6 + 80067c6: 462a mov r2, r5 + 80067c8: 4649 mov r1, r9 + 80067ca: 4648 mov r0, r9 + 80067cc: f7ff f873 bl 80058b6 + uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = x1 + z1^2 */ + 80067d0: 1d37 adds r7, r6, #4 + uECC_vli_modSquare_fast(Z1, Z1, curve); /* t3 = z1^2 */ + 80067d2: 4632 mov r2, r6 + 80067d4: 4629 mov r1, r5 + 80067d6: 4628 mov r0, r5 + 80067d8: f7ff f87d bl 80058d6 + uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = x1 + z1^2 */ + 80067dc: 463b mov r3, r7 + 80067de: 462a mov r2, r5 + 80067e0: 4621 mov r1, r4 + 80067e2: 4620 mov r0, r4 + 80067e4: f8cd 8000 str.w r8, [sp] + 80067e8: f7ff fc3e bl 8006068 + uECC_vli_modAdd(Z1, Z1, Z1, curve->p, num_words); /* t3 = 2*z1^2 */ + 80067ec: 463b mov r3, r7 + 80067ee: 462a mov r2, r5 + 80067f0: 4629 mov r1, r5 + 80067f2: 4628 mov r0, r5 + 80067f4: f8cd 8000 str.w r8, [sp] + 80067f8: f7ff fc36 bl 8006068 + uECC_vli_modSub(Z1, X1, Z1, curve->p, num_words); /* t3 = x1 - z1^2 */ + 80067fc: 463b mov r3, r7 + 80067fe: 462a mov r2, r5 + 8006800: 4621 mov r1, r4 + 8006802: 4628 mov r0, r5 + 8006804: f7ff fc5e bl 80060c4 + uECC_vli_modMult_fast(X1, X1, Z1, curve); /* t1 = x1^2 - z1^4 */ + 8006808: 4633 mov r3, r6 + 800680a: 462a mov r2, r5 + 800680c: 4621 mov r1, r4 + 800680e: 4620 mov r0, r4 + 8006810: f7ff f851 bl 80058b6 + uECC_vli_modAdd(Z1, X1, X1, curve->p, num_words); /* t3 = 2*(x1^2 - z1^4) */ + 8006814: 463b mov r3, r7 + 8006816: 4622 mov r2, r4 + 8006818: 4621 mov r1, r4 + 800681a: 4628 mov r0, r5 + 800681c: f8cd 8000 str.w r8, [sp] + 8006820: f7ff fc22 bl 8006068 + uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = 3*(x1^2 - z1^4) */ + 8006824: 463b mov r3, r7 + 8006826: f8cd 8000 str.w r8, [sp] + 800682a: 462a mov r2, r5 + 800682c: 4621 mov r1, r4 + 800682e: 4620 mov r0, r4 + 8006830: f7ff fc1a bl 8006068 + 8006834: 6823 ldr r3, [r4, #0] + if (uECC_vli_testBit(X1, 0)) { + 8006836: 07db lsls r3, r3, #31 + 8006838: d545 bpl.n 80068c6 + uECC_word_t l_carry = uECC_vli_add(X1, X1, curve->p, num_words); + 800683a: 463a mov r2, r7 + 800683c: 4621 mov r1, r4 + 800683e: 4620 mov r0, r4 + 8006840: f7ff f9c6 bl 8005bd0 + uECC_vli_rshift1(X1, num_words); + 8006844: 4641 mov r1, r8 + uECC_word_t l_carry = uECC_vli_add(X1, X1, curve->p, num_words); + 8006846: 4682 mov sl, r0 + uECC_vli_rshift1(X1, num_words); + 8006848: 4620 mov r0, r4 + 800684a: f7fe ff87 bl 800575c + X1[num_words - 1] |= l_carry << (uECC_WORD_BITS - 1); + 800684e: f108 4380 add.w r3, r8, #1073741824 ; 0x40000000 + 8006852: 3b01 subs r3, #1 + 8006854: f854 2023 ldr.w r2, [r4, r3, lsl #2] + 8006858: ea42 72ca orr.w r2, r2, sl, lsl #31 + 800685c: f844 2023 str.w r2, [r4, r3, lsl #2] + uECC_vli_modSquare_fast(Z1, X1, curve); /* t3 = B^2 */ + 8006860: 4632 mov r2, r6 + 8006862: 4621 mov r1, r4 + 8006864: 4628 mov r0, r5 + 8006866: f7ff f836 bl 80058d6 + uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - A */ + 800686a: 463b mov r3, r7 + 800686c: aa0a add r2, sp, #40 ; 0x28 + 800686e: 4629 mov r1, r5 + 8006870: 4628 mov r0, r5 + 8006872: f7ff fc27 bl 80060c4 + uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - 2A = x3 */ + 8006876: 463b mov r3, r7 + 8006878: aa0a add r2, sp, #40 ; 0x28 + 800687a: 4629 mov r1, r5 + 800687c: 4628 mov r0, r5 + 800687e: f7ff fc21 bl 80060c4 + uECC_vli_modSub(t5, t5, Z1, curve->p, num_words); /* t5 = A - x3 */ + 8006882: a90a add r1, sp, #40 ; 0x28 + 8006884: 4608 mov r0, r1 + 8006886: 463b mov r3, r7 + 8006888: 462a mov r2, r5 + 800688a: f7ff fc1b bl 80060c4 + uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = B * (A - x3) */ + 800688e: 4633 mov r3, r6 + 8006890: aa0a add r2, sp, #40 ; 0x28 + 8006892: 4621 mov r1, r4 + 8006894: 4620 mov r0, r4 + 8006896: f7ff f80e bl 80058b6 + uECC_vli_modSub(t4, X1, t4, curve->p, num_words); /* t4 = B * (A - x3) - y1^4 = y3 */ + 800689a: aa02 add r2, sp, #8 + 800689c: 463b mov r3, r7 + 800689e: 4610 mov r0, r2 + 80068a0: 4621 mov r1, r4 + 80068a2: f7ff fc0f bl 80060c4 + uECC_vli_set(X1, Z1, num_words); + 80068a6: 4642 mov r2, r8 + 80068a8: 4629 mov r1, r5 + 80068aa: 4620 mov r0, r4 + 80068ac: f7fe ff35 bl 800571a + uECC_vli_set(Z1, Y1, num_words); + 80068b0: 4649 mov r1, r9 + 80068b2: 4628 mov r0, r5 + 80068b4: f7fe ff31 bl 800571a + uECC_vli_set(Y1, t4, num_words); + 80068b8: a902 add r1, sp, #8 + 80068ba: 4648 mov r0, r9 + 80068bc: f7fe ff2d bl 800571a +} + 80068c0: b012 add sp, #72 ; 0x48 + 80068c2: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + uECC_vli_rshift1(X1, num_words); + 80068c6: 4641 mov r1, r8 + 80068c8: 4620 mov r0, r4 + 80068ca: f7fe ff47 bl 800575c + 80068ce: e7c7 b.n 8006860 + +080068d0 : + g_rng_function = rng_function; + 80068d0: 4b01 ldr r3, [pc, #4] ; (80068d8 ) + 80068d2: 6018 str r0, [r3, #0] +} + 80068d4: 4770 bx lr + 80068d6: bf00 nop + 80068d8: 2009e2a0 .word 0x2009e2a0 + +080068dc : +uECC_Curve uECC_secp256r1(void) { return &curve_secp256r1; } + 80068dc: 4800 ldr r0, [pc, #0] ; (80068e0 ) + 80068de: 4770 bx lr + 80068e0: 0800e928 .word 0x0800e928 + +080068e4 : +uECC_Curve uECC_secp256k1(void) { return &curve_secp256k1; } + 80068e4: 4800 ldr r0, [pc, #0] ; (80068e8 ) + 80068e6: 4770 bx lr + 80068e8: 0800e874 .word 0x0800e874 + +080068ec : + uECC_Curve curve) { + 80068ec: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + 80068f0: 4605 mov r5, r0 + 80068f2: b098 sub sp, #96 ; 0x60 + 80068f4: 460f mov r7, r1 + 80068f6: 4614 mov r4, r2 + 80068f8: 2640 movs r6, #64 ; 0x40 + if (!uECC_generate_random_int(private, curve->n, BITS_TO_WORDS(curve->num_n_bits))) { + 80068fa: f102 0824 add.w r8, r2, #36 ; 0x24 + 80068fe: f9b4 3002 ldrsh.w r3, [r4, #2] + 8006902: f113 021f adds.w r2, r3, #31 + 8006906: bf48 it mi + 8006908: f103 023e addmi.w r2, r3, #62 ; 0x3e + 800690c: f342 1247 sbfx r2, r2, #5, #8 + 8006910: 4641 mov r1, r8 + 8006912: 4668 mov r0, sp + 8006914: f7ff f920 bl 8005b58 + 8006918: b330 cbz r0, 8006968 + if (EccPoint_compute_public_key(public, private, curve)) { + 800691a: 4622 mov r2, r4 + 800691c: 4669 mov r1, sp + 800691e: a808 add r0, sp, #32 + 8006920: f7ff fd8f bl 8006442 + 8006924: b1f0 cbz r0, 8006964 + uECC_vli_nativeToBytes(private_key, BITS_TO_BYTES(curve->num_n_bits), private); + 8006926: f9b4 3002 ldrsh.w r3, [r4, #2] + 800692a: 1dd9 adds r1, r3, #7 + 800692c: bf48 it mi + 800692e: f103 010e addmi.w r1, r3, #14 + 8006932: 466a mov r2, sp + 8006934: 10c9 asrs r1, r1, #3 + 8006936: 4638 mov r0, r7 + 8006938: f7fe fff0 bl 800591c + uECC_vli_nativeToBytes(public_key, curve->num_bytes, public); + 800693c: f994 1001 ldrsb.w r1, [r4, #1] + 8006940: aa08 add r2, sp, #32 + 8006942: 4628 mov r0, r5 + 8006944: f7fe ffea bl 800591c + public_key + curve->num_bytes, curve->num_bytes, public + curve->num_words); + 8006948: f994 1001 ldrsb.w r1, [r4, #1] + 800694c: f994 2000 ldrsb.w r2, [r4] + uECC_vli_nativeToBytes( + 8006950: ab08 add r3, sp, #32 + 8006952: 1868 adds r0, r5, r1 + 8006954: eb03 0282 add.w r2, r3, r2, lsl #2 + 8006958: f7fe ffe0 bl 800591c + return 1; + 800695c: 2001 movs r0, #1 +} + 800695e: b018 add sp, #96 ; 0x60 + 8006960: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { + 8006964: 3e01 subs r6, #1 + 8006966: d1ca bne.n 80068fe + return 0; + 8006968: 2000 movs r0, #0 + 800696a: e7f8 b.n 800695e + +0800696c : + uECC_Curve curve) { + 800696c: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + 8006970: 461c mov r4, r3 + wordcount_t num_bytes = curve->num_bytes; + 8006972: f993 6001 ldrsb.w r6, [r3, #1] + wordcount_t num_words = curve->num_words; + 8006976: f993 9000 ldrsb.w r9, [r3] + uECC_vli_bytesToNative(private, private_key, BITS_TO_BYTES(curve->num_n_bits)); + 800697a: f9b3 3002 ldrsh.w r3, [r3, #2] + uECC_Curve curve) { + 800697e: b0a6 sub sp, #152 ; 0x98 + 8006980: 4617 mov r7, r2 + uECC_vli_bytesToNative(private, private_key, BITS_TO_BYTES(curve->num_n_bits)); + 8006982: 1dda adds r2, r3, #7 + 8006984: bf48 it mi + 8006986: f103 020e addmi.w r2, r3, #14 + uECC_word_t *p2[2] = {private, tmp}; + 800698a: f10d 0818 add.w r8, sp, #24 + uECC_Curve curve) { + 800698e: 4605 mov r5, r0 + uECC_word_t *p2[2] = {private, tmp}; + 8006990: f10d 0a38 add.w sl, sp, #56 ; 0x38 + uECC_vli_bytesToNative(private, private_key, BITS_TO_BYTES(curve->num_n_bits)); + 8006994: 10d2 asrs r2, r2, #3 + 8006996: 4640 mov r0, r8 + uECC_word_t *p2[2] = {private, tmp}; + 8006998: f8cd 8010 str.w r8, [sp, #16] + 800699c: f8cd a014 str.w sl, [sp, #20] + uECC_vli_bytesToNative(private, private_key, BITS_TO_BYTES(curve->num_n_bits)); + 80069a0: f7fe ffd0 bl 8005944 + uECC_vli_bytesToNative(public, public_key, num_bytes); + 80069a4: 4629 mov r1, r5 + 80069a6: 4632 mov r2, r6 + 80069a8: a816 add r0, sp, #88 ; 0x58 + 80069aa: f7fe ffcb bl 8005944 + uECC_vli_bytesToNative(public + num_words, public_key + num_bytes, num_bytes); + 80069ae: ab16 add r3, sp, #88 ; 0x58 + 80069b0: 19a9 adds r1, r5, r6 + 80069b2: eb03 0089 add.w r0, r3, r9, lsl #2 + 80069b6: 4632 mov r2, r6 + 80069b8: f7fe ffc4 bl 8005944 + carry = regularize_k(private, private, tmp, curve); + 80069bc: 4623 mov r3, r4 + 80069be: 4652 mov r2, sl + 80069c0: 4641 mov r1, r8 + 80069c2: 4640 mov r0, r8 + 80069c4: f7ff f929 bl 8005c1a + if (g_rng_function) { + 80069c8: 4b19 ldr r3, [pc, #100] ; (8006a30 ) + 80069ca: 681b ldr r3, [r3, #0] + carry = regularize_k(private, private, tmp, curve); + 80069cc: 4605 mov r5, r0 + if (g_rng_function) { + 80069ce: b163 cbz r3, 80069ea + if (!uECC_generate_random_int(p2[carry], curve->p, num_words)) { + 80069d0: ab26 add r3, sp, #152 ; 0x98 + 80069d2: eb03 0380 add.w r3, r3, r0, lsl #2 + 80069d6: 464a mov r2, r9 + 80069d8: f853 3c88 ldr.w r3, [r3, #-136] + 80069dc: 9303 str r3, [sp, #12] + 80069de: 4618 mov r0, r3 + 80069e0: 1d21 adds r1, r4, #4 + 80069e2: f7ff f8b9 bl 8005b58 + 80069e6: 9b03 ldr r3, [sp, #12] + 80069e8: b1f0 cbz r0, 8006a28 + EccPoint_mult(public, public, p2[!carry], initial_Z, curve->num_n_bits + 1, curve); + 80069ea: fab5 f185 clz r1, r5 + 80069ee: aa26 add r2, sp, #152 ; 0x98 + 80069f0: 0949 lsrs r1, r1, #5 + 80069f2: eb02 0181 add.w r1, r2, r1, lsl #2 + 80069f6: 8862 ldrh r2, [r4, #2] + 80069f8: 9401 str r4, [sp, #4] + 80069fa: 3201 adds r2, #1 + 80069fc: b212 sxth r2, r2 + 80069fe: 9200 str r2, [sp, #0] + 8006a00: f851 2c88 ldr.w r2, [r1, #-136] + 8006a04: a916 add r1, sp, #88 ; 0x58 + 8006a06: 4608 mov r0, r1 + 8006a08: f7ff fc50 bl 80062ac + uECC_vli_nativeToBytes(secret, num_bytes, public); + 8006a0c: aa16 add r2, sp, #88 ; 0x58 + 8006a0e: 4631 mov r1, r6 + 8006a10: 4638 mov r0, r7 + 8006a12: f7fe ff83 bl 800591c + return !EccPoint_isZero(public, curve); + 8006a16: 7821 ldrb r1, [r4, #0] + 8006a18: 0049 lsls r1, r1, #1 + 8006a1a: b249 sxtb r1, r1 + 8006a1c: 4610 mov r0, r2 + 8006a1e: f7fe fe43 bl 80056a8 + 8006a22: fab0 f080 clz r0, r0 + 8006a26: 0940 lsrs r0, r0, #5 +} + 8006a28: b026 add sp, #152 ; 0x98 + 8006a2a: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + 8006a2e: bf00 nop + 8006a30: 2009e2a0 .word 0x2009e2a0 + +08006a34 : +void uECC_compress(const uint8_t *public_key, uint8_t *compressed, uECC_Curve curve) { + 8006a34: b530 push {r4, r5, lr} + for (i = 0; i < curve->num_bytes; ++i) { + 8006a36: 2400 movs r4, #0 + 8006a38: f992 5001 ldrsb.w r5, [r2, #1] + 8006a3c: b263 sxtb r3, r4 + 8006a3e: 429d cmp r5, r3 + 8006a40: dc08 bgt.n 8006a54 + compressed[0] = 2 + (public_key[curve->num_bytes * 2 - 1] & 0x01); + 8006a42: eb00 0045 add.w r0, r0, r5, lsl #1 + 8006a46: f810 3c01 ldrb.w r3, [r0, #-1] + 8006a4a: f003 0301 and.w r3, r3, #1 + 8006a4e: 3302 adds r3, #2 + 8006a50: 700b strb r3, [r1, #0] +} + 8006a52: bd30 pop {r4, r5, pc} + compressed[i+1] = public_key[i]; + 8006a54: 5cc5 ldrb r5, [r0, r3] + 8006a56: 440b add r3, r1 + 8006a58: 3401 adds r4, #1 + 8006a5a: 705d strb r5, [r3, #1] + for (i = 0; i < curve->num_bytes; ++i) { + 8006a5c: e7ec b.n 8006a38 + +08006a5e : +void uECC_decompress(const uint8_t *compressed, uint8_t *public_key, uECC_Curve curve) { + 8006a5e: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + uECC_word_t *y = point + curve->num_words; + 8006a62: f992 8000 ldrsb.w r8, [r2] +void uECC_decompress(const uint8_t *compressed, uint8_t *public_key, uECC_Curve curve) { + 8006a66: b090 sub sp, #64 ; 0x40 + 8006a68: 4614 mov r4, r2 + 8006a6a: 4607 mov r7, r0 + uECC_vli_bytesToNative(point, compressed + 1, curve->num_bytes); + 8006a6c: f992 2001 ldrsb.w r2, [r2, #1] + uECC_word_t *y = point + curve->num_words; + 8006a70: eb0d 0588 add.w r5, sp, r8, lsl #2 +void uECC_decompress(const uint8_t *compressed, uint8_t *public_key, uECC_Curve curve) { + 8006a74: 460e mov r6, r1 + uECC_vli_bytesToNative(point, compressed + 1, curve->num_bytes); + 8006a76: 1c41 adds r1, r0, #1 + 8006a78: 4668 mov r0, sp + 8006a7a: f7fe ff63 bl 8005944 + curve->x_side(y, point, curve); + 8006a7e: 4622 mov r2, r4 + 8006a80: f8d4 30ac ldr.w r3, [r4, #172] ; 0xac + 8006a84: 4669 mov r1, sp + 8006a86: 4628 mov r0, r5 + 8006a88: 4798 blx r3 + curve->mod_sqrt(y, curve); + 8006a8a: f8d4 30a8 ldr.w r3, [r4, #168] ; 0xa8 + 8006a8e: 4621 mov r1, r4 + 8006a90: 4628 mov r0, r5 + 8006a92: 4798 blx r3 + if ((y[0] & 0x01) != (compressed[0] & 0x01)) { + 8006a94: 783b ldrb r3, [r7, #0] + 8006a96: f85d 2028 ldr.w r2, [sp, r8, lsl #2] + 8006a9a: 4053 eors r3, r2 + 8006a9c: 07db lsls r3, r3, #31 + 8006a9e: d504 bpl.n 8006aaa + uECC_vli_sub(y, curve->p, y, curve->num_words); + 8006aa0: 462a mov r2, r5 + 8006aa2: 1d21 adds r1, r4, #4 + 8006aa4: 4628 mov r0, r5 + 8006aa6: f7fe ffd1 bl 8005a4c + uECC_vli_nativeToBytes(public_key, curve->num_bytes, point); + 8006aaa: f994 1001 ldrsb.w r1, [r4, #1] + 8006aae: 466a mov r2, sp + 8006ab0: 4630 mov r0, r6 + 8006ab2: f7fe ff33 bl 800591c + uECC_vli_nativeToBytes(public_key + curve->num_bytes, curve->num_bytes, y); + 8006ab6: f994 1001 ldrsb.w r1, [r4, #1] + 8006aba: 462a mov r2, r5 + 8006abc: 1870 adds r0, r6, r1 + 8006abe: f7fe ff2d bl 800591c +} + 8006ac2: b010 add sp, #64 ; 0x40 + 8006ac4: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + +08006ac8 : +int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve) { + 8006ac8: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + if (EccPoint_isZero(point, curve)) { + 8006acc: 780d ldrb r5, [r1, #0] + wordcount_t num_words = curve->num_words; + 8006ace: f991 2000 ldrsb.w r2, [r1] +int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve) { + 8006ad2: b092 sub sp, #72 ; 0x48 + 8006ad4: 460e mov r6, r1 + if (EccPoint_isZero(point, curve)) { + 8006ad6: 0069 lsls r1, r5, #1 + 8006ad8: b249 sxtb r1, r1 +int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve) { + 8006ada: 4607 mov r7, r0 + wordcount_t num_words = curve->num_words; + 8006adc: 9201 str r2, [sp, #4] + if (EccPoint_isZero(point, curve)) { + 8006ade: f7fe fde3 bl 80056a8 + 8006ae2: 4604 mov r4, r0 + 8006ae4: bb80 cbnz r0, 8006b48 + if (uECC_vli_cmp_unsafe(curve->p, point, num_words) != 1 || + 8006ae6: f106 0804 add.w r8, r6, #4 + 8006aea: 9a01 ldr r2, [sp, #4] + 8006aec: 4639 mov r1, r7 + 8006aee: 4640 mov r0, r8 + 8006af0: f7fe fe1f bl 8005732 + 8006af4: 2801 cmp r0, #1 + 8006af6: d11a bne.n 8006b2e + uECC_vli_cmp_unsafe(curve->p, point + num_words, num_words) != 1) { + 8006af8: 9a01 ldr r2, [sp, #4] + 8006afa: 4640 mov r0, r8 + 8006afc: eb07 0182 add.w r1, r7, r2, lsl #2 + 8006b00: f7fe fe17 bl 8005732 + if (uECC_vli_cmp_unsafe(curve->p, point, num_words) != 1 || + 8006b04: 2801 cmp r0, #1 + 8006b06: d112 bne.n 8006b2e + uECC_vli_modSquare_fast(tmp1, point + num_words, curve); + 8006b08: 4632 mov r2, r6 + 8006b0a: a802 add r0, sp, #8 + curve->x_side(tmp2, point, curve); /* tmp2 = x^3 + ax + b */ + 8006b0c: f10d 0828 add.w r8, sp, #40 ; 0x28 + uECC_vli_modSquare_fast(tmp1, point + num_words, curve); + 8006b10: f7fe fee1 bl 80058d6 + curve->x_side(tmp2, point, curve); /* tmp2 = x^3 + ax + b */ + 8006b14: f8d6 30ac ldr.w r3, [r6, #172] ; 0xac + 8006b18: 4632 mov r2, r6 + 8006b1a: 4639 mov r1, r7 + 8006b1c: 4640 mov r0, r8 + 8006b1e: 4798 blx r3 + for (i = num_words - 1; i >= 0; --i) { + 8006b20: 1e6b subs r3, r5, #1 + 8006b22: b25b sxtb r3, r3 + 8006b24: 061a lsls r2, r3, #24 + 8006b26: d506 bpl.n 8006b36 + return (diff == 0); + 8006b28: fab4 f484 clz r4, r4 + 8006b2c: 0964 lsrs r4, r4, #5 +} + 8006b2e: 4620 mov r0, r4 + 8006b30: b012 add sp, #72 ; 0x48 + 8006b32: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + diff |= (left[i] ^ right[i]); + 8006b36: aa02 add r2, sp, #8 + 8006b38: f858 1023 ldr.w r1, [r8, r3, lsl #2] + 8006b3c: f852 2023 ldr.w r2, [r2, r3, lsl #2] + 8006b40: 404a eors r2, r1 + 8006b42: 4314 orrs r4, r2 + for (i = num_words - 1; i >= 0; --i) { + 8006b44: 3b01 subs r3, #1 + 8006b46: e7ed b.n 8006b24 + return 0; + 8006b48: 2400 movs r4, #0 + 8006b4a: e7f0 b.n 8006b2e + +08006b4c : +int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve) { + 8006b4c: b530 push {r4, r5, lr} + 8006b4e: 460c mov r4, r1 + 8006b50: b091 sub sp, #68 ; 0x44 + uECC_vli_bytesToNative(public, public_key, curve->num_bytes); + 8006b52: f991 2001 ldrsb.w r2, [r1, #1] +int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve) { + 8006b56: 4605 mov r5, r0 + uECC_vli_bytesToNative(public, public_key, curve->num_bytes); + 8006b58: 4601 mov r1, r0 + 8006b5a: 4668 mov r0, sp + 8006b5c: f7fe fef2 bl 8005944 + public + curve->num_words, public_key + curve->num_bytes, curve->num_bytes); + 8006b60: f994 2001 ldrsb.w r2, [r4, #1] + 8006b64: f994 0000 ldrsb.w r0, [r4] + uECC_vli_bytesToNative( + 8006b68: 18a9 adds r1, r5, r2 + 8006b6a: eb0d 0080 add.w r0, sp, r0, lsl #2 + 8006b6e: f7fe fee9 bl 8005944 + return uECC_valid_point(public, curve); + 8006b72: 4621 mov r1, r4 + 8006b74: 4668 mov r0, sp + 8006b76: f7ff ffa7 bl 8006ac8 +} + 8006b7a: b011 add sp, #68 ; 0x44 + 8006b7c: bd30 pop {r4, r5, pc} + +08006b7e : +int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve) { + 8006b7e: b570 push {r4, r5, r6, lr} + uECC_vli_bytesToNative(private, private_key, BITS_TO_BYTES(curve->num_n_bits)); + 8006b80: f9b2 3002 ldrsh.w r3, [r2, #2] +int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve) { + 8006b84: 4614 mov r4, r2 + uECC_vli_bytesToNative(private, private_key, BITS_TO_BYTES(curve->num_n_bits)); + 8006b86: 1dda adds r2, r3, #7 + 8006b88: bf48 it mi + 8006b8a: f103 020e addmi.w r2, r3, #14 +int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve) { + 8006b8e: b098 sub sp, #96 ; 0x60 + uECC_vli_bytesToNative(private, private_key, BITS_TO_BYTES(curve->num_n_bits)); + 8006b90: 10d2 asrs r2, r2, #3 +int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve) { + 8006b92: 460e mov r6, r1 + uECC_vli_bytesToNative(private, private_key, BITS_TO_BYTES(curve->num_n_bits)); + 8006b94: 4601 mov r1, r0 + 8006b96: 4668 mov r0, sp + 8006b98: f7fe fed4 bl 8005944 + if (uECC_vli_isZero(private, BITS_TO_WORDS(curve->num_n_bits))) { + 8006b9c: f9b4 3002 ldrsh.w r3, [r4, #2] + 8006ba0: f113 021f adds.w r2, r3, #31 + 8006ba4: bf48 it mi + 8006ba6: f103 023e addmi.w r2, r3, #62 ; 0x3e + 8006baa: f342 1147 sbfx r1, r2, #5, #8 + 8006bae: 4668 mov r0, sp + 8006bb0: f7fe fd7a bl 80056a8 + 8006bb4: b110 cbz r0, 8006bbc + return 0; + 8006bb6: 2000 movs r0, #0 +} + 8006bb8: b018 add sp, #96 ; 0x60 + 8006bba: bd70 pop {r4, r5, r6, pc} + if (uECC_vli_cmp(curve->n, private, BITS_TO_WORDS(curve->num_n_bits)) != 1) { + 8006bbc: 460a mov r2, r1 + 8006bbe: f104 0024 add.w r0, r4, #36 ; 0x24 + 8006bc2: 4669 mov r1, sp + 8006bc4: f7fe ffb0 bl 8005b28 + 8006bc8: 2801 cmp r0, #1 + 8006bca: 4605 mov r5, r0 + 8006bcc: d1f3 bne.n 8006bb6 + if (!EccPoint_compute_public_key(public, private, curve)) { + 8006bce: 4622 mov r2, r4 + 8006bd0: 4669 mov r1, sp + 8006bd2: a808 add r0, sp, #32 + 8006bd4: f7ff fc35 bl 8006442 + 8006bd8: 2800 cmp r0, #0 + 8006bda: d0ec beq.n 8006bb6 + uECC_vli_nativeToBytes(public_key, curve->num_bytes, public); + 8006bdc: f994 1001 ldrsb.w r1, [r4, #1] + 8006be0: aa08 add r2, sp, #32 + 8006be2: 4630 mov r0, r6 + 8006be4: f7fe fe9a bl 800591c + public_key + curve->num_bytes, curve->num_bytes, public + curve->num_words); + 8006be8: f994 1001 ldrsb.w r1, [r4, #1] + 8006bec: f994 2000 ldrsb.w r2, [r4] + uECC_vli_nativeToBytes( + 8006bf0: ab08 add r3, sp, #32 + 8006bf2: 1870 adds r0, r6, r1 + 8006bf4: eb03 0282 add.w r2, r3, r2, lsl #2 + 8006bf8: f7fe fe90 bl 800591c + return 1; + 8006bfc: 4628 mov r0, r5 + 8006bfe: e7db b.n 8006bb8 + +08006c00 : + uECC_Curve curve) { + 8006c00: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + 8006c04: b08a sub sp, #40 ; 0x28 + 8006c06: 4605 mov r5, r0 + 8006c08: f8dd 9048 ldr.w r9, [sp, #72] ; 0x48 + 8006c0c: 460e mov r6, r1 + 8006c0e: 4617 mov r7, r2 + 8006c10: 4698 mov r8, r3 + 8006c12: 2440 movs r4, #64 ; 0x40 + if (!uECC_generate_random_int(k, curve->n, BITS_TO_WORDS(curve->num_n_bits))) { + 8006c14: f109 0a24 add.w sl, r9, #36 ; 0x24 + 8006c18: f9b9 3002 ldrsh.w r3, [r9, #2] + 8006c1c: f113 021f adds.w r2, r3, #31 + 8006c20: bf48 it mi + 8006c22: f103 023e addmi.w r2, r3, #62 ; 0x3e + 8006c26: f342 1247 sbfx r2, r2, #5, #8 + 8006c2a: 4651 mov r1, sl + 8006c2c: a802 add r0, sp, #8 + 8006c2e: f7fe ff93 bl 8005b58 + 8006c32: b150 cbz r0, 8006c4a + if (uECC_sign_with_k(private_key, message_hash, hash_size, k, signature, curve)) { + 8006c34: e9cd 8900 strd r8, r9, [sp] + 8006c38: ab02 add r3, sp, #8 + 8006c3a: 463a mov r2, r7 + 8006c3c: 4631 mov r1, r6 + 8006c3e: 4628 mov r0, r5 + 8006c40: f7ff fc2a bl 8006498 + 8006c44: b928 cbnz r0, 8006c52 + for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { + 8006c46: 3c01 subs r4, #1 + 8006c48: d1e6 bne.n 8006c18 + return 0; + 8006c4a: 2000 movs r0, #0 +} + 8006c4c: b00a add sp, #40 ; 0x28 + 8006c4e: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + return 1; + 8006c52: 2001 movs r0, #1 + 8006c54: e7fa b.n 8006c4c + +08006c56 : +int uECC_sign_deterministic(const uint8_t *private_key, + const uint8_t *message_hash, + unsigned hash_size, + uECC_HashContext *hash_context, + uint8_t *signature, + uECC_Curve curve) { + 8006c56: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + 8006c5a: b091 sub sp, #68 ; 0x44 + 8006c5c: 4693 mov fp, r2 + uint8_t *K = hash_context->tmp; + uint8_t *V = K + hash_context->result_size; + wordcount_t num_bytes = curve->num_bytes; + wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); + 8006c5e: 9a1b ldr r2, [sp, #108] ; 0x6c + 8006c60: f9b2 8002 ldrsh.w r8, [r2, #2] + uint8_t *V = K + hash_context->result_size; + 8006c64: e9d3 6504 ldrd r6, r5, [r3, #16] + uECC_Curve curve) { + 8006c68: 461c mov r4, r3 + wordcount_t num_bytes = curve->num_bytes; + 8006c6a: 9b1b ldr r3, [sp, #108] ; 0x6c + wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); + 8006c6c: f118 071f adds.w r7, r8, #31 + 8006c70: bf48 it mi + 8006c72: f108 073e addmi.w r7, r8, #62 ; 0x3e + bitcount_t num_n_bits = curve->num_n_bits; + uECC_word_t tries; + unsigned i; + for (i = 0; i < hash_context->result_size; ++i) { + 8006c76: 2200 movs r2, #0 + wordcount_t num_bytes = curve->num_bytes; + 8006c78: f993 3001 ldrsb.w r3, [r3, #1] + uECC_Curve curve) { + 8006c7c: 4681 mov r9, r0 + 8006c7e: 468a mov sl, r1 + uint8_t *V = K + hash_context->result_size; + 8006c80: 442e add r6, r5 + wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); + 8006c82: f347 1747 sbfx r7, r7, #5, #8 + V[i] = 0x01; + 8006c86: 2001 movs r0, #1 + K[i] = 0; + 8006c88: 4694 mov ip, r2 + for (i = 0; i < hash_context->result_size; ++i) { + 8006c8a: 6921 ldr r1, [r4, #16] + 8006c8c: 4291 cmp r1, r2 + 8006c8e: f200 8086 bhi.w 8006d9e + } + + /* K = HMAC_K(V || 0x00 || int2octets(x) || h(m)) */ + HMAC_init(hash_context, K); + 8006c92: 4629 mov r1, r5 + 8006c94: 4620 mov r0, r4 + 8006c96: 9303 str r3, [sp, #12] + 8006c98: f7fe fe74 bl 8005984 + V[hash_context->result_size] = 0x00; + 8006c9c: 6922 ldr r2, [r4, #16] + 8006c9e: 2100 movs r1, #0 + 8006ca0: 54b1 strb r1, [r6, r2] + HMAC_update(hash_context, V, hash_context->result_size + 1); + 8006ca2: 6922 ldr r2, [r4, #16] + 8006ca4: 4631 mov r1, r6 + 8006ca6: 3201 adds r2, #1 + 8006ca8: 4620 mov r0, r4 + 8006caa: f7fe fe8c bl 80059c6 + HMAC_update(hash_context, private_key, num_bytes); + 8006cae: 9b03 ldr r3, [sp, #12] + 8006cb0: 4649 mov r1, r9 + 8006cb2: 461a mov r2, r3 + 8006cb4: 4620 mov r0, r4 + 8006cb6: f7fe fe86 bl 80059c6 + HMAC_update(hash_context, message_hash, hash_size); + 8006cba: 465a mov r2, fp + 8006cbc: 4651 mov r1, sl + 8006cbe: 4620 mov r0, r4 + 8006cc0: f7fe fe81 bl 80059c6 + HMAC_finish(hash_context, K, K); + 8006cc4: 462a mov r2, r5 + 8006cc6: 4629 mov r1, r5 + 8006cc8: 4620 mov r0, r4 + 8006cca: f7fe fe7e bl 80059ca + + update_V(hash_context, K, V); + 8006cce: 4632 mov r2, r6 + 8006cd0: 4629 mov r1, r5 + 8006cd2: 4620 mov r0, r4 + 8006cd4: f7fe fea8 bl 8005a28 + + /* K = HMAC_K(V || 0x01 || int2octets(x) || h(m)) */ + HMAC_init(hash_context, K); + 8006cd8: 4629 mov r1, r5 + 8006cda: 4620 mov r0, r4 + 8006cdc: f7fe fe52 bl 8005984 + V[hash_context->result_size] = 0x01; + 8006ce0: 6922 ldr r2, [r4, #16] + 8006ce2: 2101 movs r1, #1 + 8006ce4: 54b1 strb r1, [r6, r2] + HMAC_update(hash_context, V, hash_context->result_size + 1); + 8006ce6: 6922 ldr r2, [r4, #16] + 8006ce8: 4620 mov r0, r4 + 8006cea: 440a add r2, r1 + 8006cec: 4631 mov r1, r6 + 8006cee: f7fe fe6a bl 80059c6 + HMAC_update(hash_context, private_key, num_bytes); + 8006cf2: 9b03 ldr r3, [sp, #12] + 8006cf4: 4649 mov r1, r9 + 8006cf6: 461a mov r2, r3 + 8006cf8: 4620 mov r0, r4 + 8006cfa: f7fe fe64 bl 80059c6 + HMAC_update(hash_context, message_hash, hash_size); + 8006cfe: 465a mov r2, fp + 8006d00: 4651 mov r1, sl + 8006d02: 4620 mov r0, r4 + 8006d04: f7fe fe5f bl 80059c6 + HMAC_finish(hash_context, K, K); + 8006d08: 462a mov r2, r5 + 8006d0a: 4629 mov r1, r5 + 8006d0c: 4620 mov r0, r4 + 8006d0e: f7fe fe5c bl 80059ca + + update_V(hash_context, K, V); + 8006d12: 4632 mov r2, r6 + 8006d14: 4629 mov r1, r5 + 8006d16: 4620 mov r0, r4 + 8006d18: f7fe fe86 bl 8005a28 + wordcount_t T_bytes = 0; + for (;;) { + update_V(hash_context, K, V); + for (i = 0; i < hash_context->result_size; ++i) { + T_ptr[T_bytes++] = V[i]; + if (T_bytes >= num_n_words * uECC_WORD_SIZE) { + 8006d1c: 00bb lsls r3, r7, #2 + 8006d1e: 9304 str r3, [sp, #16] + goto filled; + } + } + } + filled: + if ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8 > num_n_bits) { + 8006d20: 017b lsls r3, r7, #5 + 8006d22: 9305 str r3, [sp, #20] + uECC_word_t mask = (uECC_word_t)-1; + T[num_n_words - 1] &= + mask >> ((bitcount_t)(num_n_words * uECC_WORD_SIZE * 8 - num_n_bits)); + 8006d24: ebc8 1347 rsb r3, r8, r7, lsl #5 + 8006d28: f04f 32ff mov.w r2, #4294967295 ; 0xffffffff + 8006d2c: b21b sxth r3, r3 + 8006d2e: fa22 f303 lsr.w r3, r2, r3 + 8006d32: 9306 str r3, [sp, #24] + 8006d34: 2340 movs r3, #64 ; 0x40 + 8006d36: 9303 str r3, [sp, #12] + T[num_n_words - 1] &= + 8006d38: 4417 add r7, r2 + 8006d3a: 446b add r3, sp + 8006d3c: eb03 0787 add.w r7, r3, r7, lsl #2 + wordcount_t T_bytes = 0; + 8006d40: 2300 movs r3, #0 + update_V(hash_context, K, V); + 8006d42: 4632 mov r2, r6 + 8006d44: 4629 mov r1, r5 + 8006d46: 4620 mov r0, r4 + 8006d48: 9307 str r3, [sp, #28] + 8006d4a: f7fe fe6d bl 8005a28 + for (i = 0; i < hash_context->result_size; ++i) { + 8006d4e: 6920 ldr r0, [r4, #16] + 8006d50: 9b07 ldr r3, [sp, #28] + 8006d52: 4631 mov r1, r6 + 8006d54: 4430 add r0, r6 + 8006d56: 461a mov r2, r3 + T_ptr[T_bytes++] = V[i]; + 8006d58: ab08 add r3, sp, #32 + 8006d5a: eb03 0c02 add.w ip, r3, r2 + for (i = 0; i < hash_context->result_size; ++i) { + 8006d5e: 4288 cmp r0, r1 + 8006d60: 4613 mov r3, r2 + 8006d62: f102 0201 add.w r2, r2, #1 + 8006d66: b252 sxtb r2, r2 + 8006d68: d0eb beq.n 8006d42 + T_ptr[T_bytes++] = V[i]; + 8006d6a: f811 3b01 ldrb.w r3, [r1], #1 + 8006d6e: f88c 3000 strb.w r3, [ip] + if (T_bytes >= num_n_words * uECC_WORD_SIZE) { + 8006d72: 9b04 ldr r3, [sp, #16] + 8006d74: 4293 cmp r3, r2 + 8006d76: dcef bgt.n 8006d58 + if ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8 > num_n_bits) { + 8006d78: 9b05 ldr r3, [sp, #20] + 8006d7a: 4598 cmp r8, r3 + 8006d7c: db14 blt.n 8006da8 + } + + if (uECC_sign_with_k(private_key, message_hash, hash_size, T, signature, curve)) { + 8006d7e: 9b1b ldr r3, [sp, #108] ; 0x6c + 8006d80: 9301 str r3, [sp, #4] + 8006d82: 9b1a ldr r3, [sp, #104] ; 0x68 + 8006d84: 9300 str r3, [sp, #0] + 8006d86: 465a mov r2, fp + 8006d88: ab08 add r3, sp, #32 + 8006d8a: 4651 mov r1, sl + 8006d8c: 4648 mov r0, r9 + 8006d8e: f7ff fb83 bl 8006498 + 8006d92: b180 cbz r0, 8006db6 + return 1; + 8006d94: 2301 movs r3, #1 + HMAC_finish(hash_context, K, K); + + update_V(hash_context, K, V); + } + return 0; +} + 8006d96: 4618 mov r0, r3 + 8006d98: b011 add sp, #68 ; 0x44 + 8006d9a: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + V[i] = 0x01; + 8006d9e: 54b0 strb r0, [r6, r2] + K[i] = 0; + 8006da0: f805 c002 strb.w ip, [r5, r2] + for (i = 0; i < hash_context->result_size; ++i) { + 8006da4: 3201 adds r2, #1 + 8006da6: e770 b.n 8006c8a + T[num_n_words - 1] &= + 8006da8: f857 3c20 ldr.w r3, [r7, #-32] + 8006dac: 9a06 ldr r2, [sp, #24] + 8006dae: 4013 ands r3, r2 + 8006db0: f847 3c20 str.w r3, [r7, #-32] + 8006db4: e7e3 b.n 8006d7e + 8006db6: 9007 str r0, [sp, #28] + HMAC_init(hash_context, K); + 8006db8: 4629 mov r1, r5 + 8006dba: 4620 mov r0, r4 + 8006dbc: f7fe fde2 bl 8005984 + V[hash_context->result_size] = 0x00; + 8006dc0: 6922 ldr r2, [r4, #16] + 8006dc2: 9b07 ldr r3, [sp, #28] + 8006dc4: 54b3 strb r3, [r6, r2] + HMAC_update(hash_context, V, hash_context->result_size + 1); + 8006dc6: 6922 ldr r2, [r4, #16] + 8006dc8: 4631 mov r1, r6 + 8006dca: 3201 adds r2, #1 + 8006dcc: 4620 mov r0, r4 + 8006dce: f7fe fdfa bl 80059c6 + HMAC_finish(hash_context, K, K); + 8006dd2: 462a mov r2, r5 + 8006dd4: 4629 mov r1, r5 + 8006dd6: 4620 mov r0, r4 + 8006dd8: f7fe fdf7 bl 80059ca + update_V(hash_context, K, V); + 8006ddc: 4632 mov r2, r6 + 8006dde: 4629 mov r1, r5 + 8006de0: 4620 mov r0, r4 + 8006de2: f7fe fe21 bl 8005a28 + for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { + 8006de6: 9b03 ldr r3, [sp, #12] + 8006de8: 3b01 subs r3, #1 + 8006dea: 9303 str r3, [sp, #12] + 8006dec: 9b07 ldr r3, [sp, #28] + 8006dee: d1a7 bne.n 8006d40 + 8006df0: e7d1 b.n 8006d96 + +08006df2 : + +int uECC_verify(const uint8_t *public_key, + const uint8_t *message_hash, + unsigned hash_size, + const uint8_t *signature, + uECC_Curve curve) { + 8006df2: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + 8006df6: ed2d 8b02 vpush {d8} + 8006dfa: b0fb sub sp, #492 ; 0x1ec + 8006dfc: 461c mov r4, r3 + 8006dfe: 9d86 ldr r5, [sp, #536] ; 0x218 + const uECC_word_t *point; + bitcount_t num_bits; + bitcount_t i; + uECC_word_t r[uECC_MAX_WORDS], s[uECC_MAX_WORDS]; + wordcount_t num_words = curve->num_words; + wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); + 8006e00: f9b5 3002 ldrsh.w r3, [r5, #2] + wordcount_t num_words = curve->num_words; + 8006e04: f995 8000 ldrsb.w r8, [r5] + wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); + 8006e08: f113 061f adds.w r6, r3, #31 + 8006e0c: bf48 it mi + 8006e0e: f103 063e addmi.w r6, r3, #62 ; 0x3e + 8006e12: f346 1647 sbfx r6, r6, #5, #8 + + rx[num_n_words - 1] = 0; + 8006e16: f106 3aff add.w sl, r6, #4294967295 ; 0xffffffff + uECC_Curve curve) { + 8006e1a: 4691 mov r9, r2 + rx[num_n_words - 1] = 0; + 8006e1c: aa22 add r2, sp, #136 ; 0x88 + 8006e1e: 2300 movs r3, #0 + 8006e20: f842 302a str.w r3, [r2, sl, lsl #2] + r[num_n_words - 1] = 0; + 8006e24: aa7a add r2, sp, #488 ; 0x1e8 + 8006e26: eb02 028a add.w r2, r2, sl, lsl #2 + uECC_Curve curve) { + 8006e2a: 4607 mov r7, r0 + r[num_n_words - 1] = 0; + 8006e2c: f842 3cc0 str.w r3, [r2, #-192] + s[num_n_words - 1] = 0; + 8006e30: f842 3ca0 str.w r3, [r2, #-160] + uECC_Curve curve) { + 8006e34: ee08 1a90 vmov s17, r1 + + uECC_vli_bytesToNative(public, public_key, curve->num_bytes); + 8006e38: f995 2001 ldrsb.w r2, [r5, #1] + 8006e3c: 4601 mov r1, r0 + 8006e3e: a85a add r0, sp, #360 ; 0x168 + 8006e40: f7fe fd80 bl 8005944 + uECC_vli_bytesToNative( + public + num_words, public_key + curve->num_bytes, curve->num_bytes); + 8006e44: ea4f 0388 mov.w r3, r8, lsl #2 + 8006e48: f995 2001 ldrsb.w r2, [r5, #1] + 8006e4c: 9304 str r3, [sp, #16] + uECC_vli_bytesToNative( + 8006e4e: ab5a add r3, sp, #360 ; 0x168 + 8006e50: eb03 0388 add.w r3, r3, r8, lsl #2 + 8006e54: 4618 mov r0, r3 + 8006e56: 18b9 adds r1, r7, r2 + 8006e58: ee08 3a10 vmov s16, r3 + 8006e5c: f7fe fd72 bl 8005944 + uECC_vli_bytesToNative(r, signature, curve->num_bytes); + 8006e60: 4621 mov r1, r4 + 8006e62: f995 2001 ldrsb.w r2, [r5, #1] + 8006e66: a84a add r0, sp, #296 ; 0x128 + 8006e68: f7fe fd6c bl 8005944 + uECC_vli_bytesToNative(s, signature + curve->num_bytes, curve->num_bytes); + 8006e6c: f995 2001 ldrsb.w r2, [r5, #1] + 8006e70: a852 add r0, sp, #328 ; 0x148 + 8006e72: 18a1 adds r1, r4, r2 + 8006e74: f7fe fd66 bl 8005944 + + /* r, s must not be 0. */ + if (uECC_vli_isZero(r, num_words) || uECC_vli_isZero(s, num_words)) { + 8006e78: 4641 mov r1, r8 + 8006e7a: a84a add r0, sp, #296 ; 0x128 + 8006e7c: f7fe fc14 bl 80056a8 + 8006e80: 2300 movs r3, #0 + 8006e82: 4604 mov r4, r0 + 8006e84: 2800 cmp r0, #0 + 8006e86: f040 812b bne.w 80070e0 + 8006e8a: a852 add r0, sp, #328 ; 0x148 + 8006e8c: f7fe fc0c bl 80056a8 + 8006e90: 9002 str r0, [sp, #8] + 8006e92: 2800 cmp r0, #0 + 8006e94: f040 8126 bne.w 80070e4 + return 0; + } + + /* r, s must be < n. */ + if (uECC_vli_cmp_unsafe(curve->n, r, num_n_words) != 1 || + 8006e98: f105 0b24 add.w fp, r5, #36 ; 0x24 + 8006e9c: 4632 mov r2, r6 + 8006e9e: a94a add r1, sp, #296 ; 0x128 + 8006ea0: 4658 mov r0, fp + 8006ea2: f7fe fc46 bl 8005732 + 8006ea6: 2801 cmp r0, #1 + 8006ea8: f040 811e bne.w 80070e8 + uECC_vli_cmp_unsafe(curve->n, s, num_n_words) != 1) { + 8006eac: 4632 mov r2, r6 + 8006eae: a952 add r1, sp, #328 ; 0x148 + 8006eb0: 4658 mov r0, fp + 8006eb2: f7fe fc3e bl 8005732 + if (uECC_vli_cmp_unsafe(curve->n, r, num_n_words) != 1 || + 8006eb6: 2801 cmp r0, #1 + uECC_vli_cmp_unsafe(curve->n, s, num_n_words) != 1) { + 8006eb8: 9005 str r0, [sp, #20] + if (uECC_vli_cmp_unsafe(curve->n, r, num_n_words) != 1 || + 8006eba: f040 8115 bne.w 80070e8 + return 0; + } + + /* Calculate u1 and u2. */ + uECC_vli_modInv(z, s, curve->n, num_n_words); /* z = 1/s */ + 8006ebe: ac1a add r4, sp, #104 ; 0x68 + u1[num_n_words - 1] = 0; + 8006ec0: af0a add r7, sp, #40 ; 0x28 + uECC_vli_modInv(z, s, curve->n, num_n_words); /* z = 1/s */ + 8006ec2: 4633 mov r3, r6 + 8006ec4: 465a mov r2, fp + 8006ec6: 4620 mov r0, r4 + 8006ec8: f7ff f84e bl 8005f68 + u1[num_n_words - 1] = 0; + 8006ecc: 9b02 ldr r3, [sp, #8] + 8006ece: f847 302a str.w r3, [r7, sl, lsl #2] + bits2int(u1, message_hash, hash_size, curve); + 8006ed2: 464a mov r2, r9 + 8006ed4: 4638 mov r0, r7 + 8006ed6: ee18 1a90 vmov r1, s17 + 8006eda: 462b mov r3, r5 + 8006edc: f7fe fddd bl 8005a9a + uECC_vli_modMult(u1, u1, z, curve->n, num_n_words); /* u1 = e/s */ + 8006ee0: 4639 mov r1, r7 + 8006ee2: 4638 mov r0, r7 + 8006ee4: 465b mov r3, fp + 8006ee6: 4622 mov r2, r4 + 8006ee8: 9600 str r6, [sp, #0] + 8006eea: f7fe fc44 bl 8005776 + uECC_vli_modMult(u2, r, z, curve->n, num_n_words); /* u2 = r/s */ + + /* Calculate sum = G + Q. */ + uECC_vli_set(sum, public, num_words); + 8006eee: f50d 7ad4 add.w sl, sp, #424 ; 0x1a8 + uECC_vli_modMult(u2, r, z, curve->n, num_n_words); /* u2 = r/s */ + 8006ef2: 465b mov r3, fp + 8006ef4: 4622 mov r2, r4 + 8006ef6: a94a add r1, sp, #296 ; 0x128 + 8006ef8: a812 add r0, sp, #72 ; 0x48 + 8006efa: 9600 str r6, [sp, #0] + 8006efc: f7fe fc3b bl 8005776 + uECC_vli_set(sum, public, num_words); + 8006f00: 4642 mov r2, r8 + 8006f02: 4650 mov r0, sl + 8006f04: a95a add r1, sp, #360 ; 0x168 + 8006f06: f7fe fc08 bl 800571a + uECC_vli_set(sum + num_words, public + num_words, num_words); + 8006f0a: 9b04 ldr r3, [sp, #16] + 8006f0c: eb0a 0903 add.w r9, sl, r3 + 8006f10: ee18 1a10 vmov r1, s16 + 8006f14: 4648 mov r0, r9 + 8006f16: f7fe fc00 bl 800571a + uECC_vli_set(tx, curve->G, num_words); + 8006f1a: f105 0344 add.w r3, r5, #68 ; 0x44 + 8006f1e: 4619 mov r1, r3 + 8006f20: a832 add r0, sp, #200 ; 0xc8 + 8006f22: 9303 str r3, [sp, #12] + 8006f24: f7fe fbf9 bl 800571a + uECC_vli_set(ty, curve->G + num_words, num_words); + 8006f28: e9dd 3103 ldrd r3, r1, [sp, #12] + 8006f2c: a83a add r0, sp, #232 ; 0xe8 + 8006f2e: 1859 adds r1, r3, r1 + 8006f30: f7fe fbf3 bl 800571a + uECC_vli_modSub(z, sum, tx, curve->p, num_words); /* z = x2 - x1 */ + 8006f34: 1d2b adds r3, r5, #4 + 8006f36: ee08 3a10 vmov s16, r3 + 8006f3a: 4651 mov r1, sl + 8006f3c: aa32 add r2, sp, #200 ; 0xc8 + 8006f3e: 4620 mov r0, r4 + 8006f40: f7ff f8c0 bl 80060c4 + XYcZ_add(tx, ty, sum, sum + num_words, curve); + 8006f44: 464b mov r3, r9 + 8006f46: 4652 mov r2, sl + 8006f48: a93a add r1, sp, #232 ; 0xe8 + 8006f4a: a832 add r0, sp, #200 ; 0xc8 + 8006f4c: 9500 str r5, [sp, #0] + 8006f4e: f7ff f94d bl 80061ec + uECC_vli_modInv(z, z, curve->p, num_words); /* z = 1/z */ + 8006f52: ee18 2a10 vmov r2, s16 + 8006f56: 4643 mov r3, r8 + 8006f58: 4621 mov r1, r4 + 8006f5a: 4620 mov r0, r4 + 8006f5c: f7ff f804 bl 8005f68 + apply_z(sum, sum + num_words, z, curve); + 8006f60: 462b mov r3, r5 + 8006f62: 4649 mov r1, r9 + 8006f64: 4650 mov r0, sl + 8006f66: 4622 mov r2, r4 + 8006f68: f7fe fcb9 bl 80058de + + /* Use Shamir's trick to calculate u1*G + u2*Q */ + points[0] = 0; + 8006f6c: 9a02 ldr r2, [sp, #8] + 8006f6e: 9206 str r2, [sp, #24] + points[1] = curve->G; + 8006f70: 9a03 ldr r2, [sp, #12] + 8006f72: 9207 str r2, [sp, #28] + points[2] = public; + points[3] = sum; + num_bits = smax(uECC_vli_numBits(u1, num_n_words), + 8006f74: 4631 mov r1, r6 + points[2] = public; + 8006f76: aa5a add r2, sp, #360 ; 0x168 + num_bits = smax(uECC_vli_numBits(u1, num_n_words), + 8006f78: 4638 mov r0, r7 + points[3] = sum; + 8006f7a: e9cd 2a08 strd r2, sl, [sp, #32] + num_bits = smax(uECC_vli_numBits(u1, num_n_words), + 8006f7e: f7fe fbac bl 80056da + 8006f82: 4631 mov r1, r6 + 8006f84: 4682 mov sl, r0 + 8006f86: a812 add r0, sp, #72 ; 0x48 + 8006f88: f7fe fba7 bl 80056da + return (a > b ? a : b); + 8006f8c: 4550 cmp r0, sl + 8006f8e: bfb8 it lt + 8006f90: 4650 movlt r0, sl + uECC_vli_numBits(u2, num_n_words)); + + point = points[(!!uECC_vli_testBit(u1, num_bits - 1)) | + 8006f92: fa1f f980 uxth.w r9, r0 + 8006f96: f109 31ff add.w r1, r9, #4294967295 ; 0xffffffff + 8006f9a: b209 sxth r1, r1 + 8006f9c: 4638 mov r0, r7 + 8006f9e: 9103 str r1, [sp, #12] + 8006fa0: f7fe fb91 bl 80056c6 + ((!!uECC_vli_testBit(u2, num_bits - 1)) << 1)]; + 8006fa4: 9903 ldr r1, [sp, #12] + point = points[(!!uECC_vli_testBit(u1, num_bits - 1)) | + 8006fa6: 1e07 subs r7, r0, #0 + ((!!uECC_vli_testBit(u2, num_bits - 1)) << 1)]; + 8006fa8: a812 add r0, sp, #72 ; 0x48 + point = points[(!!uECC_vli_testBit(u1, num_bits - 1)) | + 8006faa: bf18 it ne + 8006fac: 2701 movne r7, #1 + ((!!uECC_vli_testBit(u2, num_bits - 1)) << 1)]; + 8006fae: f7fe fb8a bl 80056c6 + 8006fb2: 2800 cmp r0, #0 + 8006fb4: bf14 ite ne + 8006fb6: 2002 movne r0, #2 + 8006fb8: 2000 moveq r0, #0 + point = points[(!!uECC_vli_testBit(u1, num_bits - 1)) | + 8006fba: ab06 add r3, sp, #24 + 8006fbc: 4307 orrs r7, r0 + uECC_vli_set(rx, point, num_words); + 8006fbe: 4642 mov r2, r8 + point = points[(!!uECC_vli_testBit(u1, num_bits - 1)) | + 8006fc0: f853 1027 ldr.w r1, [r3, r7, lsl #2] + uECC_vli_set(rx, point, num_words); + 8006fc4: a822 add r0, sp, #136 ; 0x88 + 8006fc6: f7fe fba8 bl 800571a + uECC_vli_set(ry, point + num_words, num_words); + 8006fca: 9b04 ldr r3, [sp, #16] + 8006fcc: f10d 0aa8 add.w sl, sp, #168 ; 0xa8 + 8006fd0: 4419 add r1, r3 + 8006fd2: 4650 mov r0, sl + 8006fd4: f7fe fba1 bl 800571a + uECC_vli_clear(z, num_words); + 8006fd8: 4641 mov r1, r8 + 8006fda: 4620 mov r0, r4 + 8006fdc: f7fe fb5e bl 800569c + z[0] = 1; + 8006fe0: 9b05 ldr r3, [sp, #20] + 8006fe2: 6023 str r3, [r4, #0] + + for (i = num_bits - 2; i >= 0; --i) { + 8006fe4: f1a9 0902 sub.w r9, r9, #2 + 8006fe8: ab22 add r3, sp, #136 ; 0x88 + 8006fea: fa0f f989 sxth.w r9, r9 + 8006fee: 9303 str r3, [sp, #12] + 8006ff0: f1b9 0f00 cmp.w r9, #0 + 8006ff4: da26 bge.n 8007044 + XYcZ_add(tx, ty, rx, ry, curve); + uECC_vli_modMult_fast(z, z, tz, curve); + } + } + + uECC_vli_modInv(z, z, curve->p, num_words); /* Z = 1/Z */ + 8006ff6: ee18 2a10 vmov r2, s16 + 8006ffa: 4643 mov r3, r8 + 8006ffc: 4621 mov r1, r4 + 8006ffe: 4620 mov r0, r4 + 8007000: f7fe ffb2 bl 8005f68 + apply_z(rx, ry, z, curve); + 8007004: 9803 ldr r0, [sp, #12] + 8007006: 462b mov r3, r5 + 8007008: 4622 mov r2, r4 + 800700a: 4651 mov r1, sl + 800700c: f7fe fc67 bl 80058de + + /* v = x1 (mod n) */ + if (uECC_vli_cmp_unsafe(curve->n, rx, num_n_words) != 1) { + 8007010: 9903 ldr r1, [sp, #12] + 8007012: 4632 mov r2, r6 + 8007014: 4658 mov r0, fp + 8007016: f7fe fb8c bl 8005732 + 800701a: 2801 cmp r0, #1 + 800701c: d003 beq.n 8007026 + uECC_vli_sub(rx, rx, curve->n, num_n_words); + 800701e: 465a mov r2, fp + 8007020: 4608 mov r0, r1 + 8007022: f7fe fd13 bl 8005a4c + for (i = num_words - 1; i >= 0; --i) { + 8007026: f108 33ff add.w r3, r8, #4294967295 ; 0xffffffff + 800702a: b25b sxtb r3, r3 + diff |= (left[i] ^ right[i]); + 800702c: a94a add r1, sp, #296 ; 0x128 + for (i = num_words - 1; i >= 0; --i) { + 800702e: 061a lsls r2, r3, #24 + 8007030: d54b bpl.n 80070ca + return (diff == 0); + 8007032: 9b02 ldr r3, [sp, #8] + 8007034: fab3 f083 clz r0, r3 + 8007038: 0940 lsrs r0, r0, #5 + } + + /* Accept only if v == r. */ + return (int)(uECC_vli_equal(rx, r, num_words)); +} + 800703a: b07b add sp, #492 ; 0x1ec + 800703c: ecbd 8b02 vpop {d8} + 8007040: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + curve->double_jacobian(rx, ry, z, curve); + 8007044: 462b mov r3, r5 + 8007046: 4622 mov r2, r4 + 8007048: f8d5 70a4 ldr.w r7, [r5, #164] ; 0xa4 + 800704c: 9803 ldr r0, [sp, #12] + 800704e: 4651 mov r1, sl + 8007050: 47b8 blx r7 + index = (!!uECC_vli_testBit(u1, i)) | ((!!uECC_vli_testBit(u2, i)) << 1); + 8007052: 4649 mov r1, r9 + 8007054: a80a add r0, sp, #40 ; 0x28 + 8007056: f7fe fb36 bl 80056c6 + 800705a: 4649 mov r1, r9 + 800705c: 1e07 subs r7, r0, #0 + 800705e: a812 add r0, sp, #72 ; 0x48 + 8007060: bf18 it ne + 8007062: 2701 movne r7, #1 + 8007064: f7fe fb2f bl 80056c6 + 8007068: 2800 cmp r0, #0 + 800706a: bf14 ite ne + 800706c: 2002 movne r0, #2 + 800706e: 2000 moveq r0, #0 + 8007070: 4307 orrs r7, r0 + point = points[index]; + 8007072: ab06 add r3, sp, #24 + 8007074: f853 1027 ldr.w r1, [r3, r7, lsl #2] + if (point) { + 8007078: b311 cbz r1, 80070c0 + uECC_vli_set(tx, point, num_words); + 800707a: 4642 mov r2, r8 + 800707c: a832 add r0, sp, #200 ; 0xc8 + 800707e: f7fe fb4c bl 800571a + uECC_vli_set(ty, point + num_words, num_words); + 8007082: 9b04 ldr r3, [sp, #16] + 8007084: a83a add r0, sp, #232 ; 0xe8 + 8007086: 4419 add r1, r3 + 8007088: f7fe fb47 bl 800571a + apply_z(tx, ty, z, curve); + 800708c: 4601 mov r1, r0 + 800708e: 462b mov r3, r5 + 8007090: 4622 mov r2, r4 + 8007092: a832 add r0, sp, #200 ; 0xc8 + 8007094: f7fe fc23 bl 80058de + uECC_vli_modSub(tz, rx, tx, curve->p, num_words); /* Z = x2 - x1 */ + 8007098: ee18 3a10 vmov r3, s16 + 800709c: 9903 ldr r1, [sp, #12] + 800709e: aa32 add r2, sp, #200 ; 0xc8 + 80070a0: a842 add r0, sp, #264 ; 0x108 + 80070a2: f7ff f80f bl 80060c4 + XYcZ_add(tx, ty, rx, ry, curve); + 80070a6: 9a03 ldr r2, [sp, #12] + 80070a8: 9500 str r5, [sp, #0] + 80070aa: 4653 mov r3, sl + 80070ac: a93a add r1, sp, #232 ; 0xe8 + 80070ae: a832 add r0, sp, #200 ; 0xc8 + 80070b0: f7ff f89c bl 80061ec + uECC_vli_modMult_fast(z, z, tz, curve); + 80070b4: 462b mov r3, r5 + 80070b6: aa42 add r2, sp, #264 ; 0x108 + 80070b8: 4621 mov r1, r4 + 80070ba: 4620 mov r0, r4 + 80070bc: f7fe fbfb bl 80058b6 + for (i = num_bits - 2; i >= 0; --i) { + 80070c0: f109 39ff add.w r9, r9, #4294967295 ; 0xffffffff + 80070c4: fa0f f989 sxth.w r9, r9 + 80070c8: e792 b.n 8006ff0 + diff |= (left[i] ^ right[i]); + 80070ca: 9a03 ldr r2, [sp, #12] + 80070cc: f851 0023 ldr.w r0, [r1, r3, lsl #2] + 80070d0: f852 2023 ldr.w r2, [r2, r3, lsl #2] + 80070d4: 4042 eors r2, r0 + 80070d6: 9802 ldr r0, [sp, #8] + 80070d8: 4310 orrs r0, r2 + 80070da: 9002 str r0, [sp, #8] + for (i = num_words - 1; i >= 0; --i) { + 80070dc: 3b01 subs r3, #1 + 80070de: e7a6 b.n 800702e + return 0; + 80070e0: 4618 mov r0, r3 + 80070e2: e7aa b.n 800703a + 80070e4: 4620 mov r0, r4 + 80070e6: e7a8 b.n 800703a + 80070e8: 9802 ldr r0, [sp, #8] + 80070ea: e7a6 b.n 800703a + +080070ec : +const uint32_t MSIRangeTable[12] = {100000, 200000, 400000, 800000, 1000000, 2000000, \ + 4000000, 8000000, 16000000, 24000000, 32000000, 48000000}; +uint32_t SystemCoreClock; + +// TODO: cleanup HAL stuff to not use this +uint32_t HAL_GetTick(void) { return 53; } + 80070ec: 2035 movs r0, #53 ; 0x35 + 80070ee: 4770 bx lr + +080070f0 : +uint32_t uwTickPrio = 0; /* (1UL << __NVIC_PRIO_BITS); * Invalid priority */ + +// unwanted junk from stm32l4xx_hal_rcc.c +HAL_StatusTypeDef HAL_InitTick (uint32_t TickPriority) { return 0; } + 80070f0: 2000 movs r0, #0 + 80070f2: 4770 bx lr + +080070f4 : + * or PWR_REGULATOR_VOLTAGE_SCALE1_BOOST when applicable) + */ +uint32_t HAL_PWREx_GetVoltageRange(void) +{ +#if defined(PWR_CR5_R1MODE) + if (READ_BIT(PWR->CR1, PWR_CR1_VOS) == PWR_REGULATOR_VOLTAGE_SCALE2) + 80070f4: 4b07 ldr r3, [pc, #28] ; (8007114 ) + 80070f6: 6818 ldr r0, [r3, #0] + 80070f8: f400 60c0 and.w r0, r0, #1536 ; 0x600 + 80070fc: f5b0 6f80 cmp.w r0, #1024 ; 0x400 + 8007100: d006 beq.n 8007110 + { + return PWR_REGULATOR_VOLTAGE_SCALE2; + } + else if (READ_BIT(PWR->CR5, PWR_CR5_R1MODE) == PWR_CR5_R1MODE) + 8007102: f8d3 0080 ldr.w r0, [r3, #128] ; 0x80 + { + /* PWR_CR5_R1MODE bit set means that Range 1 Boost is disabled */ + return PWR_REGULATOR_VOLTAGE_SCALE1; + 8007106: f410 7080 ands.w r0, r0, #256 ; 0x100 + 800710a: bf18 it ne + 800710c: f44f 7000 movne.w r0, #512 ; 0x200 + return PWR_REGULATOR_VOLTAGE_SCALE1_BOOST; + } +#else + return (PWR->CR1 & PWR_CR1_VOS); +#endif +} + 8007110: 4770 bx lr + 8007112: bf00 nop + 8007114: 40007000 .word 0x40007000 + +08007118 : + uint32_t wait_loop_index; + + assert_param(IS_PWR_VOLTAGE_SCALING_RANGE(VoltageScaling)); + +#if defined(PWR_CR5_R1MODE) + if (VoltageScaling == PWR_REGULATOR_VOLTAGE_SCALE1_BOOST) + 8007118: 4b29 ldr r3, [pc, #164] ; (80071c0 ) + { + /* If current range is range 2 */ + if (READ_BIT(PWR->CR1, PWR_CR1_VOS) == PWR_REGULATOR_VOLTAGE_SCALE2) + 800711a: 681a ldr r2, [r3, #0] + if (VoltageScaling == PWR_REGULATOR_VOLTAGE_SCALE1_BOOST) + 800711c: bb30 cbnz r0, 800716c + if (READ_BIT(PWR->CR1, PWR_CR1_VOS) == PWR_REGULATOR_VOLTAGE_SCALE2) + 800711e: f402 62c0 and.w r2, r2, #1536 ; 0x600 + 8007122: f5b2 6f80 cmp.w r2, #1024 ; 0x400 + { + /* Make sure Range 1 Boost is enabled */ + CLEAR_BIT(PWR->CR5, PWR_CR5_R1MODE); + 8007126: f8d3 2080 ldr.w r2, [r3, #128] ; 0x80 + 800712a: f422 7280 bic.w r2, r2, #256 ; 0x100 + 800712e: f8c3 2080 str.w r2, [r3, #128] ; 0x80 + if (READ_BIT(PWR->CR1, PWR_CR1_VOS) == PWR_REGULATOR_VOLTAGE_SCALE2) + 8007132: d11a bne.n 800716a + + /* Set Range 1 */ + MODIFY_REG(PWR->CR1, PWR_CR1_VOS, PWR_REGULATOR_VOLTAGE_SCALE1); + 8007134: 681a ldr r2, [r3, #0] + 8007136: f422 62c0 bic.w r2, r2, #1536 ; 0x600 + 800713a: f442 7200 orr.w r2, r2, #512 ; 0x200 + 800713e: 601a str r2, [r3, #0] + + /* Wait until VOSF is cleared */ + wait_loop_index = ((PWR_FLAG_SETTING_DELAY_US * SystemCoreClock) / 1000000U) + 1; + 8007140: 4a20 ldr r2, [pc, #128] ; (80071c4 ) + 8007142: 6812 ldr r2, [r2, #0] + 8007144: 2132 movs r1, #50 ; 0x32 + 8007146: 434a muls r2, r1 + 8007148: 491f ldr r1, [pc, #124] ; (80071c8 ) + 800714a: fbb2 f2f1 udiv r2, r2, r1 + 800714e: 3201 adds r2, #1 + while ((HAL_IS_BIT_SET(PWR->SR2, PWR_SR2_VOSF)) && (wait_loop_index != 0U)) + 8007150: 6959 ldr r1, [r3, #20] + 8007152: 0549 lsls r1, r1, #21 + 8007154: d500 bpl.n 8007158 + 8007156: b922 cbnz r2, 8007162 + { + wait_loop_index--; + } + if (HAL_IS_BIT_SET(PWR->SR2, PWR_SR2_VOSF)) + 8007158: 695b ldr r3, [r3, #20] + 800715a: 0558 lsls r0, r3, #21 + 800715c: d403 bmi.n 8007166 + /* No need to wait for VOSF to be cleared for this transition */ + } + } +#endif + + return HAL_OK; + 800715e: 2000 movs r0, #0 +} + 8007160: 4770 bx lr + wait_loop_index--; + 8007162: 3a01 subs r2, #1 + 8007164: e7f4 b.n 8007150 + return HAL_TIMEOUT; + 8007166: 2003 movs r0, #3 + 8007168: 4770 bx lr + CLEAR_BIT(PWR->CR5, PWR_CR5_R1MODE); + 800716a: 4770 bx lr + else if (VoltageScaling == PWR_REGULATOR_VOLTAGE_SCALE1) + 800716c: f5b0 7f00 cmp.w r0, #512 ; 0x200 + 8007170: d11f bne.n 80071b2 + if (READ_BIT(PWR->CR1, PWR_CR1_VOS) == PWR_REGULATOR_VOLTAGE_SCALE2) + 8007172: f402 62c0 and.w r2, r2, #1536 ; 0x600 + 8007176: f5b2 6f80 cmp.w r2, #1024 ; 0x400 + SET_BIT(PWR->CR5, PWR_CR5_R1MODE); + 800717a: f8d3 2080 ldr.w r2, [r3, #128] ; 0x80 + 800717e: f442 7280 orr.w r2, r2, #256 ; 0x100 + 8007182: f8c3 2080 str.w r2, [r3, #128] ; 0x80 + if (READ_BIT(PWR->CR1, PWR_CR1_VOS) == PWR_REGULATOR_VOLTAGE_SCALE2) + 8007186: d1ea bne.n 800715e + MODIFY_REG(PWR->CR1, PWR_CR1_VOS, PWR_REGULATOR_VOLTAGE_SCALE1); + 8007188: 681a ldr r2, [r3, #0] + 800718a: f422 62c0 bic.w r2, r2, #1536 ; 0x600 + 800718e: f442 7200 orr.w r2, r2, #512 ; 0x200 + 8007192: 601a str r2, [r3, #0] + wait_loop_index = ((PWR_FLAG_SETTING_DELAY_US * SystemCoreClock) / 1000000U) + 1; + 8007194: 4a0b ldr r2, [pc, #44] ; (80071c4 ) + 8007196: 6812 ldr r2, [r2, #0] + 8007198: 2132 movs r1, #50 ; 0x32 + 800719a: 434a muls r2, r1 + 800719c: 490a ldr r1, [pc, #40] ; (80071c8 ) + 800719e: fbb2 f2f1 udiv r2, r2, r1 + 80071a2: 3201 adds r2, #1 + while ((HAL_IS_BIT_SET(PWR->SR2, PWR_SR2_VOSF)) && (wait_loop_index != 0U)) + 80071a4: 6959 ldr r1, [r3, #20] + 80071a6: 0549 lsls r1, r1, #21 + 80071a8: d5d6 bpl.n 8007158 + 80071aa: 2a00 cmp r2, #0 + 80071ac: d0d4 beq.n 8007158 + wait_loop_index--; + 80071ae: 3a01 subs r2, #1 + 80071b0: e7f8 b.n 80071a4 + MODIFY_REG(PWR->CR1, PWR_CR1_VOS, PWR_REGULATOR_VOLTAGE_SCALE2); + 80071b2: f422 62c0 bic.w r2, r2, #1536 ; 0x600 + 80071b6: f442 6280 orr.w r2, r2, #1024 ; 0x400 + 80071ba: 601a str r2, [r3, #0] + 80071bc: e7cf b.n 800715e + 80071be: bf00 nop + 80071c0: 40007000 .word 0x40007000 + 80071c4: 2009e2a8 .word 0x2009e2a8 + 80071c8: 000f4240 .word 0x000f4240 + +080071cc : + +__weak void HAL_SDEx_DriveTransceiver_1_8V_Callback(FlagStatus status) +{ + // unused? +} + 80071cc: 4770 bx lr + ... + +080071d0 <__NVIC_SystemReset>: + 80071d0: f3bf 8f4f dsb sy + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 80071d4: 4905 ldr r1, [pc, #20] ; (80071ec <__NVIC_SystemReset+0x1c>) + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 80071d6: 4b06 ldr r3, [pc, #24] ; (80071f0 <__NVIC_SystemReset+0x20>) + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 80071d8: 68ca ldr r2, [r1, #12] + 80071da: f402 62e0 and.w r2, r2, #1792 ; 0x700 + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 80071de: 4313 orrs r3, r2 + 80071e0: 60cb str r3, [r1, #12] + 80071e2: f3bf 8f4f dsb sy + __NOP(); + 80071e6: bf00 nop + for(;;) /* wait until reset */ + 80071e8: e7fd b.n 80071e6 <__NVIC_SystemReset+0x16> + 80071ea: bf00 nop + 80071ec: e000ed00 .word 0xe000ed00 + 80071f0: 05fa0004 .word 0x05fa0004 + +080071f4 : +{ + 80071f4: b510 push {r4, lr} + 80071f6: 3801 subs r0, #1 + 80071f8: 440a add r2, r1 + *(acc) ^= *(more); + 80071fa: f811 4b01 ldrb.w r4, [r1], #1 + 80071fe: f810 3f01 ldrb.w r3, [r0, #1]! + for(; len; len--, more++, acc++) { + 8007202: 4291 cmp r1, r2 + *(acc) ^= *(more); + 8007204: ea83 0304 eor.w r3, r3, r4 + 8007208: 7003 strb r3, [r0, #0] + for(; len; len--, more++, acc++) { + 800720a: d1f6 bne.n 80071fa + } +} + 800720c: bd10 pop {r4, pc} + ... + +08007210 : + +// se2_write1() +// + static bool +se2_write1(uint8_t cmd, uint8_t arg) +{ + 8007210: b51f push {r0, r1, r2, r3, r4, lr} + uint8_t data[3] = { cmd, 1, arg }; + 8007212: 2301 movs r3, #1 + 8007214: f88d 300d strb.w r3, [sp, #13] + + HAL_StatusTypeDef rv = HAL_I2C_Master_Transmit(&i2c_port, I2C_ADDR, + 8007218: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + uint8_t data[3] = { cmd, 1, arg }; + 800721c: f88d 000c strb.w r0, [sp, #12] + 8007220: f88d 100e strb.w r1, [sp, #14] + HAL_StatusTypeDef rv = HAL_I2C_Master_Transmit(&i2c_port, I2C_ADDR, + 8007224: 9300 str r3, [sp, #0] + 8007226: aa03 add r2, sp, #12 + 8007228: 2303 movs r3, #3 + 800722a: 2136 movs r1, #54 ; 0x36 + 800722c: 4804 ldr r0, [pc, #16] ; (8007240 ) + 800722e: f004 fb7f bl 800b930 + data, sizeof(data), HAL_MAX_DELAY); + + return (rv != HAL_OK); +} + 8007232: 3800 subs r0, #0 + 8007234: bf18 it ne + 8007236: 2001 movne r0, #1 + 8007238: b005 add sp, #20 + 800723a: f85d fb04 ldr.w pc, [sp], #4 + 800723e: bf00 nop + 8007240: 2009e3ec .word 0x2009e3ec + +08007244 : + +// se2_write2() +// + static bool +se2_write2(uint8_t cmd, uint8_t arg1, uint8_t arg2) +{ + 8007244: b51f push {r0, r1, r2, r3, r4, lr} + uint8_t data[4] = { cmd, 2, arg1, arg2 }; + 8007246: 2302 movs r3, #2 + 8007248: f88d 300d strb.w r3, [sp, #13] + + HAL_StatusTypeDef rv = HAL_I2C_Master_Transmit(&i2c_port, I2C_ADDR, + 800724c: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + uint8_t data[4] = { cmd, 2, arg1, arg2 }; + 8007250: f88d 000c strb.w r0, [sp, #12] + 8007254: f88d 100e strb.w r1, [sp, #14] + 8007258: f88d 200f strb.w r2, [sp, #15] + HAL_StatusTypeDef rv = HAL_I2C_Master_Transmit(&i2c_port, I2C_ADDR, + 800725c: 9300 str r3, [sp, #0] + 800725e: aa03 add r2, sp, #12 + 8007260: 2304 movs r3, #4 + 8007262: 2136 movs r1, #54 ; 0x36 + 8007264: 4804 ldr r0, [pc, #16] ; (8007278 ) + 8007266: f004 fb63 bl 800b930 + data, sizeof(data), HAL_MAX_DELAY); + + return (rv != HAL_OK); +} + 800726a: 3800 subs r0, #0 + 800726c: bf18 it ne + 800726e: 2001 movne r0, #1 + 8007270: b005 add sp, #20 + 8007272: f85d fb04 ldr.w pc, [sp], #4 + 8007276: bf00 nop + 8007278: 2009e3ec .word 0x2009e3ec + +0800727c : + +// se2_write_n() +// + static bool +se2_write_n(uint8_t cmd, uint8_t *param1, const uint8_t *data_in, uint8_t len) +{ + 800727c: b5f0 push {r4, r5, r6, r7, lr} + 800727e: 460d mov r5, r1 + uint8_t data[2 + (param1?1:0) + len], *p = data; + 8007280: 2d00 cmp r5, #0 + 8007282: bf14 ite ne + 8007284: 2403 movne r4, #3 + 8007286: 2402 moveq r4, #2 + 8007288: 441c add r4, r3 +{ + 800728a: 4611 mov r1, r2 + uint8_t data[2 + (param1?1:0) + len], *p = data; + 800728c: f104 0207 add.w r2, r4, #7 +{ + 8007290: b083 sub sp, #12 + uint8_t data[2 + (param1?1:0) + len], *p = data; + 8007292: f402 727e and.w r2, r2, #1016 ; 0x3f8 +{ + 8007296: af02 add r7, sp, #8 + uint8_t data[2 + (param1?1:0) + len], *p = data; + 8007298: ebad 0d02 sub.w sp, sp, r2 + 800729c: ae02 add r6, sp, #8 + + *(p++) = cmd; + *(p++) = sizeof(data) - 2; + 800729e: f1a4 0202 sub.w r2, r4, #2 + *(p++) = cmd; + 80072a2: f88d 0008 strb.w r0, [sp, #8] + *(p++) = sizeof(data) - 2; + 80072a6: 7072 strb r2, [r6, #1] + if(param1) { + *(p++) = *param1; + 80072a8: bf1b ittet ne + 80072aa: 782a ldrbne r2, [r5, #0] + 80072ac: 70b2 strbne r2, [r6, #2] + *(p++) = sizeof(data) - 2; + 80072ae: f10d 000a addeq.w r0, sp, #10 + *(p++) = *param1; + 80072b2: f10d 000b addne.w r0, sp, #11 + } + if(len) { + 80072b6: b113 cbz r3, 80072be + memcpy(p, data_in, len); + 80072b8: 461a mov r2, r3 + 80072ba: f006 f9b3 bl 800d624 + } + + HAL_StatusTypeDef rv = HAL_I2C_Master_Transmit(&i2c_port, I2C_ADDR, + 80072be: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 80072c2: 9300 str r3, [sp, #0] + 80072c4: 4632 mov r2, r6 + 80072c6: 4623 mov r3, r4 + 80072c8: 2136 movs r1, #54 ; 0x36 + 80072ca: 4804 ldr r0, [pc, #16] ; (80072dc ) + 80072cc: f004 fb30 bl 800b930 + data, sizeof(data), HAL_MAX_DELAY); + + return (rv != HAL_OK); +} + 80072d0: 3800 subs r0, #0 + 80072d2: bf18 it ne + 80072d4: 2001 movne r0, #1 + 80072d6: 3704 adds r7, #4 + 80072d8: 46bd mov sp, r7 + 80072da: bdf0 pop {r4, r5, r6, r7, pc} + 80072dc: 2009e3ec .word 0x2009e3ec + +080072e0 : + +// rng_for_uECC() +// + static int +rng_for_uECC(uint8_t *dest, unsigned size) +{ + 80072e0: b508 push {r3, lr} + 'dest' was filled with random data, or 0 if the random data could not be generated. + The filled-in values should be either truly random, or from a cryptographically-secure PRNG. + + typedef int (*uECC_RNG_Function)(uint8_t *dest, unsigned size); + */ + rng_buffer(dest, size); + 80072e2: f7fb fa35 bl 8002750 + + return 1; +} + 80072e6: 2001 movs r0, #1 + 80072e8: bd08 pop {r3, pc} + ... + +080072ec : +{ + 80072ec: b508 push {r3, lr} + 80072ee: 4602 mov r2, r0 + CALL_CHECK(se2_write_n(0x87, NULL, data, len)); + 80072f0: b2cb uxtb r3, r1 + 80072f2: 2087 movs r0, #135 ; 0x87 + 80072f4: 2100 movs r1, #0 + 80072f6: f7ff ffc1 bl 800727c + 80072fa: b118 cbz r0, 8007304 + 80072fc: 4802 ldr r0, [pc, #8] ; (8007308 ) + 80072fe: 21c1 movs r1, #193 ; 0xc1 + 8007300: f006 f9c6 bl 800d690 +} + 8007304: bd08 pop {r3, pc} + 8007306: bf00 nop + 8007308: 2009e390 .word 0x2009e390 + +0800730c : +{ + 800730c: e92d 43f7 stmdb sp!, {r0, r1, r2, r4, r5, r6, r7, r8, r9, lr} + HAL_StatusTypeDef rv = HAL_I2C_Master_Receive(&i2c_port, I2C_ADDR, rx, len, HAL_MAX_DELAY); + 8007310: f8df 9044 ldr.w r9, [pc, #68] ; 8007358 +{ + 8007314: 4604 mov r4, r0 + 8007316: 460d mov r5, r1 + 8007318: f44f 7696 mov.w r6, #300 ; 0x12c + HAL_StatusTypeDef rv = HAL_I2C_Master_Receive(&i2c_port, I2C_ADDR, rx, len, HAL_MAX_DELAY); + 800731c: b287 uxth r7, r0 + 800731e: f04f 38ff mov.w r8, #4294967295 ; 0xffffffff + 8007322: f8cd 8000 str.w r8, [sp] + 8007326: 463b mov r3, r7 + 8007328: 462a mov r2, r5 + 800732a: 2136 movs r1, #54 ; 0x36 + 800732c: 4648 mov r0, r9 + 800732e: f004 fbb3 bl 800ba98 + if(rv == HAL_OK) { + 8007332: b938 cbnz r0, 8007344 + if(rx[0] != len-1) { + 8007334: 782b ldrb r3, [r5, #0] + 8007336: 3c01 subs r4, #1 + 8007338: 42a3 cmp r3, r4 + 800733a: d10a bne.n 8007352 + return rx[1]; + 800733c: 7868 ldrb r0, [r5, #1] +} + 800733e: b003 add sp, #12 + 8007340: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + delay_ms(1); + 8007344: 2001 movs r0, #1 + 8007346: f7fc fad7 bl 80038f8 + for(int tries=0; tries<300; tries++) { + 800734a: 3e01 subs r6, #1 + 800734c: d1e9 bne.n 8007322 + return RC_NO_ACK; + 800734e: 200f movs r0, #15 + 8007350: e7f5 b.n 800733e + return RC_WRONG_SIZE; + 8007352: 201f movs r0, #31 + 8007354: e7f3 b.n 800733e + 8007356: bf00 nop + 8007358: 2009e3ec .word 0x2009e3ec + +0800735c : +{ + 800735c: b507 push {r0, r1, r2, lr} + return se2_read_n(2, rx); + 800735e: 2002 movs r0, #2 + 8007360: a901 add r1, sp, #4 + 8007362: f7ff ffd3 bl 800730c +} + 8007366: b003 add sp, #12 + 8007368: f85d fb04 ldr.w pc, [sp], #4 + +0800736c : +{ + 800736c: b507 push {r0, r1, r2, lr} + CALL_CHECK(se2_write_n(0x96, &page_num, data, 32)); + 800736e: 2320 movs r3, #32 +{ + 8007370: 460a mov r2, r1 + 8007372: f88d 0007 strb.w r0, [sp, #7] + CALL_CHECK(se2_write_n(0x96, &page_num, data, 32)); + 8007376: f10d 0107 add.w r1, sp, #7 + 800737a: 2096 movs r0, #150 ; 0x96 + 800737c: f7ff ff7e bl 800727c + 8007380: b118 cbz r0, 800738a + 8007382: 21cb movs r1, #203 ; 0xcb + CHECK_RIGHT(se2_read1() == RC_SUCCESS); + 8007384: 4805 ldr r0, [pc, #20] ; (800739c ) + 8007386: f006 f983 bl 800d690 + 800738a: f7ff ffe7 bl 800735c + 800738e: 28aa cmp r0, #170 ; 0xaa + 8007390: d001 beq.n 8007396 + 8007392: 21cd movs r1, #205 ; 0xcd + 8007394: e7f6 b.n 8007384 +} + 8007396: b003 add sp, #12 + 8007398: f85d fb04 ldr.w pc, [sp], #4 + 800739c: 2009e390 .word 0x2009e390 + +080073a0 : + ASSERT(pubkey_num < 2); + 80073a0: 2801 cmp r0, #1 +{ + 80073a2: b508 push {r3, lr} + ASSERT(pubkey_num < 2); + 80073a4: d902 bls.n 80073ac + 80073a6: 480a ldr r0, [pc, #40] ; (80073d0 ) + 80073a8: f7f9 fb4e bl 8000a48 + CALL_CHECK(se2_write1(0xcb, (wpe <<6) | pubkey_num)); + 80073ac: ea40 1181 orr.w r1, r0, r1, lsl #6 + 80073b0: b2c9 uxtb r1, r1 + 80073b2: 20cb movs r0, #203 ; 0xcb + 80073b4: f7ff ff2c bl 8007210 + 80073b8: b118 cbz r0, 80073c2 + 80073ba: 21d9 movs r1, #217 ; 0xd9 + CHECK_RIGHT(se2_read1() == RC_SUCCESS); + 80073bc: 4805 ldr r0, [pc, #20] ; (80073d4 ) + 80073be: f006 f967 bl 800d690 + 80073c2: f7ff ffcb bl 800735c + 80073c6: 28aa cmp r0, #170 ; 0xaa + 80073c8: d001 beq.n 80073ce + 80073ca: 21db movs r1, #219 ; 0xdb + 80073cc: e7f6 b.n 80073bc +} + 80073ce: bd08 pop {r3, pc} + 80073d0: 0800e3e0 .word 0x0800e3e0 + 80073d4: 2009e390 .word 0x2009e390 + +080073d8 : +{ + 80073d8: b570 push {r4, r5, r6, lr} + 80073da: b0dc sub sp, #368 ; 0x170 + 80073dc: 460d mov r5, r1 + 80073de: f88d 0007 strb.w r0, [sp, #7] + rng_buffer(chal, sizeof(chal)); + 80073e2: 2120 movs r1, #32 + 80073e4: a802 add r0, sp, #8 +{ + 80073e6: 4616 mov r6, r2 + 80073e8: 461c mov r4, r3 + rng_buffer(chal, sizeof(chal)); + 80073ea: f7fb f9b1 bl 8002750 + se2_write_buffer(chal, sizeof(chal)); + 80073ee: 2120 movs r1, #32 + 80073f0: a802 add r0, sp, #8 + 80073f2: f7ff ff7b bl 80072ec + CALL_CHECK(se2_write1(0xa5, (keynum<<5) | page_num)); + 80073f6: f89d 3007 ldrb.w r3, [sp, #7] + 80073fa: ea43 1146 orr.w r1, r3, r6, lsl #5 + 80073fe: b2c9 uxtb r1, r1 + 8007400: 20a5 movs r0, #165 ; 0xa5 + 8007402: f7ff ff05 bl 8007210 + 8007406: b118 cbz r0, 8007410 + 8007408: 21eb movs r1, #235 ; 0xeb + CHECK_RIGHT(se2_read_n(sizeof(check), check) == RC_SUCCESS); + 800740a: 481e ldr r0, [pc, #120] ; (8007484 ) + 800740c: f006 f940 bl 800d690 + 8007410: a912 add r1, sp, #72 ; 0x48 + 8007412: 2022 movs r0, #34 ; 0x22 + 8007414: f7ff ff7a bl 800730c + 8007418: 28aa cmp r0, #170 ; 0xaa + 800741a: d001 beq.n 8007420 + 800741c: 21ee movs r1, #238 ; 0xee + 800741e: e7f4 b.n 800740a + hmac_sha256_init(&ctx); + 8007420: a81b add r0, sp, #108 ; 0x6c + 8007422: f7fe f8bb bl 800559c + hmac_sha256_update(&ctx, SE2_SECRETS->romid, 8); + 8007426: 4b18 ldr r3, [pc, #96] ; (8007488 ) + 8007428: 4918 ldr r1, [pc, #96] ; (800748c ) + 800742a: f893 20b0 ldrb.w r2, [r3, #176] ; 0xb0 + 800742e: 33b0 adds r3, #176 ; 0xb0 + 8007430: 2aff cmp r2, #255 ; 0xff + 8007432: bf18 it ne + 8007434: 4619 movne r1, r3 + 8007436: a81b add r0, sp, #108 ; 0x6c + 8007438: 2208 movs r2, #8 + 800743a: 3160 adds r1, #96 ; 0x60 + 800743c: f7fe f8b4 bl 80055a8 + hmac_sha256_update(&ctx, data, 32); + 8007440: 4629 mov r1, r5 + 8007442: a81b add r0, sp, #108 ; 0x6c + 8007444: 2220 movs r2, #32 + 8007446: f7fe f8af bl 80055a8 + hmac_sha256_update(&ctx, chal, 32); + 800744a: a902 add r1, sp, #8 + 800744c: a81b add r0, sp, #108 ; 0x6c + 800744e: 2220 movs r2, #32 + 8007450: f7fe f8aa bl 80055a8 + hmac_sha256_update(&ctx, &page_num, 1); + 8007454: f10d 0107 add.w r1, sp, #7 + 8007458: a81b add r0, sp, #108 ; 0x6c + 800745a: 2201 movs r2, #1 + 800745c: f7fe f8a4 bl 80055a8 + hmac_sha256_update(&ctx, DEV_MANID, 2); + 8007460: a81b add r0, sp, #108 ; 0x6c + 8007462: 490b ldr r1, [pc, #44] ; (8007490 ) + 8007464: 2202 movs r2, #2 + 8007466: f7fe f89f bl 80055a8 + hmac_sha256_final(&ctx, secret, expect); + 800746a: aa0a add r2, sp, #40 ; 0x28 + 800746c: 4621 mov r1, r4 + 800746e: a81b add r0, sp, #108 ; 0x6c + 8007470: f7fe f8b0 bl 80055d4 + return check_equal(expect, check+2, 32); + 8007474: 2220 movs r2, #32 + 8007476: f10d 014a add.w r1, sp, #74 ; 0x4a + 800747a: a80a add r0, sp, #40 ; 0x28 + 800747c: f7fb f919 bl 80026b2 +} + 8007480: b05c add sp, #368 ; 0x170 + 8007482: bd70 pop {r4, r5, r6, pc} + 8007484: 2009e390 .word 0x2009e390 + 8007488: 0801c000 .word 0x0801c000 + 800748c: 2009e2b0 .word 0x2009e2b0 + 8007490: 0800ea44 .word 0x0800ea44 + +08007494 : +{ + 8007494: b570 push {r4, r5, r6, lr} + 8007496: 4604 mov r4, r0 + 8007498: b08a sub sp, #40 ; 0x28 + 800749a: 460d mov r5, r1 + CALL_CHECK(se2_write1(0x69, page_num)); + 800749c: 4601 mov r1, r0 + 800749e: 2069 movs r0, #105 ; 0x69 +{ + 80074a0: 4616 mov r6, r2 + CALL_CHECK(se2_write1(0x69, page_num)); + 80074a2: f7ff feb5 bl 8007210 + 80074a6: b120 cbz r0, 80074b2 + 80074a8: f44f 7185 mov.w r1, #266 ; 0x10a + CHECK_RIGHT(se2_read_n(sizeof(rx), rx) == RC_SUCCESS); + 80074ac: 481c ldr r0, [pc, #112] ; (8007520 ) + 80074ae: f006 f8ef bl 800d690 + 80074b2: a901 add r1, sp, #4 + 80074b4: 2022 movs r0, #34 ; 0x22 + 80074b6: f7ff ff29 bl 800730c + 80074ba: 28aa cmp r0, #170 ; 0xaa + 80074bc: d002 beq.n 80074c4 + 80074be: f240 110d movw r1, #269 ; 0x10d + 80074c2: e7f3 b.n 80074ac + CHECK_RIGHT(rx[0] == 33); + 80074c4: f89d 3004 ldrb.w r3, [sp, #4] + 80074c8: 2b21 cmp r3, #33 ; 0x21 + 80074ca: d002 beq.n 80074d2 + 80074cc: f240 110f movw r1, #271 ; 0x10f + 80074d0: e7ec b.n 80074ac + CHECK_RIGHT(rx[1] == RC_SUCCESS); + 80074d2: f89d 3005 ldrb.w r3, [sp, #5] + 80074d6: 2baa cmp r3, #170 ; 0xaa + 80074d8: d002 beq.n 80074e0 + 80074da: f44f 7188 mov.w r1, #272 ; 0x110 + 80074de: e7e5 b.n 80074ac + memcpy(data, rx+2, 32); + 80074e0: f10d 0306 add.w r3, sp, #6 + 80074e4: 462a mov r2, r5 + 80074e6: f10d 0126 add.w r1, sp, #38 ; 0x26 + 80074ea: f853 0b04 ldr.w r0, [r3], #4 + 80074ee: f842 0b04 str.w r0, [r2], #4 + 80074f2: 428b cmp r3, r1 + 80074f4: d1f9 bne.n 80074ea + if(!verify) return; + 80074f6: b186 cbz r6, 800751a + CHECK_RIGHT(se2_verify_page(page_num, data, 0, SE2_SECRETS->pairing)); + 80074f8: 4b0a ldr r3, [pc, #40] ; (8007524 ) + 80074fa: 4a0b ldr r2, [pc, #44] ; (8007528 ) + 80074fc: f893 10b0 ldrb.w r1, [r3, #176] ; 0xb0 + 8007500: 4b0a ldr r3, [pc, #40] ; (800752c ) + 8007502: 4620 mov r0, r4 + 8007504: 29ff cmp r1, #255 ; 0xff + 8007506: bf18 it ne + 8007508: 4613 movne r3, r2 + 800750a: 2200 movs r2, #0 + 800750c: 4629 mov r1, r5 + 800750e: f7ff ff63 bl 80073d8 + 8007512: b910 cbnz r0, 800751a + 8007514: f44f 718b mov.w r1, #278 ; 0x116 + 8007518: e7c8 b.n 80074ac +} + 800751a: b00a add sp, #40 ; 0x28 + 800751c: bd70 pop {r4, r5, r6, pc} + 800751e: bf00 nop + 8007520: 2009e390 .word 0x2009e390 + 8007524: 0801c000 .word 0x0801c000 + 8007528: 0801c0b0 .word 0x0801c0b0 + 800752c: 2009e2b0 .word 0x2009e2b0 + +08007530 : +{ + 8007530: b570 push {r4, r5, r6, lr} + 8007532: b0d6 sub sp, #344 ; 0x158 + 8007534: 461e mov r6, r3 + ASSERT((keynum == 0) || (keynum == 2)); + 8007536: f032 0302 bics.w r3, r2, #2 +{ + 800753a: 460c mov r4, r1 + 800753c: 4615 mov r5, r2 + 800753e: f88d 0007 strb.w r0, [sp, #7] + ASSERT((keynum == 0) || (keynum == 2)); + 8007542: d002 beq.n 800754a + 8007544: 4831 ldr r0, [pc, #196] ; (800760c ) + 8007546: f7f9 fa7f bl 8000a48 + CALL_CHECK(se2_write1(0x4b, (keynum << 6) | page_num)); + 800754a: f89d 1007 ldrb.w r1, [sp, #7] + 800754e: ea41 1182 orr.w r1, r1, r2, lsl #6 + 8007552: b2c9 uxtb r1, r1 + 8007554: 204b movs r0, #75 ; 0x4b + 8007556: f7ff fe5b bl 8007210 + 800755a: b120 cbz r0, 8007566 + 800755c: f44f 71b3 mov.w r1, #358 ; 0x166 + CHECK_RIGHT(se2_read_n(sizeof(rx), rx) == RC_SUCCESS); + 8007560: 482b ldr r0, [pc, #172] ; (8007610 ) + 8007562: f006 f895 bl 800d690 + 8007566: a90a add r1, sp, #40 ; 0x28 + 8007568: 202a movs r0, #42 ; 0x2a + 800756a: f7ff fecf bl 800730c + 800756e: 28aa cmp r0, #170 ; 0xaa + 8007570: d002 beq.n 8007578 + 8007572: f240 1169 movw r1, #361 ; 0x169 + 8007576: e7f3 b.n 8007560 + CHECK_RIGHT(rx[1] == RC_SUCCESS); + 8007578: f89d 3029 ldrb.w r3, [sp, #41] ; 0x29 + 800757c: 2baa cmp r3, #170 ; 0xaa + 800757e: d002 beq.n 8007586 + 8007580: f240 116b movw r1, #363 ; 0x16b + 8007584: e7ec b.n 8007560 + memcpy(data, rx+2+8, 32); + 8007586: f10d 0332 add.w r3, sp, #50 ; 0x32 + 800758a: 4622 mov r2, r4 + 800758c: f10d 0152 add.w r1, sp, #82 ; 0x52 + 8007590: f853 0b04 ldr.w r0, [r3], #4 + 8007594: f842 0b04 str.w r0, [r2], #4 + 8007598: 428b cmp r3, r1 + 800759a: d1f9 bne.n 8007590 + hmac_sha256_init(&ctx); + 800759c: a815 add r0, sp, #84 ; 0x54 + 800759e: f7fd fffd bl 800559c + hmac_sha256_update(&ctx, chal, 8); + 80075a2: 2208 movs r2, #8 + 80075a4: f10d 012a add.w r1, sp, #42 ; 0x2a + 80075a8: a815 add r0, sp, #84 ; 0x54 + 80075aa: f7fd fffd bl 80055a8 + hmac_sha256_update(&ctx, SE2_SECRETS->romid, 8); + 80075ae: 4b19 ldr r3, [pc, #100] ; (8007614 ) + 80075b0: 4919 ldr r1, [pc, #100] ; (8007618 ) + 80075b2: f893 20b0 ldrb.w r2, [r3, #176] ; 0xb0 + 80075b6: 33b0 adds r3, #176 ; 0xb0 + 80075b8: 2aff cmp r2, #255 ; 0xff + 80075ba: bf18 it ne + 80075bc: 4619 movne r1, r3 + 80075be: 3160 adds r1, #96 ; 0x60 + 80075c0: 2208 movs r2, #8 + 80075c2: a815 add r0, sp, #84 ; 0x54 + 80075c4: f7fd fff0 bl 80055a8 + hmac_sha256_update(&ctx, &page_num, 1); + 80075c8: 2201 movs r2, #1 + 80075ca: f10d 0107 add.w r1, sp, #7 + 80075ce: a815 add r0, sp, #84 ; 0x54 + 80075d0: f7fd ffea bl 80055a8 + hmac_sha256_update(&ctx, DEV_MANID, 2); + 80075d4: 4911 ldr r1, [pc, #68] ; (800761c ) + 80075d6: 2202 movs r2, #2 + 80075d8: a815 add r0, sp, #84 ; 0x54 + 80075da: f7fd ffe5 bl 80055a8 + hmac_sha256_final(&ctx, secret, otp); + 80075de: aa02 add r2, sp, #8 + 80075e0: 4631 mov r1, r6 + 80075e2: a815 add r0, sp, #84 ; 0x54 + 80075e4: f7fd fff6 bl 80055d4 + xor_mixin(data, otp, 32); + 80075e8: 2220 movs r2, #32 + 80075ea: a902 add r1, sp, #8 + 80075ec: 4620 mov r0, r4 + 80075ee: f7ff fe01 bl 80071f4 + CHECK_RIGHT(se2_verify_page(page_num, data, keynum, secret)); + 80075f2: f89d 0007 ldrb.w r0, [sp, #7] + 80075f6: 4633 mov r3, r6 + 80075f8: 462a mov r2, r5 + 80075fa: 4621 mov r1, r4 + 80075fc: f7ff feec bl 80073d8 + 8007600: b910 cbnz r0, 8007608 + 8007602: f44f 71c0 mov.w r1, #384 ; 0x180 + 8007606: e7ab b.n 8007560 +} + 8007608: b056 add sp, #344 ; 0x158 + 800760a: bd70 pop {r4, r5, r6, pc} + 800760c: 0800e3e0 .word 0x0800e3e0 + 8007610: 2009e390 .word 0x2009e390 + 8007614: 0801c000 .word 0x0801c000 + 8007618: 2009e2b0 .word 0x2009e2b0 + 800761c: 0800ea44 .word 0x0800ea44 + +08007620 : +{ + 8007620: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + 8007624: 460e mov r6, r1 + ASSERT((keynum == 0) || (keynum == 2)); + 8007626: f032 0102 bics.w r1, r2, #2 +{ + 800762a: b0e4 sub sp, #400 ; 0x190 + 800762c: 4604 mov r4, r0 + 800762e: 4617 mov r7, r2 + 8007630: 4698 mov r8, r3 + ASSERT((keynum == 0) || (keynum == 2)); + 8007632: d002 beq.n 800763a + 8007634: 4849 ldr r0, [pc, #292] ; (800775c ) + 8007636: f7f9 fa07 bl 8000a48 + se2_read_encrypted(page_num, old_data, keynum, secret); + 800763a: a901 add r1, sp, #4 + 800763c: f7ff ff78 bl 8007530 + uint8_t PGDV = page_num | 0x80; + 8007640: f064 037f orn r3, r4, #127 ; 0x7f + rng_buffer(&chal_check[32], 8); + 8007644: 2108 movs r1, #8 + 8007646: a821 add r0, sp, #132 ; 0x84 + uint8_t PGDV = page_num | 0x80; + 8007648: f88d 3002 strb.w r3, [sp, #2] + rng_buffer(&chal_check[32], 8); + 800764c: f7fb f880 bl 8002750 + hmac_sha256_init(&ctx); + 8007650: a823 add r0, sp, #140 ; 0x8c + 8007652: f7fd ffa3 bl 800559c + hmac_sha256_update(&ctx, &chal_check[32], 8); + 8007656: 2208 movs r2, #8 + 8007658: a921 add r1, sp, #132 ; 0x84 + 800765a: a823 add r0, sp, #140 ; 0x8c + 800765c: f7fd ffa4 bl 80055a8 + hmac_sha256_update(&ctx, SE2_SECRETS->romid, 8); + 8007660: 4b3f ldr r3, [pc, #252] ; (8007760 ) + 8007662: 4940 ldr r1, [pc, #256] ; (8007764 ) + 8007664: f893 20b0 ldrb.w r2, [r3, #176] ; 0xb0 + 8007668: 33b0 adds r3, #176 ; 0xb0 + 800766a: 2aff cmp r2, #255 ; 0xff + 800766c: bf18 it ne + 800766e: 4619 movne r1, r3 + 8007670: 3160 adds r1, #96 ; 0x60 + 8007672: 2208 movs r2, #8 + 8007674: a823 add r0, sp, #140 ; 0x8c + 8007676: f7fd ff97 bl 80055a8 + hmac_sha256_update(&ctx, &PGDV, 1); + 800767a: 2201 movs r2, #1 + 800767c: f10d 0102 add.w r1, sp, #2 + 8007680: a823 add r0, sp, #140 ; 0x8c + 8007682: f7fd ff91 bl 80055a8 + hmac_sha256_update(&ctx, DEV_MANID, 2); + 8007686: 4938 ldr r1, [pc, #224] ; (8007768 ) + 8007688: 2202 movs r2, #2 + 800768a: a823 add r0, sp, #140 ; 0x8c + 800768c: f7fd ff8c bl 80055a8 + ASSERT(ctx.num_pending == 19); + 8007690: 9b63 ldr r3, [sp, #396] ; 0x18c + 8007692: 2b13 cmp r3, #19 + 8007694: d1ce bne.n 8007634 + hmac_sha256_final(&ctx, secret, otp); + 8007696: aa09 add r2, sp, #36 ; 0x24 + 8007698: 4641 mov r1, r8 + 800769a: a823 add r0, sp, #140 ; 0x8c + 800769c: f7fd ff9a bl 80055d4 + memcpy(tmp, data, 32); + 80076a0: 4635 mov r5, r6 + 80076a2: aa11 add r2, sp, #68 ; 0x44 + 80076a4: f106 0c20 add.w ip, r6, #32 + 80076a8: 6828 ldr r0, [r5, #0] + 80076aa: 6869 ldr r1, [r5, #4] + 80076ac: 4613 mov r3, r2 + 80076ae: c303 stmia r3!, {r0, r1} + 80076b0: 3508 adds r5, #8 + 80076b2: 4565 cmp r5, ip + 80076b4: 461a mov r2, r3 + 80076b6: d1f7 bne.n 80076a8 + xor_mixin(tmp, otp, 32); + 80076b8: 2220 movs r2, #32 + 80076ba: a909 add r1, sp, #36 ; 0x24 + 80076bc: a811 add r0, sp, #68 ; 0x44 + 80076be: f7ff fd99 bl 80071f4 + hmac_sha256_init(&ctx); + 80076c2: a823 add r0, sp, #140 ; 0x8c + 80076c4: f7fd ff6a bl 800559c + hmac_sha256_update(&ctx, SE2_SECRETS->romid, 8); + 80076c8: 4b25 ldr r3, [pc, #148] ; (8007760 ) + 80076ca: 4926 ldr r1, [pc, #152] ; (8007764 ) + 80076cc: f893 20b0 ldrb.w r2, [r3, #176] ; 0xb0 + 80076d0: 33b0 adds r3, #176 ; 0xb0 + 80076d2: 2aff cmp r2, #255 ; 0xff + 80076d4: bf18 it ne + 80076d6: 4619 movne r1, r3 + 80076d8: 3160 adds r1, #96 ; 0x60 + 80076da: 2208 movs r2, #8 + 80076dc: a823 add r0, sp, #140 ; 0x8c + 80076de: f7fd ff63 bl 80055a8 + hmac_sha256_update(&ctx, old_data, 32); + 80076e2: 2220 movs r2, #32 + 80076e4: a901 add r1, sp, #4 + 80076e6: a823 add r0, sp, #140 ; 0x8c + 80076e8: f7fd ff5e bl 80055a8 + hmac_sha256_update(&ctx, data, 32); + 80076ec: 2220 movs r2, #32 + 80076ee: 4631 mov r1, r6 + 80076f0: a823 add r0, sp, #140 ; 0x8c + 80076f2: f7fd ff59 bl 80055a8 + hmac_sha256_update(&ctx, &PGDV, 1); + 80076f6: 2201 movs r2, #1 + 80076f8: f10d 0102 add.w r1, sp, #2 + 80076fc: a823 add r0, sp, #140 ; 0x8c + 80076fe: f7fd ff53 bl 80055a8 + hmac_sha256_update(&ctx, DEV_MANID, 2); + 8007702: 4919 ldr r1, [pc, #100] ; (8007768 ) + 8007704: 2202 movs r2, #2 + 8007706: a823 add r0, sp, #140 ; 0x8c + 8007708: f7fd ff4e bl 80055a8 + ASSERT(ctx.num_pending == 75); + 800770c: 9b63 ldr r3, [sp, #396] ; 0x18c + 800770e: 2b4b cmp r3, #75 ; 0x4b + 8007710: d190 bne.n 8007634 + hmac_sha256_final(&ctx, secret, chal_check); + 8007712: aa19 add r2, sp, #100 ; 0x64 + 8007714: 4641 mov r1, r8 + 8007716: a823 add r0, sp, #140 ; 0x8c + 8007718: f7fd ff5c bl 80055d4 + se2_write_buffer(chal_check, sizeof(chal_check)); + 800771c: 2128 movs r1, #40 ; 0x28 + 800771e: a819 add r0, sp, #100 ; 0x64 + 8007720: f7ff fde4 bl 80072ec + uint8_t pn = (keynum << 6) | page_num; + 8007724: ea44 1487 orr.w r4, r4, r7, lsl #6 + CALL_CHECK(se2_write_n(0x99, &pn, tmp, 32)); + 8007728: 2320 movs r3, #32 + 800772a: aa11 add r2, sp, #68 ; 0x44 + 800772c: f10d 0103 add.w r1, sp, #3 + 8007730: 2099 movs r0, #153 ; 0x99 + uint8_t pn = (keynum << 6) | page_num; + 8007732: f88d 4003 strb.w r4, [sp, #3] + CALL_CHECK(se2_write_n(0x99, &pn, tmp, 32)); + 8007736: f7ff fda1 bl 800727c + 800773a: b120 cbz r0, 8007746 + 800773c: f44f 71aa mov.w r1, #340 ; 0x154 + CHECK_RIGHT(se2_read1() == RC_SUCCESS); + 8007740: 480a ldr r0, [pc, #40] ; (800776c ) + 8007742: f005 ffa5 bl 800d690 + 8007746: f7ff fe09 bl 800735c + 800774a: 28aa cmp r0, #170 ; 0xaa + 800774c: d002 beq.n 8007754 + 800774e: f44f 71ab mov.w r1, #342 ; 0x156 + 8007752: e7f5 b.n 8007740 +} + 8007754: b064 add sp, #400 ; 0x190 + 8007756: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + 800775a: bf00 nop + 800775c: 0800e3e0 .word 0x0800e3e0 + 8007760: 0801c000 .word 0x0801c000 + 8007764: 2009e2b0 .word 0x2009e2b0 + 8007768: 0800ea44 .word 0x0800ea44 + 800776c: 2009e390 .word 0x2009e390 + +08007770 : +{ + 8007770: b508 push {r3, lr} + 8007772: 4601 mov r1, r0 + CALL_CHECK(se2_write1(0xaa, page_num)); + 8007774: 20aa movs r0, #170 ; 0xaa + 8007776: f7ff fd4b bl 8007210 + 800777a: b120 cbz r0, 8007786 + 800777c: 4804 ldr r0, [pc, #16] ; (8007790 ) + 800777e: f240 118b movw r1, #395 ; 0x18b + 8007782: f005 ff85 bl 800d690 +} + 8007786: e8bd 4008 ldmia.w sp!, {r3, lr} + return se2_read1(); + 800778a: f7ff bde7 b.w 800735c + 800778e: bf00 nop + 8007790: 2009e390 .word 0x2009e390 + +08007794 : +{ + 8007794: b538 push {r3, r4, r5, lr} + 8007796: 460c mov r4, r1 + 8007798: 4605 mov r5, r0 + if(se2_get_protection(page_num) == flags) { + 800779a: f7ff ffe9 bl 8007770 + 800779e: 42a0 cmp r0, r4 + 80077a0: d011 beq.n 80077c6 + CALL_CHECK(se2_write2(0xc3, page_num, flags)); + 80077a2: 4622 mov r2, r4 + 80077a4: 4629 mov r1, r5 + 80077a6: 20c3 movs r0, #195 ; 0xc3 + 80077a8: f7ff fd4c bl 8007244 + 80077ac: b120 cbz r0, 80077b8 + 80077ae: f240 119b movw r1, #411 ; 0x19b + CHECK_RIGHT(se2_read1() == RC_SUCCESS); + 80077b2: 4805 ldr r0, [pc, #20] ; (80077c8 ) + 80077b4: f005 ff6c bl 800d690 + 80077b8: f7ff fdd0 bl 800735c + 80077bc: 28aa cmp r0, #170 ; 0xaa + 80077be: d002 beq.n 80077c6 + 80077c0: f240 119d movw r1, #413 ; 0x19d + 80077c4: e7f5 b.n 80077b2 +} + 80077c6: bd38 pop {r3, r4, r5, pc} + 80077c8: 2009e390 .word 0x2009e390 + +080077cc : +{ + 80077cc: b500 push {lr} + if(setjmp(error_env)) { + 80077ce: 4812 ldr r0, [pc, #72] ; (8007818 ) +{ + 80077d0: b089 sub sp, #36 ; 0x24 + if(setjmp(error_env)) { + 80077d2: f005 ff57 bl 800d684 + 80077d6: b120 cbz r0, 80077e2 + oled_show(screen_se2_issue); + 80077d8: 4810 ldr r0, [pc, #64] ; (800781c ) + 80077da: f7f9 fb33 bl 8000e44 + LOCKUP_FOREVER(); + 80077de: bf30 wfi + 80077e0: e7fd b.n 80077de + rng_delay(); + 80077e2: f7fa ffcb bl 800277c + if(rom_secrets->se2.pairing[0] == 0xff) { + 80077e6: 4b0e ldr r3, [pc, #56] ; (8007820 ) + 80077e8: f893 30b0 ldrb.w r3, [r3, #176] ; 0xb0 + 80077ec: 2bff cmp r3, #255 ; 0xff + 80077ee: d00f beq.n 8007810 + se2_read_page(PGN_ROM_OPTIONS, tmp, true); + 80077f0: 2201 movs r2, #1 + 80077f2: 4669 mov r1, sp + 80077f4: 201c movs r0, #28 + 80077f6: f7ff fe4d bl 8007494 + CHECK_RIGHT(check_equal(&tmp[24], rom_secrets->se2.romid, 8)); + 80077fa: 490a ldr r1, [pc, #40] ; (8007824 ) + 80077fc: 2208 movs r2, #8 + 80077fe: a806 add r0, sp, #24 + 8007800: f7fa ff57 bl 80026b2 + 8007804: b920 cbnz r0, 8007810 + 8007806: 4804 ldr r0, [pc, #16] ; (8007818 ) + 8007808: f240 11b5 movw r1, #437 ; 0x1b5 + 800780c: f005 ff40 bl 800d690 +} + 8007810: b009 add sp, #36 ; 0x24 + 8007812: f85d fb04 ldr.w pc, [sp], #4 + 8007816: bf00 nop + 8007818: 2009e390 .word 0x2009e390 + 800781c: 0800dfce .word 0x0800dfce + 8007820: 0801c000 .word 0x0801c000 + 8007824: 0801c110 .word 0x0801c110 + +08007828 : +{ + 8007828: b510 push {r4, lr} + if(setjmp(error_env)) fatal_mitm(); + 800782a: 4817 ldr r0, [pc, #92] ; (8007888 ) +{ + 800782c: b088 sub sp, #32 + if(setjmp(error_env)) fatal_mitm(); + 800782e: f005 ff29 bl 800d684 + 8007832: 4604 mov r4, r0 + 8007834: b108 cbz r0, 800783a + 8007836: f7f9 f911 bl 8000a5c + uint8_t z32[32] = {0}; + 800783a: 221c movs r2, #28 + 800783c: 4601 mov r1, r0 + 800783e: 9000 str r0, [sp, #0] + 8007840: a801 add r0, sp, #4 + 8007842: f005 ff17 bl 800d674 + se2_write_page(PGN_PUBKEY_S+0, z32); + 8007846: 4669 mov r1, sp + 8007848: 201e movs r0, #30 + 800784a: f7ff fd8f bl 800736c + se2_write_page(PGN_PUBKEY_S+1, z32); + 800784e: 4669 mov r1, sp + 8007850: 201f movs r0, #31 + 8007852: f7ff fd8b bl 800736c + se2_write_buffer(z32, 32); + 8007856: 2120 movs r1, #32 + 8007858: 4668 mov r0, sp + 800785a: f7ff fd47 bl 80072ec + CALL_CHECK(se2_write2(0x3c, (2<<6), 0)); + 800785e: 4622 mov r2, r4 + 8007860: 2180 movs r1, #128 ; 0x80 + 8007862: 203c movs r0, #60 ; 0x3c + 8007864: f7ff fcee bl 8007244 + 8007868: b120 cbz r0, 8007874 + 800786a: f240 11cd movw r1, #461 ; 0x1cd + CHECK_RIGHT(se2_read1() == RC_SUCCESS); + 800786e: 4806 ldr r0, [pc, #24] ; (8007888 ) + 8007870: f005 ff0e bl 800d690 + 8007874: f7ff fd72 bl 800735c + 8007878: 28aa cmp r0, #170 ; 0xaa + 800787a: d002 beq.n 8007882 + 800787c: f44f 71e7 mov.w r1, #462 ; 0x1ce + 8007880: e7f5 b.n 800786e +} + 8007882: b008 add sp, #32 + 8007884: bd10 pop {r4, pc} + 8007886: bf00 nop + 8007888: 2009e390 .word 0x2009e390 + +0800788c : +{ + 800788c: b570 push {r4, r5, r6, lr} + if((setjmp(error_env))) { + 800788e: 485b ldr r0, [pc, #364] ; (80079fc ) +{ + 8007890: b090 sub sp, #64 ; 0x40 + if((setjmp(error_env))) { + 8007892: f005 fef7 bl 800d684 + 8007896: 4604 mov r4, r0 + 8007898: b120 cbz r0, 80078a4 + oled_show(screen_se2_issue); + 800789a: 4859 ldr r0, [pc, #356] ; (8007a00 ) + 800789c: f7f9 fad2 bl 8000e44 + LOCKUP_FOREVER(); + 80078a0: bf30 wfi + 80078a2: e7fd b.n 80078a0 + if(rom_secrets->se2.pairing[0] != 0xff) { + 80078a4: 4b57 ldr r3, [pc, #348] ; (8007a04 ) + 80078a6: f893 10b0 ldrb.w r1, [r3, #176] ; 0xb0 + 80078aa: 29ff cmp r1, #255 ; 0xff + 80078ac: f040 80a0 bne.w 80079f0 + memset(&_tbd, 0xff, sizeof(_tbd)); + 80078b0: 4d55 ldr r5, [pc, #340] ; (8007a08 ) + 80078b2: 22e0 movs r2, #224 ; 0xe0 + 80078b4: 4628 mov r0, r5 + 80078b6: f005 fedd bl 800d674 + rng_buffer(_tbd.tpin_key, 32); + 80078ba: 2120 movs r1, #32 + 80078bc: f105 0080 add.w r0, r5, #128 ; 0x80 + 80078c0: f7fa ff46 bl 8002750 + se2_read_page(PGN_ROM_OPTIONS, tmp, false); + 80078c4: 4622 mov r2, r4 + 80078c6: 4669 mov r1, sp + 80078c8: 201c movs r0, #28 + 80078ca: f7ff fde3 bl 8007494 + ASSERT(tmp[1] == 0x00); // check ANON is not set + 80078ce: f89d 3001 ldrb.w r3, [sp, #1] + 80078d2: b113 cbz r3, 80078da + 80078d4: 484d ldr r0, [pc, #308] ; (8007a0c ) + 80078d6: f7f9 f8b7 bl 8000a48 + memcpy(_tbd.romid, tmp+24, 8); + 80078da: ab06 add r3, sp, #24 + 80078dc: cb03 ldmia r3!, {r0, r1} + 80078de: 6628 str r0, [r5, #96] ; 0x60 + 80078e0: 6669 str r1, [r5, #100] ; 0x64 + rng_buffer(tmp, 32); + 80078e2: 4668 mov r0, sp + 80078e4: 2120 movs r1, #32 + 80078e6: f7fa ff33 bl 8002750 + se2_write_page(PGN_SECRET_B, tmp); + 80078ea: 4669 mov r1, sp + 80078ec: 201a movs r0, #26 + 80078ee: f7ff fd3d bl 800736c + se2_pick_keypair(0, true); + 80078f2: 2101 movs r1, #1 + 80078f4: 4620 mov r0, r4 + 80078f6: f7ff fd53 bl 80073a0 + se2_read_page(PGN_PUBKEY_A, &_tbd.pubkey_A[0], false); + 80078fa: 4622 mov r2, r4 + 80078fc: f105 0120 add.w r1, r5, #32 + 8007900: 2010 movs r0, #16 + 8007902: f7ff fdc7 bl 8007494 + memset(tmp, 0, 32); + 8007906: 2620 movs r6, #32 + se2_read_page(PGN_PUBKEY_A+1, &_tbd.pubkey_A[32], false); + 8007908: 4622 mov r2, r4 + 800790a: f105 0140 add.w r1, r5, #64 ; 0x40 + 800790e: 2011 movs r0, #17 + 8007910: f7ff fdc0 bl 8007494 + memset(tmp, 0, 32); + 8007914: 4632 mov r2, r6 + 8007916: 4621 mov r1, r4 + 8007918: 4668 mov r0, sp + 800791a: f005 feab bl 800d674 + se2_write_page(PGN_PRIVKEY_B, tmp); + 800791e: 4669 mov r1, sp + 8007920: 2017 movs r0, #23 + 8007922: f7ff fd23 bl 800736c + se2_write_page(PGN_PRIVKEY_B+1, tmp); + 8007926: 4669 mov r1, sp + 8007928: 2018 movs r0, #24 + 800792a: f7ff fd1f bl 800736c + se2_write_page(PGN_PUBKEY_B, tmp); + 800792e: 4669 mov r1, sp + 8007930: 2012 movs r0, #18 + 8007932: f7ff fd1b bl 800736c + se2_write_page(PGN_PUBKEY_B+1, tmp); + 8007936: 4669 mov r1, sp + 8007938: 2013 movs r0, #19 + 800793a: f7ff fd17 bl 800736c + rng_buffer(_tbd.pairing, 32); + 800793e: 4631 mov r1, r6 + 8007940: 4628 mov r0, r5 + 8007942: f7fa ff05 bl 8002750 + } while(_tbd.pairing[0] == 0xff); + 8007946: 782b ldrb r3, [r5, #0] + 8007948: 2bff cmp r3, #255 ; 0xff + 800794a: d0f8 beq.n 800793e + se2_write_page(PGN_SECRET_A, _tbd.pairing); + 800794c: 4629 mov r1, r5 + 800794e: 2019 movs r0, #25 + rng_buffer(tmp, 32); + 8007950: 466d mov r5, sp + se2_write_page(PGN_SECRET_A, _tbd.pairing); + 8007952: f7ff fd0b bl 800736c + rng_buffer(tmp, 32); + 8007956: 2120 movs r1, #32 + 8007958: 4628 mov r0, r5 + 800795a: f7fa fef9 bl 8002750 + se2_write_page(PGN_SE2_EASY_KEY, tmp); + 800795e: 4629 mov r1, r5 + 8007960: 200e movs r0, #14 + 8007962: f7ff fd03 bl 800736c + memset(tmp, 0, 32); + 8007966: 2220 movs r2, #32 + 8007968: 2100 movs r1, #0 + 800796a: 4628 mov r0, r5 + 800796c: f005 fe82 bl 800d674 + for(int pn=0; pn <= PGN_LAST_TRICK; pn++) { + 8007970: 4626 mov r6, r4 + se2_write_page(pn, tmp); + 8007972: b2f0 uxtb r0, r6 + 8007974: 4629 mov r1, r5 + for(int pn=0; pn <= PGN_LAST_TRICK; pn++) { + 8007976: 3601 adds r6, #1 + se2_write_page(pn, tmp); + 8007978: f7ff fcf8 bl 800736c + for(int pn=0; pn <= PGN_LAST_TRICK; pn++) { + 800797c: 2e0e cmp r6, #14 + 800797e: d1f8 bne.n 8007972 + flash_save_se2_data(&_tbd); + 8007980: 4821 ldr r0, [pc, #132] ; (8007a08 ) + 8007982: f7fa fc2b bl 80021dc + se2_set_protection(PGN_SECRET_A, PROT_WP); + 8007986: 2102 movs r1, #2 + 8007988: 2019 movs r0, #25 + 800798a: f7ff ff03 bl 8007794 + se2_set_protection(PGN_SECRET_B, PROT_WP); + 800798e: 2102 movs r1, #2 + 8007990: 201a movs r0, #26 + 8007992: f7ff feff bl 8007794 + se2_set_protection(PGN_PUBKEY_A, PROT_WP); + 8007996: 2102 movs r1, #2 + 8007998: 2010 movs r0, #16 + 800799a: f7ff fefb bl 8007794 + se2_set_protection(PGN_PUBKEY_B, PROT_WP); + 800799e: 2102 movs r1, #2 + 80079a0: 2012 movs r0, #18 + 80079a2: f7ff fef7 bl 8007794 + se2_set_protection(PGN_SE2_EASY_KEY, PROT_EPH); + 80079a6: 2110 movs r1, #16 + 80079a8: 4630 mov r0, r6 + 80079aa: f7ff fef3 bl 8007794 + se2_set_protection(pn, PROT_EPH); + 80079ae: 2510 movs r5, #16 + 80079b0: b2e0 uxtb r0, r4 + 80079b2: 4629 mov r1, r5 + for(int pn=0; pn <= PGN_LAST_TRICK; pn++) { + 80079b4: 3401 adds r4, #1 + se2_set_protection(pn, PROT_EPH); + 80079b6: f7ff feed bl 8007794 + for(int pn=0; pn <= PGN_LAST_TRICK; pn++) { + 80079ba: 2c0e cmp r4, #14 + 80079bc: d1f8 bne.n 80079b0 + se2_set_protection(PGN_ROM_OPTIONS, PROT_APH); // not planning to change + 80079be: 2108 movs r1, #8 + 80079c0: 201c movs r0, #28 + 80079c2: f7ff fee7 bl 8007794 + se2_read_page(PGN_DEC_COUNTER, tmp, false); + 80079c6: 2200 movs r2, #0 + 80079c8: a908 add r1, sp, #32 + 80079ca: 201b movs r0, #27 + 80079cc: f7ff fd62 bl 8007494 + if(tmp[2] == 0xff) { + 80079d0: f89d 3022 ldrb.w r3, [sp, #34] ; 0x22 + 80079d4: 2bff cmp r3, #255 ; 0xff + 80079d6: d10d bne.n 80079f4 + tmp[0] = val & 0x0ff; + 80079d8: 2380 movs r3, #128 ; 0x80 + 80079da: f88d 3020 strb.w r3, [sp, #32] + se2_write_page(PGN_DEC_COUNTER, tmp); + 80079de: a908 add r1, sp, #32 + tmp[1] = (val >> 8) & 0x0ff; + 80079e0: 2300 movs r3, #0 + se2_write_page(PGN_DEC_COUNTER, tmp); + 80079e2: 201b movs r0, #27 + tmp[1] = (val >> 8) & 0x0ff; + 80079e4: f88d 3021 strb.w r3, [sp, #33] ; 0x21 + tmp[2] = (val >> 16) & 0x01; + 80079e8: f88d 3022 strb.w r3, [sp, #34] ; 0x22 + se2_write_page(PGN_DEC_COUNTER, tmp); + 80079ec: f7ff fcbe bl 800736c +} + 80079f0: b010 add sp, #64 ; 0x40 + 80079f2: bd70 pop {r4, r5, r6, pc} + puts("ctr set?"); // not expected, but keep going + 80079f4: 4806 ldr r0, [pc, #24] ; (8007a10 ) + 80079f6: f7fd f9d9 bl 8004dac + 80079fa: e7f9 b.n 80079f0 + 80079fc: 2009e390 .word 0x2009e390 + 8007a00: 0800dfce .word 0x0800dfce + 8007a04: 0801c000 .word 0x0801c000 + 8007a08: 2009e2b0 .word 0x2009e2b0 + 8007a0c: 0800e3e0 .word 0x0800e3e0 + 8007a10: 0800ea24 .word 0x0800ea24 + +08007a14 : +{ + 8007a14: b510 push {r4, lr} + 8007a16: b08a sub sp, #40 ; 0x28 + 8007a18: 9001 str r0, [sp, #4] + if(setjmp(error_env)) fatal_mitm(); + 8007a1a: 481e ldr r0, [pc, #120] ; (8007a94 ) + 8007a1c: f005 fe32 bl 800d684 + 8007a20: b108 cbz r0, 8007a26 + 8007a22: f7f9 f81b bl 8000a5c + ASSERT(check_all_ones(rom_secrets->se2.auth_pubkey, 64)); + 8007a26: 481c ldr r0, [pc, #112] ; (8007a98 ) + 8007a28: 2140 movs r1, #64 ; 0x40 + 8007a2a: f7fa fe29 bl 8002680 + 8007a2e: b910 cbnz r0, 8007a36 + 8007a30: 481a ldr r0, [pc, #104] ; (8007a9c ) + 8007a32: f7f9 f809 bl 8000a48 + memcpy(&_tbd, &rom_secrets->se2, sizeof(_tbd)); + 8007a36: 4c1a ldr r4, [pc, #104] ; (8007aa0 ) + 8007a38: 491a ldr r1, [pc, #104] ; (8007aa4 ) + 8007a3a: 22e0 movs r2, #224 ; 0xe0 + 8007a3c: 4620 mov r0, r4 + 8007a3e: f005 fdf1 bl 800d624 + rng_buffer(tmp, 32); + 8007a42: 2120 movs r1, #32 + 8007a44: a802 add r0, sp, #8 + 8007a46: f7fa fe83 bl 8002750 + se2_write_page(PGN_SE2_HARD_KEY, tmp); + 8007a4a: a902 add r1, sp, #8 + 8007a4c: 200f movs r0, #15 + 8007a4e: f7ff fc8d bl 800736c + se2_write_page(PGN_PUBKEY_C, &pubkey[0]); + 8007a52: 9901 ldr r1, [sp, #4] + 8007a54: 2014 movs r0, #20 + 8007a56: f7ff fc89 bl 800736c + se2_write_page(PGN_PUBKEY_C+1, &pubkey[32]); + 8007a5a: 9b01 ldr r3, [sp, #4] + 8007a5c: 2015 movs r0, #21 + 8007a5e: f103 0120 add.w r1, r3, #32 + 8007a62: f7ff fc83 bl 800736c + memcpy(_tbd.auth_pubkey, pubkey, 64); + 8007a66: 9b01 ldr r3, [sp, #4] + 8007a68: 34a0 adds r4, #160 ; 0xa0 + 8007a6a: f103 0240 add.w r2, r3, #64 ; 0x40 + 8007a6e: f853 1b04 ldr.w r1, [r3], #4 + 8007a72: f844 1b04 str.w r1, [r4], #4 + 8007a76: 4293 cmp r3, r2 + 8007a78: d1f9 bne.n 8007a6e + flash_save_se2_data(&_tbd); + 8007a7a: 4809 ldr r0, [pc, #36] ; (8007aa0 ) + 8007a7c: f7fa fbae bl 80021dc + se2_set_protection(PGN_SE2_HARD_KEY, PROT_WP | PROT_ECH | PROT_ECW); + 8007a80: 21c2 movs r1, #194 ; 0xc2 + 8007a82: 200f movs r0, #15 + 8007a84: f7ff fe86 bl 8007794 + se2_set_protection(PGN_PUBKEY_C, PROT_WP | PROT_RP | PROT_AUTH); + 8007a88: 2123 movs r1, #35 ; 0x23 + 8007a8a: 2014 movs r0, #20 + 8007a8c: f7ff fe82 bl 8007794 +} + 8007a90: b00a add sp, #40 ; 0x28 + 8007a92: bd10 pop {r4, pc} + 8007a94: 2009e390 .word 0x2009e390 + 8007a98: 0801c150 .word 0x0801c150 + 8007a9c: 0800e3e0 .word 0x0800e3e0 + 8007aa0: 2009e2b0 .word 0x2009e2b0 + 8007aa4: 0801c0b0 .word 0x0801c0b0 + +08007aa8 : +{ + 8007aa8: b530 push {r4, r5, lr} + 8007aaa: 4614 mov r4, r2 + ASSERT(pin_len >= 0); // 12-12 typical, but empty = blank PIN + 8007aac: 1e0a subs r2, r1, #0 +{ + 8007aae: b0c5 sub sp, #276 ; 0x114 + 8007ab0: 4605 mov r5, r0 + ASSERT(pin_len >= 0); // 12-12 typical, but empty = blank PIN + 8007ab2: da02 bge.n 8007aba + 8007ab4: 4812 ldr r0, [pc, #72] ; (8007b00 ) + 8007ab6: f7f8 ffc7 bl 8000a48 + hmac_sha256_init(&ctx); + 8007aba: a803 add r0, sp, #12 + 8007abc: 9201 str r2, [sp, #4] + 8007abe: f7fd fd6d bl 800559c + hmac_sha256_update(&ctx, (uint8_t *)pin, pin_len); + 8007ac2: 9a01 ldr r2, [sp, #4] + 8007ac4: 4629 mov r1, r5 + 8007ac6: a803 add r0, sp, #12 + 8007ac8: f7fd fd6e bl 80055a8 + hmac_sha256_final(&ctx, SE2_SECRETS->tpin_key, tpin_hash); + 8007acc: 4b0d ldr r3, [pc, #52] ; (8007b04 ) + 8007ace: 490e ldr r1, [pc, #56] ; (8007b08 ) + 8007ad0: f893 20b0 ldrb.w r2, [r3, #176] ; 0xb0 + 8007ad4: 33b0 adds r3, #176 ; 0xb0 + 8007ad6: 2aff cmp r2, #255 ; 0xff + 8007ad8: bf18 it ne + 8007ada: 4619 movne r1, r3 + 8007adc: a803 add r0, sp, #12 + 8007ade: 4622 mov r2, r4 + 8007ae0: 3180 adds r1, #128 ; 0x80 + 8007ae2: f7fd fd77 bl 80055d4 + sha256_single(tpin_hash, 32, tpin_hash); + 8007ae6: 4622 mov r2, r4 + 8007ae8: 4620 mov r0, r4 + 8007aea: 2120 movs r1, #32 + 8007aec: f7fd fd36 bl 800555c + sha256_single(tpin_hash, 32, tpin_hash); + 8007af0: 4622 mov r2, r4 + 8007af2: 2120 movs r1, #32 + 8007af4: 4620 mov r0, r4 + 8007af6: f7fd fd31 bl 800555c +} + 8007afa: b045 add sp, #276 ; 0x114 + 8007afc: bd30 pop {r4, r5, pc} + 8007afe: bf00 nop + 8007b00: 0800e3e0 .word 0x0800e3e0 + 8007b04: 0801c000 .word 0x0801c000 + 8007b08: 2009e2b0 .word 0x2009e2b0 + +08007b0c : + +// p256_gen_keypair() +// + void +p256_gen_keypair(uint8_t privkey[32], uint8_t pubkey[64]) +{ + 8007b0c: b538 push {r3, r4, r5, lr} + 8007b0e: 4605 mov r5, r0 + uECC_set_rng(rng_for_uECC); + 8007b10: 4808 ldr r0, [pc, #32] ; (8007b34 ) +{ + 8007b12: 460c mov r4, r1 + uECC_set_rng(rng_for_uECC); + 8007b14: f7fe fedc bl 80068d0 + + int ok = uECC_make_key(pubkey, privkey, uECC_secp256r1()); + 8007b18: f7fe fee0 bl 80068dc + 8007b1c: 4629 mov r1, r5 + 8007b1e: 4602 mov r2, r0 + 8007b20: 4620 mov r0, r4 + 8007b22: f7fe fee3 bl 80068ec + ASSERT(ok == 1); + 8007b26: 2801 cmp r0, #1 + 8007b28: d002 beq.n 8007b30 + 8007b2a: 4803 ldr r0, [pc, #12] ; (8007b38 ) + 8007b2c: f7f8 ff8c bl 8000a48 +} + 8007b30: bd38 pop {r3, r4, r5, pc} + 8007b32: bf00 nop + 8007b34: 080072e1 .word 0x080072e1 + 8007b38: 0800e3e0 .word 0x0800e3e0 + +08007b3c : + +// ps256_ecdh() +// + void +ps256_ecdh(const uint8_t pubkey[64], const uint8_t privkey[32], uint8_t result[32]) +{ + 8007b3c: b513 push {r0, r1, r4, lr} + 8007b3e: 4604 mov r4, r0 + uECC_set_rng(rng_for_uECC); + 8007b40: 4809 ldr r0, [pc, #36] ; (8007b68 ) +{ + 8007b42: e9cd 2100 strd r2, r1, [sp] + uECC_set_rng(rng_for_uECC); + 8007b46: f7fe fec3 bl 80068d0 + + int ok = uECC_shared_secret(pubkey, privkey, result, uECC_secp256r1()); + 8007b4a: f7fe fec7 bl 80068dc + 8007b4e: e9dd 2100 ldrd r2, r1, [sp] + 8007b52: 4603 mov r3, r0 + 8007b54: 4620 mov r0, r4 + 8007b56: f7fe ff09 bl 800696c + ASSERT(ok == 1); + 8007b5a: 2801 cmp r0, #1 + 8007b5c: d002 beq.n 8007b64 + 8007b5e: 4803 ldr r0, [pc, #12] ; (8007b6c ) + 8007b60: f7f8 ff72 bl 8000a48 +} + 8007b64: b002 add sp, #8 + 8007b66: bd10 pop {r4, pc} + 8007b68: 080072e1 .word 0x080072e1 + 8007b6c: 0800e3e0 .word 0x0800e3e0 + +08007b70 : + +// se2_read_hard_secret() +// + static bool +se2_read_hard_secret(uint8_t hard_key[32], const uint8_t pin_digest[32]) +{ + 8007b70: b510 push {r4, lr} + 8007b72: b0e8 sub sp, #416 ; 0x1a0 + 8007b74: e9cd 0102 strd r0, r1, [sp, #8] + if(setjmp(error_env)) { + 8007b78: 4836 ldr r0, [pc, #216] ; (8007c54 ) + 8007b7a: f005 fd83 bl 800d684 + 8007b7e: 2800 cmp r0, #0 + 8007b80: d165 bne.n 8007c4e + // + SHA256_CTX ctx; + + // pick a temp key pair, share public part w/ SE2 + uint8_t tmp_privkey[32], tmp_pubkey[64]; + p256_gen_keypair(tmp_privkey, tmp_pubkey); + 8007b82: a925 add r1, sp, #148 ; 0x94 + 8007b84: a805 add r0, sp, #20 + 8007b86: f7ff ffc1 bl 8007b0c + + // - this can be mitm-ed, but we sign it next so doesn't matter + se2_write_page(PGN_PUBKEY_S, &tmp_pubkey[0]); + 8007b8a: a925 add r1, sp, #148 ; 0x94 + 8007b8c: 201e movs r0, #30 + 8007b8e: f7ff fbed bl 800736c + se2_write_page(PGN_PUBKEY_S+1, &tmp_pubkey[32]); + 8007b92: a92d add r1, sp, #180 ; 0xb4 + 8007b94: 201f movs r0, #31 + 8007b96: f7ff fbe9 bl 800736c + + // pick nonce + uint8_t chal[32+32]; + rng_buffer(chal, sizeof(chal)); + 8007b9a: 2140 movs r1, #64 ; 0x40 + 8007b9c: a835 add r0, sp, #212 ; 0xd4 + 8007b9e: f7fa fdd7 bl 8002750 + se2_write_buffer(chal, sizeof(chal)); + 8007ba2: 2140 movs r1, #64 ; 0x40 + 8007ba4: a835 add r0, sp, #212 ; 0xd4 + 8007ba6: f7ff fba1 bl 80072ec + + // md = ngu.hash.sha256s(T_pubkey + chal[0:32]) + sha256_init(&ctx); + 8007baa: a855 add r0, sp, #340 ; 0x154 + 8007bac: f7fd fc6e bl 800548c + sha256_update(&ctx, tmp_pubkey, 64); + 8007bb0: 2240 movs r2, #64 ; 0x40 + 8007bb2: a925 add r1, sp, #148 ; 0x94 + 8007bb4: a855 add r0, sp, #340 ; 0x154 + 8007bb6: f7fd fc77 bl 80054a8 + sha256_update(&ctx, chal, 32); // only first 32 bytes + 8007bba: 2220 movs r2, #32 + 8007bbc: a935 add r1, sp, #212 ; 0xd4 + 8007bbe: a855 add r0, sp, #340 ; 0x154 + 8007bc0: f7fd fc72 bl 80054a8 + + uint8_t md[32]; + sha256_final(&ctx, md); + 8007bc4: a90d add r1, sp, #52 ; 0x34 + 8007bc6: a855 add r0, sp, #340 ; 0x154 + 8007bc8: f7fd fcb4 bl 8005534 + // Get that digest signed by SE1 now, and doing that requires + // the main pin, because the required slot requires auth by that key. + // - this is the critical step attackers would not be able to emulate w/o SE1 contents + // - fails here if PIN wrong + uint8_t signature[64]; + int arc = ae_sign_authed(KEYNUM_joiner_key, md, signature, KEYNUM_main_pin, pin_digest); + 8007bcc: 9b03 ldr r3, [sp, #12] + 8007bce: 9300 str r3, [sp, #0] + 8007bd0: aa45 add r2, sp, #276 ; 0x114 + 8007bd2: 2303 movs r3, #3 + 8007bd4: a90d add r1, sp, #52 ; 0x34 + 8007bd6: 2007 movs r0, #7 + 8007bd8: f7fb f8f0 bl 8002dbc + CHECK_RIGHT(arc == 0); + 8007bdc: 4604 mov r4, r0 + 8007bde: b120 cbz r0, 8007bea + 8007be0: f240 4152 movw r1, #1106 ; 0x452 + + // "Authenticate ECDSA Public Key" = 0xA8 + // cs_offset=32 ecdh_keynum=0=pubA ECDH=1 WR=0 + uint8_t param = ((32-1) << 3) | (0 << 2) | 0x2; + se2_write_n(0xA8, ¶m, signature, 64); + CHECK_RIGHT(se2_read1() == RC_SUCCESS); + 8007be4: 481b ldr r0, [pc, #108] ; (8007c54 ) + 8007be6: f005 fd53 bl 800d690 + uint8_t param = ((32-1) << 3) | (0 << 2) | 0x2; + 8007bea: 23fa movs r3, #250 ; 0xfa + 8007bec: f88d 3013 strb.w r3, [sp, #19] + se2_write_n(0xA8, ¶m, signature, 64); + 8007bf0: aa45 add r2, sp, #276 ; 0x114 + 8007bf2: 2340 movs r3, #64 ; 0x40 + 8007bf4: f10d 0113 add.w r1, sp, #19 + 8007bf8: 20a8 movs r0, #168 ; 0xa8 + 8007bfa: f7ff fb3f bl 800727c + CHECK_RIGHT(se2_read1() == RC_SUCCESS); + 8007bfe: f7ff fbad bl 800735c + 8007c02: 28aa cmp r0, #170 ; 0xaa + 8007c04: d002 beq.n 8007c0c + 8007c06: f44f 618b mov.w r1, #1112 ; 0x458 + 8007c0a: e7eb b.n 8007be4 + + uint8_t shared_x[32], shared_secret[32]; + ps256_ecdh(rom_secrets->se2.pubkey_A, tmp_privkey, shared_x); + 8007c0c: aa15 add r2, sp, #84 ; 0x54 + 8007c0e: a905 add r1, sp, #20 + 8007c10: 4811 ldr r0, [pc, #68] ; (8007c58 ) + 8007c12: f7ff ff93 bl 8007b3c + + // shared secret S will be SHA over X of shared ECDH point + chal[32:] + // s = ngu.hash.sha256s(x + chal[32:]) + sha256_init(&ctx); + 8007c16: a855 add r0, sp, #340 ; 0x154 + 8007c18: f7fd fc38 bl 800548c + sha256_update(&ctx, shared_x, 32); + 8007c1c: 2220 movs r2, #32 + 8007c1e: a915 add r1, sp, #84 ; 0x54 + 8007c20: a855 add r0, sp, #340 ; 0x154 + 8007c22: f7fd fc41 bl 80054a8 + sha256_update(&ctx, &chal[32], 32); // second half + 8007c26: 2220 movs r2, #32 + 8007c28: a93d add r1, sp, #244 ; 0xf4 + 8007c2a: a855 add r0, sp, #340 ; 0x154 + 8007c2c: f7fd fc3c bl 80054a8 + sha256_final(&ctx, shared_secret); + 8007c30: a91d add r1, sp, #116 ; 0x74 + 8007c32: a855 add r0, sp, #340 ; 0x154 + 8007c34: f7fd fc7e bl 8005534 + + se2_read_encrypted(PGN_SE2_HARD_KEY, hard_key, 2, shared_secret); + 8007c38: 200f movs r0, #15 + 8007c3a: 9902 ldr r1, [sp, #8] + 8007c3c: ab1d add r3, sp, #116 ; 0x74 + 8007c3e: 2202 movs r2, #2 + 8007c40: f7ff fc76 bl 8007530 + + // CONCERN: secret "S" is retained in SE2's sram. No API to clear it. + // - but you'd need to see our copy of that value to make use of it + // - and PIN checked already to get here, so you could re-do anyway + se2_clear_volatile(); + 8007c44: f7ff fdf0 bl 8007828 + + return false; + 8007c48: 4620 mov r0, r4 +} + 8007c4a: b068 add sp, #416 ; 0x1a0 + 8007c4c: bd10 pop {r4, pc} + return true; + 8007c4e: 2001 movs r0, #1 + 8007c50: e7fb b.n 8007c4a + 8007c52: bf00 nop + 8007c54: 2009e390 .word 0x2009e390 + 8007c58: 0801c0d0 .word 0x0801c0d0 + +08007c5c : + +// se2_calc_seed_key() +// + static bool +se2_calc_seed_key(uint8_t aes_key[32], const mcu_key_t *mcu_key, const uint8_t pin_digest[32]) +{ + 8007c5c: b570 push {r4, r5, r6, lr} + 8007c5e: b0d2 sub sp, #328 ; 0x148 + 8007c60: 4614 mov r4, r2 + // Gather key parts from all over. Combine them w/ HMAC into a AES-256 key + uint8_t se1_easy_key[32], se1_hard_key[32]; + se2_read_encrypted(PGN_SE2_EASY_KEY, se1_easy_key, 0, rom_secrets->se2.pairing); + 8007c62: 4b15 ldr r3, [pc, #84] ; (8007cb8 ) + 8007c64: 2200 movs r2, #0 +{ + 8007c66: 4605 mov r5, r0 + 8007c68: 460e mov r6, r1 + se2_read_encrypted(PGN_SE2_EASY_KEY, se1_easy_key, 0, rom_secrets->se2.pairing); + 8007c6a: 200e movs r0, #14 + 8007c6c: a901 add r1, sp, #4 + 8007c6e: f7ff fc5f bl 8007530 + + if(se2_read_hard_secret(se1_hard_key, pin_digest)) return true; + 8007c72: 4621 mov r1, r4 + 8007c74: a809 add r0, sp, #36 ; 0x24 + 8007c76: f7ff ff7b bl 8007b70 + 8007c7a: 4604 mov r4, r0 + 8007c7c: b9c8 cbnz r0, 8007cb2 + + HMAC_CTX ctx; + hmac_sha256_init(&ctx); + 8007c7e: a811 add r0, sp, #68 ; 0x44 + 8007c80: f7fd fc8c bl 800559c + hmac_sha256_update(&ctx, mcu_key->value, 32); + 8007c84: 2220 movs r2, #32 + 8007c86: 4631 mov r1, r6 + 8007c88: a811 add r0, sp, #68 ; 0x44 + 8007c8a: f7fd fc8d bl 80055a8 + hmac_sha256_update(&ctx, se1_hard_key, 32); + 8007c8e: 2220 movs r2, #32 + 8007c90: a909 add r1, sp, #36 ; 0x24 + 8007c92: a811 add r0, sp, #68 ; 0x44 + 8007c94: f7fd fc88 bl 80055a8 + hmac_sha256_update(&ctx, se1_easy_key, 32); + 8007c98: 2220 movs r2, #32 + 8007c9a: a901 add r1, sp, #4 + 8007c9c: a811 add r0, sp, #68 ; 0x44 + 8007c9e: f7fd fc83 bl 80055a8 + + // combine them all using anther MCU key via HMAC-SHA256 + hmac_sha256_final(&ctx, rom_secrets->mcu_hmac_key, aes_key); + 8007ca2: a811 add r0, sp, #68 ; 0x44 + 8007ca4: 4905 ldr r1, [pc, #20] ; (8007cbc ) + 8007ca6: 462a mov r2, r5 + 8007ca8: f7fd fc94 bl 80055d4 + hmac_sha256_init(&ctx); // clear secrets + 8007cac: a811 add r0, sp, #68 ; 0x44 + 8007cae: f7fd fc75 bl 800559c + + return false; +} + 8007cb2: 4620 mov r0, r4 + 8007cb4: b052 add sp, #328 ; 0x148 + 8007cb6: bd70 pop {r4, r5, r6, pc} + 8007cb8: 0801c0b0 .word 0x0801c0b0 + 8007cbc: 0801c090 .word 0x0801c090 + +08007cc0 : +{ + 8007cc0: b5f0 push {r4, r5, r6, r7, lr} + if(i2c_port.Instance == I2C2) { + 8007cc2: 4e1b ldr r6, [pc, #108] ; (8007d30 ) + 8007cc4: 4f1b ldr r7, [pc, #108] ; (8007d34 ) + 8007cc6: 6833 ldr r3, [r6, #0] + 8007cc8: 42bb cmp r3, r7 +{ + 8007cca: b089 sub sp, #36 ; 0x24 + if(i2c_port.Instance == I2C2) { + 8007ccc: d02e beq.n 8007d2c + __HAL_RCC_GPIOB_CLK_ENABLE(); + 8007cce: 4b1a ldr r3, [pc, #104] ; (8007d38 ) + GPIO_InitTypeDef setup = { + 8007cd0: 4d1a ldr r5, [pc, #104] ; (8007d3c ) + __HAL_RCC_GPIOB_CLK_ENABLE(); + 8007cd2: 6cda ldr r2, [r3, #76] ; 0x4c + 8007cd4: f042 0202 orr.w r2, r2, #2 + 8007cd8: 64da str r2, [r3, #76] ; 0x4c + 8007cda: 6cda ldr r2, [r3, #76] ; 0x4c + 8007cdc: f002 0202 and.w r2, r2, #2 + 8007ce0: 9201 str r2, [sp, #4] + 8007ce2: 9a01 ldr r2, [sp, #4] + __HAL_RCC_I2C2_CLK_ENABLE(); + 8007ce4: 6d9a ldr r2, [r3, #88] ; 0x58 + 8007ce6: f442 0280 orr.w r2, r2, #4194304 ; 0x400000 + 8007cea: 659a str r2, [r3, #88] ; 0x58 + 8007cec: 6d9b ldr r3, [r3, #88] ; 0x58 + 8007cee: f403 0380 and.w r3, r3, #4194304 ; 0x400000 + 8007cf2: 9302 str r3, [sp, #8] + 8007cf4: 9b02 ldr r3, [sp, #8] + GPIO_InitTypeDef setup = { + 8007cf6: cd0f ldmia r5!, {r0, r1, r2, r3} + 8007cf8: ac03 add r4, sp, #12 + 8007cfa: c40f stmia r4!, {r0, r1, r2, r3} + 8007cfc: 682b ldr r3, [r5, #0] + HAL_GPIO_Init(GPIOB, &setup); + 8007cfe: 4810 ldr r0, [pc, #64] ; (8007d40 ) + GPIO_InitTypeDef setup = { + 8007d00: 6023 str r3, [r4, #0] + HAL_GPIO_Init(GPIOB, &setup); + 8007d02: a903 add r1, sp, #12 + 8007d04: f7f9 f984 bl 8001010 + memset(&i2c_port, 0, sizeof(i2c_port)); + 8007d08: 2244 movs r2, #68 ; 0x44 + 8007d0a: 2100 movs r1, #0 + 8007d0c: f106 0008 add.w r0, r6, #8 + 8007d10: f005 fcb0 bl 800d674 + i2c_port.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + 8007d14: 2301 movs r3, #1 + 8007d16: 60f3 str r3, [r6, #12] + HAL_StatusTypeDef rv = HAL_I2C_Init(&i2c_port); + 8007d18: 4630 mov r0, r6 + i2c_port.Init.Timing = 0x00b03fb8; // 400khz "fast mode" in CubeMX @ 120Mhz (measured ok) + 8007d1a: 4b0a ldr r3, [pc, #40] ; (8007d44 ) + i2c_port.Instance = I2C2; + 8007d1c: 6037 str r7, [r6, #0] + i2c_port.Init.Timing = 0x00b03fb8; // 400khz "fast mode" in CubeMX @ 120Mhz (measured ok) + 8007d1e: 6073 str r3, [r6, #4] + HAL_StatusTypeDef rv = HAL_I2C_Init(&i2c_port); + 8007d20: f003 fdb4 bl 800b88c + ASSERT(rv == HAL_OK); + 8007d24: b110 cbz r0, 8007d2c + 8007d26: 4808 ldr r0, [pc, #32] ; (8007d48 ) + 8007d28: f7f8 fe8e bl 8000a48 +} + 8007d2c: b009 add sp, #36 ; 0x24 + 8007d2e: bdf0 pop {r4, r5, r6, r7, pc} + 8007d30: 2009e3ec .word 0x2009e3ec + 8007d34: 40005800 .word 0x40005800 + 8007d38: 40021000 .word 0x40021000 + 8007d3c: 0800ea30 .word 0x0800ea30 + 8007d40: 48000400 .word 0x48000400 + 8007d44: 00b03fb8 .word 0x00b03fb8 + 8007d48: 0800e3e0 .word 0x0800e3e0 + +08007d4c : +{ + 8007d4c: b5f0 push {r4, r5, r6, r7, lr} + 8007d4e: b089 sub sp, #36 ; 0x24 + se2_setup(); + 8007d50: f7ff ffb6 bl 8007cc0 + if(setjmp(error_env)) fatal_mitm(); + 8007d54: 480f ldr r0, [pc, #60] ; (8007d94 ) + 8007d56: f005 fc95 bl 800d684 + 8007d5a: 4604 mov r4, r0 + 8007d5c: b108 cbz r0, 8007d62 + 8007d5e: f7f8 fe7d bl 8000a5c + uint8_t tmp[32] = {0}; + 8007d62: 9000 str r0, [sp, #0] + 8007d64: 4601 mov r1, r0 + 8007d66: 221c movs r2, #28 + 8007d68: a801 add r0, sp, #4 + 8007d6a: f005 fc83 bl 800d674 + se2_write_encrypted(pn, tmp, 0, SE2_SECRETS->pairing); + 8007d6e: 4f0a ldr r7, [pc, #40] ; (8007d98 ) + 8007d70: 4e0a ldr r6, [pc, #40] ; (8007d9c ) + 8007d72: 4d0b ldr r5, [pc, #44] ; (8007da0 ) + 8007d74: f897 30b0 ldrb.w r3, [r7, #176] ; 0xb0 + 8007d78: b2e0 uxtb r0, r4 + 8007d7a: 2bff cmp r3, #255 ; 0xff + 8007d7c: bf0c ite eq + 8007d7e: 4633 moveq r3, r6 + 8007d80: 462b movne r3, r5 + 8007d82: 2200 movs r2, #0 + 8007d84: 4669 mov r1, sp + for(int pn=0; pn <= PGN_LAST_TRICK; pn++) { + 8007d86: 3401 adds r4, #1 + se2_write_encrypted(pn, tmp, 0, SE2_SECRETS->pairing); + 8007d88: f7ff fc4a bl 8007620 + for(int pn=0; pn <= PGN_LAST_TRICK; pn++) { + 8007d8c: 2c0e cmp r4, #14 + 8007d8e: d1f1 bne.n 8007d74 +} + 8007d90: b009 add sp, #36 ; 0x24 + 8007d92: bdf0 pop {r4, r5, r6, r7, pc} + 8007d94: 2009e390 .word 0x2009e390 + 8007d98: 0801c000 .word 0x0801c000 + 8007d9c: 2009e2b0 .word 0x2009e2b0 + 8007da0: 0801c0b0 .word 0x0801c0b0 + +08007da4 : +{ + 8007da4: b5f0 push {r4, r5, r6, r7, lr} + 8007da6: b087 sub sp, #28 + 8007da8: e9cd 0102 strd r0, r1, [sp, #8] + if(setjmp(error_env)) fatal_mitm(); + 8007dac: 4816 ldr r0, [pc, #88] ; (8007e08 ) +{ + 8007dae: 9201 str r2, [sp, #4] + if(setjmp(error_env)) fatal_mitm(); + 8007db0: f005 fc68 bl 800d684 + 8007db4: b108 cbz r0, 8007dba + 8007db6: f7f8 fe51 bl 8000a5c + se2_read_encrypted(slot_num+1, &data[0], 0, SE2_SECRETS->pairing); + 8007dba: 4f14 ldr r7, [pc, #80] ; (8007e0c ) + 8007dbc: 9005 str r0, [sp, #20] + se2_setup(); + 8007dbe: f7ff ff7f bl 8007cc0 + se2_read_encrypted(slot_num+1, &data[0], 0, SE2_SECRETS->pairing); + 8007dc2: f89d 4008 ldrb.w r4, [sp, #8] + 8007dc6: f897 30b0 ldrb.w r3, [r7, #176] ; 0xb0 + 8007dca: 4e11 ldr r6, [pc, #68] ; (8007e10 ) + 8007dcc: 4d11 ldr r5, [pc, #68] ; (8007e14 ) + 8007dce: 9a05 ldr r2, [sp, #20] + 8007dd0: 9901 ldr r1, [sp, #4] + 8007dd2: 9204 str r2, [sp, #16] + 8007dd4: 1c60 adds r0, r4, #1 + 8007dd6: 2bff cmp r3, #255 ; 0xff + 8007dd8: bf0c ite eq + 8007dda: 4633 moveq r3, r6 + 8007ddc: 462b movne r3, r5 + 8007dde: b2c0 uxtb r0, r0 + 8007de0: f7ff fba6 bl 8007530 + if(tc_flags & TC_XPRV_WALLET) { + 8007de4: 9b03 ldr r3, [sp, #12] + 8007de6: 051b lsls r3, r3, #20 + 8007de8: d50c bpl.n 8007e04 + se2_read_encrypted(slot_num+2, &data[32], 0, SE2_SECRETS->pairing); + 8007dea: f897 30b0 ldrb.w r3, [r7, #176] ; 0xb0 + 8007dee: 9901 ldr r1, [sp, #4] + 8007df0: 9a04 ldr r2, [sp, #16] + 8007df2: 3402 adds r4, #2 + 8007df4: 2bff cmp r3, #255 ; 0xff + 8007df6: bf0c ite eq + 8007df8: 4633 moveq r3, r6 + 8007dfa: 462b movne r3, r5 + 8007dfc: 3120 adds r1, #32 + 8007dfe: b2e0 uxtb r0, r4 + 8007e00: f7ff fb96 bl 8007530 +} + 8007e04: b007 add sp, #28 + 8007e06: bdf0 pop {r4, r5, r6, r7, pc} + 8007e08: 2009e390 .word 0x2009e390 + 8007e0c: 0801c000 .word 0x0801c000 + 8007e10: 2009e2b0 .word 0x2009e2b0 + 8007e14: 0801c0b0 .word 0x0801c0b0 + +08007e18 : +{ + 8007e18: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + 8007e1c: b0fe sub sp, #504 ; 0x1f8 + 8007e1e: e9cd 1002 strd r1, r0, [sp, #8] + 8007e22: e9cd 2300 strd r2, r3, [sp] + se2_setup(); + 8007e26: f7ff ff4b bl 8007cc0 + if(setjmp(error_env)) { + 8007e2a: 4864 ldr r0, [pc, #400] ; (8007fbc ) + 8007e2c: f005 fc2a bl 800d684 + 8007e30: 4604 mov r4, r0 + 8007e32: b138 cbz r0, 8007e44 + if(!safety_mode) fatal_mitm(); + 8007e34: 9b01 ldr r3, [sp, #4] + 8007e36: b11b cbz r3, 8007e40 + return false; + 8007e38: 2000 movs r0, #0 +} + 8007e3a: b07e add sp, #504 ; 0x1f8 + 8007e3c: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + if(!safety_mode) fatal_mitm(); + 8007e40: f7f8 fe0c bl 8000a5c + if(!pin_len) return false; + 8007e44: 9b02 ldr r3, [sp, #8] + 8007e46: 2b00 cmp r3, #0 + 8007e48: d0f6 beq.n 8007e38 + trick_pin_hash(pin, pin_len, tpin_hash); + 8007e4a: 9803 ldr r0, [sp, #12] + se2_read_encrypted(pn, slots[i], 0, SE2_SECRETS->pairing); + 8007e4c: f8df a174 ldr.w sl, [pc, #372] ; 8007fc4 + 8007e50: f8df 9174 ldr.w r9, [pc, #372] ; 8007fc8 + 8007e54: f8df 8174 ldr.w r8, [pc, #372] ; 8007fcc + trick_pin_hash(pin, pin_len, tpin_hash); + 8007e58: aa06 add r2, sp, #24 + 8007e5a: 4619 mov r1, r3 + 8007e5c: f7ff fe24 bl 8007aa8 + 8007e60: ad0e add r5, sp, #56 ; 0x38 + 8007e62: 462f mov r7, r5 + int pn = PGN_TRICK(0); + 8007e64: 4626 mov r6, r4 + se2_read_encrypted(pn, slots[i], 0, SE2_SECRETS->pairing); + 8007e66: f89a 30b0 ldrb.w r3, [sl, #176] ; 0xb0 + 8007e6a: 4639 mov r1, r7 + 8007e6c: 2bff cmp r3, #255 ; 0xff + 8007e6e: bf0c ite eq + 8007e70: 464b moveq r3, r9 + 8007e72: 4643 movne r3, r8 + 8007e74: b2f0 uxtb r0, r6 + 8007e76: 2200 movs r2, #0 + for(int i=0; ipairing); + 8007e7a: f7ff fb59 bl 8007530 + for(int i=0; i + se2_clear_volatile(); + 8007e86: f7ff fccf bl 8007828 + uint32_t blank = 0; + 8007e8a: 2700 movs r7, #0 + int found = -1; + 8007e8c: f04f 36ff mov.w r6, #4294967295 ; 0xffffffff + if(check_equal(here, tpin_hash, 28)) { + 8007e90: f04f 091c mov.w r9, #28 + blank |= (!!check_all_zeros(here, 32)) << i; + 8007e94: f04f 0820 mov.w r8, #32 + if(check_equal(here, tpin_hash, 28)) { + 8007e98: 464a mov r2, r9 + 8007e9a: a906 add r1, sp, #24 + 8007e9c: 4628 mov r0, r5 + 8007e9e: f7fa fc08 bl 80026b2 + blank |= (!!check_all_zeros(here, 32)) << i; + 8007ea2: 4641 mov r1, r8 + if(check_equal(here, tpin_hash, 28)) { + 8007ea4: 2800 cmp r0, #0 + 8007ea6: bf18 it ne + 8007ea8: 4626 movne r6, r4 + blank |= (!!check_all_zeros(here, 32)) << i; + 8007eaa: 4628 mov r0, r5 + 8007eac: f7fa fbf2 bl 8002694 + 8007eb0: 40a0 lsls r0, r4 + for(int i=0; i + rng_delay(); + 8007ec0: f7fa fc5c bl 800277c + memset(found_slot, 0, sizeof(trick_slot_t)); + 8007ec4: 9800 ldr r0, [sp, #0] + 8007ec6: 2280 movs r2, #128 ; 0x80 + 8007ec8: 2100 movs r1, #0 + 8007eca: f005 fbd3 bl 800d674 + if(safety_mode) { + 8007ece: 9b01 ldr r3, [sp, #4] + 8007ed0: b10b cbz r3, 8007ed6 + found_slot->blank_slots = blank; + 8007ed2: 9b00 ldr r3, [sp, #0] + 8007ed4: 65df str r7, [r3, #92] ; 0x5c + if(found >= 0) { + 8007ed6: 1c72 adds r2, r6, #1 + 8007ed8: d069 beq.n 8007fae + found_slot->slot_num = found; + 8007eda: 9b00 ldr r3, [sp, #0] + 8007edc: 0174 lsls r4, r6, #5 + 8007ede: 601e str r6, [r3, #0] + memcpy(meta, &slots[found][28], 4); + 8007ee0: ab15 add r3, sp, #84 ; 0x54 + xor_mixin(meta, &tpin_hash[28], 4); + 8007ee2: 2204 movs r2, #4 + memcpy(meta, &slots[found][28], 4); + 8007ee4: 591b ldr r3, [r3, r4] + 8007ee6: 9305 str r3, [sp, #20] + xor_mixin(meta, &tpin_hash[28], 4); + 8007ee8: a90d add r1, sp, #52 ; 0x34 + 8007eea: a805 add r0, sp, #20 + 8007eec: f7ff f982 bl 80071f4 + memcpy(&found_slot->tc_flags, &meta[0], 2); + 8007ef0: 9b00 ldr r3, [sp, #0] + 8007ef2: f8bd 5014 ldrh.w r5, [sp, #20] + memcpy(&found_slot->tc_arg, &meta[2], 2); + 8007ef6: 9a00 ldr r2, [sp, #0] + memcpy(&found_slot->tc_flags, &meta[0], 2); + 8007ef8: 809d strh r5, [r3, #4] + memcpy(&found_slot->tc_arg, &meta[2], 2); + 8007efa: f8bd 3016 ldrh.w r3, [sp, #22] + 8007efe: 80d3 strh r3, [r2, #6] + if(todo & TC_WORD_WALLET) { + 8007f00: 04eb lsls r3, r5, #19 + 8007f02: d513 bpl.n 8007f2c + if(found+1 < NUM_TRICKS) { + 8007f04: 2e0c cmp r6, #12 + 8007f06: dc0e bgt.n 8007f26 + memcpy(found_slot->xdata, &slots[found+1][0], 32); + 8007f08: f504 73fc add.w r3, r4, #504 ; 0x1f8 + 8007f0c: eb0d 0403 add.w r4, sp, r3 + 8007f10: f5a4 73d0 sub.w r3, r4, #416 ; 0x1a0 + 8007f14: 3208 adds r2, #8 + 8007f16: f5a4 74c0 sub.w r4, r4, #384 ; 0x180 + 8007f1a: f853 1b04 ldr.w r1, [r3], #4 + 8007f1e: f842 1b04 str.w r1, [r2], #4 + 8007f22: 42a3 cmp r3, r4 + 8007f24: d1f9 bne.n 8007f1a + if(!safety_mode && todo) { + 8007f26: 9b01 ldr r3, [sp, #4] + 8007f28: b33b cbz r3, 8007f7a + 8007f2a: e03e b.n 8007faa + } else if(todo & TC_XPRV_WALLET) { + 8007f2c: 052f lsls r7, r5, #20 + 8007f2e: d521 bpl.n 8007f74 + if(found+2 < NUM_TRICKS) { + 8007f30: 2e0b cmp r6, #11 + 8007f32: dcf8 bgt.n 8007f26 + memcpy(&found_slot->xdata[0], &slots[found+1][0], 32); + 8007f34: 9900 ldr r1, [sp, #0] + 8007f36: f504 73fc add.w r3, r4, #504 ; 0x1f8 + 8007f3a: 446b add r3, sp + 8007f3c: f5a3 72d0 sub.w r2, r3, #416 ; 0x1a0 + 8007f40: 3108 adds r1, #8 + 8007f42: f5a3 73c0 sub.w r3, r3, #384 ; 0x180 + 8007f46: f852 0b04 ldr.w r0, [r2], #4 + 8007f4a: f841 0b04 str.w r0, [r1], #4 + 8007f4e: 429a cmp r2, r3 + 8007f50: d1f9 bne.n 8007f46 + memcpy(&found_slot->xdata[32], &slots[found+2][0], 32); + 8007f52: f504 73fc add.w r3, r4, #504 ; 0x1f8 + 8007f56: 9a00 ldr r2, [sp, #0] + 8007f58: eb0d 0403 add.w r4, sp, r3 + 8007f5c: f5a4 73c0 sub.w r3, r4, #384 ; 0x180 + 8007f60: 3228 adds r2, #40 ; 0x28 + 8007f62: f5a4 74b0 sub.w r4, r4, #352 ; 0x160 + 8007f66: f853 1b04 ldr.w r1, [r3], #4 + 8007f6a: f842 1b04 str.w r1, [r2], #4 + 8007f6e: 42a3 cmp r3, r4 + 8007f70: d1f9 bne.n 8007f66 + 8007f72: e7d8 b.n 8007f26 + if(!safety_mode && todo) { + 8007f74: 9b01 ldr r3, [sp, #4] + 8007f76: b9c3 cbnz r3, 8007faa + 8007f78: b1bd cbz r5, 8007faa + if(todo & TC_WIPE) { + 8007f7a: 0428 lsls r0, r5, #16 + 8007f7c: d50a bpl.n 8007f94 + mcu_key_clear(NULL); + 8007f7e: 2000 movs r0, #0 + 8007f80: f7fa fa6a bl 8002458 + if(todo == TC_WIPE) { + 8007f84: f5b5 4f00 cmp.w r5, #32768 ; 0x8000 + 8007f88: d104 bne.n 8007f94 + oled_show(screen_wiped); + 8007f8a: 480d ldr r0, [pc, #52] ; (8007fc0 ) + 8007f8c: f7f8 ff5a bl 8000e44 + LOCKUP_FOREVER(); + 8007f90: bf30 wfi + 8007f92: e7fd b.n 8007f90 + if(todo & TC_BRICK) { + 8007f94: 0469 lsls r1, r5, #17 + 8007f96: d403 bmi.n 8007fa0 + if(todo & TC_REBOOT) { + 8007f98: 05aa lsls r2, r5, #22 + 8007f9a: d504 bpl.n 8007fa6 + NVIC_SystemReset(); + 8007f9c: f7ff f918 bl 80071d0 <__NVIC_SystemReset> + fast_brick(); + 8007fa0: f7fa fb1e bl 80025e0 + 8007fa4: e7f8 b.n 8007f98 + if(todo & TC_FAKE_OUT) { + 8007fa6: 04ab lsls r3, r5, #18 + 8007fa8: d401 bmi.n 8007fae + return true; + 8007faa: 2001 movs r0, #1 + 8007fac: e745 b.n 8007e3a + found_slot->slot_num = -1; + 8007fae: 9a00 ldr r2, [sp, #0] + 8007fb0: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 8007fb4: 6013 str r3, [r2, #0] + rng_delay(); + 8007fb6: f7fa fbe1 bl 800277c + 8007fba: e73d b.n 8007e38 + 8007fbc: 2009e390 .word 0x2009e390 + 8007fc0: 0800e310 .word 0x0800e310 + 8007fc4: 0801c000 .word 0x0801c000 + 8007fc8: 2009e2b0 .word 0x2009e2b0 + 8007fcc: 0801c0b0 .word 0x0801c0b0 + +08007fd0 : +{ + 8007fd0: b510 push {r4, lr} + 8007fd2: b0a2 sub sp, #136 ; 0x88 + 8007fd4: 4604 mov r4, r0 + bool is_trick = se2_test_trick_pin("!p", 2, &slot, true); + 8007fd6: 2301 movs r3, #1 + 8007fd8: 481d ldr r0, [pc, #116] ; (8008050 ) + 8007fda: aa02 add r2, sp, #8 + 8007fdc: 2102 movs r1, #2 + 8007fde: f7ff ff1b bl 8007e18 + if(!is_trick) return; + 8007fe2: b390 cbz r0, 800804a + if(num_fails >= slot.tc_arg) { + 8007fe4: f8bd 300e ldrh.w r3, [sp, #14] + 8007fe8: 42a3 cmp r3, r4 + 8007fea: dc2e bgt.n 800804a + if(slot.tc_flags & TC_WIPE) { + 8007fec: f9bd 300c ldrsh.w r3, [sp, #12] + 8007ff0: f8bd 000c ldrh.w r0, [sp, #12] + 8007ff4: 2b00 cmp r3, #0 + 8007ff6: da1c bge.n 8008032 + if(slot.tc_flags & TC_BRICK) { + 8007ff8: f410 4080 ands.w r0, r0, #16384 ; 0x4000 + 8007ffc: d00d beq.n 800801a + const mcu_key_t *cur = mcu_key_get(&valid); + 8007ffe: f10d 0007 add.w r0, sp, #7 + 8008002: f7fa fa09 bl 8002418 + if(valid) { + 8008006: f89d 3007 ldrb.w r3, [sp, #7] + 800800a: b193 cbz r3, 8008032 + mcu_key_clear(cur); + 800800c: f7fa fa24 bl 8002458 + oled_show(screen_wiped); + 8008010: 4810 ldr r0, [pc, #64] ; (8008054 ) + 8008012: f7f8 ff17 bl 8000e44 + LOCKUP_FOREVER(); + 8008016: bf30 wfi + 8008018: e7fd b.n 8008016 + mcu_key_clear(NULL); // does valid key check + 800801a: f7fa fa1d bl 8002458 + if(slot.tc_flags == TC_WIPE) { + 800801e: f8bd 300c ldrh.w r3, [sp, #12] + 8008022: f5b3 4f00 cmp.w r3, #32768 ; 0x8000 + 8008026: d104 bne.n 8008032 + oled_show(screen_wiped); + 8008028: 480a ldr r0, [pc, #40] ; (8008054 ) + 800802a: f7f8 ff0b bl 8000e44 + LOCKUP_FOREVER(); + 800802e: bf30 wfi + 8008030: e7fd b.n 800802e + if(slot.tc_flags & TC_BRICK) { + 8008032: f8bd 300c ldrh.w r3, [sp, #12] + 8008036: 045a lsls r2, r3, #17 + 8008038: d501 bpl.n 800803e + fast_brick(); + 800803a: f7fa fad1 bl 80025e0 + if(slot.tc_flags & TC_REBOOT) { + 800803e: f8bd 300c ldrh.w r3, [sp, #12] + 8008042: 059b lsls r3, r3, #22 + 8008044: d501 bpl.n 800804a + NVIC_SystemReset(); + 8008046: f7ff f8c3 bl 80071d0 <__NVIC_SystemReset> +} + 800804a: b022 add sp, #136 ; 0x88 + 800804c: bd10 pop {r4, pc} + 800804e: bf00 nop + 8008050: 0800ea2d .word 0x0800ea2d + 8008054: 0800e310 .word 0x0800e310 + +08008058 : +{ + 8008058: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + 800805c: b094 sub sp, #80 ; 0x50 + 800805e: 9001 str r0, [sp, #4] + se2_setup(); + 8008060: f7ff fe2e bl 8007cc0 + if(setjmp(error_env)) { + 8008064: 4848 ldr r0, [pc, #288] ; (8008188 ) + 8008066: f005 fb0d bl 800d684 + 800806a: 4604 mov r4, r0 + 800806c: 2800 cmp r0, #0 + 800806e: f040 8088 bne.w 8008182 + if((config->slot_num < 0) || (config->slot_num >= NUM_TRICKS) ) { + 8008072: 9b01 ldr r3, [sp, #4] + 8008074: 681b ldr r3, [r3, #0] + 8008076: 2b0d cmp r3, #13 + 8008078: d804 bhi.n 8008084 + if((config->slot_num >= NUM_TRICKS-1) && (config->tc_flags & TC_WORD_WALLET) ) { + 800807a: d106 bne.n 800808a + 800807c: 9b01 ldr r3, [sp, #4] + 800807e: 889b ldrh r3, [r3, #4] + 8008080: 04d9 lsls r1, r3, #19 + 8008082: d504 bpl.n 800808e + return EPIN_RANGE_ERR; + 8008084: f06f 0466 mvn.w r4, #102 ; 0x66 + 8008088: e01f b.n 80080ca + if((config->slot_num >= NUM_TRICKS-2) && (config->tc_flags & TC_XPRV_WALLET) ) { + 800808a: 2b0c cmp r3, #12 + 800808c: d103 bne.n 8008096 + 800808e: 9b01 ldr r3, [sp, #4] + 8008090: 889b ldrh r3, [r3, #4] + 8008092: 051a lsls r2, r3, #20 + 8008094: d4f6 bmi.n 8008084 + if(config->pin_len > sizeof(config->pin)) { + 8008096: 9b01 ldr r3, [sp, #4] + 8008098: 6d99 ldr r1, [r3, #88] ; 0x58 + 800809a: 2910 cmp r1, #16 + 800809c: d8f2 bhi.n 8008084 + if(config->blank_slots) { + 800809e: 6ddd ldr r5, [r3, #92] ; 0x5c + 80080a0: b31d cbz r5, 80080ea + uint8_t zeros[32] = { 0 }; + 80080a2: 2100 movs r1, #0 + 80080a4: 221c movs r2, #28 + 80080a6: a805 add r0, sp, #20 + 80080a8: 9104 str r1, [sp, #16] + 80080aa: f005 fae3 bl 800d674 + se2_write_encrypted(PGN_TRICK(i), zeros, 0, SE2_SECRETS->pairing); + 80080ae: f8df 80e4 ldr.w r8, [pc, #228] ; 8008194 + 80080b2: 4f36 ldr r7, [pc, #216] ; (800818c ) + 80080b4: 4e36 ldr r6, [pc, #216] ; (8008190 ) + for(int i=0; iblank_slots) { + 80080b8: 9a01 ldr r2, [sp, #4] + uint32_t mask = (1 << i); + 80080ba: 2301 movs r3, #1 + if(mask & config->blank_slots) { + 80080bc: 6dd2 ldr r2, [r2, #92] ; 0x5c + uint32_t mask = (1 << i); + 80080be: 40ab lsls r3, r5 + if(mask & config->blank_slots) { + 80080c0: 4213 tst r3, r2 + 80080c2: d106 bne.n 80080d2 + for(int i=0; i +} + 80080ca: 4620 mov r0, r4 + 80080cc: b014 add sp, #80 ; 0x50 + 80080ce: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + se2_write_encrypted(PGN_TRICK(i), zeros, 0, SE2_SECRETS->pairing); + 80080d2: f898 30b0 ldrb.w r3, [r8, #176] ; 0xb0 + 80080d6: 2200 movs r2, #0 + 80080d8: 2bff cmp r3, #255 ; 0xff + 80080da: bf0c ite eq + 80080dc: 463b moveq r3, r7 + 80080de: 4633 movne r3, r6 + 80080e0: a904 add r1, sp, #16 + 80080e2: b2e8 uxtb r0, r5 + 80080e4: f7ff fa9c bl 8007620 + 80080e8: e7ec b.n 80080c4 + trick_pin_hash(config->pin, config->pin_len, tpin_digest); + 80080ea: 9b01 ldr r3, [sp, #4] + se2_write_encrypted(PGN_TRICK(config->slot_num), tpin_digest, 0, SE2_SECRETS->pairing); + 80080ec: f8df 80a4 ldr.w r8, [pc, #164] ; 8008194 + 80080f0: 4f26 ldr r7, [pc, #152] ; (800818c ) + 80080f2: 4e27 ldr r6, [pc, #156] ; (8008190 ) + trick_pin_hash(config->pin, config->pin_len, tpin_digest); + 80080f4: f103 0048 add.w r0, r3, #72 ; 0x48 + 80080f8: aa0c add r2, sp, #48 ; 0x30 + 80080fa: f7ff fcd5 bl 8007aa8 + memcpy(&meta[0], &config->tc_flags, 2); + 80080fe: 9b01 ldr r3, [sp, #4] + 8008100: 889b ldrh r3, [r3, #4] + 8008102: f8ad 300c strh.w r3, [sp, #12] + memcpy(&meta[2], &config->tc_arg, 2); + 8008106: 9b01 ldr r3, [sp, #4] + xor_mixin(&tpin_digest[28], meta, 4); + 8008108: 2204 movs r2, #4 + memcpy(&meta[2], &config->tc_arg, 2); + 800810a: 88db ldrh r3, [r3, #6] + 800810c: f8ad 300e strh.w r3, [sp, #14] + xor_mixin(&tpin_digest[28], meta, 4); + 8008110: a903 add r1, sp, #12 + 8008112: a813 add r0, sp, #76 ; 0x4c + 8008114: f7ff f86e bl 80071f4 + se2_write_encrypted(PGN_TRICK(config->slot_num), tpin_digest, 0, SE2_SECRETS->pairing); + 8008118: f898 30b0 ldrb.w r3, [r8, #176] ; 0xb0 + 800811c: 9801 ldr r0, [sp, #4] + 800811e: 2bff cmp r3, #255 ; 0xff + 8008120: bf0c ite eq + 8008122: 463b moveq r3, r7 + 8008124: 4633 movne r3, r6 + 8008126: 7800 ldrb r0, [r0, #0] + 8008128: 462a mov r2, r5 + 800812a: a90c add r1, sp, #48 ; 0x30 + 800812c: f7ff fa78 bl 8007620 + if(config->tc_flags & (TC_WORD_WALLET | TC_XPRV_WALLET)) { + 8008130: 9b01 ldr r3, [sp, #4] + 8008132: 889b ldrh r3, [r3, #4] + 8008134: f403 53c0 and.w r3, r3, #6144 ; 0x1800 + 8008138: b9a3 cbnz r3, 8008164 + if(config->tc_flags & TC_XPRV_WALLET) { + 800813a: 9b01 ldr r3, [sp, #4] + 800813c: 889b ldrh r3, [r3, #4] + 800813e: 051b lsls r3, r3, #20 + 8008140: d5c3 bpl.n 80080ca + se2_write_encrypted(PGN_TRICK(config->slot_num+2), &config->xdata[32], + 8008142: 9901 ldr r1, [sp, #4] + 0, SE2_SECRETS->pairing); + 8008144: 4b13 ldr r3, [pc, #76] ; (8008194 ) + se2_write_encrypted(PGN_TRICK(config->slot_num+2), &config->xdata[32], + 8008146: f851 0b28 ldr.w r0, [r1], #40 + 0, SE2_SECRETS->pairing); + 800814a: f893 50b0 ldrb.w r5, [r3, #176] ; 0xb0 + se2_write_encrypted(PGN_TRICK(config->slot_num+2), &config->xdata[32], + 800814e: 4a10 ldr r2, [pc, #64] ; (8008190 ) + 8008150: 4b0e ldr r3, [pc, #56] ; (800818c ) + 8008152: 3002 adds r0, #2 + 8008154: 2dff cmp r5, #255 ; 0xff + 8008156: bf18 it ne + 8008158: 4613 movne r3, r2 + 800815a: b2c0 uxtb r0, r0 + 800815c: 2200 movs r2, #0 + 800815e: f7ff fa5f bl 8007620 + 8008162: e7b2 b.n 80080ca + se2_write_encrypted(PGN_TRICK(config->slot_num+1), &config->xdata[0], + 8008164: 9901 ldr r1, [sp, #4] + 0, SE2_SECRETS->pairing); + 8008166: f898 30b0 ldrb.w r3, [r8, #176] ; 0xb0 + se2_write_encrypted(PGN_TRICK(config->slot_num+1), &config->xdata[0], + 800816a: f851 0b08 ldr.w r0, [r1], #8 + 800816e: 3001 adds r0, #1 + 8008170: 2bff cmp r3, #255 ; 0xff + 8008172: bf0c ite eq + 8008174: 463b moveq r3, r7 + 8008176: 4633 movne r3, r6 + 8008178: 462a mov r2, r5 + 800817a: b2c0 uxtb r0, r0 + 800817c: f7ff fa50 bl 8007620 + 8008180: e7db b.n 800813a + return EPIN_SE2_FAIL; + 8008182: f06f 0472 mvn.w r4, #114 ; 0x72 + 8008186: e7a0 b.n 80080ca + 8008188: 2009e390 .word 0x2009e390 + 800818c: 2009e2b0 .word 0x2009e2b0 + 8008190: 0801c0b0 .word 0x0801c0b0 + 8008194: 0801c000 .word 0x0801c000 + +08008198 : +// + bool +se2_encrypt_secret(const uint8_t secret[], int secret_len, int offset, + uint8_t main_slot[], uint8_t *check_value, + const uint8_t pin_digest[32]) +{ + 8008198: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + 800819c: f5ad 7d10 sub.w sp, sp, #576 ; 0x240 + 80081a0: 4699 mov r9, r3 + 80081a2: 4682 mov sl, r0 + 80081a4: 460f mov r7, r1 + 80081a6: 4614 mov r4, r2 + 80081a8: f8dd 8260 ldr.w r8, [sp, #608] ; 0x260 + se2_setup(); + 80081ac: f7ff fd88 bl 8007cc0 + + bool is_valid; + const mcu_key_t *cur = mcu_key_get(&is_valid); + 80081b0: f10d 000b add.w r0, sp, #11 + 80081b4: f7fa f930 bl 8002418 + + if(!is_valid) { + 80081b8: f89d 300b ldrb.w r3, [sp, #11] + 80081bc: b953 cbnz r3, 80081d4 + if(!check_value) { + 80081be: f1b8 0f00 cmp.w r8, #0 + 80081c2: d105 bne.n 80081d0 + // problem: we are not writing the check value but it would be changed. + // ie: change long secret before real secret--unlikely + return true; + 80081c4: 2501 movs r5, #1 + ctx.num_pending = 32; + aes_done(&ctx, check_value, 32, aes_key, nonce); + } + + return false; +} + 80081c6: 4628 mov r0, r5 + 80081c8: f50d 7d10 add.w sp, sp, #576 ; 0x240 + 80081cc: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + cur = mcu_key_pick(); + 80081d0: f7fa f98a bl 80024e8 + if(se2_calc_seed_key(aes_key, cur, pin_digest)) return true; + 80081d4: 4601 mov r1, r0 + 80081d6: 9a99 ldr r2, [sp, #612] ; 0x264 + 80081d8: a807 add r0, sp, #28 + 80081da: f7ff fd3f bl 8007c5c + 80081de: 4605 mov r5, r0 + 80081e0: 2800 cmp r0, #0 + 80081e2: d1ef bne.n 80081c4 + memcpy(nonce, rom_secrets->mcu_hmac_key, sizeof(nonce)-1); + 80081e4: 4b16 ldr r3, [pc, #88] ; (8008240 ) + 80081e6: cb0f ldmia r3, {r0, r1, r2, r3} + 80081e8: ae03 add r6, sp, #12 + 80081ea: 46b4 mov ip, r6 + 80081ec: e8ac 0007 stmia.w ip!, {r0, r1, r2} + nonce[15] = offset / AES_BLOCK_SIZE; + 80081f0: 2c00 cmp r4, #0 + memcpy(nonce, rom_secrets->mcu_hmac_key, sizeof(nonce)-1); + 80081f2: f82c 3b02 strh.w r3, [ip], #2 + nonce[15] = offset / AES_BLOCK_SIZE; + 80081f6: bfb8 it lt + 80081f8: 340f addlt r4, #15 + memcpy(nonce, rom_secrets->mcu_hmac_key, sizeof(nonce)-1); + 80081fa: 0c1b lsrs r3, r3, #16 + 80081fc: f88c 3000 strb.w r3, [ip] + aes_init(&ctx); + 8008200: a80f add r0, sp, #60 ; 0x3c + nonce[15] = offset / AES_BLOCK_SIZE; + 8008202: 1124 asrs r4, r4, #4 + 8008204: 73f4 strb r4, [r6, #15] + aes_init(&ctx); + 8008206: f000 f92b bl 8008460 + aes_add(&ctx, secret, secret_len); + 800820a: 463a mov r2, r7 + 800820c: 4651 mov r1, sl + 800820e: a80f add r0, sp, #60 ; 0x3c + 8008210: f000 f92c bl 800846c + aes_done(&ctx, main_slot, secret_len, aes_key, nonce); + 8008214: 9600 str r6, [sp, #0] + 8008216: ab07 add r3, sp, #28 + 8008218: 463a mov r2, r7 + 800821a: 4649 mov r1, r9 + 800821c: a80f add r0, sp, #60 ; 0x3c + 800821e: f000 f93b bl 8008498 + if(check_value) { + 8008222: f1b8 0f00 cmp.w r8, #0 + 8008226: d0ce beq.n 80081c6 + aes_init(&ctx); + 8008228: a80f add r0, sp, #60 ; 0x3c + 800822a: f000 f919 bl 8008460 + ctx.num_pending = 32; + 800822e: 2220 movs r2, #32 + aes_done(&ctx, check_value, 32, aes_key, nonce); + 8008230: 9600 str r6, [sp, #0] + 8008232: ab07 add r3, sp, #28 + 8008234: 4641 mov r1, r8 + 8008236: a80f add r0, sp, #60 ; 0x3c + ctx.num_pending = 32; + 8008238: 928f str r2, [sp, #572] ; 0x23c + aes_done(&ctx, check_value, 32, aes_key, nonce); + 800823a: f000 f92d bl 8008498 + 800823e: e7c2 b.n 80081c6 + 8008240: 0801c090 .word 0x0801c090 + +08008244 : +// + void +se2_decrypt_secret(uint8_t secret[], int secret_len, int offset, + const uint8_t main_slot[], const uint8_t *check_value, + const uint8_t pin_digest[32], bool *is_valid) +{ + 8008244: b530 push {r4, r5, lr} + 8008246: f5ad 7d1f sub.w sp, sp, #636 ; 0x27c + 800824a: e9cd 2306 strd r2, r3, [sp, #24] + 800824e: 9005 str r0, [sp, #20] + 8008250: 9103 str r1, [sp, #12] + se2_setup(); + 8008252: f7ff fd35 bl 8007cc0 + + const mcu_key_t *cur = mcu_key_get(is_valid); + 8008256: 98a4 ldr r0, [sp, #656] ; 0x290 + 8008258: f7fa f8de bl 8002418 + if(!*is_valid) { + 800825c: 9ba4 ldr r3, [sp, #656] ; 0x290 + const mcu_key_t *cur = mcu_key_get(is_valid); + 800825e: 9004 str r0, [sp, #16] + if(!*is_valid) { + 8008260: 781b ldrb r3, [r3, #0] + 8008262: b133 cbz r3, 8008272 + // no key set? won't be able to decrypt. + return; + } + + int line_num; + if((line_num = setjmp(error_env))) { + 8008264: 4825 ldr r0, [pc, #148] ; (80082fc ) + 8008266: f005 fa0d bl 800d684 + 800826a: b128 cbz r0, 8008278 + // internal failures / broken i2c buses will come here + *is_valid = false; + 800826c: 9aa4 ldr r2, [sp, #656] ; 0x290 + 800826e: 2300 movs r3, #0 + 8008270: 7013 strb r3, [r2, #0] + + // decrypt the real data + aes_init(&ctx); + aes_add(&ctx, main_slot, secret_len); + aes_done(&ctx, secret, secret_len, aes_key, nonce); +} + 8008272: f50d 7d1f add.w sp, sp, #636 ; 0x27c + 8008276: bd30 pop {r4, r5, pc} + if(se2_calc_seed_key(aes_key, cur, pin_digest)) { + 8008278: 9aa3 ldr r2, [sp, #652] ; 0x28c + 800827a: 9904 ldr r1, [sp, #16] + 800827c: a80d add r0, sp, #52 ; 0x34 + 800827e: f7ff fced bl 8007c5c + 8008282: 2800 cmp r0, #0 + 8008284: d1f2 bne.n 800826c + memcpy(nonce, rom_secrets->mcu_hmac_key, sizeof(nonce)-1); + 8008286: 4b1e ldr r3, [pc, #120] ; (8008300 ) + 8008288: cb0f ldmia r3, {r0, r1, r2, r3} + 800828a: ad09 add r5, sp, #36 ; 0x24 + 800828c: 462c mov r4, r5 + 800828e: c407 stmia r4!, {r0, r1, r2} + 8008290: f824 3b02 strh.w r3, [r4], #2 + 8008294: 0c1b lsrs r3, r3, #16 + 8008296: 7023 strb r3, [r4, #0] + nonce[15] = offset / AES_BLOCK_SIZE; + 8008298: 9b06 ldr r3, [sp, #24] + 800829a: 2b00 cmp r3, #0 + 800829c: bfb8 it lt + 800829e: 330f addlt r3, #15 + 80082a0: 111b asrs r3, r3, #4 + 80082a2: 73eb strb r3, [r5, #15] + if(check_value) { + 80082a4: 9ba2 ldr r3, [sp, #648] ; 0x288 + 80082a6: b1bb cbz r3, 80082d8 + aes_init(&ctx); + 80082a8: a81d add r0, sp, #116 ; 0x74 + 80082aa: f000 f8d9 bl 8008460 + aes_add(&ctx, check_value, 32); + 80082ae: 99a2 ldr r1, [sp, #648] ; 0x288 + 80082b0: 2220 movs r2, #32 + 80082b2: a81d add r0, sp, #116 ; 0x74 + 80082b4: f000 f8da bl 800846c + aes_done(&ctx, got, 32, aes_key, nonce); + 80082b8: ab09 add r3, sp, #36 ; 0x24 + 80082ba: 9300 str r3, [sp, #0] + 80082bc: a915 add r1, sp, #84 ; 0x54 + 80082be: a81d add r0, sp, #116 ; 0x74 + 80082c0: ab0d add r3, sp, #52 ; 0x34 + 80082c2: 2220 movs r2, #32 + 80082c4: f000 f8e8 bl 8008498 + if(!check_all_zeros(got, 32)) { + 80082c8: 2120 movs r1, #32 + 80082ca: a815 add r0, sp, #84 ; 0x54 + 80082cc: f7fa f9e2 bl 8002694 + 80082d0: b910 cbnz r0, 80082d8 + *is_valid = false; + 80082d2: 9ba4 ldr r3, [sp, #656] ; 0x290 + 80082d4: 7018 strb r0, [r3, #0] + return; + 80082d6: e7cc b.n 8008272 + aes_init(&ctx); + 80082d8: a81d add r0, sp, #116 ; 0x74 + 80082da: f000 f8c1 bl 8008460 + aes_add(&ctx, main_slot, secret_len); + 80082de: 9a03 ldr r2, [sp, #12] + 80082e0: 9907 ldr r1, [sp, #28] + 80082e2: a81d add r0, sp, #116 ; 0x74 + 80082e4: f000 f8c2 bl 800846c + aes_done(&ctx, secret, secret_len, aes_key, nonce); + 80082e8: ab09 add r3, sp, #36 ; 0x24 + 80082ea: 9300 str r3, [sp, #0] + 80082ec: 9a03 ldr r2, [sp, #12] + 80082ee: 9905 ldr r1, [sp, #20] + 80082f0: ab0d add r3, sp, #52 ; 0x34 + 80082f2: a81d add r0, sp, #116 ; 0x74 + 80082f4: f000 f8d0 bl 8008498 + 80082f8: e7bb b.n 8008272 + 80082fa: bf00 nop + 80082fc: 2009e390 .word 0x2009e390 + 8008300: 0801c090 .word 0x0801c090 + +08008304 : +// +// Hash up a PIN code for login attempt: to tie it into SE2's contents. +// + void +se2_pin_hash(uint8_t digest_io[32], uint32_t purpose) +{ + 8008304: b5f0 push {r4, r5, r6, r7, lr} + if(purpose != PIN_PURPOSE_NORMAL) { + 8008306: 4b41 ldr r3, [pc, #260] ; (800840c ) +{ + 8008308: b0d5 sub sp, #340 ; 0x154 + if(purpose != PIN_PURPOSE_NORMAL) { + 800830a: 4299 cmp r1, r3 +{ + 800830c: e9cd 0100 strd r0, r1, [sp] + if(purpose != PIN_PURPOSE_NORMAL) { + 8008310: d17a bne.n 8008408 + // do nothing except for real PIN case (ie. not for prefix words) + return; + } + + se2_setup(); + 8008312: f7ff fcd5 bl 8007cc0 + if((setjmp(error_env))) { + 8008316: 483e ldr r0, [pc, #248] ; (8008410 ) + 8008318: f005 f9b4 bl 800d684 + 800831c: 4604 mov r4, r0 + 800831e: b120 cbz r0, 800832a + oled_show(screen_se2_issue); + 8008320: 483c ldr r0, [pc, #240] ; (8008414 ) + 8008322: f7f8 fd8f bl 8000e44 + + LOCKUP_FOREVER(); + 8008326: bf30 wfi + 8008328: e7fd b.n 8008326 + uint8_t rx[34]; // 2 bytes of len+status, then 32 bytes of data + uint8_t tmp[32]; + HMAC_CTX ctx; + + // HMAC(key=tpin_key, msg=given hash so far) + hmac_sha256_init(&ctx); + 800832a: a813 add r0, sp, #76 ; 0x4c + 800832c: f7fd f936 bl 800559c + hmac_sha256_update(&ctx, digest_io, 32); + 8008330: 9900 ldr r1, [sp, #0] + 8008332: 2220 movs r2, #32 + 8008334: a813 add r0, sp, #76 ; 0x4c + 8008336: f7fd f937 bl 80055a8 + hmac_sha256_update(&ctx, (uint8_t *)&purpose, 4); + 800833a: 2204 movs r2, #4 + 800833c: eb0d 0102 add.w r1, sp, r2 + 8008340: a813 add r0, sp, #76 ; 0x4c + 8008342: f7fd f931 bl 80055a8 + hmac_sha256_final(&ctx, SE2_SECRETS->tpin_key, tmp); + 8008346: 4b34 ldr r3, [pc, #208] ; (8008418 ) + 8008348: 4934 ldr r1, [pc, #208] ; (800841c ) + 800834a: f893 20b0 ldrb.w r2, [r3, #176] ; 0xb0 + 800834e: 33b0 adds r3, #176 ; 0xb0 + 8008350: 2aff cmp r2, #255 ; 0xff + 8008352: bf18 it ne + 8008354: 4619 movne r1, r3 + 8008356: 3180 adds r1, #128 ; 0x80 + 8008358: aa02 add r2, sp, #8 + 800835a: a813 add r0, sp, #76 ; 0x4c + 800835c: f7fd f93a bl 80055d4 + + // NOTE: exposed as cleartext here + se2_write_buffer(tmp, 32); + 8008360: 2120 movs r1, #32 + 8008362: a802 add r0, sp, #8 + 8008364: f7fe ffc2 bl 80072ec + 8008368: 25aa movs r5, #170 ; 0xaa + se2_write_buffer(rx+2, 32); + } + + // HMAC(key=secret-B, msg=consts+easy_key+buffer+consts) + // - result put in secret-S (ram) + CALL_CHECK(se2_write2(0x3c, (2<<6) | (1<<4) | PGN_SE2_EASY_KEY, 0)); + 800836a: 269e movs r6, #158 ; 0x9e + 800836c: 273c movs r7, #60 ; 0x3c + 800836e: 4622 mov r2, r4 + 8008370: 4631 mov r1, r6 + 8008372: 4638 mov r0, r7 + 8008374: f7fe ff66 bl 8007244 + 8008378: b150 cbz r0, 8008390 + 800837a: f240 511d movw r1, #1309 ; 0x51d + CHECK_RIGHT(se2_read1() == RC_SUCCESS); + 800837e: 4824 ldr r0, [pc, #144] ; (8008410 ) + 8008380: f005 f986 bl 800d690 + se2_write_buffer(rx+2, 32); + 8008384: 2120 movs r1, #32 + 8008386: f10d 002a add.w r0, sp, #42 ; 0x2a + 800838a: f7fe ffaf bl 80072ec + 800838e: e7ee b.n 800836e + CHECK_RIGHT(se2_read1() == RC_SUCCESS); + 8008390: f7fe ffe4 bl 800735c + 8008394: 28aa cmp r0, #170 ; 0xaa + 8008396: d002 beq.n 800839e + 8008398: f240 511e movw r1, #1310 ; 0x51e + 800839c: e7ef b.n 800837e + + // HMAC(key=S, msg=counter+junk), so we have something to read out + // - not 100% clear what contents of 'buffer' are here, but seems + // to be deterministic and unchanged from prev command + CALL_CHECK(se2_write1(0xa5, (2<<5) | PGN_DEC_COUNTER)); + 800839e: 215b movs r1, #91 ; 0x5b + 80083a0: 20a5 movs r0, #165 ; 0xa5 + 80083a2: f7fe ff35 bl 8007210 + 80083a6: b110 cbz r0, 80083ae + 80083a8: f240 5123 movw r1, #1315 ; 0x523 + 80083ac: e7e7 b.n 800837e + + CHECK_RIGHT(se2_read_n(sizeof(rx), rx) == RC_SUCCESS); + 80083ae: a90a add r1, sp, #40 ; 0x28 + 80083b0: 2022 movs r0, #34 ; 0x22 + 80083b2: f7fe ffab bl 800730c + 80083b6: 28aa cmp r0, #170 ; 0xaa + 80083b8: d002 beq.n 80083c0 + 80083ba: f240 5125 movw r1, #1317 ; 0x525 + 80083be: e7de b.n 800837e + CHECK_RIGHT(rx[1] == RC_SUCCESS); + 80083c0: f89d 3029 ldrb.w r3, [sp, #41] ; 0x29 + 80083c4: 2baa cmp r3, #170 ; 0xaa + 80083c6: d002 beq.n 80083ce + 80083c8: f240 5126 movw r1, #1318 ; 0x526 + 80083cc: e7d7 b.n 800837e + for(int i=0; i + } + + // one final HMAC because we had to read cleartext from bus + hmac_sha256_init(&ctx); + 80083d2: a813 add r0, sp, #76 ; 0x4c + 80083d4: f7fd f8e2 bl 800559c + hmac_sha256_update(&ctx, rx+2, 32); + 80083d8: 2220 movs r2, #32 + 80083da: f10d 012a add.w r1, sp, #42 ; 0x2a + 80083de: a813 add r0, sp, #76 ; 0x4c + 80083e0: f7fd f8e2 bl 80055a8 + hmac_sha256_update(&ctx, digest_io, 32); + 80083e4: 9900 ldr r1, [sp, #0] + 80083e6: 2220 movs r2, #32 + 80083e8: a813 add r0, sp, #76 ; 0x4c + 80083ea: f7fd f8dd bl 80055a8 + hmac_sha256_final(&ctx, SE2_SECRETS->tpin_key, digest_io); + 80083ee: 4b0a ldr r3, [pc, #40] ; (8008418 ) + 80083f0: 490a ldr r1, [pc, #40] ; (800841c ) + 80083f2: f893 20b0 ldrb.w r2, [r3, #176] ; 0xb0 + 80083f6: 33b0 adds r3, #176 ; 0xb0 + 80083f8: 2aff cmp r2, #255 ; 0xff + 80083fa: bf18 it ne + 80083fc: 4619 movne r1, r3 + 80083fe: 3180 adds r1, #128 ; 0x80 + 8008400: 9a00 ldr r2, [sp, #0] + 8008402: a813 add r0, sp, #76 ; 0x4c + 8008404: f7fd f8e6 bl 80055d4 +} + 8008408: b055 add sp, #340 ; 0x154 + 800840a: bdf0 pop {r4, r5, r6, r7, pc} + 800840c: 334d1858 .word 0x334d1858 + 8008410: 2009e390 .word 0x2009e390 + 8008414: 0800dfce .word 0x0800dfce + 8008418: 0801c000 .word 0x0801c000 + 800841c: 2009e2b0 .word 0x2009e2b0 + +08008420 : +// +// Read some random bytes, which we know cannot be MitM'ed. +// + void +se2_read_rng(uint8_t value[8]) +{ + 8008420: b500 push {lr} + 8008422: b08b sub sp, #44 ; 0x2c + 8008424: 9001 str r0, [sp, #4] + // funny business means MitM here + se2_setup(); + 8008426: f7ff fc4b bl 8007cc0 + if(setjmp(error_env)) fatal_mitm(); + 800842a: 4809 ldr r0, [pc, #36] ; (8008450 ) + 800842c: f005 f92a bl 800d684 + 8008430: b108 cbz r0, 8008436 + 8008432: f7f8 fb13 bl 8000a5c + + // read a field with "RPS" bytes, and verify those were read true + uint8_t tmp[32]; + se2_read_page(PGN_ROM_OPTIONS, tmp, true); + 8008436: a902 add r1, sp, #8 + 8008438: 2201 movs r2, #1 + 800843a: 201c movs r0, #28 + 800843c: f7ff f82a bl 8007494 + + memcpy(value, &tmp[4], 8); + 8008440: ab03 add r3, sp, #12 + 8008442: cb03 ldmia r3!, {r0, r1} + 8008444: 9b01 ldr r3, [sp, #4] + 8008446: 6018 str r0, [r3, #0] + 8008448: 6059 str r1, [r3, #4] +} + 800844a: b00b add sp, #44 ; 0x2c + 800844c: f85d fb04 ldr.w pc, [sp], #4 + 8008450: 2009e390 .word 0x2009e390 + +08008454 : + uint32_t rv; + + if(((uint32_t)src) & 0x3) { + memcpy(&rv, *src, 4); + } else { + rv = *(uint32_t *)(*src); + 8008454: 6803 ldr r3, [r0, #0] + 8008456: f853 2b04 ldr.w r2, [r3], #4 + } + (*src) += 4; + 800845a: 6003 str r3, [r0, #0] + + return __REV(rv); +} + 800845c: ba10 rev r0, r2 + 800845e: 4770 bx lr + +08008460 : + memset(ctx, 0, sizeof(AES_CTX)); + 8008460: f44f 7201 mov.w r2, #516 ; 0x204 + 8008464: 2100 movs r1, #0 + 8008466: f005 b905 b.w 800d674 + ... + +0800846c : +{ + 800846c: b538 push {r3, r4, r5, lr} + 800846e: 4605 mov r5, r0 + memcpy(ctx->pending+ctx->num_pending, data_in, len); + 8008470: f8d0 0200 ldr.w r0, [r0, #512] ; 0x200 + 8008474: 4428 add r0, r5 +{ + 8008476: 4614 mov r4, r2 + memcpy(ctx->pending+ctx->num_pending, data_in, len); + 8008478: f005 f8d4 bl 800d624 + ctx->num_pending += len; + 800847c: f8d5 2200 ldr.w r2, [r5, #512] ; 0x200 + 8008480: 4422 add r2, r4 + ASSERT(ctx->num_pending < sizeof(ctx->pending)); + 8008482: f5b2 7f00 cmp.w r2, #512 ; 0x200 + ctx->num_pending += len; + 8008486: f8c5 2200 str.w r2, [r5, #512] ; 0x200 + ASSERT(ctx->num_pending < sizeof(ctx->pending)); + 800848a: d302 bcc.n 8008492 + 800848c: 4801 ldr r0, [pc, #4] ; (8008494 ) + 800848e: f7f8 fadb bl 8000a48 +} + 8008492: bd38 pop {r3, r4, r5, pc} + 8008494: 0800e3e0 .word 0x0800e3e0 + +08008498 : +// +// Do the decryption. +// + void +aes_done(AES_CTX *ctx, uint8_t data_out[], uint32_t len, const uint8_t key[32], const uint8_t nonce[AES_BLOCK_SIZE]) +{ + 8008498: e92d 43f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, lr} + 800849c: 4688 mov r8, r1 + 800849e: 4611 mov r1, r2 + ASSERT(len <= ctx->num_pending); + 80084a0: f8d0 2200 ldr.w r2, [r0, #512] ; 0x200 +{ + 80084a4: b085 sub sp, #20 + ASSERT(len <= ctx->num_pending); + 80084a6: 428a cmp r2, r1 +{ + 80084a8: f8dd 9030 ldr.w r9, [sp, #48] ; 0x30 + 80084ac: 4606 mov r6, r0 + ASSERT(len <= ctx->num_pending); + 80084ae: d202 bcs.n 80084b6 + 80084b0: 4858 ldr r0, [pc, #352] ; (8008614 ) + 80084b2: f7f8 fac9 bl 8000a48 + + // enable clock to block + __HAL_RCC_AES_CLK_ENABLE(); + 80084b6: 4d58 ldr r5, [pc, #352] ; (8008618 ) + + // most changes have to be made w/ module disabled + AES->CR &= ~AES_CR_EN; + 80084b8: 4c58 ldr r4, [pc, #352] ; (800861c ) + __HAL_RCC_AES_CLK_ENABLE(); + 80084ba: 6cea ldr r2, [r5, #76] ; 0x4c + 80084bc: f442 3280 orr.w r2, r2, #65536 ; 0x10000 + 80084c0: 64ea str r2, [r5, #76] ; 0x4c + 80084c2: 6cea ldr r2, [r5, #76] ; 0x4c + 80084c4: f402 3280 and.w r2, r2, #65536 ; 0x10000 + 80084c8: 9201 str r2, [sp, #4] + 80084ca: 9a01 ldr r2, [sp, #4] + AES->CR &= ~AES_CR_EN; + 80084cc: 6822 ldr r2, [r4, #0] + 80084ce: f022 0201 bic.w r2, r2, #1 + 80084d2: 6022 str r2, [r4, #0] + + // set the key size and operation mode + MODIFY_REG(AES->CR, AES_CR_KEYSIZE, CRYP_KEYSIZE_256B); + 80084d4: 6822 ldr r2, [r4, #0] + 80084d6: f442 2280 orr.w r2, r2, #262144 ; 0x40000 + 80084da: 6022 str r2, [r4, #0] + MODIFY_REG(AES->CR, AES_CR_DATATYPE|AES_CR_MODE|AES_CR_CHMOD, + 80084dc: 6827 ldr r7, [r4, #0] + 80084de: f427 3780 bic.w r7, r7, #65536 ; 0x10000 + 80084e2: f027 077e bic.w r7, r7, #126 ; 0x7e + 80084e6: f047 0744 orr.w r7, r7, #68 ; 0x44 + 80084ea: 6027 str r7, [r4, #0] + CRYP_DATATYPE_8B | CRYP_ALGOMODE_ENCRYPT | CRYP_CHAINMODE_AES_CTR); + + // load key and IV values + const uint8_t *K = key; + AES->KEYR7 = word_pump_bytes(&K); + 80084ec: a802 add r0, sp, #8 + const uint8_t *K = key; + 80084ee: 9302 str r3, [sp, #8] + AES->KEYR7 = word_pump_bytes(&K); + 80084f0: f7ff ffb0 bl 8008454 + 80084f4: 63e0 str r0, [r4, #60] ; 0x3c + AES->KEYR6 = word_pump_bytes(&K); + 80084f6: a802 add r0, sp, #8 + 80084f8: f7ff ffac bl 8008454 + 80084fc: 63a0 str r0, [r4, #56] ; 0x38 + AES->KEYR5 = word_pump_bytes(&K); + 80084fe: a802 add r0, sp, #8 + 8008500: f7ff ffa8 bl 8008454 + 8008504: 6360 str r0, [r4, #52] ; 0x34 + AES->KEYR4 = word_pump_bytes(&K); + 8008506: a802 add r0, sp, #8 + 8008508: f7ff ffa4 bl 8008454 + 800850c: 6320 str r0, [r4, #48] ; 0x30 + AES->KEYR3 = word_pump_bytes(&K); + 800850e: a802 add r0, sp, #8 + 8008510: f7ff ffa0 bl 8008454 + 8008514: 61e0 str r0, [r4, #28] + AES->KEYR2 = word_pump_bytes(&K); + 8008516: a802 add r0, sp, #8 + 8008518: f7ff ff9c bl 8008454 + 800851c: 61a0 str r0, [r4, #24] + AES->KEYR1 = word_pump_bytes(&K); + 800851e: a802 add r0, sp, #8 + 8008520: f7ff ff98 bl 8008454 + 8008524: 6160 str r0, [r4, #20] + AES->KEYR0 = word_pump_bytes(&K); + 8008526: a802 add r0, sp, #8 + 8008528: f7ff ff94 bl 8008454 + 800852c: 6120 str r0, [r4, #16] + + if(nonce) { + 800852e: f1b9 0f00 cmp.w r9, #0 + 8008532: d045 beq.n 80085c0 + const uint8_t *N = nonce; + AES->IVR3 = word_pump_bytes(&N); + 8008534: a803 add r0, sp, #12 + const uint8_t *N = nonce; + 8008536: f8cd 900c str.w r9, [sp, #12] + AES->IVR3 = word_pump_bytes(&N); + 800853a: f7ff ff8b bl 8008454 + 800853e: 62e0 str r0, [r4, #44] ; 0x2c + AES->IVR2 = word_pump_bytes(&N); + 8008540: a803 add r0, sp, #12 + 8008542: f7ff ff87 bl 8008454 + 8008546: 62a0 str r0, [r4, #40] ; 0x28 + AES->IVR1 = word_pump_bytes(&N); + 8008548: a803 add r0, sp, #12 + 800854a: f7ff ff83 bl 8008454 + 800854e: 6260 str r0, [r4, #36] ; 0x24 + AES->IVR0 = word_pump_bytes(&N); + 8008550: a803 add r0, sp, #12 + 8008552: f7ff ff7f bl 8008454 + 8008556: 6220 str r0, [r4, #32] + AES->IVR1 = 0; + AES->IVR0 = 0; // maybe should be byte-swapped one, but whatever + } + + // Enable the Peripheral + AES->CR |= AES_CR_EN; + 8008558: 4b30 ldr r3, [pc, #192] ; (800861c ) + 800855a: 681a ldr r2, [r3, #0] + + ASSERT((((uint32_t)&ctx->pending) & 3) == 0); // safe because of special attr + 800855c: 07b0 lsls r0, r6, #30 + AES->CR |= AES_CR_EN; + 800855e: f042 0201 orr.w r2, r2, #1 + 8008562: 601a str r2, [r3, #0] + ASSERT((((uint32_t)&ctx->pending) & 3) == 0); // safe because of special attr + 8008564: d1a4 bne.n 80084b0 + + uint32_t *p = (uint32_t *)ctx->pending; + for(int i=0; i < ctx->num_pending; i += 16) { + 8008566: f06f 070f mvn.w r7, #15 + 800856a: f8d6 0200 ldr.w r0, [r6, #512] ; 0x200 + 800856e: f106 0410 add.w r4, r6, #16 + 8008572: 1bbf subs r7, r7, r6 + 8008574: 193a adds r2, r7, r4 + 8008576: 4282 cmp r2, r0 + 8008578: db2b blt.n 80085d2 + *out = AES->DOUTR; out++; + *out = AES->DOUTR; out++; + *out = AES->DOUTR; + } + + memcpy(data_out, ctx->pending, len); + 800857a: 460a mov r2, r1 + 800857c: 4640 mov r0, r8 + 800857e: 4631 mov r1, r6 + 8008580: f005 f850 bl 800d624 + + memset(ctx, 0, sizeof(AES_CTX)); + 8008584: f44f 7201 mov.w r2, #516 ; 0x204 + 8008588: 2100 movs r1, #0 + 800858a: 4630 mov r0, r6 + 800858c: f005 f872 bl 800d674 + + // reset state of chip block, and leave clock off as well + __HAL_RCC_AES_CLK_ENABLE(); + 8008590: 6ceb ldr r3, [r5, #76] ; 0x4c + 8008592: f443 3380 orr.w r3, r3, #65536 ; 0x10000 + 8008596: 64eb str r3, [r5, #76] ; 0x4c + 8008598: 6ceb ldr r3, [r5, #76] ; 0x4c + 800859a: f403 3380 and.w r3, r3, #65536 ; 0x10000 + 800859e: 9303 str r3, [sp, #12] + 80085a0: 9b03 ldr r3, [sp, #12] + __HAL_RCC_AES_FORCE_RESET(); + 80085a2: 6aeb ldr r3, [r5, #44] ; 0x2c + 80085a4: f443 3380 orr.w r3, r3, #65536 ; 0x10000 + 80085a8: 62eb str r3, [r5, #44] ; 0x2c + __HAL_RCC_AES_RELEASE_RESET(); + 80085aa: 6aeb ldr r3, [r5, #44] ; 0x2c + 80085ac: f423 3380 bic.w r3, r3, #65536 ; 0x10000 + 80085b0: 62eb str r3, [r5, #44] ; 0x2c + __HAL_RCC_AES_CLK_DISABLE(); + 80085b2: 6ceb ldr r3, [r5, #76] ; 0x4c + 80085b4: f423 3380 bic.w r3, r3, #65536 ; 0x10000 + 80085b8: 64eb str r3, [r5, #76] ; 0x4c +} + 80085ba: b005 add sp, #20 + 80085bc: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + AES->IVR3 = 0; + 80085c0: f8c4 902c str.w r9, [r4, #44] ; 0x2c + AES->IVR2 = 0; + 80085c4: f8c4 9028 str.w r9, [r4, #40] ; 0x28 + AES->IVR1 = 0; + 80085c8: f8c4 9024 str.w r9, [r4, #36] ; 0x24 + AES->IVR0 = 0; // maybe should be byte-swapped one, but whatever + 80085cc: f8c4 9020 str.w r9, [r4, #32] + 80085d0: e7c2 b.n 8008558 + AES->DINR = *p; p++; + 80085d2: f854 2c10 ldr.w r2, [r4, #-16] + 80085d6: 609a str r2, [r3, #8] + AES->DINR = *p; p++; + 80085d8: f854 2c0c ldr.w r2, [r4, #-12] + 80085dc: 609a str r2, [r3, #8] + AES->DINR = *p; p++; + 80085de: f854 2c08 ldr.w r2, [r4, #-8] + 80085e2: 609a str r2, [r3, #8] + AES->DINR = *p; p++; + 80085e4: f854 2c04 ldr.w r2, [r4, #-4] + 80085e8: 609a str r2, [r3, #8] + while(HAL_IS_BIT_CLR(AES->SR, AES_SR_CCF)) { + 80085ea: 685a ldr r2, [r3, #4] + 80085ec: 07d2 lsls r2, r2, #31 + 80085ee: d5fc bpl.n 80085ea + SET_BIT(AES->CR, CRYP_CCF_CLEAR); + 80085f0: 681a ldr r2, [r3, #0] + 80085f2: f042 0280 orr.w r2, r2, #128 ; 0x80 + 80085f6: 601a str r2, [r3, #0] + *out = AES->DOUTR; out++; + 80085f8: 68da ldr r2, [r3, #12] + 80085fa: f844 2c10 str.w r2, [r4, #-16] + *out = AES->DOUTR; out++; + 80085fe: 68da ldr r2, [r3, #12] + 8008600: f844 2c0c str.w r2, [r4, #-12] + *out = AES->DOUTR; out++; + 8008604: 68da ldr r2, [r3, #12] + 8008606: f844 2c08 str.w r2, [r4, #-8] + *out = AES->DOUTR; + 800860a: 68da ldr r2, [r3, #12] + 800860c: f844 2c04 str.w r2, [r4, #-4] + for(int i=0; i < ctx->num_pending; i += 16) { + 8008610: 3410 adds r4, #16 + 8008612: e7af b.n 8008574 + 8008614: 0800e3e0 .word 0x0800e3e0 + 8008618: 40021000 .word 0x40021000 + 800861c: 50060000 .word 0x50060000 + +08008620 : + voltage range. + * @param msirange MSI range value from RCC_MSIRANGE_0 to RCC_MSIRANGE_11 + * @retval HAL status + */ +static HAL_StatusTypeDef RCC_SetFlashLatencyFromMSIRange(uint32_t msirange) +{ + 8008620: b537 push {r0, r1, r2, r4, r5, lr} + uint32_t vos; + uint32_t latency = FLASH_LATENCY_0; /* default value 0WS */ + + if(__HAL_RCC_PWR_IS_CLK_ENABLED()) + 8008622: 4d1c ldr r5, [pc, #112] ; (8008694 ) + 8008624: 6dab ldr r3, [r5, #88] ; 0x58 + 8008626: 00da lsls r2, r3, #3 +{ + 8008628: 4604 mov r4, r0 + if(__HAL_RCC_PWR_IS_CLK_ENABLED()) + 800862a: d518 bpl.n 800865e + { + vos = HAL_PWREx_GetVoltageRange(); + 800862c: f7fe fd62 bl 80070f4 + __HAL_RCC_PWR_CLK_ENABLE(); + vos = HAL_PWREx_GetVoltageRange(); + __HAL_RCC_PWR_CLK_DISABLE(); + } + + if(vos == PWR_REGULATOR_VOLTAGE_SCALE1) + 8008630: f5b0 7f00 cmp.w r0, #512 ; 0x200 + 8008634: d123 bne.n 800867e + { + if(msirange > RCC_MSIRANGE_8) + 8008636: 2c80 cmp r4, #128 ; 0x80 + 8008638: d928 bls.n 800868c + latency = FLASH_LATENCY_2; /* 2WS */ + } + else + { + /* MSI 24Mhz or 32Mhz */ + latency = FLASH_LATENCY_1; /* 1WS */ + 800863a: 2ca0 cmp r4, #160 ; 0xa0 + 800863c: bf8c ite hi + 800863e: 2002 movhi r0, #2 + 8008640: 2001 movls r0, #1 + /* else MSI < 8Mhz default FLASH_LATENCY_0 0WS */ + } +#endif + } + + __HAL_FLASH_SET_LATENCY(latency); + 8008642: 4a15 ldr r2, [pc, #84] ; (8008698 ) + 8008644: 6813 ldr r3, [r2, #0] + 8008646: f023 030f bic.w r3, r3, #15 + 800864a: 4303 orrs r3, r0 + 800864c: 6013 str r3, [r2, #0] + + /* Check that the new number of wait states is taken into account to access the Flash + memory by reading the FLASH_ACR register */ + if(__HAL_FLASH_GET_LATENCY() != latency) + 800864e: 6813 ldr r3, [r2, #0] + 8008650: f003 030f and.w r3, r3, #15 + { + return HAL_ERROR; + } + + return HAL_OK; +} + 8008654: 1a18 subs r0, r3, r0 + 8008656: bf18 it ne + 8008658: 2001 movne r0, #1 + 800865a: b003 add sp, #12 + 800865c: bd30 pop {r4, r5, pc} + __HAL_RCC_PWR_CLK_ENABLE(); + 800865e: 6dab ldr r3, [r5, #88] ; 0x58 + 8008660: f043 5380 orr.w r3, r3, #268435456 ; 0x10000000 + 8008664: 65ab str r3, [r5, #88] ; 0x58 + 8008666: 6dab ldr r3, [r5, #88] ; 0x58 + 8008668: f003 5380 and.w r3, r3, #268435456 ; 0x10000000 + 800866c: 9301 str r3, [sp, #4] + 800866e: 9b01 ldr r3, [sp, #4] + vos = HAL_PWREx_GetVoltageRange(); + 8008670: f7fe fd40 bl 80070f4 + __HAL_RCC_PWR_CLK_DISABLE(); + 8008674: 6dab ldr r3, [r5, #88] ; 0x58 + 8008676: f023 5380 bic.w r3, r3, #268435456 ; 0x10000000 + 800867a: 65ab str r3, [r5, #88] ; 0x58 + 800867c: e7d8 b.n 8008630 + if(msirange >= RCC_MSIRANGE_8) + 800867e: 2c7f cmp r4, #127 ; 0x7f + 8008680: d806 bhi.n 8008690 + if(msirange == RCC_MSIRANGE_7) + 8008682: f1a4 0370 sub.w r3, r4, #112 ; 0x70 + 8008686: 4258 negs r0, r3 + 8008688: 4158 adcs r0, r3 + 800868a: e7da b.n 8008642 + uint32_t latency = FLASH_LATENCY_0; /* default value 0WS */ + 800868c: 2000 movs r0, #0 + 800868e: e7d8 b.n 8008642 + latency = FLASH_LATENCY_2; /* 2WS */ + 8008690: 2002 movs r0, #2 + 8008692: e7d6 b.n 8008642 + 8008694: 40021000 .word 0x40021000 + 8008698: 40022000 .word 0x40022000 + +0800869c : +{ + 800869c: b5f8 push {r3, r4, r5, r6, r7, lr} + SET_BIT(RCC->CR, RCC_CR_MSION); + 800869e: 4c32 ldr r4, [pc, #200] ; (8008768 ) + 80086a0: 6823 ldr r3, [r4, #0] + 80086a2: f043 0301 orr.w r3, r3, #1 + 80086a6: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 80086a8: f7fe fd20 bl 80070ec + 80086ac: 4605 mov r5, r0 + while(READ_BIT(RCC->CR, RCC_CR_MSIRDY) == 0U) + 80086ae: 6823 ldr r3, [r4, #0] + 80086b0: 079b lsls r3, r3, #30 + 80086b2: d543 bpl.n 800873c + MODIFY_REG(RCC->CR, RCC_CR_MSIRANGE, RCC_MSIRANGE_6); + 80086b4: 6823 ldr r3, [r4, #0] + SystemCoreClock = MSI_VALUE; + 80086b6: 4a2d ldr r2, [pc, #180] ; (800876c ) + MODIFY_REG(RCC->CR, RCC_CR_MSIRANGE, RCC_MSIRANGE_6); + 80086b8: f023 03f0 bic.w r3, r3, #240 ; 0xf0 + 80086bc: f043 0360 orr.w r3, r3, #96 ; 0x60 + 80086c0: 6023 str r3, [r4, #0] + CLEAR_REG(RCC->CFGR); + 80086c2: 2300 movs r3, #0 + 80086c4: 60a3 str r3, [r4, #8] + SystemCoreClock = MSI_VALUE; + 80086c6: 4b2a ldr r3, [pc, #168] ; (8008770 ) + 80086c8: 601a str r2, [r3, #0] + if(HAL_InitTick(uwTickPrio) != HAL_OK) + 80086ca: 4b2a ldr r3, [pc, #168] ; (8008774 ) + 80086cc: 6818 ldr r0, [r3, #0] + 80086ce: f7fe fd0f bl 80070f0 + 80086d2: 4605 mov r5, r0 + 80086d4: 2800 cmp r0, #0 + 80086d6: d145 bne.n 8008764 + tickstart = HAL_GetTick(); + 80086d8: f7fe fd08 bl 80070ec + if((HAL_GetTick() - tickstart) > CLOCKSWITCH_TIMEOUT_VALUE) + 80086dc: f241 3788 movw r7, #5000 ; 0x1388 + tickstart = HAL_GetTick(); + 80086e0: 4606 mov r6, r0 + while(READ_BIT(RCC->CFGR, RCC_CFGR_SWS) != RCC_CFGR_SWS_MSI) + 80086e2: 68a3 ldr r3, [r4, #8] + 80086e4: f013 0f0c tst.w r3, #12 + 80086e8: d130 bne.n 800874c + CLEAR_BIT(RCC->CR, RCC_CR_HSEON | RCC_CR_HSION | RCC_CR_HSIKERON| RCC_CR_HSIASFS | RCC_CR_PLLON | RCC_CR_PLLSAI1ON | RCC_CR_PLLSAI2ON); + 80086ea: 6822 ldr r2, [r4, #0] + 80086ec: 4b22 ldr r3, [pc, #136] ; (8008778 ) + 80086ee: 4013 ands r3, r2 + 80086f0: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 80086f2: f7fe fcfb bl 80070ec + 80086f6: 4606 mov r6, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLRDY | RCC_CR_PLLSAI1RDY | RCC_CR_PLLSAI2RDY) != 0U) + 80086f8: 6823 ldr r3, [r4, #0] + 80086fa: f013 5328 ands.w r3, r3, #704643072 ; 0x2a000000 + 80086fe: d12b bne.n 8008758 + CLEAR_REG(RCC->PLLCFGR); + 8008700: 60e3 str r3, [r4, #12] + SET_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN_4 ); + 8008702: 68e2 ldr r2, [r4, #12] + 8008704: f442 5280 orr.w r2, r2, #4096 ; 0x1000 + 8008708: 60e2 str r2, [r4, #12] + CLEAR_REG(RCC->PLLSAI1CFGR); + 800870a: 6123 str r3, [r4, #16] + SET_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1N_4 ); + 800870c: 6922 ldr r2, [r4, #16] + 800870e: f442 5280 orr.w r2, r2, #4096 ; 0x1000 + 8008712: 6122 str r2, [r4, #16] + CLEAR_REG(RCC->PLLSAI2CFGR); + 8008714: 6163 str r3, [r4, #20] + SET_BIT(RCC->PLLSAI2CFGR, RCC_PLLSAI2CFGR_PLLSAI2N_4 ); + 8008716: 6962 ldr r2, [r4, #20] + 8008718: f442 5280 orr.w r2, r2, #4096 ; 0x1000 + 800871c: 6162 str r2, [r4, #20] + CLEAR_BIT(RCC->CR, RCC_CR_HSEBYP); + 800871e: 6822 ldr r2, [r4, #0] + 8008720: f422 2280 bic.w r2, r2, #262144 ; 0x40000 + 8008724: 6022 str r2, [r4, #0] + CLEAR_REG(RCC->CIER); + 8008726: 61a3 str r3, [r4, #24] + WRITE_REG(RCC->CICR, 0xFFFFFFFFU); + 8008728: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 800872c: 6223 str r3, [r4, #32] + SET_BIT(RCC->CSR, RCC_CSR_RMVF); + 800872e: f8d4 3094 ldr.w r3, [r4, #148] ; 0x94 + 8008732: f443 0300 orr.w r3, r3, #8388608 ; 0x800000 + 8008736: f8c4 3094 str.w r3, [r4, #148] ; 0x94 + return HAL_OK; + 800873a: e005 b.n 8008748 + if((HAL_GetTick() - tickstart) > MSI_TIMEOUT_VALUE) + 800873c: f7fe fcd6 bl 80070ec + 8008740: 1b40 subs r0, r0, r5 + 8008742: 2802 cmp r0, #2 + 8008744: d9b3 bls.n 80086ae + return HAL_TIMEOUT; + 8008746: 2503 movs r5, #3 +} + 8008748: 4628 mov r0, r5 + 800874a: bdf8 pop {r3, r4, r5, r6, r7, pc} + if((HAL_GetTick() - tickstart) > CLOCKSWITCH_TIMEOUT_VALUE) + 800874c: f7fe fcce bl 80070ec + 8008750: 1b80 subs r0, r0, r6 + 8008752: 42b8 cmp r0, r7 + 8008754: d9c5 bls.n 80086e2 + 8008756: e7f6 b.n 8008746 + if((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE) + 8008758: f7fe fcc8 bl 80070ec + 800875c: 1b80 subs r0, r0, r6 + 800875e: 2802 cmp r0, #2 + 8008760: d9ca bls.n 80086f8 + 8008762: e7f0 b.n 8008746 + return HAL_ERROR; + 8008764: 2501 movs r5, #1 + 8008766: e7ef b.n 8008748 + 8008768: 40021000 .word 0x40021000 + 800876c: 003d0900 .word 0x003d0900 + 8008770: 2009e2a8 .word 0x2009e2a8 + 8008774: 2009e2ac .word 0x2009e2ac + 8008778: eafef4ff .word 0xeafef4ff + +0800877c : +{ + 800877c: b570 push {r4, r5, r6, lr} + __MCO1_CLK_ENABLE(); + 800877e: 4c12 ldr r4, [pc, #72] ; (80087c8 ) + 8008780: 6ce3 ldr r3, [r4, #76] ; 0x4c + 8008782: f043 0301 orr.w r3, r3, #1 + 8008786: 64e3 str r3, [r4, #76] ; 0x4c + 8008788: 6ce3 ldr r3, [r4, #76] ; 0x4c +{ + 800878a: b086 sub sp, #24 + __MCO1_CLK_ENABLE(); + 800878c: f003 0301 and.w r3, r3, #1 + 8008790: 9300 str r3, [sp, #0] + 8008792: 9b00 ldr r3, [sp, #0] +{ + 8008794: 4616 mov r6, r2 + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + 8008796: 2302 movs r3, #2 + 8008798: f44f 7280 mov.w r2, #256 ; 0x100 + 800879c: e9cd 2301 strd r2, r3, [sp, #4] +{ + 80087a0: 460d mov r5, r1 + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + 80087a2: 9304 str r3, [sp, #16] + HAL_GPIO_Init(MCO1_GPIO_PORT, &GPIO_InitStruct); + 80087a4: a901 add r1, sp, #4 + GPIO_InitStruct.Pull = GPIO_NOPULL; + 80087a6: 2300 movs r3, #0 + HAL_GPIO_Init(MCO1_GPIO_PORT, &GPIO_InitStruct); + 80087a8: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + GPIO_InitStruct.Pull = GPIO_NOPULL; + 80087ac: 9303 str r3, [sp, #12] + GPIO_InitStruct.Alternate = GPIO_AF0_MCO; + 80087ae: 9305 str r3, [sp, #20] + HAL_GPIO_Init(MCO1_GPIO_PORT, &GPIO_InitStruct); + 80087b0: f7f8 fc2e bl 8001010 + MODIFY_REG(RCC->CFGR, (RCC_CFGR_MCOSEL | RCC_CFGR_MCOPRE), (RCC_MCOSource | RCC_MCODiv )); + 80087b4: 68a3 ldr r3, [r4, #8] + 80087b6: f023 43fe bic.w r3, r3, #2130706432 ; 0x7f000000 + 80087ba: ea43 0206 orr.w r2, r3, r6 + 80087be: 432a orrs r2, r5 + 80087c0: 60a2 str r2, [r4, #8] +} + 80087c2: b006 add sp, #24 + 80087c4: bd70 pop {r4, r5, r6, pc} + 80087c6: bf00 nop + 80087c8: 40021000 .word 0x40021000 + +080087cc : + sysclk_source = __HAL_RCC_GET_SYSCLK_SOURCE(); + 80087cc: 4b22 ldr r3, [pc, #136] ; (8008858 ) + 80087ce: 689a ldr r2, [r3, #8] + pll_oscsource = __HAL_RCC_GET_PLL_OSCSOURCE(); + 80087d0: 68d9 ldr r1, [r3, #12] + if((sysclk_source == RCC_CFGR_SWS_MSI) || + 80087d2: f012 020c ands.w r2, r2, #12 + 80087d6: d005 beq.n 80087e4 + 80087d8: 2a0c cmp r2, #12 + 80087da: d115 bne.n 8008808 + pll_oscsource = __HAL_RCC_GET_PLL_OSCSOURCE(); + 80087dc: f001 0103 and.w r1, r1, #3 + ((sysclk_source == RCC_CFGR_SWS_PLL) && (pll_oscsource == RCC_PLLSOURCE_MSI))) + 80087e0: 2901 cmp r1, #1 + 80087e2: d118 bne.n 8008816 + if(READ_BIT(RCC->CR, RCC_CR_MSIRGSEL) == 0U) + 80087e4: 6819 ldr r1, [r3, #0] + msirange = MSIRangeTable[msirange]; + 80087e6: 481d ldr r0, [pc, #116] ; (800885c ) + if(READ_BIT(RCC->CR, RCC_CR_MSIRGSEL) == 0U) + 80087e8: 0709 lsls r1, r1, #28 + msirange = READ_BIT(RCC->CSR, RCC_CSR_MSISRANGE) >> RCC_CSR_MSISRANGE_Pos; + 80087ea: bf55 itete pl + 80087ec: f8d3 1094 ldrpl.w r1, [r3, #148] ; 0x94 + msirange = READ_BIT(RCC->CR, RCC_CR_MSIRANGE) >> RCC_CR_MSIRANGE_Pos; + 80087f0: 6819 ldrmi r1, [r3, #0] + msirange = READ_BIT(RCC->CSR, RCC_CSR_MSISRANGE) >> RCC_CSR_MSISRANGE_Pos; + 80087f2: f3c1 2103 ubfxpl r1, r1, #8, #4 + msirange = READ_BIT(RCC->CR, RCC_CR_MSIRANGE) >> RCC_CR_MSIRANGE_Pos; + 80087f6: f3c1 1103 ubfxmi r1, r1, #4, #4 + msirange = MSIRangeTable[msirange]; + 80087fa: f850 0021 ldr.w r0, [r0, r1, lsl #2] + if(sysclk_source == RCC_CFGR_SWS_MSI) + 80087fe: b34a cbz r2, 8008854 + if(sysclk_source == RCC_CFGR_SWS_PLL) + 8008800: 2a0c cmp r2, #12 + 8008802: d009 beq.n 8008818 + 8008804: 2000 movs r0, #0 + return sysclockfreq; + 8008806: 4770 bx lr + else if(sysclk_source == RCC_CFGR_SWS_HSI) + 8008808: 2a04 cmp r2, #4 + 800880a: d022 beq.n 8008852 + else if(sysclk_source == RCC_CFGR_SWS_HSE) + 800880c: 2a08 cmp r2, #8 + 800880e: 4814 ldr r0, [pc, #80] ; (8008860 ) + 8008810: bf18 it ne + 8008812: 2000 movne r0, #0 + 8008814: 4770 bx lr + uint32_t msirange = 0U, sysclockfreq = 0U; + 8008816: 2000 movs r0, #0 + pllsource = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLSRC); + 8008818: 68da ldr r2, [r3, #12] + 800881a: f002 0203 and.w r2, r2, #3 + switch (pllsource) + 800881e: 2a02 cmp r2, #2 + 8008820: d015 beq.n 800884e + 8008822: 490f ldr r1, [pc, #60] ; (8008860 ) + 8008824: 2a03 cmp r2, #3 + 8008826: bf08 it eq + 8008828: 4608 moveq r0, r1 + pllm = (READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U ; + 800882a: 68d9 ldr r1, [r3, #12] + pllvco = (pllvco * (READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos)) / pllm; + 800882c: 68da ldr r2, [r3, #12] + 800882e: f3c2 2206 ubfx r2, r2, #8, #7 + 8008832: 4342 muls r2, r0 + pllr = ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos) + 1U ) * 2U; + 8008834: 68d8 ldr r0, [r3, #12] + 8008836: f3c0 6041 ubfx r0, r0, #25, #2 + pllm = (READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U ; + 800883a: f3c1 1103 ubfx r1, r1, #4, #4 + pllr = ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos) + 1U ) * 2U; + 800883e: 3001 adds r0, #1 + pllm = (READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U ; + 8008840: 3101 adds r1, #1 + pllr = ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos) + 1U ) * 2U; + 8008842: 0040 lsls r0, r0, #1 + pllvco = (pllvco * (READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos)) / pllm; + 8008844: fbb2 f2f1 udiv r2, r2, r1 + sysclockfreq = pllvco / pllr; + 8008848: fbb2 f0f0 udiv r0, r2, r0 + 800884c: 4770 bx lr + pllvco = HSI_VALUE; + 800884e: 4805 ldr r0, [pc, #20] ; (8008864 ) + 8008850: e7eb b.n 800882a + sysclockfreq = HSI_VALUE; + 8008852: 4804 ldr r0, [pc, #16] ; (8008864 ) +} + 8008854: 4770 bx lr + 8008856: bf00 nop + 8008858: 40021000 .word 0x40021000 + 800885c: 0800e9f4 .word 0x0800e9f4 + 8008860: 007a1200 .word 0x007a1200 + 8008864: 00f42400 .word 0x00f42400 + +08008868 : +{ + 8008868: e92d 43f7 stmdb sp!, {r0, r1, r2, r4, r5, r6, r7, r8, r9, lr} + if(RCC_OscInitStruct == NULL) + 800886c: 4605 mov r5, r0 + 800886e: b908 cbnz r0, 8008874 + return HAL_ERROR; + 8008870: 2001 movs r0, #1 + 8008872: e047 b.n 8008904 + sysclk_source = __HAL_RCC_GET_SYSCLK_SOURCE(); + 8008874: 4c94 ldr r4, [pc, #592] ; (8008ac8 ) + if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_MSI) == RCC_OSCILLATORTYPE_MSI) + 8008876: 6803 ldr r3, [r0, #0] + sysclk_source = __HAL_RCC_GET_SYSCLK_SOURCE(); + 8008878: 68a6 ldr r6, [r4, #8] + pll_config = __HAL_RCC_GET_PLL_OSCSOURCE(); + 800887a: 68e7 ldr r7, [r4, #12] + if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_MSI) == RCC_OSCILLATORTYPE_MSI) + 800887c: 06db lsls r3, r3, #27 + sysclk_source = __HAL_RCC_GET_SYSCLK_SOURCE(); + 800887e: f006 060c and.w r6, r6, #12 + pll_config = __HAL_RCC_GET_PLL_OSCSOURCE(); + 8008882: f007 0703 and.w r7, r7, #3 + if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_MSI) == RCC_OSCILLATORTYPE_MSI) + 8008886: d575 bpl.n 8008974 + if((sysclk_source == RCC_CFGR_SWS_MSI) || + 8008888: b11e cbz r6, 8008892 + 800888a: 2e0c cmp r6, #12 + 800888c: d154 bne.n 8008938 + ((sysclk_source == RCC_CFGR_SWS_PLL) && (pll_config == RCC_PLLSOURCE_MSI))) + 800888e: 2f01 cmp r7, #1 + 8008890: d152 bne.n 8008938 + if((READ_BIT(RCC->CR, RCC_CR_MSIRDY) != 0U) && (RCC_OscInitStruct->MSIState == RCC_MSI_OFF)) + 8008892: 6823 ldr r3, [r4, #0] + 8008894: 0798 lsls r0, r3, #30 + 8008896: d502 bpl.n 800889e + 8008898: 69ab ldr r3, [r5, #24] + 800889a: 2b00 cmp r3, #0 + 800889c: d0e8 beq.n 8008870 + if(RCC_OscInitStruct->MSIClockRange > __HAL_RCC_GET_MSI_RANGE()) + 800889e: 6823 ldr r3, [r4, #0] + 80088a0: 6a28 ldr r0, [r5, #32] + 80088a2: 0719 lsls r1, r3, #28 + 80088a4: bf56 itet pl + 80088a6: f8d4 3094 ldrpl.w r3, [r4, #148] ; 0x94 + 80088aa: 6823 ldrmi r3, [r4, #0] + 80088ac: 091b lsrpl r3, r3, #4 + 80088ae: f003 03f0 and.w r3, r3, #240 ; 0xf0 + 80088b2: 4298 cmp r0, r3 + 80088b4: d929 bls.n 800890a + if(RCC_SetFlashLatencyFromMSIRange(RCC_OscInitStruct->MSIClockRange) != HAL_OK) + 80088b6: f7ff feb3 bl 8008620 + 80088ba: 2800 cmp r0, #0 + 80088bc: d1d8 bne.n 8008870 + __HAL_RCC_MSI_RANGE_CONFIG(RCC_OscInitStruct->MSIClockRange); + 80088be: 6823 ldr r3, [r4, #0] + 80088c0: f043 0308 orr.w r3, r3, #8 + 80088c4: 6023 str r3, [r4, #0] + 80088c6: 6823 ldr r3, [r4, #0] + 80088c8: 6a2a ldr r2, [r5, #32] + 80088ca: f023 03f0 bic.w r3, r3, #240 ; 0xf0 + 80088ce: 4313 orrs r3, r2 + 80088d0: 6023 str r3, [r4, #0] + __HAL_RCC_MSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->MSICalibrationValue); + 80088d2: 6863 ldr r3, [r4, #4] + 80088d4: 69ea ldr r2, [r5, #28] + 80088d6: f423 437f bic.w r3, r3, #65280 ; 0xff00 + 80088da: ea43 2302 orr.w r3, r3, r2, lsl #8 + 80088de: 6063 str r3, [r4, #4] + SystemCoreClock = HAL_RCC_GetSysClockFreq() >> (AHBPrescTable[READ_BIT(RCC->CFGR, RCC_CFGR_HPRE) >> RCC_CFGR_HPRE_Pos] & 0x1FU); + 80088e0: f7ff ff74 bl 80087cc + 80088e4: 68a3 ldr r3, [r4, #8] + 80088e6: 4a79 ldr r2, [pc, #484] ; (8008acc ) + 80088e8: f3c3 1303 ubfx r3, r3, #4, #4 + 80088ec: 5cd3 ldrb r3, [r2, r3] + 80088ee: f003 031f and.w r3, r3, #31 + 80088f2: 40d8 lsrs r0, r3 + 80088f4: 4b76 ldr r3, [pc, #472] ; (8008ad0 ) + 80088f6: 6018 str r0, [r3, #0] + status = HAL_InitTick(uwTickPrio); + 80088f8: 4b76 ldr r3, [pc, #472] ; (8008ad4 ) + 80088fa: 6818 ldr r0, [r3, #0] + 80088fc: f7fe fbf8 bl 80070f0 + if(status != HAL_OK) + 8008900: 2800 cmp r0, #0 + 8008902: d037 beq.n 8008974 +} + 8008904: b003 add sp, #12 + 8008906: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + __HAL_RCC_MSI_RANGE_CONFIG(RCC_OscInitStruct->MSIClockRange); + 800890a: 6823 ldr r3, [r4, #0] + 800890c: f043 0308 orr.w r3, r3, #8 + 8008910: 6023 str r3, [r4, #0] + 8008912: 6823 ldr r3, [r4, #0] + 8008914: f023 03f0 bic.w r3, r3, #240 ; 0xf0 + 8008918: 4303 orrs r3, r0 + 800891a: 6023 str r3, [r4, #0] + __HAL_RCC_MSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->MSICalibrationValue); + 800891c: 6863 ldr r3, [r4, #4] + 800891e: 69ea ldr r2, [r5, #28] + 8008920: f423 437f bic.w r3, r3, #65280 ; 0xff00 + 8008924: ea43 2302 orr.w r3, r3, r2, lsl #8 + 8008928: 6063 str r3, [r4, #4] + if(sysclk_source == RCC_CFGR_SWS_MSI) + 800892a: 2e00 cmp r6, #0 + 800892c: d1d8 bne.n 80088e0 + if(RCC_SetFlashLatencyFromMSIRange(RCC_OscInitStruct->MSIClockRange) != HAL_OK) + 800892e: f7ff fe77 bl 8008620 + 8008932: 2800 cmp r0, #0 + 8008934: d0d4 beq.n 80088e0 + 8008936: e79b b.n 8008870 + if(RCC_OscInitStruct->MSIState != RCC_MSI_OFF) + 8008938: 69ab ldr r3, [r5, #24] + 800893a: 2b00 cmp r3, #0 + 800893c: d03a beq.n 80089b4 + __HAL_RCC_MSI_ENABLE(); + 800893e: 6823 ldr r3, [r4, #0] + 8008940: f043 0301 orr.w r3, r3, #1 + 8008944: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 8008946: f7fe fbd1 bl 80070ec + 800894a: 4680 mov r8, r0 + while(READ_BIT(RCC->CR, RCC_CR_MSIRDY) == 0U) + 800894c: 6823 ldr r3, [r4, #0] + 800894e: 079a lsls r2, r3, #30 + 8008950: d528 bpl.n 80089a4 + __HAL_RCC_MSI_RANGE_CONFIG(RCC_OscInitStruct->MSIClockRange); + 8008952: 6823 ldr r3, [r4, #0] + 8008954: f043 0308 orr.w r3, r3, #8 + 8008958: 6023 str r3, [r4, #0] + 800895a: 6823 ldr r3, [r4, #0] + 800895c: 6a2a ldr r2, [r5, #32] + 800895e: f023 03f0 bic.w r3, r3, #240 ; 0xf0 + 8008962: 4313 orrs r3, r2 + 8008964: 6023 str r3, [r4, #0] + __HAL_RCC_MSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->MSICalibrationValue); + 8008966: 6863 ldr r3, [r4, #4] + 8008968: 69ea ldr r2, [r5, #28] + 800896a: f423 437f bic.w r3, r3, #65280 ; 0xff00 + 800896e: ea43 2302 orr.w r3, r3, r2, lsl #8 + 8008972: 6063 str r3, [r4, #4] + if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_HSE) == RCC_OSCILLATORTYPE_HSE) + 8008974: 682b ldr r3, [r5, #0] + 8008976: 07d8 lsls r0, r3, #31 + 8008978: d42d bmi.n 80089d6 + if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_HSI) == RCC_OSCILLATORTYPE_HSI) + 800897a: 682b ldr r3, [r5, #0] + 800897c: 0799 lsls r1, r3, #30 + 800897e: d46b bmi.n 8008a58 + if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_LSI) == RCC_OSCILLATORTYPE_LSI) + 8008980: 682b ldr r3, [r5, #0] + 8008982: 0718 lsls r0, r3, #28 + 8008984: f100 80a8 bmi.w 8008ad8 + if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_LSE) == RCC_OSCILLATORTYPE_LSE) + 8008988: 682b ldr r3, [r5, #0] + 800898a: 0759 lsls r1, r3, #29 + 800898c: f100 80ce bmi.w 8008b2c + if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_HSI48) == RCC_OSCILLATORTYPE_HSI48) + 8008990: 682b ldr r3, [r5, #0] + 8008992: 069f lsls r7, r3, #26 + 8008994: f100 8137 bmi.w 8008c06 + if(RCC_OscInitStruct->PLL.PLLState != RCC_PLL_NONE) + 8008998: 6aab ldr r3, [r5, #40] ; 0x28 + 800899a: 2b00 cmp r3, #0 + 800899c: f040 815d bne.w 8008c5a + return HAL_OK; + 80089a0: 2000 movs r0, #0 + 80089a2: e7af b.n 8008904 + if((HAL_GetTick() - tickstart) > MSI_TIMEOUT_VALUE) + 80089a4: f7fe fba2 bl 80070ec + 80089a8: eba0 0008 sub.w r0, r0, r8 + 80089ac: 2802 cmp r0, #2 + 80089ae: d9cd bls.n 800894c + return HAL_TIMEOUT; + 80089b0: 2003 movs r0, #3 + 80089b2: e7a7 b.n 8008904 + __HAL_RCC_MSI_DISABLE(); + 80089b4: 6823 ldr r3, [r4, #0] + 80089b6: f023 0301 bic.w r3, r3, #1 + 80089ba: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 80089bc: f7fe fb96 bl 80070ec + 80089c0: 4680 mov r8, r0 + while(READ_BIT(RCC->CR, RCC_CR_MSIRDY) != 0U) + 80089c2: 6823 ldr r3, [r4, #0] + 80089c4: 079b lsls r3, r3, #30 + 80089c6: d5d5 bpl.n 8008974 + if((HAL_GetTick() - tickstart) > MSI_TIMEOUT_VALUE) + 80089c8: f7fe fb90 bl 80070ec + 80089cc: eba0 0008 sub.w r0, r0, r8 + 80089d0: 2802 cmp r0, #2 + 80089d2: d9f6 bls.n 80089c2 + 80089d4: e7ec b.n 80089b0 + if((sysclk_source == RCC_CFGR_SWS_HSE) || + 80089d6: 2e08 cmp r6, #8 + 80089d8: d003 beq.n 80089e2 + 80089da: 2e0c cmp r6, #12 + 80089dc: d108 bne.n 80089f0 + ((sysclk_source == RCC_CFGR_SWS_PLL) && (pll_config == RCC_PLLSOURCE_HSE))) + 80089de: 2f03 cmp r7, #3 + 80089e0: d106 bne.n 80089f0 + if((READ_BIT(RCC->CR, RCC_CR_HSERDY) != 0U) && (RCC_OscInitStruct->HSEState == RCC_HSE_OFF)) + 80089e2: 6823 ldr r3, [r4, #0] + 80089e4: 039a lsls r2, r3, #14 + 80089e6: d5c8 bpl.n 800897a + 80089e8: 686b ldr r3, [r5, #4] + 80089ea: 2b00 cmp r3, #0 + 80089ec: d1c5 bne.n 800897a + 80089ee: e73f b.n 8008870 + __HAL_RCC_HSE_CONFIG(RCC_OscInitStruct->HSEState); + 80089f0: 686b ldr r3, [r5, #4] + 80089f2: f5b3 3f80 cmp.w r3, #65536 ; 0x10000 + 80089f6: d110 bne.n 8008a1a + 80089f8: 6823 ldr r3, [r4, #0] + 80089fa: f443 3380 orr.w r3, r3, #65536 ; 0x10000 + 80089fe: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 8008a00: f7fe fb74 bl 80070ec + 8008a04: 4680 mov r8, r0 + while(READ_BIT(RCC->CR, RCC_CR_HSERDY) == 0U) + 8008a06: 6823 ldr r3, [r4, #0] + 8008a08: 039b lsls r3, r3, #14 + 8008a0a: d4b6 bmi.n 800897a + if((HAL_GetTick() - tickstart) > HSE_TIMEOUT_VALUE) + 8008a0c: f7fe fb6e bl 80070ec + 8008a10: eba0 0008 sub.w r0, r0, r8 + 8008a14: 2864 cmp r0, #100 ; 0x64 + 8008a16: d9f6 bls.n 8008a06 + 8008a18: e7ca b.n 80089b0 + __HAL_RCC_HSE_CONFIG(RCC_OscInitStruct->HSEState); + 8008a1a: f5b3 2fa0 cmp.w r3, #327680 ; 0x50000 + 8008a1e: d104 bne.n 8008a2a + 8008a20: 6823 ldr r3, [r4, #0] + 8008a22: f443 2380 orr.w r3, r3, #262144 ; 0x40000 + 8008a26: 6023 str r3, [r4, #0] + 8008a28: e7e6 b.n 80089f8 + 8008a2a: 6822 ldr r2, [r4, #0] + 8008a2c: f422 3280 bic.w r2, r2, #65536 ; 0x10000 + 8008a30: 6022 str r2, [r4, #0] + 8008a32: 6822 ldr r2, [r4, #0] + 8008a34: f422 2280 bic.w r2, r2, #262144 ; 0x40000 + 8008a38: 6022 str r2, [r4, #0] + if(RCC_OscInitStruct->HSEState != RCC_HSE_OFF) + 8008a3a: 2b00 cmp r3, #0 + 8008a3c: d1e0 bne.n 8008a00 + tickstart = HAL_GetTick(); + 8008a3e: f7fe fb55 bl 80070ec + 8008a42: 4680 mov r8, r0 + while(READ_BIT(RCC->CR, RCC_CR_HSERDY) != 0U) + 8008a44: 6823 ldr r3, [r4, #0] + 8008a46: 0398 lsls r0, r3, #14 + 8008a48: d597 bpl.n 800897a + if((HAL_GetTick() - tickstart) > HSE_TIMEOUT_VALUE) + 8008a4a: f7fe fb4f bl 80070ec + 8008a4e: eba0 0008 sub.w r0, r0, r8 + 8008a52: 2864 cmp r0, #100 ; 0x64 + 8008a54: d9f6 bls.n 8008a44 + 8008a56: e7ab b.n 80089b0 + if((sysclk_source == RCC_CFGR_SWS_HSI) || + 8008a58: 2e04 cmp r6, #4 + 8008a5a: d003 beq.n 8008a64 + 8008a5c: 2e0c cmp r6, #12 + 8008a5e: d110 bne.n 8008a82 + ((sysclk_source == RCC_CFGR_SWS_PLL) && (pll_config == RCC_PLLSOURCE_HSI))) + 8008a60: 2f02 cmp r7, #2 + 8008a62: d10e bne.n 8008a82 + if((READ_BIT(RCC->CR, RCC_CR_HSIRDY) != 0U) && (RCC_OscInitStruct->HSIState == RCC_HSI_OFF)) + 8008a64: 6823 ldr r3, [r4, #0] + 8008a66: 0559 lsls r1, r3, #21 + 8008a68: d503 bpl.n 8008a72 + 8008a6a: 68eb ldr r3, [r5, #12] + 8008a6c: 2b00 cmp r3, #0 + 8008a6e: f43f aeff beq.w 8008870 + __HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->HSICalibrationValue); + 8008a72: 6863 ldr r3, [r4, #4] + 8008a74: 692a ldr r2, [r5, #16] + 8008a76: f023 43fe bic.w r3, r3, #2130706432 ; 0x7f000000 + 8008a7a: ea43 6302 orr.w r3, r3, r2, lsl #24 + 8008a7e: 6063 str r3, [r4, #4] + 8008a80: e77e b.n 8008980 + if(RCC_OscInitStruct->HSIState != RCC_HSI_OFF) + 8008a82: 68eb ldr r3, [r5, #12] + 8008a84: b17b cbz r3, 8008aa6 + __HAL_RCC_HSI_ENABLE(); + 8008a86: 6823 ldr r3, [r4, #0] + 8008a88: f443 7380 orr.w r3, r3, #256 ; 0x100 + 8008a8c: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 8008a8e: f7fe fb2d bl 80070ec + 8008a92: 4607 mov r7, r0 + while(READ_BIT(RCC->CR, RCC_CR_HSIRDY) == 0U) + 8008a94: 6823 ldr r3, [r4, #0] + 8008a96: 055a lsls r2, r3, #21 + 8008a98: d4eb bmi.n 8008a72 + if((HAL_GetTick() - tickstart) > HSI_TIMEOUT_VALUE) + 8008a9a: f7fe fb27 bl 80070ec + 8008a9e: 1bc0 subs r0, r0, r7 + 8008aa0: 2802 cmp r0, #2 + 8008aa2: d9f7 bls.n 8008a94 + 8008aa4: e784 b.n 80089b0 + __HAL_RCC_HSI_DISABLE(); + 8008aa6: 6823 ldr r3, [r4, #0] + 8008aa8: f423 7380 bic.w r3, r3, #256 ; 0x100 + 8008aac: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 8008aae: f7fe fb1d bl 80070ec + 8008ab2: 4607 mov r7, r0 + while(READ_BIT(RCC->CR, RCC_CR_HSIRDY) != 0U) + 8008ab4: 6823 ldr r3, [r4, #0] + 8008ab6: 055b lsls r3, r3, #21 + 8008ab8: f57f af62 bpl.w 8008980 + if((HAL_GetTick() - tickstart) > HSI_TIMEOUT_VALUE) + 8008abc: f7fe fb16 bl 80070ec + 8008ac0: 1bc0 subs r0, r0, r7 + 8008ac2: 2802 cmp r0, #2 + 8008ac4: d9f6 bls.n 8008ab4 + 8008ac6: e773 b.n 80089b0 + 8008ac8: 40021000 .word 0x40021000 + 8008acc: 0800e9dc .word 0x0800e9dc + 8008ad0: 2009e2a8 .word 0x2009e2a8 + 8008ad4: 2009e2ac .word 0x2009e2ac + if(RCC_OscInitStruct->LSIState != RCC_LSI_OFF) + 8008ad8: 696b ldr r3, [r5, #20] + 8008ada: b19b cbz r3, 8008b04 + __HAL_RCC_LSI_ENABLE(); + 8008adc: f8d4 3094 ldr.w r3, [r4, #148] ; 0x94 + 8008ae0: f043 0301 orr.w r3, r3, #1 + 8008ae4: f8c4 3094 str.w r3, [r4, #148] ; 0x94 + tickstart = HAL_GetTick(); + 8008ae8: f7fe fb00 bl 80070ec + 8008aec: 4607 mov r7, r0 + while(READ_BIT(RCC->CSR, RCC_CSR_LSIRDY) == 0U) + 8008aee: f8d4 3094 ldr.w r3, [r4, #148] ; 0x94 + 8008af2: 079a lsls r2, r3, #30 + 8008af4: f53f af48 bmi.w 8008988 + if((HAL_GetTick() - tickstart) > LSI_TIMEOUT_VALUE) + 8008af8: f7fe faf8 bl 80070ec + 8008afc: 1bc0 subs r0, r0, r7 + 8008afe: 2802 cmp r0, #2 + 8008b00: d9f5 bls.n 8008aee + 8008b02: e755 b.n 80089b0 + __HAL_RCC_LSI_DISABLE(); + 8008b04: f8d4 3094 ldr.w r3, [r4, #148] ; 0x94 + 8008b08: f023 0301 bic.w r3, r3, #1 + 8008b0c: f8c4 3094 str.w r3, [r4, #148] ; 0x94 + tickstart = HAL_GetTick(); + 8008b10: f7fe faec bl 80070ec + 8008b14: 4607 mov r7, r0 + while(READ_BIT(RCC->CSR, RCC_CSR_LSIRDY) != 0U) + 8008b16: f8d4 3094 ldr.w r3, [r4, #148] ; 0x94 + 8008b1a: 079b lsls r3, r3, #30 + 8008b1c: f57f af34 bpl.w 8008988 + if((HAL_GetTick() - tickstart) > LSI_TIMEOUT_VALUE) + 8008b20: f7fe fae4 bl 80070ec + 8008b24: 1bc0 subs r0, r0, r7 + 8008b26: 2802 cmp r0, #2 + 8008b28: d9f5 bls.n 8008b16 + 8008b2a: e741 b.n 80089b0 + if(HAL_IS_BIT_CLR(RCC->APB1ENR1, RCC_APB1ENR1_PWREN)) + 8008b2c: 6da3 ldr r3, [r4, #88] ; 0x58 + 8008b2e: 00df lsls r7, r3, #3 + 8008b30: d429 bmi.n 8008b86 + __HAL_RCC_PWR_CLK_ENABLE(); + 8008b32: 6da3 ldr r3, [r4, #88] ; 0x58 + 8008b34: f043 5380 orr.w r3, r3, #268435456 ; 0x10000000 + 8008b38: 65a3 str r3, [r4, #88] ; 0x58 + 8008b3a: 6da3 ldr r3, [r4, #88] ; 0x58 + 8008b3c: f003 5380 and.w r3, r3, #268435456 ; 0x10000000 + 8008b40: 9301 str r3, [sp, #4] + 8008b42: 9b01 ldr r3, [sp, #4] + pwrclkchanged = SET; + 8008b44: f04f 0801 mov.w r8, #1 + if(HAL_IS_BIT_CLR(PWR->CR1, PWR_CR1_DBP)) + 8008b48: 4f9c ldr r7, [pc, #624] ; (8008dbc ) + 8008b4a: 683b ldr r3, [r7, #0] + 8008b4c: 05d8 lsls r0, r3, #23 + 8008b4e: d51d bpl.n 8008b8c + __HAL_RCC_LSE_CONFIG(RCC_OscInitStruct->LSEState); + 8008b50: 68ab ldr r3, [r5, #8] + 8008b52: 2b01 cmp r3, #1 + 8008b54: d12b bne.n 8008bae + 8008b56: f8d4 3090 ldr.w r3, [r4, #144] ; 0x90 + 8008b5a: f043 0301 orr.w r3, r3, #1 + 8008b5e: f8c4 3090 str.w r3, [r4, #144] ; 0x90 + tickstart = HAL_GetTick(); + 8008b62: f7fe fac3 bl 80070ec + if((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) + 8008b66: f241 3988 movw r9, #5000 ; 0x1388 + tickstart = HAL_GetTick(); + 8008b6a: 4607 mov r7, r0 + while(READ_BIT(RCC->BDCR, RCC_BDCR_LSERDY) == 0U) + 8008b6c: f8d4 3090 ldr.w r3, [r4, #144] ; 0x90 + 8008b70: 079a lsls r2, r3, #30 + 8008b72: d542 bpl.n 8008bfa + if(pwrclkchanged == SET) + 8008b74: f1b8 0f00 cmp.w r8, #0 + 8008b78: f43f af0a beq.w 8008990 + __HAL_RCC_PWR_CLK_DISABLE(); + 8008b7c: 6da3 ldr r3, [r4, #88] ; 0x58 + 8008b7e: f023 5380 bic.w r3, r3, #268435456 ; 0x10000000 + 8008b82: 65a3 str r3, [r4, #88] ; 0x58 + 8008b84: e704 b.n 8008990 + FlagStatus pwrclkchanged = RESET; + 8008b86: f04f 0800 mov.w r8, #0 + 8008b8a: e7dd b.n 8008b48 + SET_BIT(PWR->CR1, PWR_CR1_DBP); + 8008b8c: 683b ldr r3, [r7, #0] + 8008b8e: f443 7380 orr.w r3, r3, #256 ; 0x100 + 8008b92: 603b str r3, [r7, #0] + tickstart = HAL_GetTick(); + 8008b94: f7fe faaa bl 80070ec + 8008b98: 4681 mov r9, r0 + while(HAL_IS_BIT_CLR(PWR->CR1, PWR_CR1_DBP)) + 8008b9a: 683b ldr r3, [r7, #0] + 8008b9c: 05d9 lsls r1, r3, #23 + 8008b9e: d4d7 bmi.n 8008b50 + if((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE) + 8008ba0: f7fe faa4 bl 80070ec + 8008ba4: eba0 0009 sub.w r0, r0, r9 + 8008ba8: 2802 cmp r0, #2 + 8008baa: d9f6 bls.n 8008b9a + 8008bac: e700 b.n 80089b0 + __HAL_RCC_LSE_CONFIG(RCC_OscInitStruct->LSEState); + 8008bae: 2b05 cmp r3, #5 + 8008bb0: d106 bne.n 8008bc0 + 8008bb2: f8d4 3090 ldr.w r3, [r4, #144] ; 0x90 + 8008bb6: f043 0304 orr.w r3, r3, #4 + 8008bba: f8c4 3090 str.w r3, [r4, #144] ; 0x90 + 8008bbe: e7ca b.n 8008b56 + 8008bc0: f8d4 2090 ldr.w r2, [r4, #144] ; 0x90 + 8008bc4: f022 0201 bic.w r2, r2, #1 + 8008bc8: f8c4 2090 str.w r2, [r4, #144] ; 0x90 + 8008bcc: f8d4 2090 ldr.w r2, [r4, #144] ; 0x90 + 8008bd0: f022 0204 bic.w r2, r2, #4 + 8008bd4: f8c4 2090 str.w r2, [r4, #144] ; 0x90 + if(RCC_OscInitStruct->LSEState != RCC_LSE_OFF) + 8008bd8: 2b00 cmp r3, #0 + 8008bda: d1c2 bne.n 8008b62 + tickstart = HAL_GetTick(); + 8008bdc: f7fe fa86 bl 80070ec + if((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) + 8008be0: f241 3988 movw r9, #5000 ; 0x1388 + tickstart = HAL_GetTick(); + 8008be4: 4607 mov r7, r0 + while(READ_BIT(RCC->BDCR, RCC_BDCR_LSERDY) != 0U) + 8008be6: f8d4 3090 ldr.w r3, [r4, #144] ; 0x90 + 8008bea: 079b lsls r3, r3, #30 + 8008bec: d5c2 bpl.n 8008b74 + if((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) + 8008bee: f7fe fa7d bl 80070ec + 8008bf2: 1bc0 subs r0, r0, r7 + 8008bf4: 4548 cmp r0, r9 + 8008bf6: d9f6 bls.n 8008be6 + 8008bf8: e6da b.n 80089b0 + if((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) + 8008bfa: f7fe fa77 bl 80070ec + 8008bfe: 1bc0 subs r0, r0, r7 + 8008c00: 4548 cmp r0, r9 + 8008c02: d9b3 bls.n 8008b6c + 8008c04: e6d4 b.n 80089b0 + if(RCC_OscInitStruct->HSI48State != RCC_HSI48_OFF) + 8008c06: 6a6b ldr r3, [r5, #36] ; 0x24 + 8008c08: b19b cbz r3, 8008c32 + __HAL_RCC_HSI48_ENABLE(); + 8008c0a: f8d4 3098 ldr.w r3, [r4, #152] ; 0x98 + 8008c0e: f043 0301 orr.w r3, r3, #1 + 8008c12: f8c4 3098 str.w r3, [r4, #152] ; 0x98 + tickstart = HAL_GetTick(); + 8008c16: f7fe fa69 bl 80070ec + 8008c1a: 4607 mov r7, r0 + while(READ_BIT(RCC->CRRCR, RCC_CRRCR_HSI48RDY) == 0U) + 8008c1c: f8d4 3098 ldr.w r3, [r4, #152] ; 0x98 + 8008c20: 0798 lsls r0, r3, #30 + 8008c22: f53f aeb9 bmi.w 8008998 + if((HAL_GetTick() - tickstart) > HSI48_TIMEOUT_VALUE) + 8008c26: f7fe fa61 bl 80070ec + 8008c2a: 1bc0 subs r0, r0, r7 + 8008c2c: 2802 cmp r0, #2 + 8008c2e: d9f5 bls.n 8008c1c + 8008c30: e6be b.n 80089b0 + __HAL_RCC_HSI48_DISABLE(); + 8008c32: f8d4 3098 ldr.w r3, [r4, #152] ; 0x98 + 8008c36: f023 0301 bic.w r3, r3, #1 + 8008c3a: f8c4 3098 str.w r3, [r4, #152] ; 0x98 + tickstart = HAL_GetTick(); + 8008c3e: f7fe fa55 bl 80070ec + 8008c42: 4607 mov r7, r0 + while(READ_BIT(RCC->CRRCR, RCC_CRRCR_HSI48RDY) != 0U) + 8008c44: f8d4 3098 ldr.w r3, [r4, #152] ; 0x98 + 8008c48: 0799 lsls r1, r3, #30 + 8008c4a: f57f aea5 bpl.w 8008998 + if((HAL_GetTick() - tickstart) > HSI48_TIMEOUT_VALUE) + 8008c4e: f7fe fa4d bl 80070ec + 8008c52: 1bc0 subs r0, r0, r7 + 8008c54: 2802 cmp r0, #2 + 8008c56: d9f5 bls.n 8008c44 + 8008c58: e6aa b.n 80089b0 + if(RCC_OscInitStruct->PLL.PLLState == RCC_PLL_ON) + 8008c5a: 2b02 cmp r3, #2 + 8008c5c: f040 808c bne.w 8008d78 + pll_config = RCC->PLLCFGR; + 8008c60: 68e3 ldr r3, [r4, #12] + if((READ_BIT(pll_config, RCC_PLLCFGR_PLLSRC) != RCC_OscInitStruct->PLL.PLLSource) || + 8008c62: 6aea ldr r2, [r5, #44] ; 0x2c + 8008c64: f003 0103 and.w r1, r3, #3 + 8008c68: 4291 cmp r1, r2 + 8008c6a: d122 bne.n 8008cb2 + (READ_BIT(pll_config, RCC_PLLCFGR_PLLM) != ((RCC_OscInitStruct->PLL.PLLM - 1U) << RCC_PLLCFGR_PLLM_Pos)) || + 8008c6c: 6b29 ldr r1, [r5, #48] ; 0x30 + 8008c6e: f003 02f0 and.w r2, r3, #240 ; 0xf0 + 8008c72: 3901 subs r1, #1 + if((READ_BIT(pll_config, RCC_PLLCFGR_PLLSRC) != RCC_OscInitStruct->PLL.PLLSource) || + 8008c74: ebb2 1f01 cmp.w r2, r1, lsl #4 + 8008c78: d11b bne.n 8008cb2 + (READ_BIT(pll_config, RCC_PLLCFGR_PLLN) != (RCC_OscInitStruct->PLL.PLLN << RCC_PLLCFGR_PLLN_Pos)) || + 8008c7a: 6b69 ldr r1, [r5, #52] ; 0x34 + 8008c7c: f403 42fe and.w r2, r3, #32512 ; 0x7f00 + (READ_BIT(pll_config, RCC_PLLCFGR_PLLM) != ((RCC_OscInitStruct->PLL.PLLM - 1U) << RCC_PLLCFGR_PLLM_Pos)) || + 8008c80: ebb2 2f01 cmp.w r2, r1, lsl #8 + 8008c84: d115 bne.n 8008cb2 + (READ_BIT(pll_config, RCC_PLLCFGR_PLLPDIV) != (RCC_OscInitStruct->PLL.PLLP << RCC_PLLCFGR_PLLPDIV_Pos)) || + 8008c86: 6ba9 ldr r1, [r5, #56] ; 0x38 + 8008c88: f003 4278 and.w r2, r3, #4160749568 ; 0xf8000000 + (READ_BIT(pll_config, RCC_PLLCFGR_PLLN) != (RCC_OscInitStruct->PLL.PLLN << RCC_PLLCFGR_PLLN_Pos)) || + 8008c8c: ebb2 6fc1 cmp.w r2, r1, lsl #27 + 8008c90: d10f bne.n 8008cb2 + (READ_BIT(pll_config, RCC_PLLCFGR_PLLQ) != ((((RCC_OscInitStruct->PLL.PLLQ) >> 1U) - 1U) << RCC_PLLCFGR_PLLQ_Pos)) || + 8008c92: 6bea ldr r2, [r5, #60] ; 0x3c + 8008c94: 0852 lsrs r2, r2, #1 + 8008c96: f403 01c0 and.w r1, r3, #6291456 ; 0x600000 + 8008c9a: 3a01 subs r2, #1 + (READ_BIT(pll_config, RCC_PLLCFGR_PLLPDIV) != (RCC_OscInitStruct->PLL.PLLP << RCC_PLLCFGR_PLLPDIV_Pos)) || + 8008c9c: ebb1 5f42 cmp.w r1, r2, lsl #21 + 8008ca0: d107 bne.n 8008cb2 + (READ_BIT(pll_config, RCC_PLLCFGR_PLLR) != ((((RCC_OscInitStruct->PLL.PLLR) >> 1U) - 1U) << RCC_PLLCFGR_PLLR_Pos))) + 8008ca2: 6c2a ldr r2, [r5, #64] ; 0x40 + 8008ca4: 0852 lsrs r2, r2, #1 + 8008ca6: f003 63c0 and.w r3, r3, #100663296 ; 0x6000000 + 8008caa: 3a01 subs r2, #1 + (READ_BIT(pll_config, RCC_PLLCFGR_PLLQ) != ((((RCC_OscInitStruct->PLL.PLLQ) >> 1U) - 1U) << RCC_PLLCFGR_PLLQ_Pos)) || + 8008cac: ebb3 6f42 cmp.w r3, r2, lsl #25 + 8008cb0: d049 beq.n 8008d46 + if(sysclk_source != RCC_CFGR_SWS_PLL) + 8008cb2: 2e0c cmp r6, #12 + 8008cb4: f43f addc beq.w 8008870 + if((READ_BIT(RCC->CR, RCC_CR_PLLSAI1ON) != 0U) + 8008cb8: 6823 ldr r3, [r4, #0] + 8008cba: 015a lsls r2, r3, #5 + 8008cbc: f53f add8 bmi.w 8008870 + || (READ_BIT(RCC->CR, RCC_CR_PLLSAI2ON) != 0U) + 8008cc0: 6823 ldr r3, [r4, #0] + 8008cc2: 00db lsls r3, r3, #3 + 8008cc4: f53f add4 bmi.w 8008870 + __HAL_RCC_PLL_DISABLE(); + 8008cc8: 6823 ldr r3, [r4, #0] + 8008cca: f023 7380 bic.w r3, r3, #16777216 ; 0x1000000 + 8008cce: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 8008cd0: f7fe fa0c bl 80070ec + 8008cd4: 4606 mov r6, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLRDY) != 0U) + 8008cd6: 6823 ldr r3, [r4, #0] + 8008cd8: 019f lsls r7, r3, #6 + 8008cda: d42e bmi.n 8008d3a + __HAL_RCC_PLL_CONFIG(RCC_OscInitStruct->PLL.PLLSource, + 8008cdc: 68e2 ldr r2, [r4, #12] + 8008cde: 4b38 ldr r3, [pc, #224] ; (8008dc0 ) + 8008ce0: 4013 ands r3, r2 + 8008ce2: 6aea ldr r2, [r5, #44] ; 0x2c + 8008ce4: 4313 orrs r3, r2 + 8008ce6: 6b6a ldr r2, [r5, #52] ; 0x34 + 8008ce8: ea43 2302 orr.w r3, r3, r2, lsl #8 + 8008cec: 6baa ldr r2, [r5, #56] ; 0x38 + 8008cee: ea43 63c2 orr.w r3, r3, r2, lsl #27 + 8008cf2: 6b2a ldr r2, [r5, #48] ; 0x30 + 8008cf4: 3a01 subs r2, #1 + 8008cf6: ea43 1302 orr.w r3, r3, r2, lsl #4 + 8008cfa: 6bea ldr r2, [r5, #60] ; 0x3c + 8008cfc: 0852 lsrs r2, r2, #1 + 8008cfe: 3a01 subs r2, #1 + 8008d00: ea43 5342 orr.w r3, r3, r2, lsl #21 + 8008d04: 6c2a ldr r2, [r5, #64] ; 0x40 + 8008d06: 0852 lsrs r2, r2, #1 + 8008d08: 3a01 subs r2, #1 + 8008d0a: ea43 6342 orr.w r3, r3, r2, lsl #25 + 8008d0e: 60e3 str r3, [r4, #12] + __HAL_RCC_PLL_ENABLE(); + 8008d10: 6823 ldr r3, [r4, #0] + 8008d12: f043 7380 orr.w r3, r3, #16777216 ; 0x1000000 + 8008d16: 6023 str r3, [r4, #0] + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL_SYSCLK); + 8008d18: 68e3 ldr r3, [r4, #12] + 8008d1a: f043 7380 orr.w r3, r3, #16777216 ; 0x1000000 + 8008d1e: 60e3 str r3, [r4, #12] + tickstart = HAL_GetTick(); + 8008d20: f7fe f9e4 bl 80070ec + 8008d24: 4605 mov r5, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLRDY) == 0U) + 8008d26: 6823 ldr r3, [r4, #0] + 8008d28: 0198 lsls r0, r3, #6 + 8008d2a: f53f ae39 bmi.w 80089a0 + if((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE) + 8008d2e: f7fe f9dd bl 80070ec + 8008d32: 1b40 subs r0, r0, r5 + 8008d34: 2802 cmp r0, #2 + 8008d36: d9f6 bls.n 8008d26 + 8008d38: e63a b.n 80089b0 + if((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE) + 8008d3a: f7fe f9d7 bl 80070ec + 8008d3e: 1b80 subs r0, r0, r6 + 8008d40: 2802 cmp r0, #2 + 8008d42: d9c8 bls.n 8008cd6 + 8008d44: e634 b.n 80089b0 + if(READ_BIT(RCC->CR, RCC_CR_PLLRDY) == 0U) + 8008d46: 6823 ldr r3, [r4, #0] + 8008d48: 0199 lsls r1, r3, #6 + 8008d4a: f53f ae29 bmi.w 80089a0 + __HAL_RCC_PLL_ENABLE(); + 8008d4e: 6823 ldr r3, [r4, #0] + 8008d50: f043 7380 orr.w r3, r3, #16777216 ; 0x1000000 + 8008d54: 6023 str r3, [r4, #0] + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL_SYSCLK); + 8008d56: 68e3 ldr r3, [r4, #12] + 8008d58: f043 7380 orr.w r3, r3, #16777216 ; 0x1000000 + 8008d5c: 60e3 str r3, [r4, #12] + tickstart = HAL_GetTick(); + 8008d5e: f7fe f9c5 bl 80070ec + 8008d62: 4605 mov r5, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLRDY) == 0U) + 8008d64: 6823 ldr r3, [r4, #0] + 8008d66: 019a lsls r2, r3, #6 + 8008d68: f53f ae1a bmi.w 80089a0 + if((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE) + 8008d6c: f7fe f9be bl 80070ec + 8008d70: 1b40 subs r0, r0, r5 + 8008d72: 2802 cmp r0, #2 + 8008d74: d9f6 bls.n 8008d64 + 8008d76: e61b b.n 80089b0 + if(sysclk_source != RCC_CFGR_SWS_PLL) + 8008d78: 2e0c cmp r6, #12 + 8008d7a: f43f ad79 beq.w 8008870 + __HAL_RCC_PLL_DISABLE(); + 8008d7e: 6823 ldr r3, [r4, #0] + 8008d80: f023 7380 bic.w r3, r3, #16777216 ; 0x1000000 + 8008d84: 6023 str r3, [r4, #0] + if(READ_BIT(RCC->CR, (RCC_CR_PLLSAI1RDY | RCC_CR_PLLSAI2RDY)) == 0U) + 8008d86: 6823 ldr r3, [r4, #0] + 8008d88: f013 5f20 tst.w r3, #671088640 ; 0x28000000 + MODIFY_REG(RCC->PLLCFGR, RCC_PLLCFGR_PLLSRC, RCC_PLLSOURCE_NONE); + 8008d8c: bf02 ittt eq + 8008d8e: 68e3 ldreq r3, [r4, #12] + 8008d90: f023 0303 biceq.w r3, r3, #3 + 8008d94: 60e3 streq r3, [r4, #12] + __HAL_RCC_PLLCLKOUT_DISABLE(RCC_PLL_SYSCLK | RCC_PLL_48M1CLK | RCC_PLL_SAI3CLK); + 8008d96: 68e3 ldr r3, [r4, #12] + 8008d98: f023 7388 bic.w r3, r3, #17825792 ; 0x1100000 + 8008d9c: f423 3380 bic.w r3, r3, #65536 ; 0x10000 + 8008da0: 60e3 str r3, [r4, #12] + tickstart = HAL_GetTick(); + 8008da2: f7fe f9a3 bl 80070ec + 8008da6: 4605 mov r5, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLRDY) != 0U) + 8008da8: 6823 ldr r3, [r4, #0] + 8008daa: 019b lsls r3, r3, #6 + 8008dac: f57f adf8 bpl.w 80089a0 + if((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE) + 8008db0: f7fe f99c bl 80070ec + 8008db4: 1b40 subs r0, r0, r5 + 8008db6: 2802 cmp r0, #2 + 8008db8: d9f6 bls.n 8008da8 + 8008dba: e5f9 b.n 80089b0 + 8008dbc: 40007000 .word 0x40007000 + 8008dc0: 019d800c .word 0x019d800c + +08008dc4 : +{ + 8008dc4: e92d 43f8 stmdb sp!, {r3, r4, r5, r6, r7, r8, r9, lr} + 8008dc8: 460e mov r6, r1 + if(RCC_ClkInitStruct == NULL) + 8008dca: 4605 mov r5, r0 + 8008dcc: b910 cbnz r0, 8008dd4 + return HAL_ERROR; + 8008dce: 2001 movs r0, #1 +} + 8008dd0: e8bd 83f8 ldmia.w sp!, {r3, r4, r5, r6, r7, r8, r9, pc} + if(FLatency > __HAL_FLASH_GET_LATENCY()) + 8008dd4: 4a6f ldr r2, [pc, #444] ; (8008f94 ) + 8008dd6: 6813 ldr r3, [r2, #0] + 8008dd8: f003 030f and.w r3, r3, #15 + 8008ddc: 428b cmp r3, r1 + 8008dde: d335 bcc.n 8008e4c + if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_SYSCLK) == RCC_CLOCKTYPE_SYSCLK) + 8008de0: 6829 ldr r1, [r5, #0] + 8008de2: f011 0701 ands.w r7, r1, #1 + 8008de6: d13c bne.n 8008e62 + if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_HCLK) == RCC_CLOCKTYPE_HCLK) + 8008de8: 682a ldr r2, [r5, #0] + 8008dea: 0791 lsls r1, r2, #30 + 8008dec: f140 80b7 bpl.w 8008f5e + MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_ClkInitStruct->AHBCLKDivider); + 8008df0: 4969 ldr r1, [pc, #420] ; (8008f98 ) + 8008df2: 68a8 ldr r0, [r5, #8] + 8008df4: 688b ldr r3, [r1, #8] + 8008df6: f023 03f0 bic.w r3, r3, #240 ; 0xf0 + 8008dfa: 4303 orrs r3, r0 + MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_SYSCLK_DIV1); + 8008dfc: 608b str r3, [r1, #8] + if(FLatency < __HAL_FLASH_GET_LATENCY()) + 8008dfe: 4965 ldr r1, [pc, #404] ; (8008f94 ) + 8008e00: 680b ldr r3, [r1, #0] + 8008e02: f003 030f and.w r3, r3, #15 + 8008e06: 42b3 cmp r3, r6 + 8008e08: f200 80b1 bhi.w 8008f6e + if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK1) == RCC_CLOCKTYPE_PCLK1) + 8008e0c: f012 0f04 tst.w r2, #4 + 8008e10: 4c61 ldr r4, [pc, #388] ; (8008f98 ) + 8008e12: f040 80b8 bne.w 8008f86 + if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK2) == RCC_CLOCKTYPE_PCLK2) + 8008e16: 0713 lsls r3, r2, #28 + 8008e18: d506 bpl.n 8008e28 + MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE2, ((RCC_ClkInitStruct->APB2CLKDivider) << 3U)); + 8008e1a: 68a3 ldr r3, [r4, #8] + 8008e1c: 692a ldr r2, [r5, #16] + 8008e1e: f423 5360 bic.w r3, r3, #14336 ; 0x3800 + 8008e22: ea43 03c2 orr.w r3, r3, r2, lsl #3 + 8008e26: 60a3 str r3, [r4, #8] + SystemCoreClock = HAL_RCC_GetSysClockFreq() >> (AHBPrescTable[READ_BIT(RCC->CFGR, RCC_CFGR_HPRE) >> RCC_CFGR_HPRE_Pos] & 0x1FU); + 8008e28: f7ff fcd0 bl 80087cc + 8008e2c: 68a3 ldr r3, [r4, #8] + 8008e2e: 4a5b ldr r2, [pc, #364] ; (8008f9c ) + 8008e30: f3c3 1303 ubfx r3, r3, #4, #4 + 8008e34: 5cd3 ldrb r3, [r2, r3] + 8008e36: f003 031f and.w r3, r3, #31 + 8008e3a: 40d8 lsrs r0, r3 + 8008e3c: 4b58 ldr r3, [pc, #352] ; (8008fa0 ) + 8008e3e: 6018 str r0, [r3, #0] + status = HAL_InitTick(uwTickPrio); + 8008e40: 4b58 ldr r3, [pc, #352] ; (8008fa4 ) + 8008e42: 6818 ldr r0, [r3, #0] +} + 8008e44: e8bd 43f8 ldmia.w sp!, {r3, r4, r5, r6, r7, r8, r9, lr} + status = HAL_InitTick(uwTickPrio); + 8008e48: f7fe b952 b.w 80070f0 + __HAL_FLASH_SET_LATENCY(FLatency); + 8008e4c: 6813 ldr r3, [r2, #0] + 8008e4e: f023 030f bic.w r3, r3, #15 + 8008e52: 430b orrs r3, r1 + 8008e54: 6013 str r3, [r2, #0] + if(__HAL_FLASH_GET_LATENCY() != FLatency) + 8008e56: 6813 ldr r3, [r2, #0] + 8008e58: f003 030f and.w r3, r3, #15 + 8008e5c: 428b cmp r3, r1 + 8008e5e: d1b6 bne.n 8008dce + 8008e60: e7be b.n 8008de0 + if(RCC_ClkInitStruct->SYSCLKSource == RCC_SYSCLKSOURCE_PLLCLK) + 8008e62: 686b ldr r3, [r5, #4] + 8008e64: 4c4c ldr r4, [pc, #304] ; (8008f98 ) + 8008e66: 2b03 cmp r3, #3 + 8008e68: d163 bne.n 8008f32 + if(READ_BIT(RCC->CR, RCC_CR_PLLRDY) == 0U) + 8008e6a: 6823 ldr r3, [r4, #0] + 8008e6c: 019b lsls r3, r3, #6 + 8008e6e: d5ae bpl.n 8008dce +static uint32_t RCC_GetSysClockFreqFromPLLSource(void) +{ + uint32_t msirange = 0U; + uint32_t pllvco, pllsource, pllr, pllm, sysclockfreq; /* no init needed */ + + if(__HAL_RCC_GET_PLL_OSCSOURCE() == RCC_PLLSOURCE_MSI) + 8008e70: 68e3 ldr r3, [r4, #12] + 8008e72: f003 0303 and.w r3, r3, #3 + 8008e76: 2b01 cmp r3, #1 + 8008e78: d145 bne.n 8008f06 + { + /* Get MSI range source */ + if(READ_BIT(RCC->CR, RCC_CR_MSIRGSEL) == 0U) + 8008e7a: 6823 ldr r3, [r4, #0] + else + { /* MSIRANGE from RCC_CR applies */ + msirange = READ_BIT(RCC->CR, RCC_CR_MSIRANGE) >> RCC_CR_MSIRANGE_Pos; + } + /*MSI frequency range in HZ*/ + msirange = MSIRangeTable[msirange]; + 8008e7c: 4a4a ldr r2, [pc, #296] ; (8008fa8 ) + if(READ_BIT(RCC->CR, RCC_CR_MSIRGSEL) == 0U) + 8008e7e: 071f lsls r7, r3, #28 + msirange = READ_BIT(RCC->CSR, RCC_CSR_MSISRANGE) >> RCC_CSR_MSISRANGE_Pos; + 8008e80: bf55 itete pl + 8008e82: f8d4 3094 ldrpl.w r3, [r4, #148] ; 0x94 + msirange = READ_BIT(RCC->CR, RCC_CR_MSIRANGE) >> RCC_CR_MSIRANGE_Pos; + 8008e86: 6823 ldrmi r3, [r4, #0] + msirange = READ_BIT(RCC->CSR, RCC_CSR_MSISRANGE) >> RCC_CSR_MSISRANGE_Pos; + 8008e88: f3c3 2303 ubfxpl r3, r3, #8, #4 + msirange = READ_BIT(RCC->CR, RCC_CR_MSIRANGE) >> RCC_CR_MSIRANGE_Pos; + 8008e8c: f3c3 1303 ubfxmi r3, r3, #4, #4 + msirange = MSIRangeTable[msirange]; + 8008e90: f852 2023 ldr.w r2, [r2, r3, lsl #2] + } + + /* PLL_VCO = (HSE_VALUE or HSI_VALUE or MSI_VALUE) * PLLN / PLLM + SYSCLK = PLL_VCO / PLLR + */ + pllsource = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLSRC); + 8008e94: 68e3 ldr r3, [r4, #12] + 8008e96: f003 0303 and.w r3, r3, #3 + + switch (pllsource) + 8008e9a: 2b02 cmp r3, #2 + 8008e9c: d035 beq.n 8008f0a + 8008e9e: 4843 ldr r0, [pc, #268] ; (8008fac ) + 8008ea0: 2b03 cmp r3, #3 + 8008ea2: bf08 it eq + 8008ea4: 4602 moveq r2, r0 + case RCC_PLLSOURCE_MSI: /* MSI used as PLL clock source */ + default: + pllvco = msirange; + break; + } + pllm = (READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U ; + 8008ea6: 68e0 ldr r0, [r4, #12] + pllvco = (pllvco * (READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos)) / pllm; + 8008ea8: 68e3 ldr r3, [r4, #12] + 8008eaa: f3c3 2306 ubfx r3, r3, #8, #7 + 8008eae: 4353 muls r3, r2 + pllr = ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos) + 1U ) * 2U; + 8008eb0: 68e2 ldr r2, [r4, #12] + 8008eb2: f3c2 6241 ubfx r2, r2, #25, #2 + pllm = (READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U ; + 8008eb6: f3c0 1003 ubfx r0, r0, #4, #4 + pllr = ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos) + 1U ) * 2U; + 8008eba: 3201 adds r2, #1 + 8008ebc: 0052 lsls r2, r2, #1 + pllm = (READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U ; + 8008ebe: 3001 adds r0, #1 + pllvco = (pllvco * (READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos)) / pllm; + 8008ec0: fbb3 f3f0 udiv r3, r3, r0 + sysclockfreq = pllvco / pllr; + 8008ec4: fbb3 f3f2 udiv r3, r3, r2 + if(RCC_GetSysClockFreqFromPLLSource() > 80000000U) + 8008ec8: 4a39 ldr r2, [pc, #228] ; (8008fb0 ) + 8008eca: 4293 cmp r3, r2 + 8008ecc: d81f bhi.n 8008f0e + uint32_t hpre = RCC_SYSCLK_DIV1; + 8008ece: 2700 movs r7, #0 + MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_ClkInitStruct->SYSCLKSource); + 8008ed0: 68a3 ldr r3, [r4, #8] + 8008ed2: 686a ldr r2, [r5, #4] + 8008ed4: f023 0303 bic.w r3, r3, #3 + 8008ed8: 4313 orrs r3, r2 + 8008eda: 60a3 str r3, [r4, #8] + tickstart = HAL_GetTick(); + 8008edc: f7fe f906 bl 80070ec + if((HAL_GetTick() - tickstart) > CLOCKSWITCH_TIMEOUT_VALUE) + 8008ee0: f241 3988 movw r9, #5000 ; 0x1388 + tickstart = HAL_GetTick(); + 8008ee4: 4680 mov r8, r0 + while(__HAL_RCC_GET_SYSCLK_SOURCE() != (RCC_ClkInitStruct->SYSCLKSource << RCC_CFGR_SWS_Pos)) + 8008ee6: 68a3 ldr r3, [r4, #8] + 8008ee8: 686a ldr r2, [r5, #4] + 8008eea: f003 030c and.w r3, r3, #12 + 8008eee: ebb3 0f82 cmp.w r3, r2, lsl #2 + 8008ef2: f43f af79 beq.w 8008de8 + if((HAL_GetTick() - tickstart) > CLOCKSWITCH_TIMEOUT_VALUE) + 8008ef6: f7fe f8f9 bl 80070ec + 8008efa: eba0 0008 sub.w r0, r0, r8 + 8008efe: 4548 cmp r0, r9 + 8008f00: d9f1 bls.n 8008ee6 + return HAL_TIMEOUT; + 8008f02: 2003 movs r0, #3 + 8008f04: e764 b.n 8008dd0 + uint32_t msirange = 0U; + 8008f06: 2200 movs r2, #0 + 8008f08: e7c4 b.n 8008e94 + pllvco = HSI_VALUE; + 8008f0a: 4a2a ldr r2, [pc, #168] ; (8008fb4 ) + 8008f0c: e7cb b.n 8008ea6 + if(READ_BIT(RCC->CFGR, RCC_CFGR_HPRE) == RCC_SYSCLK_DIV1) + 8008f0e: 68a3 ldr r3, [r4, #8] + 8008f10: f013 0ff0 tst.w r3, #240 ; 0xf0 + 8008f14: d107 bne.n 8008f26 + MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_SYSCLK_DIV2); + 8008f16: 68a3 ldr r3, [r4, #8] + 8008f18: f023 03f0 bic.w r3, r3, #240 ; 0xf0 + 8008f1c: f043 0380 orr.w r3, r3, #128 ; 0x80 + 8008f20: 60a3 str r3, [r4, #8] + hpre = RCC_SYSCLK_DIV2; + 8008f22: 2780 movs r7, #128 ; 0x80 + 8008f24: e7d4 b.n 8008ed0 + else if((((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_HCLK) == RCC_CLOCKTYPE_HCLK) && (RCC_ClkInitStruct->AHBCLKDivider == RCC_SYSCLK_DIV1)) + 8008f26: 0788 lsls r0, r1, #30 + 8008f28: d5d1 bpl.n 8008ece + 8008f2a: 68ab ldr r3, [r5, #8] + 8008f2c: 2b00 cmp r3, #0 + 8008f2e: d1ce bne.n 8008ece + 8008f30: e7f1 b.n 8008f16 + if(RCC_ClkInitStruct->SYSCLKSource == RCC_SYSCLKSOURCE_HSE) + 8008f32: 2b02 cmp r3, #2 + 8008f34: d10a bne.n 8008f4c + if(READ_BIT(RCC->CR, RCC_CR_HSERDY) == 0U) + 8008f36: 6823 ldr r3, [r4, #0] + 8008f38: f413 3f00 tst.w r3, #131072 ; 0x20000 + if(READ_BIT(RCC->CR, RCC_CR_HSIRDY) == 0U) + 8008f3c: f43f af47 beq.w 8008dce + if(HAL_RCC_GetSysClockFreq() > 80000000U) + 8008f40: f7ff fc44 bl 80087cc + 8008f44: 4b1a ldr r3, [pc, #104] ; (8008fb0 ) + 8008f46: 4298 cmp r0, r3 + 8008f48: d9c1 bls.n 8008ece + 8008f4a: e7e4 b.n 8008f16 + else if(RCC_ClkInitStruct->SYSCLKSource == RCC_SYSCLKSOURCE_MSI) + 8008f4c: b91b cbnz r3, 8008f56 + if(READ_BIT(RCC->CR, RCC_CR_MSIRDY) == 0U) + 8008f4e: 6823 ldr r3, [r4, #0] + 8008f50: f013 0f02 tst.w r3, #2 + 8008f54: e7f2 b.n 8008f3c + if(READ_BIT(RCC->CR, RCC_CR_HSIRDY) == 0U) + 8008f56: 6823 ldr r3, [r4, #0] + 8008f58: f413 6f80 tst.w r3, #1024 ; 0x400 + 8008f5c: e7ee b.n 8008f3c + if(hpre == RCC_SYSCLK_DIV2) + 8008f5e: 2f80 cmp r7, #128 ; 0x80 + 8008f60: f47f af4d bne.w 8008dfe + MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_SYSCLK_DIV1); + 8008f64: 490c ldr r1, [pc, #48] ; (8008f98 ) + 8008f66: 688b ldr r3, [r1, #8] + 8008f68: f023 03f0 bic.w r3, r3, #240 ; 0xf0 + 8008f6c: e746 b.n 8008dfc + __HAL_FLASH_SET_LATENCY(FLatency); + 8008f6e: 680b ldr r3, [r1, #0] + 8008f70: f023 030f bic.w r3, r3, #15 + 8008f74: 4333 orrs r3, r6 + 8008f76: 600b str r3, [r1, #0] + if(__HAL_FLASH_GET_LATENCY() != FLatency) + 8008f78: 680b ldr r3, [r1, #0] + 8008f7a: f003 030f and.w r3, r3, #15 + 8008f7e: 42b3 cmp r3, r6 + 8008f80: f47f af25 bne.w 8008dce + 8008f84: e742 b.n 8008e0c + MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, RCC_ClkInitStruct->APB1CLKDivider); + 8008f86: 68a3 ldr r3, [r4, #8] + 8008f88: 68e9 ldr r1, [r5, #12] + 8008f8a: f423 63e0 bic.w r3, r3, #1792 ; 0x700 + 8008f8e: 430b orrs r3, r1 + 8008f90: 60a3 str r3, [r4, #8] + 8008f92: e740 b.n 8008e16 + 8008f94: 40022000 .word 0x40022000 + 8008f98: 40021000 .word 0x40021000 + 8008f9c: 0800e9dc .word 0x0800e9dc + 8008fa0: 2009e2a8 .word 0x2009e2a8 + 8008fa4: 2009e2ac .word 0x2009e2ac + 8008fa8: 0800e9f4 .word 0x0800e9f4 + 8008fac: 007a1200 .word 0x007a1200 + 8008fb0: 04c4b400 .word 0x04c4b400 + 8008fb4: 00f42400 .word 0x00f42400 + +08008fb8 : +} + 8008fb8: 4b01 ldr r3, [pc, #4] ; (8008fc0 ) + 8008fba: 6818 ldr r0, [r3, #0] + 8008fbc: 4770 bx lr + 8008fbe: bf00 nop + 8008fc0: 2009e2a8 .word 0x2009e2a8 + +08008fc4 : + return (HAL_RCC_GetHCLKFreq() >> (APBPrescTable[READ_BIT(RCC->CFGR, RCC_CFGR_PPRE1) >> RCC_CFGR_PPRE1_Pos] & 0x1FU)); + 8008fc4: 4b05 ldr r3, [pc, #20] ; (8008fdc ) + 8008fc6: 4a06 ldr r2, [pc, #24] ; (8008fe0 ) + 8008fc8: 689b ldr r3, [r3, #8] + 8008fca: f3c3 2302 ubfx r3, r3, #8, #3 + 8008fce: 5cd3 ldrb r3, [r2, r3] + 8008fd0: 4a04 ldr r2, [pc, #16] ; (8008fe4 ) + 8008fd2: 6810 ldr r0, [r2, #0] + 8008fd4: f003 031f and.w r3, r3, #31 +} + 8008fd8: 40d8 lsrs r0, r3 + 8008fda: 4770 bx lr + 8008fdc: 40021000 .word 0x40021000 + 8008fe0: 0800e9ec .word 0x0800e9ec + 8008fe4: 2009e2a8 .word 0x2009e2a8 + +08008fe8 : + return (HAL_RCC_GetHCLKFreq()>> (APBPrescTable[READ_BIT(RCC->CFGR, RCC_CFGR_PPRE2) >> RCC_CFGR_PPRE2_Pos] & 0x1FU)); + 8008fe8: 4b05 ldr r3, [pc, #20] ; (8009000 ) + 8008fea: 4a06 ldr r2, [pc, #24] ; (8009004 ) + 8008fec: 689b ldr r3, [r3, #8] + 8008fee: f3c3 23c2 ubfx r3, r3, #11, #3 + 8008ff2: 5cd3 ldrb r3, [r2, r3] + 8008ff4: 4a04 ldr r2, [pc, #16] ; (8009008 ) + 8008ff6: 6810 ldr r0, [r2, #0] + 8008ff8: f003 031f and.w r3, r3, #31 +} + 8008ffc: 40d8 lsrs r0, r3 + 8008ffe: 4770 bx lr + 8009000: 40021000 .word 0x40021000 + 8009004: 0800e9ec .word 0x0800e9ec + 8009008: 2009e2a8 .word 0x2009e2a8 + +0800900c : + RCC_OscInitStruct->OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_MSI | \ + 800900c: 233f movs r3, #63 ; 0x3f + 800900e: 6003 str r3, [r0, #0] + if(READ_BIT(RCC->CR, RCC_CR_HSEBYP) == RCC_CR_HSEBYP) + 8009010: 4b2e ldr r3, [pc, #184] ; (80090cc ) + 8009012: 681a ldr r2, [r3, #0] + 8009014: 0351 lsls r1, r2, #13 + 8009016: d54a bpl.n 80090ae + RCC_OscInitStruct->HSEState = RCC_HSE_BYPASS; + 8009018: f44f 22a0 mov.w r2, #327680 ; 0x50000 + RCC_OscInitStruct->HSEState = RCC_HSE_OFF; + 800901c: 6042 str r2, [r0, #4] + if(READ_BIT(RCC->CR, RCC_CR_MSION) == RCC_CR_MSION) + 800901e: 681a ldr r2, [r3, #0] + 8009020: f002 0201 and.w r2, r2, #1 + 8009024: 6182 str r2, [r0, #24] + RCC_OscInitStruct->MSICalibrationValue = READ_BIT(RCC->ICSCR, RCC_ICSCR_MSITRIM) >> RCC_ICSCR_MSITRIM_Pos; + 8009026: 685a ldr r2, [r3, #4] + 8009028: f3c2 2207 ubfx r2, r2, #8, #8 + 800902c: 61c2 str r2, [r0, #28] + RCC_OscInitStruct->MSIClockRange = READ_BIT(RCC->CR, RCC_CR_MSIRANGE); + 800902e: 681a ldr r2, [r3, #0] + 8009030: f002 02f0 and.w r2, r2, #240 ; 0xf0 + 8009034: 6202 str r2, [r0, #32] + if(READ_BIT(RCC->CR, RCC_CR_HSION) == RCC_CR_HSION) + 8009036: 681a ldr r2, [r3, #0] + RCC_OscInitStruct->HSIState = RCC_HSI_ON; + 8009038: f402 7280 and.w r2, r2, #256 ; 0x100 + 800903c: 60c2 str r2, [r0, #12] + RCC_OscInitStruct->HSICalibrationValue = READ_BIT(RCC->ICSCR, RCC_ICSCR_HSITRIM) >> RCC_ICSCR_HSITRIM_Pos; + 800903e: 685a ldr r2, [r3, #4] + 8009040: f3c2 6206 ubfx r2, r2, #24, #7 + 8009044: 6102 str r2, [r0, #16] + if(READ_BIT(RCC->BDCR, RCC_BDCR_LSEBYP) == RCC_BDCR_LSEBYP) + 8009046: f8d3 2090 ldr.w r2, [r3, #144] ; 0x90 + 800904a: 0752 lsls r2, r2, #29 + 800904c: d536 bpl.n 80090bc + RCC_OscInitStruct->LSEState = RCC_LSE_BYPASS; + 800904e: 2205 movs r2, #5 + RCC_OscInitStruct->LSEState = RCC_LSE_OFF; + 8009050: 6082 str r2, [r0, #8] + if(READ_BIT(RCC->CSR, RCC_CSR_LSION) == RCC_CSR_LSION) + 8009052: f8d3 2094 ldr.w r2, [r3, #148] ; 0x94 + 8009056: f002 0201 and.w r2, r2, #1 + 800905a: 6142 str r2, [r0, #20] + if(READ_BIT(RCC->CRRCR, RCC_CRRCR_HSI48ON) == RCC_CRRCR_HSI48ON) + 800905c: f8d3 2098 ldr.w r2, [r3, #152] ; 0x98 + 8009060: f002 0201 and.w r2, r2, #1 + 8009064: 6242 str r2, [r0, #36] ; 0x24 + if(READ_BIT(RCC->CR, RCC_CR_PLLON) == RCC_CR_PLLON) + 8009066: 681a ldr r2, [r3, #0] + RCC_OscInitStruct->PLL.PLLState = RCC_PLL_OFF; + 8009068: f012 7f80 tst.w r2, #16777216 ; 0x1000000 + 800906c: bf14 ite ne + 800906e: 2202 movne r2, #2 + 8009070: 2201 moveq r2, #1 + 8009072: 6282 str r2, [r0, #40] ; 0x28 + RCC_OscInitStruct->PLL.PLLSource = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLSRC); + 8009074: 68da ldr r2, [r3, #12] + 8009076: f002 0203 and.w r2, r2, #3 + 800907a: 62c2 str r2, [r0, #44] ; 0x2c + RCC_OscInitStruct->PLL.PLLM = (READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U; + 800907c: 68da ldr r2, [r3, #12] + 800907e: f3c2 1203 ubfx r2, r2, #4, #4 + 8009082: 3201 adds r2, #1 + 8009084: 6302 str r2, [r0, #48] ; 0x30 + RCC_OscInitStruct->PLL.PLLN = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos; + 8009086: 68da ldr r2, [r3, #12] + 8009088: f3c2 2206 ubfx r2, r2, #8, #7 + 800908c: 6342 str r2, [r0, #52] ; 0x34 + RCC_OscInitStruct->PLL.PLLQ = (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLQ) >> RCC_PLLCFGR_PLLQ_Pos) + 1U) << 1U); + 800908e: 68da ldr r2, [r3, #12] + 8009090: f3c2 5241 ubfx r2, r2, #21, #2 + 8009094: 3201 adds r2, #1 + 8009096: 0052 lsls r2, r2, #1 + 8009098: 63c2 str r2, [r0, #60] ; 0x3c + RCC_OscInitStruct->PLL.PLLR = (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos) + 1U) << 1U); + 800909a: 68da ldr r2, [r3, #12] + 800909c: f3c2 6241 ubfx r2, r2, #25, #2 + 80090a0: 3201 adds r2, #1 + 80090a2: 0052 lsls r2, r2, #1 + 80090a4: 6402 str r2, [r0, #64] ; 0x40 + RCC_OscInitStruct->PLL.PLLP = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLPDIV) >> RCC_PLLCFGR_PLLPDIV_Pos; + 80090a6: 68db ldr r3, [r3, #12] + 80090a8: 0edb lsrs r3, r3, #27 + 80090aa: 6383 str r3, [r0, #56] ; 0x38 +} + 80090ac: 4770 bx lr + else if(READ_BIT(RCC->CR, RCC_CR_HSEON) == RCC_CR_HSEON) + 80090ae: 681a ldr r2, [r3, #0] + 80090b0: f412 3280 ands.w r2, r2, #65536 ; 0x10000 + RCC_OscInitStruct->HSEState = RCC_HSE_ON; + 80090b4: bf18 it ne + 80090b6: f44f 3280 movne.w r2, #65536 ; 0x10000 + 80090ba: e7af b.n 800901c + else if(READ_BIT(RCC->BDCR, RCC_BDCR_LSEON) == RCC_BDCR_LSEON) + 80090bc: f8d3 2090 ldr.w r2, [r3, #144] ; 0x90 + 80090c0: f012 0201 ands.w r2, r2, #1 + RCC_OscInitStruct->LSEState = RCC_LSE_ON; + 80090c4: bf18 it ne + 80090c6: 2201 movne r2, #1 + 80090c8: e7c2 b.n 8009050 + 80090ca: bf00 nop + 80090cc: 40021000 .word 0x40021000 + +080090d0 : + RCC_ClkInitStruct->ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; + 80090d0: 230f movs r3, #15 + 80090d2: 6003 str r3, [r0, #0] + RCC_ClkInitStruct->SYSCLKSource = READ_BIT(RCC->CFGR, RCC_CFGR_SW); + 80090d4: 4b0b ldr r3, [pc, #44] ; (8009104 ) + 80090d6: 689a ldr r2, [r3, #8] + 80090d8: f002 0203 and.w r2, r2, #3 + 80090dc: 6042 str r2, [r0, #4] + RCC_ClkInitStruct->AHBCLKDivider = READ_BIT(RCC->CFGR, RCC_CFGR_HPRE); + 80090de: 689a ldr r2, [r3, #8] + 80090e0: f002 02f0 and.w r2, r2, #240 ; 0xf0 + 80090e4: 6082 str r2, [r0, #8] + RCC_ClkInitStruct->APB1CLKDivider = READ_BIT(RCC->CFGR, RCC_CFGR_PPRE1); + 80090e6: 689a ldr r2, [r3, #8] + 80090e8: f402 62e0 and.w r2, r2, #1792 ; 0x700 + 80090ec: 60c2 str r2, [r0, #12] + RCC_ClkInitStruct->APB2CLKDivider = (READ_BIT(RCC->CFGR, RCC_CFGR_PPRE2) >> 3U); + 80090ee: 689b ldr r3, [r3, #8] + 80090f0: 08db lsrs r3, r3, #3 + 80090f2: f403 63e0 and.w r3, r3, #1792 ; 0x700 + 80090f6: 6103 str r3, [r0, #16] + *pFLatency = __HAL_FLASH_GET_LATENCY(); + 80090f8: 4b03 ldr r3, [pc, #12] ; (8009108 ) + 80090fa: 681b ldr r3, [r3, #0] + 80090fc: f003 030f and.w r3, r3, #15 + 8009100: 600b str r3, [r1, #0] +} + 8009102: 4770 bx lr + 8009104: 40021000 .word 0x40021000 + 8009108: 40022000 .word 0x40022000 + +0800910c : + SET_BIT(RCC->CR, RCC_CR_CSSON) ; + 800910c: 4a02 ldr r2, [pc, #8] ; (8009118 ) + 800910e: 6813 ldr r3, [r2, #0] + 8009110: f443 2300 orr.w r3, r3, #524288 ; 0x80000 + 8009114: 6013 str r3, [r2, #0] +} + 8009116: 4770 bx lr + 8009118: 40021000 .word 0x40021000 + +0800911c : +} + 800911c: 4770 bx lr + ... + +08009120 : +{ + 8009120: b510 push {r4, lr} + if(__HAL_RCC_GET_IT(RCC_IT_CSS)) + 8009122: 4c05 ldr r4, [pc, #20] ; (8009138 ) + 8009124: 69e3 ldr r3, [r4, #28] + 8009126: 05db lsls r3, r3, #23 + 8009128: d504 bpl.n 8009134 + HAL_RCC_CSSCallback(); + 800912a: f7ff fff7 bl 800911c + __HAL_RCC_CLEAR_IT(RCC_IT_CSS); + 800912e: f44f 7380 mov.w r3, #256 ; 0x100 + 8009132: 6223 str r3, [r4, #32] +} + 8009134: bd10 pop {r4, pc} + 8009136: bf00 nop + 8009138: 40021000 .word 0x40021000 + +0800913c : +#if defined(RCC_PLLP_SUPPORT) + uint32_t pllp = 0U; +#endif /* RCC_PLLP_SUPPORT */ + + /* Handle SAIs */ + if(PeriphClk == RCC_PERIPHCLK_SAI1) + 800913c: f5b0 6f00 cmp.w r0, #2048 ; 0x800 + 8009140: 4a3d ldr r2, [pc, #244] ; (8009238 ) + 8009142: d108 bne.n 8009156 + { + srcclk = __HAL_RCC_GET_SAI1_SOURCE(); + 8009144: f8d2 309c ldr.w r3, [r2, #156] ; 0x9c + 8009148: f003 03e0 and.w r3, r3, #224 ; 0xe0 + if(srcclk == RCC_SAI1CLKSOURCE_PIN) + 800914c: 2b60 cmp r3, #96 ; 0x60 + 800914e: d12d bne.n 80091ac + { + frequency = EXTERNAL_SAI1_CLOCK_VALUE; + 8009150: f64b 3080 movw r0, #48000 ; 0xbb80 + 8009154: 4770 bx lr + /* Else, PLL clock output to check below */ + } +#if defined(SAI2) + else + { + if(PeriphClk == RCC_PERIPHCLK_SAI2) + 8009156: f5b0 5f80 cmp.w r0, #4096 ; 0x1000 + 800915a: d12a bne.n 80091b2 + { + srcclk = __HAL_RCC_GET_SAI2_SOURCE(); + 800915c: f8d2 309c ldr.w r3, [r2, #156] ; 0x9c + 8009160: f403 63e0 and.w r3, r3, #1792 ; 0x700 + if(srcclk == RCC_SAI2CLKSOURCE_PIN) + 8009164: f5b3 7f40 cmp.w r3, #768 ; 0x300 + 8009168: d0f2 beq.n 8009150 + if(frequency == 0U) + { + pllvco = InputFrequency; + +#if defined(SAI2) + if((srcclk == RCC_SAI1CLKSOURCE_PLL) || (srcclk == RCC_SAI2CLKSOURCE_PLL)) + 800916a: f5b3 7f00 cmp.w r3, #512 ; 0x200 + 800916e: d15c bne.n 800922a + { + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLLRDY) && (__HAL_RCC_GET_PLLCLKOUT_CONFIG(RCC_PLL_SAI3CLK) != 0U)) + 8009170: 6810 ldr r0, [r2, #0] + 8009172: f010 7000 ands.w r0, r0, #33554432 ; 0x2000000 + 8009176: d05d beq.n 8009234 + 8009178: 68d0 ldr r0, [r2, #12] + 800917a: f410 3080 ands.w r0, r0, #65536 ; 0x10000 + 800917e: d059 beq.n 8009234 + { + /* f(PLL Source) / PLLM */ + pllvco = (pllvco / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009180: 68d0 ldr r0, [r2, #12] + 8009182: f3c0 1003 ubfx r0, r0, #4, #4 + 8009186: 3001 adds r0, #1 + 8009188: fbb1 f0f0 udiv r0, r1, r0 + /* f(PLLSAI3CLK) = f(VCO input) * PLLN / PLLP */ + plln = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos; + 800918c: 68d1 ldr r1, [r2, #12] +#if defined(RCC_PLLP_DIV_2_31_SUPPORT) + pllp = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLPDIV) >> RCC_PLLCFGR_PLLPDIV_Pos; + 800918e: 68d3 ldr r3, [r2, #12] +#endif + if(pllp == 0U) + 8009190: 0edb lsrs r3, r3, #27 + plln = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos; + 8009192: f3c1 2106 ubfx r1, r1, #8, #7 + if(pllp == 0U) + 8009196: d105 bne.n 80091a4 + { + if(READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLP) != 0U) + 8009198: 68d3 ldr r3, [r2, #12] + { + pllp = 17U; + } + else + { + pllp = 7U; + 800919a: f413 3f00 tst.w r3, #131072 ; 0x20000 + 800919e: bf14 ite ne + 80091a0: 2311 movne r3, #17 + 80091a2: 2307 moveq r3, #7 + } + } + frequency = (pllvco * plln) / pllp; + 80091a4: 4348 muls r0, r1 + 80091a6: fbb0 f0f3 udiv r0, r0, r3 + 80091aa: 4770 bx lr + if((srcclk == RCC_SAI1CLKSOURCE_PLL) || (srcclk == RCC_SAI2CLKSOURCE_PLL)) + 80091ac: 2b40 cmp r3, #64 ; 0x40 + 80091ae: d0df beq.n 8009170 + else if(srcclk == 0U) /* RCC_SAI1CLKSOURCE_PLLSAI1 || RCC_SAI2CLKSOURCE_PLLSAI1 */ + 80091b0: b9ab cbnz r3, 80091de + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLLSAI1RDY) && (__HAL_RCC_GET_PLLSAI1CLKOUT_CONFIG(RCC_PLLSAI1_SAI1CLK) != 0U)) + 80091b2: 6810 ldr r0, [r2, #0] + 80091b4: f010 6000 ands.w r0, r0, #134217728 ; 0x8000000 + 80091b8: d03c beq.n 8009234 + 80091ba: 6910 ldr r0, [r2, #16] + 80091bc: f410 3080 ands.w r0, r0, #65536 ; 0x10000 + 80091c0: d038 beq.n 8009234 + pllvco = (pllvco / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 80091c2: 6913 ldr r3, [r2, #16] + plln = READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1N) >> RCC_PLLSAI1CFGR_PLLSAI1N_Pos; + 80091c4: 6910 ldr r0, [r2, #16] + pllvco = (pllvco / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 80091c6: f3c3 1303 ubfx r3, r3, #4, #4 + 80091ca: 3301 adds r3, #1 + 80091cc: fbb1 f1f3 udiv r1, r1, r3 + pllp = READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1PDIV) >> RCC_PLLSAI1CFGR_PLLSAI1PDIV_Pos; + 80091d0: 6913 ldr r3, [r2, #16] + if(pllp == 0U) + 80091d2: 0edb lsrs r3, r3, #27 + plln = READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1N) >> RCC_PLLSAI1CFGR_PLLSAI1N_Pos; + 80091d4: f3c0 2006 ubfx r0, r0, #8, #7 + if(pllp == 0U) + 80091d8: d1e4 bne.n 80091a4 + if(READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1P) != 0U) + 80091da: 6913 ldr r3, [r2, #16] + 80091dc: e7dd b.n 800919a + else if((srcclk == RCC_SAI1CLKSOURCE_HSI) || (srcclk == RCC_SAI2CLKSOURCE_HSI)) + 80091de: 2b80 cmp r3, #128 ; 0x80 + 80091e0: d106 bne.n 80091f0 + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSIRDY)) + 80091e2: 6810 ldr r0, [r2, #0] + frequency = HSI_VALUE; + 80091e4: 4b15 ldr r3, [pc, #84] ; (800923c ) + 80091e6: f410 6080 ands.w r0, r0, #1024 ; 0x400 + 80091ea: bf18 it ne + 80091ec: 4618 movne r0, r3 + 80091ee: 4770 bx lr + else if((srcclk == RCC_SAI1CLKSOURCE_PLLSAI2) || (srcclk == RCC_SAI2CLKSOURCE_PLLSAI2)) + 80091f0: 2b20 cmp r3, #32 + 80091f2: d002 beq.n 80091fa + 80091f4: f5b3 7f80 cmp.w r3, #256 ; 0x100 + 80091f8: d115 bne.n 8009226 + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLLSAI2RDY) && (__HAL_RCC_GET_PLLSAI2CLKOUT_CONFIG(RCC_PLLSAI2_SAI2CLK) != 0U)) + 80091fa: 6810 ldr r0, [r2, #0] + 80091fc: f010 5000 ands.w r0, r0, #536870912 ; 0x20000000 + 8009200: d018 beq.n 8009234 + 8009202: 6950 ldr r0, [r2, #20] + 8009204: f410 3080 ands.w r0, r0, #65536 ; 0x10000 + 8009208: d014 beq.n 8009234 + pllvco = (pllvco / ((READ_BIT(RCC->PLLSAI2CFGR, RCC_PLLSAI2CFGR_PLLSAI2M) >> RCC_PLLSAI2CFGR_PLLSAI2M_Pos) + 1U)); + 800920a: 6953 ldr r3, [r2, #20] + 800920c: f3c3 1303 ubfx r3, r3, #4, #4 + 8009210: 3301 adds r3, #1 + 8009212: fbb1 f0f3 udiv r0, r1, r3 + plln = READ_BIT(RCC->PLLSAI2CFGR, RCC_PLLSAI2CFGR_PLLSAI2N) >> RCC_PLLSAI2CFGR_PLLSAI2N_Pos; + 8009216: 6951 ldr r1, [r2, #20] + pllp = READ_BIT(RCC->PLLSAI2CFGR, RCC_PLLSAI2CFGR_PLLSAI2PDIV) >> RCC_PLLSAI2CFGR_PLLSAI2PDIV_Pos; + 8009218: 6953 ldr r3, [r2, #20] + if(pllp == 0U) + 800921a: 0edb lsrs r3, r3, #27 + plln = READ_BIT(RCC->PLLSAI2CFGR, RCC_PLLSAI2CFGR_PLLSAI2N) >> RCC_PLLSAI2CFGR_PLLSAI2N_Pos; + 800921c: f3c1 2106 ubfx r1, r1, #8, #7 + if(pllp == 0U) + 8009220: d1c0 bne.n 80091a4 + if(READ_BIT(RCC->PLLSAI2CFGR, RCC_PLLSAI2CFGR_PLLSAI2P) != 0U) + 8009222: 6953 ldr r3, [r2, #20] + 8009224: e7b9 b.n 800919a + 8009226: 2000 movs r0, #0 + /* No clock source, frequency default init at 0 */ + } + } + + + return frequency; + 8009228: 4770 bx lr + else if(srcclk == 0U) /* RCC_SAI1CLKSOURCE_PLLSAI1 || RCC_SAI2CLKSOURCE_PLLSAI1 */ + 800922a: 2b00 cmp r3, #0 + 800922c: d0c1 beq.n 80091b2 + else if((srcclk == RCC_SAI1CLKSOURCE_HSI) || (srcclk == RCC_SAI2CLKSOURCE_HSI)) + 800922e: f5b3 6f80 cmp.w r3, #1024 ; 0x400 + 8009232: e7d5 b.n 80091e0 +} + 8009234: 4770 bx lr + 8009236: bf00 nop + 8009238: 40021000 .word 0x40021000 + 800923c: 00f42400 .word 0x00f42400 + +08009240 : +{ + 8009240: b5f8 push {r3, r4, r5, r6, r7, lr} + if(__HAL_RCC_GET_PLL_OSCSOURCE() != RCC_PLLSOURCE_NONE) + 8009242: 4c3c ldr r4, [pc, #240] ; (8009334 ) + if((__HAL_RCC_GET_PLL_OSCSOURCE() != PllSai1->PLLSAI1Source) + 8009244: 6803 ldr r3, [r0, #0] + if(__HAL_RCC_GET_PLL_OSCSOURCE() != RCC_PLLSOURCE_NONE) + 8009246: 68e2 ldr r2, [r4, #12] +{ + 8009248: 4605 mov r5, r0 + if(__HAL_RCC_GET_PLL_OSCSOURCE() != RCC_PLLSOURCE_NONE) + 800924a: 0790 lsls r0, r2, #30 +{ + 800924c: 460f mov r7, r1 + if(__HAL_RCC_GET_PLL_OSCSOURCE() != RCC_PLLSOURCE_NONE) + 800924e: d023 beq.n 8009298 + if((__HAL_RCC_GET_PLL_OSCSOURCE() != PllSai1->PLLSAI1Source) + 8009250: 68e2 ldr r2, [r4, #12] + 8009252: f002 0203 and.w r2, r2, #3 + 8009256: 429a cmp r2, r3 + 8009258: d16a bne.n 8009330 + || + 800925a: 2a00 cmp r2, #0 + 800925c: d068 beq.n 8009330 + __HAL_RCC_PLLSAI1_DISABLE(); + 800925e: 6823 ldr r3, [r4, #0] + 8009260: f023 6380 bic.w r3, r3, #67108864 ; 0x4000000 + 8009264: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 8009266: f7fd ff41 bl 80070ec + 800926a: 4606 mov r6, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI1RDY) != 0U) + 800926c: 6823 ldr r3, [r4, #0] + 800926e: 011a lsls r2, r3, #4 + 8009270: d42d bmi.n 80092ce + MODIFY_REG(RCC->PLLSAI1CFGR, + 8009272: 68ab ldr r3, [r5, #8] + 8009274: 021e lsls r6, r3, #8 + 8009276: 686b ldr r3, [r5, #4] + 8009278: 3b01 subs r3, #1 + 800927a: 0118 lsls r0, r3, #4 + if(Divider == DIVIDER_P_UPDATE) + 800927c: b377 cbz r7, 80092dc + else if(Divider == DIVIDER_Q_UPDATE) + 800927e: 2f01 cmp r7, #1 + 8009280: d145 bne.n 800930e + MODIFY_REG(RCC->PLLSAI1CFGR, + 8009282: 692b ldr r3, [r5, #16] + 8009284: 6927 ldr r7, [r4, #16] + 8009286: 085b lsrs r3, r3, #1 + 8009288: 1e59 subs r1, r3, #1 + 800928a: 4b2b ldr r3, [pc, #172] ; (8009338 ) + 800928c: 403b ands r3, r7 + 800928e: 4333 orrs r3, r6 + 8009290: 4303 orrs r3, r0 + 8009292: ea43 5341 orr.w r3, r3, r1, lsl #21 + 8009296: e029 b.n 80092ec + switch(PllSai1->PLLSAI1Source) + 8009298: 2b02 cmp r3, #2 + 800929a: d00d beq.n 80092b8 + 800929c: 2b03 cmp r3, #3 + 800929e: d00f beq.n 80092c0 + 80092a0: 2b01 cmp r3, #1 + 80092a2: d145 bne.n 8009330 + if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_MSIRDY)) + 80092a4: 6822 ldr r2, [r4, #0] + 80092a6: f012 0f02 tst.w r2, #2 + if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_HSEBYP)) + 80092aa: d041 beq.n 8009330 + MODIFY_REG(RCC->PLLCFGR, RCC_PLLCFGR_PLLSRC, PllSai1->PLLSAI1Source); + 80092ac: 68e0 ldr r0, [r4, #12] + 80092ae: f020 0003 bic.w r0, r0, #3 + 80092b2: 4318 orrs r0, r3 + 80092b4: 60e0 str r0, [r4, #12] + if(status == HAL_OK) + 80092b6: e7d2 b.n 800925e + if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_HSIRDY)) + 80092b8: 6822 ldr r2, [r4, #0] + 80092ba: f412 6f80 tst.w r2, #1024 ; 0x400 + 80092be: e7f4 b.n 80092aa + if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_HSERDY)) + 80092c0: 6822 ldr r2, [r4, #0] + 80092c2: 0391 lsls r1, r2, #14 + 80092c4: d4f2 bmi.n 80092ac + if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_HSEBYP)) + 80092c6: 6822 ldr r2, [r4, #0] + 80092c8: f412 2f80 tst.w r2, #262144 ; 0x40000 + 80092cc: e7ed b.n 80092aa + if((HAL_GetTick() - tickstart) > PLLSAI1_TIMEOUT_VALUE) + 80092ce: f7fd ff0d bl 80070ec + 80092d2: 1b80 subs r0, r0, r6 + 80092d4: 2802 cmp r0, #2 + 80092d6: d9c9 bls.n 800926c + status = HAL_TIMEOUT; + 80092d8: 2003 movs r0, #3 +} + 80092da: bdf8 pop {r3, r4, r5, r6, r7, pc} + MODIFY_REG(RCC->PLLSAI1CFGR, + 80092dc: 68e9 ldr r1, [r5, #12] + 80092de: 6922 ldr r2, [r4, #16] + 80092e0: ea46 63c1 orr.w r3, r6, r1, lsl #27 + 80092e4: 4915 ldr r1, [pc, #84] ; (800933c ) + 80092e6: 4011 ands r1, r2 + 80092e8: 430b orrs r3, r1 + 80092ea: 4303 orrs r3, r0 + MODIFY_REG(RCC->PLLSAI1CFGR, + 80092ec: 6123 str r3, [r4, #16] + __HAL_RCC_PLLSAI1_ENABLE(); + 80092ee: 6823 ldr r3, [r4, #0] + 80092f0: f043 6380 orr.w r3, r3, #67108864 ; 0x4000000 + 80092f4: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 80092f6: f7fd fef9 bl 80070ec + 80092fa: 4606 mov r6, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI1RDY) == 0U) + 80092fc: 6823 ldr r3, [r4, #0] + 80092fe: 011b lsls r3, r3, #4 + 8009300: d510 bpl.n 8009324 + __HAL_RCC_PLLSAI1CLKOUT_ENABLE(PllSai1->PLLSAI1ClockOut); + 8009302: 6923 ldr r3, [r4, #16] + 8009304: 69aa ldr r2, [r5, #24] + 8009306: 4313 orrs r3, r2 + 8009308: 6123 str r3, [r4, #16] + 800930a: 2000 movs r0, #0 + return status; + 800930c: e7e5 b.n 80092da + MODIFY_REG(RCC->PLLSAI1CFGR, + 800930e: 696b ldr r3, [r5, #20] + 8009310: 6921 ldr r1, [r4, #16] + 8009312: 085b lsrs r3, r3, #1 + 8009314: 1e5a subs r2, r3, #1 + 8009316: 4b0a ldr r3, [pc, #40] ; (8009340 ) + 8009318: 400b ands r3, r1 + 800931a: 4333 orrs r3, r6 + 800931c: 4303 orrs r3, r0 + 800931e: ea43 6342 orr.w r3, r3, r2, lsl #25 + 8009322: e7e3 b.n 80092ec + if((HAL_GetTick() - tickstart) > PLLSAI1_TIMEOUT_VALUE) + 8009324: f7fd fee2 bl 80070ec + 8009328: 1b80 subs r0, r0, r6 + 800932a: 2802 cmp r0, #2 + 800932c: d9e6 bls.n 80092fc + 800932e: e7d3 b.n 80092d8 + status = HAL_ERROR; + 8009330: 2001 movs r0, #1 + 8009332: e7d2 b.n 80092da + 8009334: 40021000 .word 0x40021000 + 8009338: ff9f800f .word 0xff9f800f + 800933c: 07ff800f .word 0x07ff800f + 8009340: f9ff800f .word 0xf9ff800f + +08009344 : +static HAL_StatusTypeDef RCCEx_PLLSAI2_Config(RCC_PLLSAI2InitTypeDef *PllSai2, uint32_t Divider) + 8009344: b570 push {r4, r5, r6, lr} + if(__HAL_RCC_GET_PLL_OSCSOURCE() != RCC_PLLSOURCE_NONE) + 8009346: 4c2f ldr r4, [pc, #188] ; (8009404 ) + if((__HAL_RCC_GET_PLL_OSCSOURCE() != PllSai2->PLLSAI2Source) + 8009348: 6803 ldr r3, [r0, #0] + if(__HAL_RCC_GET_PLL_OSCSOURCE() != RCC_PLLSOURCE_NONE) + 800934a: 68e2 ldr r2, [r4, #12] +static HAL_StatusTypeDef RCCEx_PLLSAI2_Config(RCC_PLLSAI2InitTypeDef *PllSai2, uint32_t Divider) + 800934c: 4605 mov r5, r0 + if(__HAL_RCC_GET_PLL_OSCSOURCE() != RCC_PLLSOURCE_NONE) + 800934e: 0790 lsls r0, r2, #30 + 8009350: d026 beq.n 80093a0 + if((__HAL_RCC_GET_PLL_OSCSOURCE() != PllSai2->PLLSAI2Source) + 8009352: 68e2 ldr r2, [r4, #12] + 8009354: f002 0203 and.w r2, r2, #3 + 8009358: 429a cmp r2, r3 + 800935a: d151 bne.n 8009400 + || + 800935c: 2a00 cmp r2, #0 + 800935e: d04f beq.n 8009400 + __HAL_RCC_PLLSAI2_DISABLE(); + 8009360: 6823 ldr r3, [r4, #0] + 8009362: f023 5380 bic.w r3, r3, #268435456 ; 0x10000000 + 8009366: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 8009368: f7fd fec0 bl 80070ec + 800936c: 4606 mov r6, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI2RDY) != 0U) + 800936e: 6823 ldr r3, [r4, #0] + 8009370: 009a lsls r2, r3, #2 + 8009372: d430 bmi.n 80093d6 + MODIFY_REG(RCC->PLLSAI2CFGR, + 8009374: e9d5 2302 ldrd r2, r3, [r5, #8] + 8009378: 06db lsls r3, r3, #27 + 800937a: 6961 ldr r1, [r4, #20] + 800937c: ea43 2302 orr.w r3, r3, r2, lsl #8 + 8009380: 4a21 ldr r2, [pc, #132] ; (8009408 ) + 8009382: 400a ands r2, r1 + 8009384: 4313 orrs r3, r2 + 8009386: 686a ldr r2, [r5, #4] + 8009388: 3a01 subs r2, #1 + 800938a: ea43 1302 orr.w r3, r3, r2, lsl #4 + 800938e: 6163 str r3, [r4, #20] + __HAL_RCC_PLLSAI2_ENABLE(); + 8009390: 6823 ldr r3, [r4, #0] + 8009392: f043 5380 orr.w r3, r3, #268435456 ; 0x10000000 + 8009396: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 8009398: f7fd fea8 bl 80070ec + 800939c: 4606 mov r6, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI2RDY) == 0U) + 800939e: e026 b.n 80093ee + switch(PllSai2->PLLSAI2Source) + 80093a0: 2b02 cmp r3, #2 + 80093a2: d00d beq.n 80093c0 + 80093a4: 2b03 cmp r3, #3 + 80093a6: d00f beq.n 80093c8 + 80093a8: 2b01 cmp r3, #1 + 80093aa: d129 bne.n 8009400 + if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_MSIRDY)) + 80093ac: 6822 ldr r2, [r4, #0] + 80093ae: f012 0f02 tst.w r2, #2 + if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_HSEBYP)) + 80093b2: d025 beq.n 8009400 + MODIFY_REG(RCC->PLLCFGR, RCC_PLLCFGR_PLLSRC, PllSai2->PLLSAI2Source); + 80093b4: 68e0 ldr r0, [r4, #12] + 80093b6: f020 0003 bic.w r0, r0, #3 + 80093ba: 4318 orrs r0, r3 + 80093bc: 60e0 str r0, [r4, #12] + if(status == HAL_OK) + 80093be: e7cf b.n 8009360 + if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_HSIRDY)) + 80093c0: 6822 ldr r2, [r4, #0] + 80093c2: f412 6f80 tst.w r2, #1024 ; 0x400 + 80093c6: e7f4 b.n 80093b2 + if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_HSERDY)) + 80093c8: 6822 ldr r2, [r4, #0] + 80093ca: 0391 lsls r1, r2, #14 + 80093cc: d4f2 bmi.n 80093b4 + if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_HSEBYP)) + 80093ce: 6822 ldr r2, [r4, #0] + 80093d0: f412 2f80 tst.w r2, #262144 ; 0x40000 + 80093d4: e7ed b.n 80093b2 + if((HAL_GetTick() - tickstart) > PLLSAI2_TIMEOUT_VALUE) + 80093d6: f7fd fe89 bl 80070ec + 80093da: 1b80 subs r0, r0, r6 + 80093dc: 2802 cmp r0, #2 + 80093de: d9c6 bls.n 800936e + status = HAL_TIMEOUT; + 80093e0: 2003 movs r0, #3 +} + 80093e2: bd70 pop {r4, r5, r6, pc} + if((HAL_GetTick() - tickstart) > PLLSAI2_TIMEOUT_VALUE) + 80093e4: f7fd fe82 bl 80070ec + 80093e8: 1b80 subs r0, r0, r6 + 80093ea: 2802 cmp r0, #2 + 80093ec: d8f8 bhi.n 80093e0 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI2RDY) == 0U) + 80093ee: 6823 ldr r3, [r4, #0] + 80093f0: 009b lsls r3, r3, #2 + 80093f2: d5f7 bpl.n 80093e4 + __HAL_RCC_PLLSAI2CLKOUT_ENABLE(PllSai2->PLLSAI2ClockOut); + 80093f4: 6963 ldr r3, [r4, #20] + 80093f6: 69aa ldr r2, [r5, #24] + 80093f8: 4313 orrs r3, r2 + 80093fa: 6163 str r3, [r4, #20] + 80093fc: 2000 movs r0, #0 + return status; + 80093fe: e7f0 b.n 80093e2 + status = HAL_ERROR; + 8009400: 2001 movs r0, #1 + 8009402: e7ee b.n 80093e2 + 8009404: 40021000 .word 0x40021000 + 8009408: 07ff800f .word 0x07ff800f + +0800940c : +{ + 800940c: e92d 47f3 stmdb sp!, {r0, r1, r4, r5, r6, r7, r8, r9, sl, lr} + if((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAI1) == RCC_PERIPHCLK_SAI1)) + 8009410: 6806 ldr r6, [r0, #0] + 8009412: f416 6600 ands.w r6, r6, #2048 ; 0x800 +{ + 8009416: 4604 mov r4, r0 + if((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAI1) == RCC_PERIPHCLK_SAI1)) + 8009418: d007 beq.n 800942a + switch(PeriphClkInit->Sai1ClockSelection) + 800941a: 6ec1 ldr r1, [r0, #108] ; 0x6c + 800941c: 2940 cmp r1, #64 ; 0x40 + 800941e: d022 beq.n 8009466 + 8009420: d812 bhi.n 8009448 + 8009422: b331 cbz r1, 8009472 + 8009424: 2920 cmp r1, #32 + 8009426: d02b beq.n 8009480 + 8009428: 2601 movs r6, #1 + if((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAI2) == RCC_PERIPHCLK_SAI2)) + 800942a: 6823 ldr r3, [r4, #0] + 800942c: 04db lsls r3, r3, #19 + 800942e: d509 bpl.n 8009444 + switch(PeriphClkInit->Sai2ClockSelection) + 8009430: 6f21 ldr r1, [r4, #112] ; 0x70 + 8009432: f5b1 7f00 cmp.w r1, #512 ; 0x200 + 8009436: d02f beq.n 8009498 + 8009438: d826 bhi.n 8009488 + 800943a: b399 cbz r1, 80094a4 + 800943c: f5b1 7f80 cmp.w r1, #256 ; 0x100 + 8009440: d073 beq.n 800952a + 8009442: 2601 movs r6, #1 + 8009444: 4635 mov r5, r6 + 8009446: e03c b.n 80094c2 + switch(PeriphClkInit->Sai1ClockSelection) + 8009448: 2960 cmp r1, #96 ; 0x60 + 800944a: d001 beq.n 8009450 + 800944c: 2980 cmp r1, #128 ; 0x80 + 800944e: d1eb bne.n 8009428 + __HAL_RCC_SAI1_CONFIG(PeriphClkInit->Sai1ClockSelection); + 8009450: 4a3b ldr r2, [pc, #236] ; (8009540 ) + 8009452: 6ee1 ldr r1, [r4, #108] ; 0x6c + 8009454: f8d2 309c ldr.w r3, [r2, #156] ; 0x9c + 8009458: f023 03e0 bic.w r3, r3, #224 ; 0xe0 + 800945c: 430b orrs r3, r1 + 800945e: f8c2 309c str.w r3, [r2, #156] ; 0x9c + 8009462: 2600 movs r6, #0 + 8009464: e7e1 b.n 800942a + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL_SAI3CLK); + 8009466: 4a36 ldr r2, [pc, #216] ; (8009540 ) + 8009468: 68d3 ldr r3, [r2, #12] + 800946a: f443 3380 orr.w r3, r3, #65536 ; 0x10000 + 800946e: 60d3 str r3, [r2, #12] + if(ret == HAL_OK) + 8009470: e7ee b.n 8009450 + ret = RCCEx_PLLSAI1_Config(&(PeriphClkInit->PLLSAI1), DIVIDER_P_UPDATE); + 8009472: 3004 adds r0, #4 + 8009474: f7ff fee4 bl 8009240 + ret = RCCEx_PLLSAI2_Config(&(PeriphClkInit->PLLSAI2), DIVIDER_P_UPDATE); + 8009478: 4606 mov r6, r0 + if(ret == HAL_OK) + 800947a: 2800 cmp r0, #0 + 800947c: d1d5 bne.n 800942a + 800947e: e7e7 b.n 8009450 + ret = RCCEx_PLLSAI2_Config(&(PeriphClkInit->PLLSAI2), DIVIDER_P_UPDATE); + 8009480: 3020 adds r0, #32 + 8009482: f7ff ff5f bl 8009344 + 8009486: e7f7 b.n 8009478 + switch(PeriphClkInit->Sai2ClockSelection) + 8009488: f5b1 7f40 cmp.w r1, #768 ; 0x300 + 800948c: d002 beq.n 8009494 + 800948e: f5b1 6f80 cmp.w r1, #1024 ; 0x400 + 8009492: d1d6 bne.n 8009442 + 8009494: 4635 mov r5, r6 + 8009496: e009 b.n 80094ac + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL_SAI3CLK); + 8009498: 4a29 ldr r2, [pc, #164] ; (8009540 ) + 800949a: 68d3 ldr r3, [r2, #12] + 800949c: f443 3380 orr.w r3, r3, #65536 ; 0x10000 + 80094a0: 60d3 str r3, [r2, #12] + break; + 80094a2: e7f7 b.n 8009494 + ret = RCCEx_PLLSAI1_Config(&(PeriphClkInit->PLLSAI1), DIVIDER_P_UPDATE); + 80094a4: 1d20 adds r0, r4, #4 + 80094a6: f7ff fecb bl 8009240 + ret = RCCEx_PLLSAI2_Config(&(PeriphClkInit->PLLSAI2), DIVIDER_P_UPDATE); + 80094aa: 4605 mov r5, r0 + if(ret == HAL_OK) + 80094ac: 2d00 cmp r5, #0 + 80094ae: d141 bne.n 8009534 + __HAL_RCC_SAI2_CONFIG(PeriphClkInit->Sai2ClockSelection); + 80094b0: 4a23 ldr r2, [pc, #140] ; (8009540 ) + 80094b2: 6f21 ldr r1, [r4, #112] ; 0x70 + 80094b4: f8d2 309c ldr.w r3, [r2, #156] ; 0x9c + 80094b8: f423 63e0 bic.w r3, r3, #1792 ; 0x700 + 80094bc: 430b orrs r3, r1 + 80094be: f8c2 309c str.w r3, [r2, #156] ; 0x9c + if((PeriphClkInit->PeriphClockSelection & RCC_PERIPHCLK_RTC) == RCC_PERIPHCLK_RTC) + 80094c2: 6823 ldr r3, [r4, #0] + 80094c4: 039f lsls r7, r3, #14 + 80094c6: f140 817d bpl.w 80097c4 + if(__HAL_RCC_PWR_IS_CLK_DISABLED() != 0U) + 80094ca: 4f1d ldr r7, [pc, #116] ; (8009540 ) + 80094cc: 6dbb ldr r3, [r7, #88] ; 0x58 + 80094ce: 00d8 lsls r0, r3, #3 + 80094d0: d432 bmi.n 8009538 + __HAL_RCC_PWR_CLK_ENABLE(); + 80094d2: 6dbb ldr r3, [r7, #88] ; 0x58 + 80094d4: f043 5380 orr.w r3, r3, #268435456 ; 0x10000000 + 80094d8: 65bb str r3, [r7, #88] ; 0x58 + 80094da: 6dbb ldr r3, [r7, #88] ; 0x58 + 80094dc: f003 5380 and.w r3, r3, #268435456 ; 0x10000000 + 80094e0: 9301 str r3, [sp, #4] + 80094e2: 9b01 ldr r3, [sp, #4] + pwrclkchanged = SET; + 80094e4: f04f 0801 mov.w r8, #1 + SET_BIT(PWR->CR1, PWR_CR1_DBP); + 80094e8: f8df 9058 ldr.w r9, [pc, #88] ; 8009544 + 80094ec: f8d9 3000 ldr.w r3, [r9] + 80094f0: f443 7380 orr.w r3, r3, #256 ; 0x100 + 80094f4: f8c9 3000 str.w r3, [r9] + tickstart = HAL_GetTick(); + 80094f8: f7fd fdf8 bl 80070ec + 80094fc: 4682 mov sl, r0 + while(READ_BIT(PWR->CR1, PWR_CR1_DBP) == 0U) + 80094fe: f8d9 3000 ldr.w r3, [r9] + 8009502: 05d9 lsls r1, r3, #23 + 8009504: d520 bpl.n 8009548 + if(ret == HAL_OK) + 8009506: bb35 cbnz r5, 8009556 + tmpregister = READ_BIT(RCC->BDCR, RCC_BDCR_RTCSEL); + 8009508: f8d7 3090 ldr.w r3, [r7, #144] ; 0x90 + if((tmpregister != RCC_RTCCLKSOURCE_NONE) && (tmpregister != PeriphClkInit->RTCClockSelection)) + 800950c: f413 7340 ands.w r3, r3, #768 ; 0x300 + 8009510: f040 812e bne.w 8009770 + __HAL_RCC_RTC_CONFIG(PeriphClkInit->RTCClockSelection); + 8009514: f8d7 3090 ldr.w r3, [r7, #144] ; 0x90 + 8009518: f8d4 2090 ldr.w r2, [r4, #144] ; 0x90 + 800951c: f423 7340 bic.w r3, r3, #768 ; 0x300 + 8009520: 4313 orrs r3, r2 + 8009522: f8c7 3090 str.w r3, [r7, #144] ; 0x90 + 8009526: 4635 mov r5, r6 + 8009528: e015 b.n 8009556 + ret = RCCEx_PLLSAI2_Config(&(PeriphClkInit->PLLSAI2), DIVIDER_P_UPDATE); + 800952a: f104 0020 add.w r0, r4, #32 + 800952e: f7ff ff09 bl 8009344 + 8009532: e7ba b.n 80094aa + 8009534: 462e mov r6, r5 + 8009536: e7c4 b.n 80094c2 + FlagStatus pwrclkchanged = RESET; + 8009538: f04f 0800 mov.w r8, #0 + 800953c: e7d4 b.n 80094e8 + 800953e: bf00 nop + 8009540: 40021000 .word 0x40021000 + 8009544: 40007000 .word 0x40007000 + if((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE) + 8009548: f7fd fdd0 bl 80070ec + 800954c: eba0 000a sub.w r0, r0, sl + 8009550: 2802 cmp r0, #2 + 8009552: d9d4 bls.n 80094fe + ret = HAL_TIMEOUT; + 8009554: 2503 movs r5, #3 + if(pwrclkchanged == SET) + 8009556: f1b8 0f00 cmp.w r8, #0 + 800955a: d003 beq.n 8009564 + __HAL_RCC_PWR_CLK_DISABLE(); + 800955c: 6dbb ldr r3, [r7, #88] ; 0x58 + 800955e: f023 5380 bic.w r3, r3, #268435456 ; 0x10000000 + 8009562: 65bb str r3, [r7, #88] ; 0x58 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_USART1) == RCC_PERIPHCLK_USART1) + 8009564: 6823 ldr r3, [r4, #0] + 8009566: 07d8 lsls r0, r3, #31 + 8009568: d508 bpl.n 800957c + __HAL_RCC_USART1_CONFIG(PeriphClkInit->Usart1ClockSelection); + 800956a: 49b2 ldr r1, [pc, #712] ; (8009834 ) + 800956c: 6be0 ldr r0, [r4, #60] ; 0x3c + 800956e: f8d1 2088 ldr.w r2, [r1, #136] ; 0x88 + 8009572: f022 0203 bic.w r2, r2, #3 + 8009576: 4302 orrs r2, r0 + 8009578: f8c1 2088 str.w r2, [r1, #136] ; 0x88 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_USART2) == RCC_PERIPHCLK_USART2) + 800957c: 0799 lsls r1, r3, #30 + 800957e: d508 bpl.n 8009592 + __HAL_RCC_USART2_CONFIG(PeriphClkInit->Usart2ClockSelection); + 8009580: 49ac ldr r1, [pc, #688] ; (8009834 ) + 8009582: 6c20 ldr r0, [r4, #64] ; 0x40 + 8009584: f8d1 2088 ldr.w r2, [r1, #136] ; 0x88 + 8009588: f022 020c bic.w r2, r2, #12 + 800958c: 4302 orrs r2, r0 + 800958e: f8c1 2088 str.w r2, [r1, #136] ; 0x88 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_USART3) == RCC_PERIPHCLK_USART3) + 8009592: 075a lsls r2, r3, #29 + 8009594: d508 bpl.n 80095a8 + __HAL_RCC_USART3_CONFIG(PeriphClkInit->Usart3ClockSelection); + 8009596: 49a7 ldr r1, [pc, #668] ; (8009834 ) + 8009598: 6c60 ldr r0, [r4, #68] ; 0x44 + 800959a: f8d1 2088 ldr.w r2, [r1, #136] ; 0x88 + 800959e: f022 0230 bic.w r2, r2, #48 ; 0x30 + 80095a2: 4302 orrs r2, r0 + 80095a4: f8c1 2088 str.w r2, [r1, #136] ; 0x88 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_UART4) == RCC_PERIPHCLK_UART4) + 80095a8: 071f lsls r7, r3, #28 + 80095aa: d508 bpl.n 80095be + __HAL_RCC_UART4_CONFIG(PeriphClkInit->Uart4ClockSelection); + 80095ac: 49a1 ldr r1, [pc, #644] ; (8009834 ) + 80095ae: 6ca0 ldr r0, [r4, #72] ; 0x48 + 80095b0: f8d1 2088 ldr.w r2, [r1, #136] ; 0x88 + 80095b4: f022 02c0 bic.w r2, r2, #192 ; 0xc0 + 80095b8: 4302 orrs r2, r0 + 80095ba: f8c1 2088 str.w r2, [r1, #136] ; 0x88 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_UART5) == RCC_PERIPHCLK_UART5) + 80095be: 06de lsls r6, r3, #27 + 80095c0: d508 bpl.n 80095d4 + __HAL_RCC_UART5_CONFIG(PeriphClkInit->Uart5ClockSelection); + 80095c2: 499c ldr r1, [pc, #624] ; (8009834 ) + 80095c4: 6ce0 ldr r0, [r4, #76] ; 0x4c + 80095c6: f8d1 2088 ldr.w r2, [r1, #136] ; 0x88 + 80095ca: f422 7240 bic.w r2, r2, #768 ; 0x300 + 80095ce: 4302 orrs r2, r0 + 80095d0: f8c1 2088 str.w r2, [r1, #136] ; 0x88 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_LPUART1) == RCC_PERIPHCLK_LPUART1) + 80095d4: 0698 lsls r0, r3, #26 + 80095d6: d508 bpl.n 80095ea + __HAL_RCC_LPUART1_CONFIG(PeriphClkInit->Lpuart1ClockSelection); + 80095d8: 4996 ldr r1, [pc, #600] ; (8009834 ) + 80095da: 6d20 ldr r0, [r4, #80] ; 0x50 + 80095dc: f8d1 2088 ldr.w r2, [r1, #136] ; 0x88 + 80095e0: f422 6240 bic.w r2, r2, #3072 ; 0xc00 + 80095e4: 4302 orrs r2, r0 + 80095e6: f8c1 2088 str.w r2, [r1, #136] ; 0x88 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_LPTIM1) == (RCC_PERIPHCLK_LPTIM1)) + 80095ea: 0599 lsls r1, r3, #22 + 80095ec: d508 bpl.n 8009600 + __HAL_RCC_LPTIM1_CONFIG(PeriphClkInit->Lptim1ClockSelection); + 80095ee: 4991 ldr r1, [pc, #580] ; (8009834 ) + 80095f0: 6e60 ldr r0, [r4, #100] ; 0x64 + 80095f2: f8d1 2088 ldr.w r2, [r1, #136] ; 0x88 + 80095f6: f422 2240 bic.w r2, r2, #786432 ; 0xc0000 + 80095fa: 4302 orrs r2, r0 + 80095fc: f8c1 2088 str.w r2, [r1, #136] ; 0x88 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_LPTIM2) == (RCC_PERIPHCLK_LPTIM2)) + 8009600: 055a lsls r2, r3, #21 + 8009602: d508 bpl.n 8009616 + __HAL_RCC_LPTIM2_CONFIG(PeriphClkInit->Lptim2ClockSelection); + 8009604: 498b ldr r1, [pc, #556] ; (8009834 ) + 8009606: 6ea0 ldr r0, [r4, #104] ; 0x68 + 8009608: f8d1 2088 ldr.w r2, [r1, #136] ; 0x88 + 800960c: f422 1240 bic.w r2, r2, #3145728 ; 0x300000 + 8009610: 4302 orrs r2, r0 + 8009612: f8c1 2088 str.w r2, [r1, #136] ; 0x88 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2C1) == RCC_PERIPHCLK_I2C1) + 8009616: 065f lsls r7, r3, #25 + 8009618: d508 bpl.n 800962c + __HAL_RCC_I2C1_CONFIG(PeriphClkInit->I2c1ClockSelection); + 800961a: 4986 ldr r1, [pc, #536] ; (8009834 ) + 800961c: 6d60 ldr r0, [r4, #84] ; 0x54 + 800961e: f8d1 2088 ldr.w r2, [r1, #136] ; 0x88 + 8009622: f422 5240 bic.w r2, r2, #12288 ; 0x3000 + 8009626: 4302 orrs r2, r0 + 8009628: f8c1 2088 str.w r2, [r1, #136] ; 0x88 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2C2) == RCC_PERIPHCLK_I2C2) + 800962c: 061e lsls r6, r3, #24 + 800962e: d508 bpl.n 8009642 + __HAL_RCC_I2C2_CONFIG(PeriphClkInit->I2c2ClockSelection); + 8009630: 4980 ldr r1, [pc, #512] ; (8009834 ) + 8009632: 6da0 ldr r0, [r4, #88] ; 0x58 + 8009634: f8d1 2088 ldr.w r2, [r1, #136] ; 0x88 + 8009638: f422 4240 bic.w r2, r2, #49152 ; 0xc000 + 800963c: 4302 orrs r2, r0 + 800963e: f8c1 2088 str.w r2, [r1, #136] ; 0x88 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2C3) == RCC_PERIPHCLK_I2C3) + 8009642: 05d8 lsls r0, r3, #23 + 8009644: d508 bpl.n 8009658 + __HAL_RCC_I2C3_CONFIG(PeriphClkInit->I2c3ClockSelection); + 8009646: 497b ldr r1, [pc, #492] ; (8009834 ) + 8009648: 6de0 ldr r0, [r4, #92] ; 0x5c + 800964a: f8d1 2088 ldr.w r2, [r1, #136] ; 0x88 + 800964e: f422 3240 bic.w r2, r2, #196608 ; 0x30000 + 8009652: 4302 orrs r2, r0 + 8009654: f8c1 2088 str.w r2, [r1, #136] ; 0x88 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2C4) == RCC_PERIPHCLK_I2C4) + 8009658: 02d9 lsls r1, r3, #11 + 800965a: d508 bpl.n 800966e + __HAL_RCC_I2C4_CONFIG(PeriphClkInit->I2c4ClockSelection); + 800965c: 4975 ldr r1, [pc, #468] ; (8009834 ) + 800965e: 6e20 ldr r0, [r4, #96] ; 0x60 + 8009660: f8d1 209c ldr.w r2, [r1, #156] ; 0x9c + 8009664: f022 0203 bic.w r2, r2, #3 + 8009668: 4302 orrs r2, r0 + 800966a: f8c1 209c str.w r2, [r1, #156] ; 0x9c + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_USB) == (RCC_PERIPHCLK_USB)) + 800966e: 049a lsls r2, r3, #18 + 8009670: d510 bpl.n 8009694 + __HAL_RCC_USB_CONFIG(PeriphClkInit->UsbClockSelection); + 8009672: 4a70 ldr r2, [pc, #448] ; (8009834 ) + 8009674: 6f61 ldr r1, [r4, #116] ; 0x74 + 8009676: f8d2 3088 ldr.w r3, [r2, #136] ; 0x88 + 800967a: f023 6340 bic.w r3, r3, #201326592 ; 0xc000000 + 800967e: 430b orrs r3, r1 + if(PeriphClkInit->UsbClockSelection == RCC_USBCLKSOURCE_PLL) + 8009680: f1b1 6f00 cmp.w r1, #134217728 ; 0x8000000 + __HAL_RCC_USB_CONFIG(PeriphClkInit->UsbClockSelection); + 8009684: f8c2 3088 str.w r3, [r2, #136] ; 0x88 + if(PeriphClkInit->UsbClockSelection == RCC_USBCLKSOURCE_PLL) + 8009688: f040 809e bne.w 80097c8 + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL_48M1CLK); + 800968c: 68d3 ldr r3, [r2, #12] + 800968e: f443 1380 orr.w r3, r3, #1048576 ; 0x100000 + 8009692: 60d3 str r3, [r2, #12] + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SDMMC1) == (RCC_PERIPHCLK_SDMMC1)) + 8009694: 6823 ldr r3, [r4, #0] + 8009696: 031b lsls r3, r3, #12 + 8009698: d50f bpl.n 80096ba + __HAL_RCC_SDMMC1_CONFIG(PeriphClkInit->Sdmmc1ClockSelection); + 800969a: 6fa1 ldr r1, [r4, #120] ; 0x78 + 800969c: 4b65 ldr r3, [pc, #404] ; (8009834 ) + 800969e: f5b1 4f80 cmp.w r1, #16384 ; 0x4000 + 80096a2: f8d3 209c ldr.w r2, [r3, #156] ; 0x9c + 80096a6: f040 809b bne.w 80097e0 + 80096aa: f442 4280 orr.w r2, r2, #16384 ; 0x4000 + 80096ae: f8c3 209c str.w r2, [r3, #156] ; 0x9c + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL_SAI3CLK); + 80096b2: 68da ldr r2, [r3, #12] + 80096b4: f442 3280 orr.w r2, r2, #65536 ; 0x10000 + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL_48M1CLK); + 80096b8: 60da str r2, [r3, #12] + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_RNG) == (RCC_PERIPHCLK_RNG)) + 80096ba: 6823 ldr r3, [r4, #0] + 80096bc: 035f lsls r7, r3, #13 + 80096be: d510 bpl.n 80096e2 + __HAL_RCC_RNG_CONFIG(PeriphClkInit->RngClockSelection); + 80096c0: 4a5c ldr r2, [pc, #368] ; (8009834 ) + 80096c2: 6fe1 ldr r1, [r4, #124] ; 0x7c + 80096c4: f8d2 3088 ldr.w r3, [r2, #136] ; 0x88 + 80096c8: f023 6340 bic.w r3, r3, #201326592 ; 0xc000000 + 80096cc: 430b orrs r3, r1 + if(PeriphClkInit->RngClockSelection == RCC_RNGCLKSOURCE_PLL) + 80096ce: f1b1 6f00 cmp.w r1, #134217728 ; 0x8000000 + __HAL_RCC_RNG_CONFIG(PeriphClkInit->RngClockSelection); + 80096d2: f8c2 3088 str.w r3, [r2, #136] ; 0x88 + if(PeriphClkInit->RngClockSelection == RCC_RNGCLKSOURCE_PLL) + 80096d6: f040 80a1 bne.w 800981c + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL_48M1CLK); + 80096da: 68d3 ldr r3, [r2, #12] + 80096dc: f443 1380 orr.w r3, r3, #1048576 ; 0x100000 + 80096e0: 60d3 str r3, [r2, #12] + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_ADC) == RCC_PERIPHCLK_ADC) + 80096e2: 6823 ldr r3, [r4, #0] + 80096e4: 045e lsls r6, r3, #17 + 80096e6: d513 bpl.n 8009710 + __HAL_RCC_ADC_CONFIG(PeriphClkInit->AdcClockSelection); + 80096e8: 4952 ldr r1, [pc, #328] ; (8009834 ) + 80096ea: f8d4 2080 ldr.w r2, [r4, #128] ; 0x80 + 80096ee: f8d1 3088 ldr.w r3, [r1, #136] ; 0x88 + 80096f2: f023 5340 bic.w r3, r3, #805306368 ; 0x30000000 + 80096f6: 4313 orrs r3, r2 + if(PeriphClkInit->AdcClockSelection == RCC_ADCCLKSOURCE_PLLSAI1) + 80096f8: f1b2 5f80 cmp.w r2, #268435456 ; 0x10000000 + __HAL_RCC_ADC_CONFIG(PeriphClkInit->AdcClockSelection); + 80096fc: f8c1 3088 str.w r3, [r1, #136] ; 0x88 + if(PeriphClkInit->AdcClockSelection == RCC_ADCCLKSOURCE_PLLSAI1) + 8009700: d106 bne.n 8009710 + ret = RCCEx_PLLSAI1_Config(&(PeriphClkInit->PLLSAI1), DIVIDER_R_UPDATE); + 8009702: 2102 movs r1, #2 + 8009704: 1d20 adds r0, r4, #4 + 8009706: f7ff fd9b bl 8009240 + if(ret != HAL_OK) + 800970a: 2800 cmp r0, #0 + 800970c: bf18 it ne + 800970e: 4605 movne r5, r0 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_DFSDM1) == RCC_PERIPHCLK_DFSDM1) + 8009710: 6822 ldr r2, [r4, #0] + 8009712: 03d0 lsls r0, r2, #15 + 8009714: d509 bpl.n 800972a + __HAL_RCC_DFSDM1_CONFIG(PeriphClkInit->Dfsdm1ClockSelection); + 8009716: 4947 ldr r1, [pc, #284] ; (8009834 ) + 8009718: f8d4 0084 ldr.w r0, [r4, #132] ; 0x84 + 800971c: f8d1 309c ldr.w r3, [r1, #156] ; 0x9c + 8009720: f023 0304 bic.w r3, r3, #4 + 8009724: 4303 orrs r3, r0 + 8009726: f8c1 309c str.w r3, [r1, #156] ; 0x9c + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_DFSDM1AUDIO) == RCC_PERIPHCLK_DFSDM1AUDIO) + 800972a: 0291 lsls r1, r2, #10 + 800972c: d509 bpl.n 8009742 + __HAL_RCC_DFSDM1AUDIO_CONFIG(PeriphClkInit->Dfsdm1AudioClockSelection); + 800972e: 4941 ldr r1, [pc, #260] ; (8009834 ) + 8009730: f8d4 0088 ldr.w r0, [r4, #136] ; 0x88 + 8009734: f8d1 309c ldr.w r3, [r1, #156] ; 0x9c + 8009738: f023 0318 bic.w r3, r3, #24 + 800973c: 4303 orrs r3, r0 + 800973e: f8c1 309c str.w r3, [r1, #156] ; 0x9c + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_OSPI) == RCC_PERIPHCLK_OSPI) + 8009742: 01d3 lsls r3, r2, #7 + 8009744: d510 bpl.n 8009768 + __HAL_RCC_OSPI_CONFIG(PeriphClkInit->OspiClockSelection); + 8009746: 4a3b ldr r2, [pc, #236] ; (8009834 ) + 8009748: f8d4 108c ldr.w r1, [r4, #140] ; 0x8c + 800974c: f8d2 309c ldr.w r3, [r2, #156] ; 0x9c + 8009750: f423 1340 bic.w r3, r3, #3145728 ; 0x300000 + 8009754: 430b orrs r3, r1 + 8009756: f8c2 309c str.w r3, [r2, #156] ; 0x9c + if(PeriphClkInit->OspiClockSelection == RCC_OSPICLKSOURCE_PLL) + 800975a: f5b1 1f00 cmp.w r1, #2097152 ; 0x200000 + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL_48M1CLK); + 800975e: bf02 ittt eq + 8009760: 68d3 ldreq r3, [r2, #12] + 8009762: f443 1380 orreq.w r3, r3, #1048576 ; 0x100000 + 8009766: 60d3 streq r3, [r2, #12] +} + 8009768: 4628 mov r0, r5 + 800976a: b002 add sp, #8 + 800976c: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + if((tmpregister != RCC_RTCCLKSOURCE_NONE) && (tmpregister != PeriphClkInit->RTCClockSelection)) + 8009770: f8d4 2090 ldr.w r2, [r4, #144] ; 0x90 + 8009774: 429a cmp r2, r3 + 8009776: f43f aecd beq.w 8009514 + tmpregister = READ_BIT(RCC->BDCR, ~(RCC_BDCR_RTCSEL)); + 800977a: f8d7 2090 ldr.w r2, [r7, #144] ; 0x90 + __HAL_RCC_BACKUPRESET_FORCE(); + 800977e: f8d7 3090 ldr.w r3, [r7, #144] ; 0x90 + 8009782: f443 3380 orr.w r3, r3, #65536 ; 0x10000 + 8009786: f8c7 3090 str.w r3, [r7, #144] ; 0x90 + __HAL_RCC_BACKUPRESET_RELEASE(); + 800978a: f8d7 3090 ldr.w r3, [r7, #144] ; 0x90 + tmpregister = READ_BIT(RCC->BDCR, ~(RCC_BDCR_RTCSEL)); + 800978e: f422 7140 bic.w r1, r2, #768 ; 0x300 + __HAL_RCC_BACKUPRESET_RELEASE(); + 8009792: f423 3380 bic.w r3, r3, #65536 ; 0x10000 + if (HAL_IS_BIT_SET(tmpregister, RCC_BDCR_LSEON)) + 8009796: 07d2 lsls r2, r2, #31 + __HAL_RCC_BACKUPRESET_RELEASE(); + 8009798: f8c7 3090 str.w r3, [r7, #144] ; 0x90 + RCC->BDCR = tmpregister; + 800979c: f8c7 1090 str.w r1, [r7, #144] ; 0x90 + if (HAL_IS_BIT_SET(tmpregister, RCC_BDCR_LSEON)) + 80097a0: f57f aeb8 bpl.w 8009514 + tickstart = HAL_GetTick(); + 80097a4: f7fd fca2 bl 80070ec + if((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) + 80097a8: f241 3988 movw r9, #5000 ; 0x1388 + tickstart = HAL_GetTick(); + 80097ac: 4605 mov r5, r0 + while(READ_BIT(RCC->BDCR, RCC_BDCR_LSERDY) == 0U) + 80097ae: f8d7 3090 ldr.w r3, [r7, #144] ; 0x90 + 80097b2: 079b lsls r3, r3, #30 + 80097b4: f53f aeae bmi.w 8009514 + if((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) + 80097b8: f7fd fc98 bl 80070ec + 80097bc: 1b40 subs r0, r0, r5 + 80097be: 4548 cmp r0, r9 + 80097c0: d9f5 bls.n 80097ae + 80097c2: e6c7 b.n 8009554 + 80097c4: 4635 mov r5, r6 + 80097c6: e6cd b.n 8009564 + if(PeriphClkInit->UsbClockSelection == RCC_USBCLKSOURCE_PLLSAI1) + 80097c8: f1b1 6f80 cmp.w r1, #67108864 ; 0x4000000 + 80097cc: f47f af62 bne.w 8009694 + ret = RCCEx_PLLSAI1_Config(&(PeriphClkInit->PLLSAI1), DIVIDER_Q_UPDATE); + 80097d0: 2101 movs r1, #1 + 80097d2: 1d20 adds r0, r4, #4 + 80097d4: f7ff fd34 bl 8009240 + if(ret != HAL_OK) + 80097d8: 2800 cmp r0, #0 + 80097da: bf18 it ne + 80097dc: 4605 movne r5, r0 + 80097de: e759 b.n 8009694 + __HAL_RCC_SDMMC1_CONFIG(PeriphClkInit->Sdmmc1ClockSelection); + 80097e0: f422 4280 bic.w r2, r2, #16384 ; 0x4000 + 80097e4: f8c3 209c str.w r2, [r3, #156] ; 0x9c + 80097e8: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 80097ec: f022 6240 bic.w r2, r2, #201326592 ; 0xc000000 + 80097f0: 430a orrs r2, r1 + if(PeriphClkInit->Sdmmc1ClockSelection == RCC_SDMMC1CLKSOURCE_PLL) /* PLL "Q" ? */ + 80097f2: f1b1 6f00 cmp.w r1, #134217728 ; 0x8000000 + __HAL_RCC_SDMMC1_CONFIG(PeriphClkInit->Sdmmc1ClockSelection); + 80097f6: f8c3 2088 str.w r2, [r3, #136] ; 0x88 + if(PeriphClkInit->Sdmmc1ClockSelection == RCC_SDMMC1CLKSOURCE_PLL) /* PLL "Q" ? */ + 80097fa: d103 bne.n 8009804 + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL_48M1CLK); + 80097fc: 68da ldr r2, [r3, #12] + 80097fe: f442 1280 orr.w r2, r2, #1048576 ; 0x100000 + 8009802: e759 b.n 80096b8 + else if(PeriphClkInit->Sdmmc1ClockSelection == RCC_SDMMC1CLKSOURCE_PLLSAI1) + 8009804: f1b1 6f80 cmp.w r1, #67108864 ; 0x4000000 + 8009808: f47f af57 bne.w 80096ba + ret = RCCEx_PLLSAI1_Config(&(PeriphClkInit->PLLSAI1), DIVIDER_Q_UPDATE); + 800980c: 2101 movs r1, #1 + 800980e: 1d20 adds r0, r4, #4 + 8009810: f7ff fd16 bl 8009240 + if(ret != HAL_OK) + 8009814: 2800 cmp r0, #0 + 8009816: bf18 it ne + 8009818: 4605 movne r5, r0 + 800981a: e74e b.n 80096ba + else if(PeriphClkInit->RngClockSelection == RCC_RNGCLKSOURCE_PLLSAI1) + 800981c: f1b1 6f80 cmp.w r1, #67108864 ; 0x4000000 + 8009820: f47f af5f bne.w 80096e2 + ret = RCCEx_PLLSAI1_Config(&(PeriphClkInit->PLLSAI1), DIVIDER_Q_UPDATE); + 8009824: 2101 movs r1, #1 + 8009826: 1d20 adds r0, r4, #4 + 8009828: f7ff fd0a bl 8009240 + if(ret != HAL_OK) + 800982c: 2800 cmp r0, #0 + 800982e: bf18 it ne + 8009830: 4605 movne r5, r0 + 8009832: e756 b.n 80096e2 + 8009834: 40021000 .word 0x40021000 + +08009838 : + PeriphClkInit->PeriphClockSelection = RCC_PERIPHCLK_USART1 | RCC_PERIPHCLK_USART2 | RCC_PERIPHCLK_USART3 | RCC_PERIPHCLK_UART4 | RCC_PERIPHCLK_UART5 | \ + 8009838: 4b5b ldr r3, [pc, #364] ; (80099a8 ) + 800983a: 6003 str r3, [r0, #0] + PeriphClkInit->PLLSAI1.PLLSAI1Source = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLSRC) >> RCC_PLLCFGR_PLLSRC_Pos; + 800983c: 4b5b ldr r3, [pc, #364] ; (80099ac ) + 800983e: 68d9 ldr r1, [r3, #12] + 8009840: f001 0103 and.w r1, r1, #3 + 8009844: 6041 str r1, [r0, #4] + PeriphClkInit->PLLSAI1.PLLSAI1M = (READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U; + 8009846: 691a ldr r2, [r3, #16] + 8009848: f3c2 1203 ubfx r2, r2, #4, #4 + 800984c: 3201 adds r2, #1 + 800984e: 6082 str r2, [r0, #8] + PeriphClkInit->PLLSAI1.PLLSAI1N = READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1N) >> RCC_PLLSAI1CFGR_PLLSAI1N_Pos; + 8009850: 691a ldr r2, [r3, #16] + 8009852: f3c2 2206 ubfx r2, r2, #8, #7 + 8009856: 60c2 str r2, [r0, #12] + PeriphClkInit->PLLSAI1.PLLSAI1P = ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1P) >> RCC_PLLSAI1CFGR_PLLSAI1P_Pos) << 4U) + 7U; + 8009858: 691a ldr r2, [r3, #16] + 800985a: 0b52 lsrs r2, r2, #13 + 800985c: f002 0210 and.w r2, r2, #16 + 8009860: 3207 adds r2, #7 + 8009862: 6102 str r2, [r0, #16] + PeriphClkInit->PLLSAI1.PLLSAI1Q = ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1Q) >> RCC_PLLSAI1CFGR_PLLSAI1Q_Pos) + 1U) * 2U; + 8009864: 691a ldr r2, [r3, #16] + 8009866: f3c2 5241 ubfx r2, r2, #21, #2 + 800986a: 3201 adds r2, #1 + 800986c: 0052 lsls r2, r2, #1 + 800986e: 6142 str r2, [r0, #20] + PeriphClkInit->PLLSAI1.PLLSAI1R = ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1R) >> RCC_PLLSAI1CFGR_PLLSAI1R_Pos) + 1U) * 2U; + 8009870: 691a ldr r2, [r3, #16] + PeriphClkInit->PLLSAI2.PLLSAI2Source = PeriphClkInit->PLLSAI1.PLLSAI1Source; + 8009872: 6201 str r1, [r0, #32] + PeriphClkInit->PLLSAI1.PLLSAI1R = ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1R) >> RCC_PLLSAI1CFGR_PLLSAI1R_Pos) + 1U) * 2U; + 8009874: f3c2 6241 ubfx r2, r2, #25, #2 + 8009878: 3201 adds r2, #1 + 800987a: 0052 lsls r2, r2, #1 + 800987c: 6182 str r2, [r0, #24] + PeriphClkInit->PLLSAI2.PLLSAI2M = (READ_BIT(RCC->PLLSAI2CFGR, RCC_PLLSAI2CFGR_PLLSAI2M) >> RCC_PLLSAI2CFGR_PLLSAI2M_Pos) + 1U; + 800987e: 695a ldr r2, [r3, #20] + 8009880: f3c2 1203 ubfx r2, r2, #4, #4 + 8009884: 3201 adds r2, #1 + 8009886: 6242 str r2, [r0, #36] ; 0x24 + PeriphClkInit->PLLSAI2.PLLSAI2N = READ_BIT(RCC->PLLSAI2CFGR, RCC_PLLSAI2CFGR_PLLSAI2N) >> RCC_PLLSAI2CFGR_PLLSAI2N_Pos; + 8009888: 695a ldr r2, [r3, #20] + 800988a: f3c2 2206 ubfx r2, r2, #8, #7 + 800988e: 6282 str r2, [r0, #40] ; 0x28 + PeriphClkInit->PLLSAI2.PLLSAI2P = ((READ_BIT(RCC->PLLSAI2CFGR, RCC_PLLSAI2CFGR_PLLSAI2P) >> RCC_PLLSAI2CFGR_PLLSAI2P_Pos) << 4U) + 7U; + 8009890: 695a ldr r2, [r3, #20] + 8009892: 0b52 lsrs r2, r2, #13 + 8009894: f002 0210 and.w r2, r2, #16 + 8009898: 3207 adds r2, #7 + 800989a: 62c2 str r2, [r0, #44] ; 0x2c + PeriphClkInit->PLLSAI2.PLLSAI2Q = ((READ_BIT(RCC->PLLSAI2CFGR, RCC_PLLSAI2CFGR_PLLSAI2Q) >> RCC_PLLSAI2CFGR_PLLSAI2Q_Pos) + 1U) * 2U; + 800989c: 695a ldr r2, [r3, #20] + 800989e: f3c2 5241 ubfx r2, r2, #21, #2 + 80098a2: 3201 adds r2, #1 + 80098a4: 0052 lsls r2, r2, #1 + 80098a6: 6302 str r2, [r0, #48] ; 0x30 + PeriphClkInit->PLLSAI2.PLLSAI2R = ((READ_BIT(RCC->PLLSAI2CFGR, RCC_PLLSAI2CFGR_PLLSAI2R)>> RCC_PLLSAI2CFGR_PLLSAI2R_Pos) + 1U) * 2U; + 80098a8: 695a ldr r2, [r3, #20] + 80098aa: f3c2 6241 ubfx r2, r2, #25, #2 + 80098ae: 3201 adds r2, #1 + 80098b0: 0052 lsls r2, r2, #1 + 80098b2: 6342 str r2, [r0, #52] ; 0x34 + PeriphClkInit->Usart1ClockSelection = __HAL_RCC_GET_USART1_SOURCE(); + 80098b4: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 80098b8: f002 0203 and.w r2, r2, #3 + 80098bc: 63c2 str r2, [r0, #60] ; 0x3c + PeriphClkInit->Usart2ClockSelection = __HAL_RCC_GET_USART2_SOURCE(); + 80098be: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 80098c2: f002 020c and.w r2, r2, #12 + 80098c6: 6402 str r2, [r0, #64] ; 0x40 + PeriphClkInit->Usart3ClockSelection = __HAL_RCC_GET_USART3_SOURCE(); + 80098c8: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 80098cc: f002 0230 and.w r2, r2, #48 ; 0x30 + 80098d0: 6442 str r2, [r0, #68] ; 0x44 + PeriphClkInit->Uart4ClockSelection = __HAL_RCC_GET_UART4_SOURCE(); + 80098d2: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 80098d6: f002 02c0 and.w r2, r2, #192 ; 0xc0 + 80098da: 6482 str r2, [r0, #72] ; 0x48 + PeriphClkInit->Uart5ClockSelection = __HAL_RCC_GET_UART5_SOURCE(); + 80098dc: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 80098e0: f402 7240 and.w r2, r2, #768 ; 0x300 + 80098e4: 64c2 str r2, [r0, #76] ; 0x4c + PeriphClkInit->Lpuart1ClockSelection = __HAL_RCC_GET_LPUART1_SOURCE(); + 80098e6: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 80098ea: f402 6240 and.w r2, r2, #3072 ; 0xc00 + 80098ee: 6502 str r2, [r0, #80] ; 0x50 + PeriphClkInit->I2c1ClockSelection = __HAL_RCC_GET_I2C1_SOURCE(); + 80098f0: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 80098f4: f402 5240 and.w r2, r2, #12288 ; 0x3000 + 80098f8: 6542 str r2, [r0, #84] ; 0x54 + PeriphClkInit->I2c2ClockSelection = __HAL_RCC_GET_I2C2_SOURCE(); + 80098fa: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 80098fe: f402 4240 and.w r2, r2, #49152 ; 0xc000 + 8009902: 6582 str r2, [r0, #88] ; 0x58 + PeriphClkInit->I2c3ClockSelection = __HAL_RCC_GET_I2C3_SOURCE(); + 8009904: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 8009908: f402 3240 and.w r2, r2, #196608 ; 0x30000 + 800990c: 65c2 str r2, [r0, #92] ; 0x5c + PeriphClkInit->I2c4ClockSelection = __HAL_RCC_GET_I2C4_SOURCE(); + 800990e: f8d3 209c ldr.w r2, [r3, #156] ; 0x9c + 8009912: f002 0203 and.w r2, r2, #3 + 8009916: 6602 str r2, [r0, #96] ; 0x60 + PeriphClkInit->Lptim1ClockSelection = __HAL_RCC_GET_LPTIM1_SOURCE(); + 8009918: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 800991c: f402 2240 and.w r2, r2, #786432 ; 0xc0000 + 8009920: 6642 str r2, [r0, #100] ; 0x64 + PeriphClkInit->Lptim2ClockSelection = __HAL_RCC_GET_LPTIM2_SOURCE(); + 8009922: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 8009926: f402 1240 and.w r2, r2, #3145728 ; 0x300000 + 800992a: 6682 str r2, [r0, #104] ; 0x68 + PeriphClkInit->Sai1ClockSelection = __HAL_RCC_GET_SAI1_SOURCE(); + 800992c: f8d3 209c ldr.w r2, [r3, #156] ; 0x9c + 8009930: f002 02e0 and.w r2, r2, #224 ; 0xe0 + 8009934: 66c2 str r2, [r0, #108] ; 0x6c + PeriphClkInit->Sai2ClockSelection = __HAL_RCC_GET_SAI2_SOURCE(); + 8009936: f8d3 209c ldr.w r2, [r3, #156] ; 0x9c + 800993a: f402 62e0 and.w r2, r2, #1792 ; 0x700 + 800993e: 6702 str r2, [r0, #112] ; 0x70 + PeriphClkInit->RTCClockSelection = __HAL_RCC_GET_RTC_SOURCE(); + 8009940: f8d3 2090 ldr.w r2, [r3, #144] ; 0x90 + 8009944: f402 7240 and.w r2, r2, #768 ; 0x300 + 8009948: f8c0 2090 str.w r2, [r0, #144] ; 0x90 + PeriphClkInit->UsbClockSelection = __HAL_RCC_GET_USB_SOURCE(); + 800994c: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 8009950: f002 6240 and.w r2, r2, #201326592 ; 0xc000000 + 8009954: 6742 str r2, [r0, #116] ; 0x74 + PeriphClkInit->Sdmmc1ClockSelection = __HAL_RCC_GET_SDMMC1_SOURCE(); + 8009956: f8d3 209c ldr.w r2, [r3, #156] ; 0x9c + 800995a: 0452 lsls r2, r2, #17 + 800995c: bf56 itet pl + 800995e: f8d3 2088 ldrpl.w r2, [r3, #136] ; 0x88 + 8009962: f44f 4280 movmi.w r2, #16384 ; 0x4000 + 8009966: f002 6240 andpl.w r2, r2, #201326592 ; 0xc000000 + 800996a: 6782 str r2, [r0, #120] ; 0x78 + PeriphClkInit->RngClockSelection = __HAL_RCC_GET_RNG_SOURCE(); + 800996c: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 8009970: f002 6240 and.w r2, r2, #201326592 ; 0xc000000 + 8009974: 67c2 str r2, [r0, #124] ; 0x7c + PeriphClkInit->AdcClockSelection = __HAL_RCC_GET_ADC_SOURCE(); + 8009976: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 800997a: f002 5240 and.w r2, r2, #805306368 ; 0x30000000 + 800997e: f8c0 2080 str.w r2, [r0, #128] ; 0x80 + PeriphClkInit->Dfsdm1ClockSelection = __HAL_RCC_GET_DFSDM1_SOURCE(); + 8009982: f8d3 209c ldr.w r2, [r3, #156] ; 0x9c + 8009986: f002 0204 and.w r2, r2, #4 + 800998a: f8c0 2084 str.w r2, [r0, #132] ; 0x84 + PeriphClkInit->Dfsdm1AudioClockSelection = __HAL_RCC_GET_DFSDM1AUDIO_SOURCE(); + 800998e: f8d3 209c ldr.w r2, [r3, #156] ; 0x9c + 8009992: f002 0218 and.w r2, r2, #24 + 8009996: f8c0 2088 str.w r2, [r0, #136] ; 0x88 + PeriphClkInit->OspiClockSelection = __HAL_RCC_GET_OSPI_SOURCE(); + 800999a: f8d3 309c ldr.w r3, [r3, #156] ; 0x9c + 800999e: f403 1340 and.w r3, r3, #3145728 ; 0x300000 + 80099a2: f8c0 308c str.w r3, [r0, #140] ; 0x8c +} + 80099a6: 4770 bx lr + 80099a8: 013f7fff .word 0x013f7fff + 80099ac: 40021000 .word 0x40021000 + +080099b0 : + if(PeriphClk == RCC_PERIPHCLK_RTC) + 80099b0: f5b0 3f00 cmp.w r0, #131072 ; 0x20000 +{ + 80099b4: b4f0 push {r4, r5, r6, r7} + 80099b6: 4d9a ldr r5, [pc, #616] ; (8009c20 ) + if(PeriphClk == RCC_PERIPHCLK_RTC) + 80099b8: d11c bne.n 80099f4 + srcclk = __HAL_RCC_GET_RTC_SOURCE(); + 80099ba: f8d5 3090 ldr.w r3, [r5, #144] ; 0x90 + 80099be: f403 7340 and.w r3, r3, #768 ; 0x300 + switch(srcclk) + 80099c2: f5b3 7f00 cmp.w r3, #512 ; 0x200 + 80099c6: f000 8085 beq.w 8009ad4 + 80099ca: f5b3 7f40 cmp.w r3, #768 ; 0x300 + 80099ce: d00a beq.n 80099e6 + 80099d0: f5b3 7f80 cmp.w r3, #256 ; 0x100 + 80099d4: d154 bne.n 8009a80 + if(HAL_IS_BIT_SET(RCC->BDCR, RCC_BDCR_LSERDY)) + 80099d6: f8d5 0090 ldr.w r0, [r5, #144] ; 0x90 + frequency = LSE_VALUE; + 80099da: f010 0002 ands.w r0, r0, #2 + 80099de: bf18 it ne + 80099e0: f44f 4000 movne.w r0, #32768 ; 0x8000 + 80099e4: e11a b.n 8009c1c + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSERDY)) + 80099e6: 6828 ldr r0, [r5, #0] + frequency = HSE_VALUE / 32U; + 80099e8: 4b8e ldr r3, [pc, #568] ; (8009c24 ) + 80099ea: f410 3000 ands.w r0, r0, #131072 ; 0x20000 + frequency = HSI_VALUE; + 80099ee: bf18 it ne + 80099f0: 4618 movne r0, r3 + 80099f2: e113 b.n 8009c1c + pll_oscsource = __HAL_RCC_GET_PLL_OSCSOURCE(); + 80099f4: 68eb ldr r3, [r5, #12] + 80099f6: f003 0303 and.w r3, r3, #3 + switch(pll_oscsource) + 80099fa: 2b02 cmp r3, #2 + 80099fc: d02f beq.n 8009a5e + 80099fe: 2b03 cmp r3, #3 + 8009a00: d034 beq.n 8009a6c + 8009a02: 2b01 cmp r3, #1 + 8009a04: d137 bne.n 8009a76 + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_MSIRDY)) + 8009a06: 6829 ldr r1, [r5, #0] + 8009a08: f011 0102 ands.w r1, r1, #2 + 8009a0c: d00c beq.n 8009a28 + pllvco = MSIRangeTable[(__HAL_RCC_GET_MSI_RANGE() >> 4U)]; + 8009a0e: 682b ldr r3, [r5, #0] + 8009a10: 4a85 ldr r2, [pc, #532] ; (8009c28 ) + 8009a12: 0719 lsls r1, r3, #28 + 8009a14: bf4b itete mi + 8009a16: 682b ldrmi r3, [r5, #0] + 8009a18: f8d5 3094 ldrpl.w r3, [r5, #148] ; 0x94 + 8009a1c: f3c3 1303 ubfxmi r3, r3, #4, #4 + 8009a20: f3c3 2303 ubfxpl r3, r3, #8, #4 + 8009a24: f852 1023 ldr.w r1, [r2, r3, lsl #2] + switch(PeriphClk) + 8009a28: f5b0 6f80 cmp.w r0, #1024 ; 0x400 + 8009a2c: f000 8226 beq.w 8009e7c + 8009a30: d858 bhi.n 8009ae4 + 8009a32: 2820 cmp r0, #32 + 8009a34: f000 81be beq.w 8009db4 + 8009a38: d824 bhi.n 8009a84 + 8009a3a: 2808 cmp r0, #8 + 8009a3c: d81d bhi.n 8009a7a + 8009a3e: 2800 cmp r0, #0 + 8009a40: f000 80ec beq.w 8009c1c + 8009a44: 3801 subs r0, #1 + 8009a46: 2807 cmp r0, #7 + 8009a48: d81a bhi.n 8009a80 + 8009a4a: e8df f010 tbh [pc, r0, lsl #1] + 8009a4e: 0164 .short 0x0164 + 8009a50: 00190177 .word 0x00190177 + 8009a54: 00190189 .word 0x00190189 + 8009a58: 00190019 .word 0x00190019 + 8009a5c: 0196 .short 0x0196 + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSIRDY)) + 8009a5e: 6829 ldr r1, [r5, #0] + pllvco = HSI_VALUE; + 8009a60: 4b72 ldr r3, [pc, #456] ; (8009c2c ) + 8009a62: f411 6180 ands.w r1, r1, #1024 ; 0x400 + pllvco = HSE_VALUE; + 8009a66: bf18 it ne + 8009a68: 4619 movne r1, r3 + 8009a6a: e7dd b.n 8009a28 + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSERDY)) + 8009a6c: 6829 ldr r1, [r5, #0] + pllvco = HSE_VALUE; + 8009a6e: 4b70 ldr r3, [pc, #448] ; (8009c30 ) + 8009a70: f411 3100 ands.w r1, r1, #131072 ; 0x20000 + 8009a74: e7f7 b.n 8009a66 + switch(pll_oscsource) + 8009a76: 2100 movs r1, #0 + 8009a78: e7d6 b.n 8009a28 + switch(PeriphClk) + 8009a7a: 2810 cmp r0, #16 + 8009a7c: f000 818a beq.w 8009d94 + 8009a80: 2000 movs r0, #0 + 8009a82: e0cb b.n 8009c1c + 8009a84: f5b0 7f80 cmp.w r0, #256 ; 0x100 + 8009a88: f000 81ea beq.w 8009e60 + 8009a8c: d80f bhi.n 8009aae + 8009a8e: 2840 cmp r0, #64 ; 0x40 + 8009a90: f000 81d5 beq.w 8009e3e + 8009a94: 2880 cmp r0, #128 ; 0x80 + 8009a96: d1f3 bne.n 8009a80 + srcclk = __HAL_RCC_GET_I2C2_SOURCE(); + 8009a98: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 8009a9c: f403 4340 and.w r3, r3, #49152 ; 0xc000 + switch(srcclk) + 8009aa0: f5b3 4f80 cmp.w r3, #16384 ; 0x4000 + 8009aa4: f000 8157 beq.w 8009d56 + 8009aa8: f5b3 4f00 cmp.w r3, #32768 ; 0x8000 + 8009aac: e1d0 b.n 8009e50 + switch(PeriphClk) + 8009aae: f5b0 7f00 cmp.w r0, #512 ; 0x200 + 8009ab2: d1e5 bne.n 8009a80 + srcclk = __HAL_RCC_GET_LPTIM1_SOURCE(); + 8009ab4: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 8009ab8: f403 2340 and.w r3, r3, #786432 ; 0xc0000 + switch(srcclk) + 8009abc: f5b3 2f00 cmp.w r3, #524288 ; 0x80000 + 8009ac0: f000 8137 beq.w 8009d32 + 8009ac4: f200 81d7 bhi.w 8009e76 + 8009ac8: 2b00 cmp r3, #0 + 8009aca: f000 81c6 beq.w 8009e5a + 8009ace: f5b3 2f80 cmp.w r3, #262144 ; 0x40000 + 8009ad2: d1d5 bne.n 8009a80 + if(HAL_IS_BIT_SET(RCC->CSR, RCC_CSR_LSIRDY)) + 8009ad4: f8d5 0094 ldr.w r0, [r5, #148] ; 0x94 + frequency = LSI_VALUE; + 8009ad8: f010 0002 ands.w r0, r0, #2 + 8009adc: bf18 it ne + 8009ade: f44f 40fa movne.w r0, #32000 ; 0x7d00 + 8009ae2: e09b b.n 8009c1c + switch(PeriphClk) + 8009ae4: f5b0 2f80 cmp.w r0, #262144 ; 0x40000 + 8009ae8: d040 beq.n 8009b6c + 8009aea: d819 bhi.n 8009b20 + 8009aec: f5b0 5f00 cmp.w r0, #8192 ; 0x2000 + 8009af0: d03c beq.n 8009b6c + 8009af2: d808 bhi.n 8009b06 + 8009af4: f5b0 6f00 cmp.w r0, #2048 ; 0x800 + 8009af8: d002 beq.n 8009b00 + 8009afa: f5b0 5f80 cmp.w r0, #4096 ; 0x1000 + 8009afe: d1bf bne.n 8009a80 +} + 8009b00: bcf0 pop {r4, r5, r6, r7} + frequency = RCCEx_GetSAIxPeriphCLKFreq(RCC_PERIPHCLK_SAI1, pllvco); + 8009b02: f7ff bb1b b.w 800913c + switch(PeriphClk) + 8009b06: f5b0 4f80 cmp.w r0, #16384 ; 0x4000 + 8009b0a: f000 8163 beq.w 8009dd4 + 8009b0e: f5b0 3f80 cmp.w r0, #65536 ; 0x10000 + 8009b12: d1b5 bne.n 8009a80 + srcclk = __HAL_RCC_GET_DFSDM1_SOURCE(); + 8009b14: f8d5 309c ldr.w r3, [r5, #156] ; 0x9c + if(srcclk == RCC_DFSDM1CLKSOURCE_PCLK2) + 8009b18: 075a lsls r2, r3, #29 + 8009b1a: f100 811c bmi.w 8009d56 + 8009b1e: e105 b.n 8009d2c + switch(PeriphClk) + 8009b20: f5b0 1f00 cmp.w r0, #2097152 ; 0x200000 + 8009b24: f000 817c beq.w 8009e20 + 8009b28: d80f bhi.n 8009b4a + 8009b2a: f5b0 2f00 cmp.w r0, #524288 ; 0x80000 + 8009b2e: f000 8081 beq.w 8009c34 + 8009b32: f5b0 1f80 cmp.w r0, #1048576 ; 0x100000 + 8009b36: d1a3 bne.n 8009a80 + srcclk = __HAL_RCC_GET_I2C4_SOURCE(); + 8009b38: f8d5 309c ldr.w r3, [r5, #156] ; 0x9c + 8009b3c: f003 0303 and.w r3, r3, #3 + switch(srcclk) + 8009b40: 2b01 cmp r3, #1 + 8009b42: f000 8108 beq.w 8009d56 + 8009b46: 2b02 cmp r3, #2 + 8009b48: e182 b.n 8009e50 + switch(PeriphClk) + 8009b4a: f1b0 7f80 cmp.w r0, #16777216 ; 0x1000000 + 8009b4e: d197 bne.n 8009a80 + srcclk = __HAL_RCC_GET_OSPI_SOURCE(); + 8009b50: f8d5 309c ldr.w r3, [r5, #156] ; 0x9c + 8009b54: f403 1340 and.w r3, r3, #3145728 ; 0x300000 + switch(srcclk) + 8009b58: f5b3 1f80 cmp.w r3, #1048576 ; 0x100000 + 8009b5c: d033 beq.n 8009bc6 + 8009b5e: f5b3 1f00 cmp.w r3, #2097152 ; 0x200000 + 8009b62: f000 819c beq.w 8009e9e + 8009b66: 2b00 cmp r3, #0 + 8009b68: d18a bne.n 8009a80 + 8009b6a: e0f4 b.n 8009d56 + srcclk = READ_BIT(RCC->CCIPR, RCC_CCIPR_CLK48SEL); + 8009b6c: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 8009b70: f003 6340 and.w r3, r3, #201326592 ; 0xc000000 + switch(srcclk) + 8009b74: f1b3 6f00 cmp.w r3, #134217728 ; 0x8000000 + 8009b78: d037 beq.n 8009bea + 8009b7a: d820 bhi.n 8009bbe + 8009b7c: 2b00 cmp r3, #0 + 8009b7e: f000 80c4 beq.w 8009d0a + 8009b82: f1b3 6f80 cmp.w r3, #67108864 ; 0x4000000 + 8009b86: f47f af7b bne.w 8009a80 + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLLSAI1RDY)) + 8009b8a: 6828 ldr r0, [r5, #0] + 8009b8c: f010 6000 ands.w r0, r0, #134217728 ; 0x8000000 + 8009b90: d044 beq.n 8009c1c + if(HAL_IS_BIT_SET(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1QEN)) + 8009b92: 6928 ldr r0, [r5, #16] + 8009b94: f410 1080 ands.w r0, r0, #1048576 ; 0x100000 + 8009b98: d040 beq.n 8009c1c + plln = READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1N) >> RCC_PLLSAI1CFGR_PLLSAI1N_Pos; + 8009b9a: 692f ldr r7, [r5, #16] + 8009b9c: f3c7 2706 ubfx r7, r7, #8, #7 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 8009ba0: 4379 muls r1, r7 + 8009ba2: 692f ldr r7, [r5, #16] + frequency = (pllvco / (((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1Q) >> RCC_PLLSAI1CFGR_PLLSAI1Q_Pos) + 1U) << 1U)); + 8009ba4: 6928 ldr r0, [r5, #16] + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 8009ba6: f3c7 1703 ubfx r7, r7, #4, #4 + 8009baa: 3701 adds r7, #1 + 8009bac: fbb1 f1f7 udiv r1, r1, r7 + frequency = (pllvco / (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLQ) >> RCC_PLLCFGR_PLLQ_Pos) + 1U) << 1U)); + 8009bb0: f3c0 5041 ubfx r0, r0, #21, #2 + 8009bb4: 3001 adds r0, #1 + 8009bb6: 0040 lsls r0, r0, #1 + 8009bb8: fbb1 f0f0 udiv r0, r1, r0 + 8009bbc: e02e b.n 8009c1c + 8009bbe: f1b3 6f40 cmp.w r3, #201326592 ; 0xc000000 + 8009bc2: f47f af5d bne.w 8009a80 + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_MSIRDY)) + 8009bc6: 6828 ldr r0, [r5, #0] + 8009bc8: f010 0002 ands.w r0, r0, #2 + 8009bcc: d026 beq.n 8009c1c + frequency = MSIRangeTable[(__HAL_RCC_GET_MSI_RANGE() >> 4U)]; + 8009bce: 682b ldr r3, [r5, #0] + 8009bd0: 4a15 ldr r2, [pc, #84] ; (8009c28 ) + 8009bd2: 071b lsls r3, r3, #28 + 8009bd4: bf4b itete mi + 8009bd6: 682b ldrmi r3, [r5, #0] + 8009bd8: f8d5 3094 ldrpl.w r3, [r5, #148] ; 0x94 + 8009bdc: f3c3 1303 ubfxmi r3, r3, #4, #4 + 8009be0: f3c3 2303 ubfxpl r3, r3, #8, #4 + 8009be4: f852 0023 ldr.w r0, [r2, r3, lsl #2] + 8009be8: e018 b.n 8009c1c + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLLRDY)) + 8009bea: 6828 ldr r0, [r5, #0] + 8009bec: f010 7000 ands.w r0, r0, #33554432 ; 0x2000000 + 8009bf0: d014 beq.n 8009c1c + if(HAL_IS_BIT_SET(RCC->PLLCFGR, RCC_PLLCFGR_PLLQEN)) + 8009bf2: 68e8 ldr r0, [r5, #12] + 8009bf4: f410 1080 ands.w r0, r0, #1048576 ; 0x100000 + 8009bf8: d010 beq.n 8009c1c + plln = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos; + 8009bfa: 68e8 ldr r0, [r5, #12] + 8009bfc: f3c0 2006 ubfx r0, r0, #8, #7 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009c00: 4348 muls r0, r1 + 8009c02: 68e9 ldr r1, [r5, #12] + frequency = (pllvco / (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLQ) >> RCC_PLLCFGR_PLLQ_Pos) + 1U) << 1U)); + 8009c04: 68ed ldr r5, [r5, #12] + 8009c06: f3c5 5541 ubfx r5, r5, #21, #2 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009c0a: f3c1 1103 ubfx r1, r1, #4, #4 + frequency = (pllvco / (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLQ) >> RCC_PLLCFGR_PLLQ_Pos) + 1U) << 1U)); + 8009c0e: 3501 adds r5, #1 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009c10: 3101 adds r1, #1 + frequency = (pllvco / (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLQ) >> RCC_PLLCFGR_PLLQ_Pos) + 1U) << 1U)); + 8009c12: 006d lsls r5, r5, #1 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009c14: fbb0 f0f1 udiv r0, r0, r1 + frequency = (pllvco / (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLQ) >> RCC_PLLCFGR_PLLQ_Pos) + 1U) << 1U)); + 8009c18: fbb0 f0f5 udiv r0, r0, r5 +} + 8009c1c: bcf0 pop {r4, r5, r6, r7} + 8009c1e: 4770 bx lr + 8009c20: 40021000 .word 0x40021000 + 8009c24: 0003d090 .word 0x0003d090 + 8009c28: 0800e9f4 .word 0x0800e9f4 + 8009c2c: 00f42400 .word 0x00f42400 + 8009c30: 007a1200 .word 0x007a1200 + if(HAL_IS_BIT_SET(RCC->CCIPR2, RCC_CCIPR2_SDMMCSEL)) /* PLL "P" ? */ + 8009c34: f8d5 009c ldr.w r0, [r5, #156] ; 0x9c + 8009c38: f410 4080 ands.w r0, r0, #16384 ; 0x4000 + 8009c3c: d01f beq.n 8009c7e + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLLRDY)) + 8009c3e: 6828 ldr r0, [r5, #0] + 8009c40: f010 7000 ands.w r0, r0, #33554432 ; 0x2000000 + 8009c44: d0ea beq.n 8009c1c + if(HAL_IS_BIT_SET(RCC->PLLCFGR, RCC_PLLCFGR_PLLPEN)) + 8009c46: 68e8 ldr r0, [r5, #12] + 8009c48: f410 3080 ands.w r0, r0, #65536 ; 0x10000 + 8009c4c: d0e6 beq.n 8009c1c + plln = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos; + 8009c4e: 68ee ldr r6, [r5, #12] + 8009c50: f3c6 2606 ubfx r6, r6, #8, #7 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009c54: fb01 f006 mul.w r0, r1, r6 + 8009c58: 68ee ldr r6, [r5, #12] + pllp = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLPDIV) >> RCC_PLLCFGR_PLLPDIV_Pos; + 8009c5a: 68eb ldr r3, [r5, #12] + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009c5c: f3c6 1603 ubfx r6, r6, #4, #4 + if(pllp == 0U) + 8009c60: 0edb lsrs r3, r3, #27 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009c62: f106 0601 add.w r6, r6, #1 + 8009c66: fbb0 f0f6 udiv r0, r0, r6 + if(pllp == 0U) + 8009c6a: d105 bne.n 8009c78 + if(READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLP) != 0U) + 8009c6c: 68eb ldr r3, [r5, #12] + pllp = 7U; + 8009c6e: f413 3f00 tst.w r3, #131072 ; 0x20000 + 8009c72: bf14 ite ne + 8009c74: 2311 movne r3, #17 + 8009c76: 2307 moveq r3, #7 + frequency = (pllvco / pllp); + 8009c78: fbb0 f0f3 udiv r0, r0, r3 + 8009c7c: e7ce b.n 8009c1c + srcclk = READ_BIT(RCC->CCIPR, RCC_CCIPR_CLK48SEL); + 8009c7e: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 8009c82: f003 6340 and.w r3, r3, #201326592 ; 0xc000000 + switch(srcclk) + 8009c86: f1b3 6f00 cmp.w r3, #134217728 ; 0x8000000 + 8009c8a: d024 beq.n 8009cd6 + 8009c8c: d81e bhi.n 8009ccc + 8009c8e: 2b00 cmp r3, #0 + 8009c90: d03b beq.n 8009d0a + 8009c92: f1b3 6f80 cmp.w r3, #67108864 ; 0x4000000 + 8009c96: d1c1 bne.n 8009c1c + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLLSAI1RDY)) + 8009c98: 6828 ldr r0, [r5, #0] + 8009c9a: f010 6000 ands.w r0, r0, #134217728 ; 0x8000000 + 8009c9e: d0bd beq.n 8009c1c + if(HAL_IS_BIT_SET(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1QEN)) + 8009ca0: 6928 ldr r0, [r5, #16] + 8009ca2: f410 1080 ands.w r0, r0, #1048576 ; 0x100000 + 8009ca6: d0b9 beq.n 8009c1c + plln = READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1N) >> RCC_PLLSAI1CFGR_PLLSAI1N_Pos; + 8009ca8: 692a ldr r2, [r5, #16] + 8009caa: f3c2 2206 ubfx r2, r2, #8, #7 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 8009cae: 434a muls r2, r1 + 8009cb0: 6929 ldr r1, [r5, #16] + frequency = (pllvco / (((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1Q) >> RCC_PLLSAI1CFGR_PLLSAI1Q_Pos) + 1U) << 1U)); + 8009cb2: 6928 ldr r0, [r5, #16] + 8009cb4: f3c0 5041 ubfx r0, r0, #21, #2 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 8009cb8: f3c1 1103 ubfx r1, r1, #4, #4 + frequency = (pllvco / (((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1Q) >> RCC_PLLSAI1CFGR_PLLSAI1Q_Pos) + 1U) << 1U)); + 8009cbc: 3001 adds r0, #1 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 8009cbe: 3101 adds r1, #1 + frequency = (pllvco / (((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1Q) >> RCC_PLLSAI1CFGR_PLLSAI1Q_Pos) + 1U) << 1U)); + 8009cc0: 0040 lsls r0, r0, #1 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 8009cc2: fbb2 f2f1 udiv r2, r2, r1 + frequency = (pllvco / (((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1Q) >> RCC_PLLSAI1CFGR_PLLSAI1Q_Pos) + 1U) << 1U)); + 8009cc6: fbb2 f0f0 udiv r0, r2, r0 + 8009cca: e7a7 b.n 8009c1c + 8009ccc: f1b3 6f40 cmp.w r3, #201326592 ; 0xc000000 + 8009cd0: f43f af79 beq.w 8009bc6 + 8009cd4: e7a2 b.n 8009c1c + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLLRDY)) + 8009cd6: 6828 ldr r0, [r5, #0] + 8009cd8: f010 7000 ands.w r0, r0, #33554432 ; 0x2000000 + 8009cdc: d09e beq.n 8009c1c + if(HAL_IS_BIT_SET(RCC->PLLCFGR, RCC_PLLCFGR_PLLQEN)) + 8009cde: 68e8 ldr r0, [r5, #12] + 8009ce0: f410 1080 ands.w r0, r0, #1048576 ; 0x100000 + 8009ce4: d09a beq.n 8009c1c + plln = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos; + 8009ce6: 68ec ldr r4, [r5, #12] + 8009ce8: f3c4 2406 ubfx r4, r4, #8, #7 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009cec: 434c muls r4, r1 + 8009cee: 68e9 ldr r1, [r5, #12] + frequency = (pllvco / (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLQ) >> RCC_PLLCFGR_PLLQ_Pos) + 1U) << 1U)); + 8009cf0: 68e8 ldr r0, [r5, #12] + 8009cf2: f3c0 5041 ubfx r0, r0, #21, #2 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009cf6: f3c1 1103 ubfx r1, r1, #4, #4 + frequency = (pllvco / (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLQ) >> RCC_PLLCFGR_PLLQ_Pos) + 1U) << 1U)); + 8009cfa: 3001 adds r0, #1 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009cfc: 3101 adds r1, #1 + frequency = (pllvco / (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLQ) >> RCC_PLLCFGR_PLLQ_Pos) + 1U) << 1U)); + 8009cfe: 0040 lsls r0, r0, #1 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009d00: fbb4 f4f1 udiv r4, r4, r1 + frequency = (pllvco / (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLQ) >> RCC_PLLCFGR_PLLQ_Pos) + 1U) << 1U)); + 8009d04: fbb4 f0f0 udiv r0, r4, r0 + 8009d08: e788 b.n 8009c1c + if(HAL_IS_BIT_SET(RCC->CRRCR, RCC_CRRCR_HSI48RDY)) /* HSI48 ? */ + 8009d0a: f8d5 0098 ldr.w r0, [r5, #152] ; 0x98 + frequency = HSI48_VALUE; + 8009d0e: 4b6f ldr r3, [pc, #444] ; (8009ecc ) + 8009d10: f010 0002 ands.w r0, r0, #2 + 8009d14: e66b b.n 80099ee + srcclk = __HAL_RCC_GET_USART1_SOURCE(); + 8009d16: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 8009d1a: f003 0303 and.w r3, r3, #3 + switch(srcclk) + 8009d1e: 2b02 cmp r3, #2 + 8009d20: d007 beq.n 8009d32 + 8009d22: 2b03 cmp r3, #3 + 8009d24: f43f ae57 beq.w 80099d6 + 8009d28: 2b01 cmp r3, #1 + 8009d2a: d014 beq.n 8009d56 +} + 8009d2c: bcf0 pop {r4, r5, r6, r7} + frequency = HAL_RCC_GetPCLK2Freq(); + 8009d2e: f7ff b95b b.w 8008fe8 + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSIRDY)) + 8009d32: 6828 ldr r0, [r5, #0] + frequency = HSI_VALUE; + 8009d34: 4b66 ldr r3, [pc, #408] ; (8009ed0 ) + 8009d36: f410 6080 ands.w r0, r0, #1024 ; 0x400 + 8009d3a: e658 b.n 80099ee + srcclk = __HAL_RCC_GET_USART2_SOURCE(); + 8009d3c: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 8009d40: f003 030c and.w r3, r3, #12 + switch(srcclk) + 8009d44: 2b08 cmp r3, #8 + 8009d46: d0f4 beq.n 8009d32 + 8009d48: d808 bhi.n 8009d5c + 8009d4a: 2b00 cmp r3, #0 + 8009d4c: f000 8085 beq.w 8009e5a + 8009d50: 2b04 cmp r3, #4 + 8009d52: f47f ae95 bne.w 8009a80 +} + 8009d56: bcf0 pop {r4, r5, r6, r7} + frequency = HAL_RCC_GetSysClockFreq(); + 8009d58: f7fe bd38 b.w 80087cc + 8009d5c: 2b0c cmp r3, #12 + 8009d5e: e639 b.n 80099d4 + srcclk = __HAL_RCC_GET_USART3_SOURCE(); + 8009d60: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 8009d64: f003 0330 and.w r3, r3, #48 ; 0x30 + switch(srcclk) + 8009d68: 2b20 cmp r3, #32 + 8009d6a: d0e2 beq.n 8009d32 + 8009d6c: d803 bhi.n 8009d76 + 8009d6e: 2b00 cmp r3, #0 + 8009d70: d073 beq.n 8009e5a + 8009d72: 2b10 cmp r3, #16 + 8009d74: e7ed b.n 8009d52 + 8009d76: 2b30 cmp r3, #48 ; 0x30 + 8009d78: e62c b.n 80099d4 + srcclk = __HAL_RCC_GET_UART4_SOURCE(); + 8009d7a: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 8009d7e: f003 03c0 and.w r3, r3, #192 ; 0xc0 + switch(srcclk) + 8009d82: 2b80 cmp r3, #128 ; 0x80 + 8009d84: d0d5 beq.n 8009d32 + 8009d86: d803 bhi.n 8009d90 + 8009d88: 2b00 cmp r3, #0 + 8009d8a: d066 beq.n 8009e5a + 8009d8c: 2b40 cmp r3, #64 ; 0x40 + 8009d8e: e7e0 b.n 8009d52 + 8009d90: 2bc0 cmp r3, #192 ; 0xc0 + 8009d92: e61f b.n 80099d4 + srcclk = __HAL_RCC_GET_UART5_SOURCE(); + 8009d94: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 8009d98: f403 7340 and.w r3, r3, #768 ; 0x300 + switch(srcclk) + 8009d9c: f5b3 7f00 cmp.w r3, #512 ; 0x200 + 8009da0: d0c7 beq.n 8009d32 + 8009da2: d804 bhi.n 8009dae + 8009da4: 2b00 cmp r3, #0 + 8009da6: d058 beq.n 8009e5a + 8009da8: f5b3 7f80 cmp.w r3, #256 ; 0x100 + 8009dac: e7d1 b.n 8009d52 + 8009dae: f5b3 7f40 cmp.w r3, #768 ; 0x300 + 8009db2: e60f b.n 80099d4 + srcclk = __HAL_RCC_GET_LPUART1_SOURCE(); + 8009db4: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 8009db8: f403 6340 and.w r3, r3, #3072 ; 0xc00 + switch(srcclk) + 8009dbc: f5b3 6f00 cmp.w r3, #2048 ; 0x800 + 8009dc0: d0b7 beq.n 8009d32 + 8009dc2: d804 bhi.n 8009dce + 8009dc4: 2b00 cmp r3, #0 + 8009dc6: d048 beq.n 8009e5a + 8009dc8: f5b3 6f80 cmp.w r3, #1024 ; 0x400 + 8009dcc: e7c1 b.n 8009d52 + 8009dce: f5b3 6f40 cmp.w r3, #3072 ; 0xc00 + 8009dd2: e5ff b.n 80099d4 + srcclk = __HAL_RCC_GET_ADC_SOURCE(); + 8009dd4: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 8009dd8: f003 5340 and.w r3, r3, #805306368 ; 0x30000000 + switch(srcclk) + 8009ddc: f1b3 5f80 cmp.w r3, #268435456 ; 0x10000000 + 8009de0: d002 beq.n 8009de8 + 8009de2: f1b3 5f40 cmp.w r3, #805306368 ; 0x30000000 + 8009de6: e7b4 b.n 8009d52 + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLLSAI1RDY) && (__HAL_RCC_GET_PLLSAI1CLKOUT_CONFIG(RCC_PLLSAI1_ADC1CLK) != 0U)) + 8009de8: 6828 ldr r0, [r5, #0] + 8009dea: f010 6000 ands.w r0, r0, #134217728 ; 0x8000000 + 8009dee: f43f af15 beq.w 8009c1c + 8009df2: 6928 ldr r0, [r5, #16] + 8009df4: f010 7080 ands.w r0, r0, #16777216 ; 0x1000000 + 8009df8: f43f af10 beq.w 8009c1c + plln = READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1N) >> RCC_PLLSAI1CFGR_PLLSAI1N_Pos; + 8009dfc: 692b ldr r3, [r5, #16] + 8009dfe: f3c3 2306 ubfx r3, r3, #8, #7 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 8009e02: 434b muls r3, r1 + 8009e04: 6929 ldr r1, [r5, #16] + frequency = (pllvco / (((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1R) >> RCC_PLLSAI1CFGR_PLLSAI1R_Pos) + 1U) << 1U)); + 8009e06: 6928 ldr r0, [r5, #16] + 8009e08: f3c0 6041 ubfx r0, r0, #25, #2 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 8009e0c: f3c1 1103 ubfx r1, r1, #4, #4 + frequency = (pllvco / (((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1R) >> RCC_PLLSAI1CFGR_PLLSAI1R_Pos) + 1U) << 1U)); + 8009e10: 3001 adds r0, #1 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 8009e12: 3101 adds r1, #1 + frequency = (pllvco / (((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1R) >> RCC_PLLSAI1CFGR_PLLSAI1R_Pos) + 1U) << 1U)); + 8009e14: 0040 lsls r0, r0, #1 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 8009e16: fbb3 f3f1 udiv r3, r3, r1 + frequency = (pllvco / (((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1R) >> RCC_PLLSAI1CFGR_PLLSAI1R_Pos) + 1U) << 1U)); + 8009e1a: fbb3 f0f0 udiv r0, r3, r0 + 8009e1e: e6fd b.n 8009c1c + srcclk = __HAL_RCC_GET_DFSDM1AUDIO_SOURCE(); + 8009e20: f8d5 309c ldr.w r3, [r5, #156] ; 0x9c + 8009e24: f003 0318 and.w r3, r3, #24 + switch(srcclk) + 8009e28: 2b08 cmp r3, #8 + 8009e2a: d082 beq.n 8009d32 + 8009e2c: 2b10 cmp r3, #16 + 8009e2e: f43f aeca beq.w 8009bc6 + 8009e32: 2b00 cmp r3, #0 + 8009e34: f47f ae24 bne.w 8009a80 + frequency = RCCEx_GetSAIxPeriphCLKFreq(RCC_PERIPHCLK_SAI1, pllvco); + 8009e38: f44f 6000 mov.w r0, #2048 ; 0x800 + 8009e3c: e660 b.n 8009b00 + srcclk = __HAL_RCC_GET_I2C1_SOURCE(); + 8009e3e: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 8009e42: f403 5340 and.w r3, r3, #12288 ; 0x3000 + switch(srcclk) + 8009e46: f5b3 5f80 cmp.w r3, #4096 ; 0x1000 + 8009e4a: d084 beq.n 8009d56 + 8009e4c: f5b3 5f00 cmp.w r3, #8192 ; 0x2000 + 8009e50: f43f af6f beq.w 8009d32 + 8009e54: 2b00 cmp r3, #0 + 8009e56: f47f ae13 bne.w 8009a80 +} + 8009e5a: bcf0 pop {r4, r5, r6, r7} + frequency = HAL_RCC_GetPCLK1Freq(); + 8009e5c: f7ff b8b2 b.w 8008fc4 + srcclk = __HAL_RCC_GET_I2C3_SOURCE(); + 8009e60: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 8009e64: f403 3340 and.w r3, r3, #196608 ; 0x30000 + switch(srcclk) + 8009e68: f5b3 3f80 cmp.w r3, #65536 ; 0x10000 + 8009e6c: f43f af73 beq.w 8009d56 + 8009e70: f5b3 3f00 cmp.w r3, #131072 ; 0x20000 + 8009e74: e7ec b.n 8009e50 + 8009e76: f5b3 2f40 cmp.w r3, #786432 ; 0xc0000 + 8009e7a: e5ab b.n 80099d4 + srcclk = __HAL_RCC_GET_LPTIM2_SOURCE(); + 8009e7c: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 8009e80: f403 1340 and.w r3, r3, #3145728 ; 0x300000 + switch(srcclk) + 8009e84: f5b3 1f00 cmp.w r3, #2097152 ; 0x200000 + 8009e88: f43f af53 beq.w 8009d32 + 8009e8c: d804 bhi.n 8009e98 + 8009e8e: 2b00 cmp r3, #0 + 8009e90: d0e3 beq.n 8009e5a + 8009e92: f5b3 1f80 cmp.w r3, #1048576 ; 0x100000 + 8009e96: e61c b.n 8009ad2 + 8009e98: f5b3 1f40 cmp.w r3, #3145728 ; 0x300000 + 8009e9c: e59a b.n 80099d4 + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLLRDY)) + 8009e9e: 6828 ldr r0, [r5, #0] + 8009ea0: f010 7000 ands.w r0, r0, #33554432 ; 0x2000000 + 8009ea4: f43f aeba beq.w 8009c1c + if(HAL_IS_BIT_SET(RCC->PLLCFGR, RCC_PLLCFGR_PLLQEN)) + 8009ea8: 68e8 ldr r0, [r5, #12] + 8009eaa: f410 1080 ands.w r0, r0, #1048576 ; 0x100000 + 8009eae: f43f aeb5 beq.w 8009c1c + plln = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos; + 8009eb2: 68e8 ldr r0, [r5, #12] + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009eb4: 68eb ldr r3, [r5, #12] + plln = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos; + 8009eb6: f3c0 2006 ubfx r0, r0, #8, #7 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009eba: f3c3 1303 ubfx r3, r3, #4, #4 + 8009ebe: 4341 muls r1, r0 + 8009ec0: 3301 adds r3, #1 + frequency = (pllvco / (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLQ) >> RCC_PLLCFGR_PLLQ_Pos) + 1U) << 1U)); + 8009ec2: 68e8 ldr r0, [r5, #12] + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009ec4: fbb1 f1f3 udiv r1, r1, r3 + 8009ec8: e672 b.n 8009bb0 + 8009eca: bf00 nop + 8009ecc: 02dc6c00 .word 0x02dc6c00 + 8009ed0: 00f42400 .word 0x00f42400 + +08009ed4 : +{ + 8009ed4: b570 push {r4, r5, r6, lr} + __HAL_RCC_PLLSAI1_DISABLE(); + 8009ed6: 4c20 ldr r4, [pc, #128] ; (8009f58 ) + 8009ed8: 6823 ldr r3, [r4, #0] + 8009eda: f023 6380 bic.w r3, r3, #67108864 ; 0x4000000 + 8009ede: 6023 str r3, [r4, #0] +{ + 8009ee0: 4605 mov r5, r0 + tickstart = HAL_GetTick(); + 8009ee2: f7fd f903 bl 80070ec + 8009ee6: 4606 mov r6, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI1RDY) != 0U) + 8009ee8: 6823 ldr r3, [r4, #0] + 8009eea: 011a lsls r2, r3, #4 + 8009eec: d423 bmi.n 8009f36 + __HAL_RCC_PLLSAI1_CONFIG(PLLSAI1Init->PLLSAI1M, PLLSAI1Init->PLLSAI1N, PLLSAI1Init->PLLSAI1P, PLLSAI1Init->PLLSAI1Q, PLLSAI1Init->PLLSAI1R); + 8009eee: e9d5 2302 ldrd r2, r3, [r5, #8] + 8009ef2: 06db lsls r3, r3, #27 + 8009ef4: 6921 ldr r1, [r4, #16] + 8009ef6: ea43 2302 orr.w r3, r3, r2, lsl #8 + 8009efa: 4a18 ldr r2, [pc, #96] ; (8009f5c ) + 8009efc: 400a ands r2, r1 + 8009efe: 4313 orrs r3, r2 + 8009f00: 686a ldr r2, [r5, #4] + 8009f02: 3a01 subs r2, #1 + 8009f04: ea43 1302 orr.w r3, r3, r2, lsl #4 + 8009f08: 692a ldr r2, [r5, #16] + 8009f0a: 0852 lsrs r2, r2, #1 + 8009f0c: 3a01 subs r2, #1 + 8009f0e: ea43 5342 orr.w r3, r3, r2, lsl #21 + 8009f12: 696a ldr r2, [r5, #20] + 8009f14: 0852 lsrs r2, r2, #1 + 8009f16: 3a01 subs r2, #1 + 8009f18: ea43 6342 orr.w r3, r3, r2, lsl #25 + 8009f1c: 6123 str r3, [r4, #16] + __HAL_RCC_PLLSAI1CLKOUT_ENABLE(PLLSAI1Init->PLLSAI1ClockOut); + 8009f1e: 6923 ldr r3, [r4, #16] + 8009f20: 69aa ldr r2, [r5, #24] + 8009f22: 4313 orrs r3, r2 + 8009f24: 6123 str r3, [r4, #16] + __HAL_RCC_PLLSAI1_ENABLE(); + 8009f26: 6823 ldr r3, [r4, #0] + 8009f28: f043 6380 orr.w r3, r3, #67108864 ; 0x4000000 + 8009f2c: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 8009f2e: f7fd f8dd bl 80070ec + 8009f32: 4605 mov r5, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI1RDY) == 0U) + 8009f34: e00b b.n 8009f4e + if((HAL_GetTick() - tickstart) > PLLSAI1_TIMEOUT_VALUE) + 8009f36: f7fd f8d9 bl 80070ec + 8009f3a: 1b80 subs r0, r0, r6 + 8009f3c: 2802 cmp r0, #2 + 8009f3e: d9d3 bls.n 8009ee8 + status = HAL_TIMEOUT; + 8009f40: 2003 movs r0, #3 +} + 8009f42: bd70 pop {r4, r5, r6, pc} + if((HAL_GetTick() - tickstart) > PLLSAI1_TIMEOUT_VALUE) + 8009f44: f7fd f8d2 bl 80070ec + 8009f48: 1b40 subs r0, r0, r5 + 8009f4a: 2802 cmp r0, #2 + 8009f4c: d8f8 bhi.n 8009f40 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI1RDY) == 0U) + 8009f4e: 6823 ldr r3, [r4, #0] + 8009f50: 011b lsls r3, r3, #4 + 8009f52: d5f7 bpl.n 8009f44 + 8009f54: 2000 movs r0, #0 + return status; + 8009f56: e7f4 b.n 8009f42 + 8009f58: 40021000 .word 0x40021000 + 8009f5c: 019d800f .word 0x019d800f + +08009f60 : +{ + 8009f60: b538 push {r3, r4, r5, lr} + __HAL_RCC_PLLSAI1_DISABLE(); + 8009f62: 4c11 ldr r4, [pc, #68] ; (8009fa8 ) + 8009f64: 6823 ldr r3, [r4, #0] + 8009f66: f023 6380 bic.w r3, r3, #67108864 ; 0x4000000 + 8009f6a: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 8009f6c: f7fd f8be bl 80070ec + 8009f70: 4605 mov r5, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI1RDY) != 0U) + 8009f72: 6823 ldr r3, [r4, #0] + 8009f74: f013 6300 ands.w r3, r3, #134217728 ; 0x8000000 + 8009f78: d10f bne.n 8009f9a + HAL_StatusTypeDef status = HAL_OK; + 8009f7a: 4618 mov r0, r3 + __HAL_RCC_PLLSAI1CLKOUT_DISABLE(RCC_PLLSAI1CFGR_PLLSAI1PEN|RCC_PLLSAI1CFGR_PLLSAI1QEN|RCC_PLLSAI1CFGR_PLLSAI1REN); + 8009f7c: 6923 ldr r3, [r4, #16] + 8009f7e: f023 7388 bic.w r3, r3, #17825792 ; 0x1100000 + 8009f82: f423 3380 bic.w r3, r3, #65536 ; 0x10000 + 8009f86: 6123 str r3, [r4, #16] + if(READ_BIT(RCC->CR, (RCC_CR_PLLRDY | RCC_CR_PLLSAI2RDY)) == 0U) + 8009f88: 6823 ldr r3, [r4, #0] + 8009f8a: f013 5f08 tst.w r3, #570425344 ; 0x22000000 + MODIFY_REG(RCC->PLLCFGR, RCC_PLLCFGR_PLLSRC, RCC_PLLSOURCE_NONE); + 8009f8e: bf02 ittt eq + 8009f90: 68e3 ldreq r3, [r4, #12] + 8009f92: f023 0303 biceq.w r3, r3, #3 + 8009f96: 60e3 streq r3, [r4, #12] +} + 8009f98: bd38 pop {r3, r4, r5, pc} + if((HAL_GetTick() - tickstart) > PLLSAI1_TIMEOUT_VALUE) + 8009f9a: f7fd f8a7 bl 80070ec + 8009f9e: 1b40 subs r0, r0, r5 + 8009fa0: 2802 cmp r0, #2 + 8009fa2: d9e6 bls.n 8009f72 + status = HAL_TIMEOUT; + 8009fa4: 2003 movs r0, #3 + 8009fa6: e7e9 b.n 8009f7c + 8009fa8: 40021000 .word 0x40021000 + +08009fac : +{ + 8009fac: b570 push {r4, r5, r6, lr} + __HAL_RCC_PLLSAI2_DISABLE(); + 8009fae: 4c20 ldr r4, [pc, #128] ; (800a030 ) + 8009fb0: 6823 ldr r3, [r4, #0] + 8009fb2: f023 5380 bic.w r3, r3, #268435456 ; 0x10000000 + 8009fb6: 6023 str r3, [r4, #0] +{ + 8009fb8: 4605 mov r5, r0 + tickstart = HAL_GetTick(); + 8009fba: f7fd f897 bl 80070ec + 8009fbe: 4606 mov r6, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI2RDY) != 0U) + 8009fc0: 6823 ldr r3, [r4, #0] + 8009fc2: 009a lsls r2, r3, #2 + 8009fc4: d423 bmi.n 800a00e + __HAL_RCC_PLLSAI2_CONFIG(PLLSAI2Init->PLLSAI2M, PLLSAI2Init->PLLSAI2N, PLLSAI2Init->PLLSAI2P, PLLSAI2Init->PLLSAI2Q, PLLSAI2Init->PLLSAI2R); + 8009fc6: e9d5 2302 ldrd r2, r3, [r5, #8] + 8009fca: 06db lsls r3, r3, #27 + 8009fcc: 6961 ldr r1, [r4, #20] + 8009fce: ea43 2302 orr.w r3, r3, r2, lsl #8 + 8009fd2: 4a18 ldr r2, [pc, #96] ; (800a034 ) + 8009fd4: 400a ands r2, r1 + 8009fd6: 4313 orrs r3, r2 + 8009fd8: 686a ldr r2, [r5, #4] + 8009fda: 3a01 subs r2, #1 + 8009fdc: ea43 1302 orr.w r3, r3, r2, lsl #4 + 8009fe0: 692a ldr r2, [r5, #16] + 8009fe2: 0852 lsrs r2, r2, #1 + 8009fe4: 3a01 subs r2, #1 + 8009fe6: ea43 5342 orr.w r3, r3, r2, lsl #21 + 8009fea: 696a ldr r2, [r5, #20] + 8009fec: 0852 lsrs r2, r2, #1 + 8009fee: 3a01 subs r2, #1 + 8009ff0: ea43 6342 orr.w r3, r3, r2, lsl #25 + 8009ff4: 6163 str r3, [r4, #20] + __HAL_RCC_PLLSAI2CLKOUT_ENABLE(PLLSAI2Init->PLLSAI2ClockOut); + 8009ff6: 6963 ldr r3, [r4, #20] + 8009ff8: 69aa ldr r2, [r5, #24] + 8009ffa: 4313 orrs r3, r2 + 8009ffc: 6163 str r3, [r4, #20] + __HAL_RCC_PLLSAI2_ENABLE(); + 8009ffe: 6823 ldr r3, [r4, #0] + 800a000: f043 5380 orr.w r3, r3, #268435456 ; 0x10000000 + 800a004: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 800a006: f7fd f871 bl 80070ec + 800a00a: 4605 mov r5, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI2RDY) == 0U) + 800a00c: e00b b.n 800a026 + if((HAL_GetTick() - tickstart) > PLLSAI2_TIMEOUT_VALUE) + 800a00e: f7fd f86d bl 80070ec + 800a012: 1b80 subs r0, r0, r6 + 800a014: 2802 cmp r0, #2 + 800a016: d9d3 bls.n 8009fc0 + status = HAL_TIMEOUT; + 800a018: 2003 movs r0, #3 +} + 800a01a: bd70 pop {r4, r5, r6, pc} + if((HAL_GetTick() - tickstart) > PLLSAI2_TIMEOUT_VALUE) + 800a01c: f7fd f866 bl 80070ec + 800a020: 1b40 subs r0, r0, r5 + 800a022: 2802 cmp r0, #2 + 800a024: d8f8 bhi.n 800a018 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI2RDY) == 0U) + 800a026: 6823 ldr r3, [r4, #0] + 800a028: 009b lsls r3, r3, #2 + 800a02a: d5f7 bpl.n 800a01c + 800a02c: 2000 movs r0, #0 + return status; + 800a02e: e7f4 b.n 800a01a + 800a030: 40021000 .word 0x40021000 + 800a034: 019d800f .word 0x019d800f + +0800a038 : +{ + 800a038: b538 push {r3, r4, r5, lr} + __HAL_RCC_PLLSAI2_DISABLE(); + 800a03a: 4c11 ldr r4, [pc, #68] ; (800a080 ) + 800a03c: 6823 ldr r3, [r4, #0] + 800a03e: f023 5380 bic.w r3, r3, #268435456 ; 0x10000000 + 800a042: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 800a044: f7fd f852 bl 80070ec + 800a048: 4605 mov r5, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI2RDY) != 0U) + 800a04a: 6823 ldr r3, [r4, #0] + 800a04c: f013 5300 ands.w r3, r3, #536870912 ; 0x20000000 + 800a050: d10f bne.n 800a072 + HAL_StatusTypeDef status = HAL_OK; + 800a052: 4618 mov r0, r3 + __HAL_RCC_PLLSAI2CLKOUT_DISABLE(RCC_PLLSAI2CFGR_PLLSAI2PEN|RCC_PLLSAI2CFGR_PLLSAI2QEN|RCC_PLLSAI2CFGR_PLLSAI2REN); + 800a054: 6963 ldr r3, [r4, #20] + 800a056: f023 7388 bic.w r3, r3, #17825792 ; 0x1100000 + 800a05a: f423 3380 bic.w r3, r3, #65536 ; 0x10000 + 800a05e: 6163 str r3, [r4, #20] + if(READ_BIT(RCC->CR, (RCC_CR_PLLRDY | RCC_CR_PLLSAI1RDY)) == 0U) + 800a060: 6823 ldr r3, [r4, #0] + 800a062: f013 6f20 tst.w r3, #167772160 ; 0xa000000 + MODIFY_REG(RCC->PLLCFGR, RCC_PLLCFGR_PLLSRC, RCC_PLLSOURCE_NONE); + 800a066: bf02 ittt eq + 800a068: 68e3 ldreq r3, [r4, #12] + 800a06a: f023 0303 biceq.w r3, r3, #3 + 800a06e: 60e3 streq r3, [r4, #12] +} + 800a070: bd38 pop {r3, r4, r5, pc} + if((HAL_GetTick() - tickstart) > PLLSAI2_TIMEOUT_VALUE) + 800a072: f7fd f83b bl 80070ec + 800a076: 1b40 subs r0, r0, r5 + 800a078: 2802 cmp r0, #2 + 800a07a: d9e6 bls.n 800a04a + status = HAL_TIMEOUT; + 800a07c: 2003 movs r0, #3 + 800a07e: e7e9 b.n 800a054 + 800a080: 40021000 .word 0x40021000 + +0800a084 : + __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(WakeUpClk); + 800a084: 4a03 ldr r2, [pc, #12] ; (800a094 ) + 800a086: 6893 ldr r3, [r2, #8] + 800a088: f423 4300 bic.w r3, r3, #32768 ; 0x8000 + 800a08c: 4318 orrs r0, r3 + 800a08e: 6090 str r0, [r2, #8] +} + 800a090: 4770 bx lr + 800a092: bf00 nop + 800a094: 40021000 .word 0x40021000 + +0800a098 : + __HAL_RCC_MSI_STANDBY_RANGE_CONFIG(MSIRange); + 800a098: 4a04 ldr r2, [pc, #16] ; (800a0ac ) + 800a09a: f8d2 3094 ldr.w r3, [r2, #148] ; 0x94 + 800a09e: f423 6370 bic.w r3, r3, #3840 ; 0xf00 + 800a0a2: ea43 1000 orr.w r0, r3, r0, lsl #4 + 800a0a6: f8c2 0094 str.w r0, [r2, #148] ; 0x94 +} + 800a0aa: 4770 bx lr + 800a0ac: 40021000 .word 0x40021000 + +0800a0b0 : + SET_BIT(RCC->BDCR, RCC_BDCR_LSECSSON); + 800a0b0: 4a03 ldr r2, [pc, #12] ; (800a0c0 ) + 800a0b2: f8d2 3090 ldr.w r3, [r2, #144] ; 0x90 + 800a0b6: f043 0320 orr.w r3, r3, #32 + 800a0ba: f8c2 3090 str.w r3, [r2, #144] ; 0x90 +} + 800a0be: 4770 bx lr + 800a0c0: 40021000 .word 0x40021000 + +0800a0c4 : + CLEAR_BIT(RCC->BDCR, RCC_BDCR_LSECSSON) ; + 800a0c4: 4b05 ldr r3, [pc, #20] ; (800a0dc ) + 800a0c6: f8d3 2090 ldr.w r2, [r3, #144] ; 0x90 + 800a0ca: f022 0220 bic.w r2, r2, #32 + 800a0ce: f8c3 2090 str.w r2, [r3, #144] ; 0x90 + __HAL_RCC_DISABLE_IT(RCC_IT_LSECSS); + 800a0d2: 699a ldr r2, [r3, #24] + 800a0d4: f422 7200 bic.w r2, r2, #512 ; 0x200 + 800a0d8: 619a str r2, [r3, #24] +} + 800a0da: 4770 bx lr + 800a0dc: 40021000 .word 0x40021000 + +0800a0e0 : + SET_BIT(RCC->BDCR, RCC_BDCR_LSECSSON) ; + 800a0e0: 4b0a ldr r3, [pc, #40] ; (800a10c ) + 800a0e2: f8d3 2090 ldr.w r2, [r3, #144] ; 0x90 + 800a0e6: f042 0220 orr.w r2, r2, #32 + 800a0ea: f8c3 2090 str.w r2, [r3, #144] ; 0x90 + __HAL_RCC_ENABLE_IT(RCC_IT_LSECSS); + 800a0ee: 699a ldr r2, [r3, #24] + 800a0f0: f442 7200 orr.w r2, r2, #512 ; 0x200 + 800a0f4: 619a str r2, [r3, #24] + __HAL_RCC_LSECSS_EXTI_ENABLE_IT(); + 800a0f6: f5a3 3386 sub.w r3, r3, #68608 ; 0x10c00 + 800a0fa: 681a ldr r2, [r3, #0] + 800a0fc: f442 2200 orr.w r2, r2, #524288 ; 0x80000 + 800a100: 601a str r2, [r3, #0] + __HAL_RCC_LSECSS_EXTI_ENABLE_RISING_EDGE(); + 800a102: 689a ldr r2, [r3, #8] + 800a104: f442 2200 orr.w r2, r2, #524288 ; 0x80000 + 800a108: 609a str r2, [r3, #8] +} + 800a10a: 4770 bx lr + 800a10c: 40021000 .word 0x40021000 + +0800a110 : +} + 800a110: 4770 bx lr + ... + +0800a114 : +{ + 800a114: b510 push {r4, lr} + if(__HAL_RCC_GET_IT(RCC_IT_LSECSS)) + 800a116: 4c05 ldr r4, [pc, #20] ; (800a12c ) + 800a118: 69e3 ldr r3, [r4, #28] + 800a11a: 059b lsls r3, r3, #22 + 800a11c: d504 bpl.n 800a128 + HAL_RCCEx_LSECSS_Callback(); + 800a11e: f7ff fff7 bl 800a110 + __HAL_RCC_CLEAR_IT(RCC_IT_LSECSS); + 800a122: f44f 7300 mov.w r3, #512 ; 0x200 + 800a126: 6223 str r3, [r4, #32] +} + 800a128: bd10 pop {r4, pc} + 800a12a: bf00 nop + 800a12c: 40021000 .word 0x40021000 + +0800a130 : + SET_BIT(RCC->CR, RCC_CR_MSIPLLEN) ; + 800a130: 4a02 ldr r2, [pc, #8] ; (800a13c ) + 800a132: 6813 ldr r3, [r2, #0] + 800a134: f043 0304 orr.w r3, r3, #4 + 800a138: 6013 str r3, [r2, #0] +} + 800a13a: 4770 bx lr + 800a13c: 40021000 .word 0x40021000 + +0800a140 : + CLEAR_BIT(RCC->CR, RCC_CR_MSIPLLEN) ; + 800a140: 4a02 ldr r2, [pc, #8] ; (800a14c ) + 800a142: 6813 ldr r3, [r2, #0] + 800a144: f023 0304 bic.w r3, r3, #4 + 800a148: 6013 str r3, [r2, #0] +} + 800a14a: 4770 bx lr + 800a14c: 40021000 .word 0x40021000 + +0800a150 : + MODIFY_REG(RCC->DLYCFGR, RCC_DLYCFGR_OCTOSPI1_DLY|RCC_DLYCFGR_OCTOSPI2_DLY, (Delay1 | (Delay2 << RCC_DLYCFGR_OCTOSPI2_DLY_Pos))) ; + 800a150: 4a05 ldr r2, [pc, #20] ; (800a168 ) + 800a152: f8d2 30a4 ldr.w r3, [r2, #164] ; 0xa4 + 800a156: f023 03ff bic.w r3, r3, #255 ; 0xff + 800a15a: 4318 orrs r0, r3 + 800a15c: ea40 1101 orr.w r1, r0, r1, lsl #4 + 800a160: f8c2 10a4 str.w r1, [r2, #164] ; 0xa4 +} + 800a164: 4770 bx lr + 800a166: bf00 nop + 800a168: 40021000 .word 0x40021000 + +0800a16c : + __HAL_RCC_CRS_FORCE_RESET(); + 800a16c: 4b10 ldr r3, [pc, #64] ; (800a1b0 ) + 800a16e: 6b9a ldr r2, [r3, #56] ; 0x38 + 800a170: f042 7280 orr.w r2, r2, #16777216 ; 0x1000000 + 800a174: 639a str r2, [r3, #56] ; 0x38 + __HAL_RCC_CRS_RELEASE_RESET(); + 800a176: 6b9a ldr r2, [r3, #56] ; 0x38 + 800a178: f022 7280 bic.w r2, r2, #16777216 ; 0x1000000 + 800a17c: 639a str r2, [r3, #56] ; 0x38 + value = (pInit->Prescaler | pInit->Source | pInit->Polarity); + 800a17e: e9d0 3200 ldrd r3, r2, [r0] + 800a182: 4313 orrs r3, r2 + 800a184: 6882 ldr r2, [r0, #8] + 800a186: 4313 orrs r3, r2 + value |= pInit->ReloadValue; + 800a188: 68c2 ldr r2, [r0, #12] + 800a18a: 4313 orrs r3, r2 + value |= (pInit->ErrorLimitValue << CRS_CFGR_FELIM_Pos); + 800a18c: 6902 ldr r2, [r0, #16] + 800a18e: ea43 4302 orr.w r3, r3, r2, lsl #16 + WRITE_REG(CRS->CFGR, value); + 800a192: 4a08 ldr r2, [pc, #32] ; (800a1b4 ) + 800a194: 6053 str r3, [r2, #4] + MODIFY_REG(CRS->CR, CRS_CR_TRIM, (pInit->HSI48CalibrationValue << CRS_CR_TRIM_Pos)); + 800a196: 6813 ldr r3, [r2, #0] + 800a198: 6941 ldr r1, [r0, #20] + 800a19a: f423 537c bic.w r3, r3, #16128 ; 0x3f00 + 800a19e: ea43 2301 orr.w r3, r3, r1, lsl #8 + 800a1a2: 6013 str r3, [r2, #0] + SET_BIT(CRS->CR, CRS_CR_AUTOTRIMEN | CRS_CR_CEN); + 800a1a4: 6813 ldr r3, [r2, #0] + 800a1a6: f043 0360 orr.w r3, r3, #96 ; 0x60 + 800a1aa: 6013 str r3, [r2, #0] +} + 800a1ac: 4770 bx lr + 800a1ae: bf00 nop + 800a1b0: 40021000 .word 0x40021000 + 800a1b4: 40006000 .word 0x40006000 + +0800a1b8 : + SET_BIT(CRS->CR, CRS_CR_SWSYNC); + 800a1b8: 4a02 ldr r2, [pc, #8] ; (800a1c4 ) + 800a1ba: 6813 ldr r3, [r2, #0] + 800a1bc: f043 0380 orr.w r3, r3, #128 ; 0x80 + 800a1c0: 6013 str r3, [r2, #0] +} + 800a1c2: 4770 bx lr + 800a1c4: 40006000 .word 0x40006000 + +0800a1c8 : + pSynchroInfo->ReloadValue = (READ_BIT(CRS->CFGR, CRS_CFGR_RELOAD)); + 800a1c8: 4b07 ldr r3, [pc, #28] ; (800a1e8 ) + 800a1ca: 685a ldr r2, [r3, #4] + 800a1cc: b292 uxth r2, r2 + 800a1ce: 6002 str r2, [r0, #0] + pSynchroInfo->HSI48CalibrationValue = (READ_BIT(CRS->CR, CRS_CR_TRIM) >> CRS_CR_TRIM_Pos); + 800a1d0: 681a ldr r2, [r3, #0] + 800a1d2: f3c2 2205 ubfx r2, r2, #8, #6 + 800a1d6: 6042 str r2, [r0, #4] + pSynchroInfo->FreqErrorCapture = (READ_BIT(CRS->ISR, CRS_ISR_FECAP) >> CRS_ISR_FECAP_Pos); + 800a1d8: 689a ldr r2, [r3, #8] + 800a1da: 0c12 lsrs r2, r2, #16 + 800a1dc: 6082 str r2, [r0, #8] + pSynchroInfo->FreqErrorDirection = (READ_BIT(CRS->ISR, CRS_ISR_FEDIR)); + 800a1de: 689b ldr r3, [r3, #8] + 800a1e0: f403 4300 and.w r3, r3, #32768 ; 0x8000 + 800a1e4: 60c3 str r3, [r0, #12] +} + 800a1e6: 4770 bx lr + 800a1e8: 40006000 .word 0x40006000 + +0800a1ec : +{ + 800a1ec: b5f8 push {r3, r4, r5, r6, r7, lr} + 800a1ee: 4605 mov r5, r0 + tickstart = HAL_GetTick(); + 800a1f0: f7fc ff7c bl 80070ec + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_SYNCOK)) + 800a1f4: 4c1e ldr r4, [pc, #120] ; (800a270 ) + tickstart = HAL_GetTick(); + 800a1f6: 4606 mov r6, r0 + __HAL_RCC_CRS_CLEAR_FLAG(RCC_CRS_FLAG_SYNCOK); + 800a1f8: 2701 movs r7, #1 + if(Timeout != HAL_MAX_DELAY) + 800a1fa: 1c68 adds r0, r5, #1 + 800a1fc: d12f bne.n 800a25e + crsstatus = RCC_CRS_TIMEOUT; + 800a1fe: 2000 movs r0, #0 + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_SYNCOK)) + 800a200: 68a2 ldr r2, [r4, #8] + 800a202: 07d1 lsls r1, r2, #31 + __HAL_RCC_CRS_CLEAR_FLAG(RCC_CRS_FLAG_SYNCOK); + 800a204: bf48 it mi + 800a206: 60e7 strmi r7, [r4, #12] + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_SYNCWARN)) + 800a208: 68a2 ldr r2, [r4, #8] + crsstatus |= RCC_CRS_SYNCOK; + 800a20a: bf48 it mi + 800a20c: f040 0002 orrmi.w r0, r0, #2 + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_SYNCWARN)) + 800a210: 0792 lsls r2, r2, #30 + __HAL_RCC_CRS_CLEAR_FLAG(RCC_CRS_FLAG_SYNCWARN); + 800a212: bf44 itt mi + 800a214: 2202 movmi r2, #2 + 800a216: 60e2 strmi r2, [r4, #12] + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_TRIMOVF)) + 800a218: 68a2 ldr r2, [r4, #8] + crsstatus |= RCC_CRS_SYNCWARN; + 800a21a: bf48 it mi + 800a21c: f040 0004 orrmi.w r0, r0, #4 + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_TRIMOVF)) + 800a220: 0553 lsls r3, r2, #21 + __HAL_RCC_CRS_CLEAR_FLAG(RCC_CRS_FLAG_TRIMOVF); + 800a222: bf44 itt mi + 800a224: 2204 movmi r2, #4 + 800a226: 60e2 strmi r2, [r4, #12] + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_SYNCERR)) + 800a228: 68a2 ldr r2, [r4, #8] + crsstatus |= RCC_CRS_TRIMOVF; + 800a22a: bf48 it mi + 800a22c: f040 0020 orrmi.w r0, r0, #32 + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_SYNCERR)) + 800a230: 05d1 lsls r1, r2, #23 + __HAL_RCC_CRS_CLEAR_FLAG(RCC_CRS_FLAG_SYNCERR); + 800a232: bf44 itt mi + 800a234: 2204 movmi r2, #4 + 800a236: 60e2 strmi r2, [r4, #12] + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_SYNCMISS)) + 800a238: 68a2 ldr r2, [r4, #8] + crsstatus |= RCC_CRS_SYNCERR; + 800a23a: bf48 it mi + 800a23c: f040 0008 orrmi.w r0, r0, #8 + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_SYNCMISS)) + 800a240: 0592 lsls r2, r2, #22 + __HAL_RCC_CRS_CLEAR_FLAG(RCC_CRS_FLAG_SYNCMISS); + 800a242: bf44 itt mi + 800a244: 2204 movmi r2, #4 + 800a246: 60e2 strmi r2, [r4, #12] + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_ESYNC)) + 800a248: 68a2 ldr r2, [r4, #8] + crsstatus |= RCC_CRS_SYNCMISS; + 800a24a: bf48 it mi + 800a24c: f040 0010 orrmi.w r0, r0, #16 + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_ESYNC)) + 800a250: 0713 lsls r3, r2, #28 + __HAL_RCC_CRS_CLEAR_FLAG(RCC_CRS_FLAG_ESYNC); + 800a252: bf44 itt mi + 800a254: 2208 movmi r2, #8 + 800a256: 60e2 strmi r2, [r4, #12] + } while(RCC_CRS_NONE == crsstatus); + 800a258: 2800 cmp r0, #0 + 800a25a: d0ce beq.n 800a1fa +} + 800a25c: bdf8 pop {r3, r4, r5, r6, r7, pc} + if(((HAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U)) + 800a25e: f7fc ff45 bl 80070ec + 800a262: 1b80 subs r0, r0, r6 + 800a264: 42a8 cmp r0, r5 + 800a266: d801 bhi.n 800a26c + 800a268: 2d00 cmp r5, #0 + 800a26a: d1c8 bne.n 800a1fe + crsstatus = RCC_CRS_TIMEOUT; + 800a26c: 2001 movs r0, #1 + 800a26e: e7c7 b.n 800a200 + 800a270: 40006000 .word 0x40006000 + +0800a274 : + 800a274: 4770 bx lr + +0800a276 : + 800a276: 4770 bx lr + +0800a278 : + 800a278: 4770 bx lr + +0800a27a : +} + 800a27a: 4770 bx lr + +0800a27c : + uint32_t itflags = READ_REG(CRS->ISR); + 800a27c: 491b ldr r1, [pc, #108] ; (800a2ec ) +{ + 800a27e: b508 push {r3, lr} + uint32_t itflags = READ_REG(CRS->ISR); + 800a280: 688b ldr r3, [r1, #8] + uint32_t itsources = READ_REG(CRS->CR); + 800a282: 680a ldr r2, [r1, #0] + if(((itflags & RCC_CRS_FLAG_SYNCOK) != 0U) && ((itsources & RCC_CRS_IT_SYNCOK) != 0U)) + 800a284: 07d8 lsls r0, r3, #31 + 800a286: d506 bpl.n 800a296 + 800a288: 07d0 lsls r0, r2, #31 + 800a28a: d504 bpl.n 800a296 + WRITE_REG(CRS->ICR, CRS_ICR_SYNCOKC); + 800a28c: 2301 movs r3, #1 + 800a28e: 60cb str r3, [r1, #12] + HAL_RCCEx_CRS_SyncOkCallback(); + 800a290: f7ff fff0 bl 800a274 +} + 800a294: bd08 pop {r3, pc} + else if(((itflags & RCC_CRS_FLAG_SYNCWARN) != 0U) && ((itsources & RCC_CRS_IT_SYNCWARN) != 0U)) + 800a296: 0798 lsls r0, r3, #30 + 800a298: d507 bpl.n 800a2aa + 800a29a: 0791 lsls r1, r2, #30 + 800a29c: d505 bpl.n 800a2aa + WRITE_REG(CRS->ICR, CRS_ICR_SYNCWARNC); + 800a29e: 4b13 ldr r3, [pc, #76] ; (800a2ec ) + 800a2a0: 2202 movs r2, #2 + 800a2a2: 60da str r2, [r3, #12] + HAL_RCCEx_CRS_SyncWarnCallback(); + 800a2a4: f7ff ffe7 bl 800a276 + 800a2a8: e7f4 b.n 800a294 + else if(((itflags & RCC_CRS_FLAG_ESYNC) != 0U) && ((itsources & RCC_CRS_IT_ESYNC) != 0U)) + 800a2aa: 0718 lsls r0, r3, #28 + 800a2ac: d507 bpl.n 800a2be + 800a2ae: 0711 lsls r1, r2, #28 + 800a2b0: d505 bpl.n 800a2be + WRITE_REG(CRS->ICR, CRS_ICR_ESYNCC); + 800a2b2: 4b0e ldr r3, [pc, #56] ; (800a2ec ) + 800a2b4: 2208 movs r2, #8 + 800a2b6: 60da str r2, [r3, #12] + HAL_RCCEx_CRS_ExpectedSyncCallback(); + 800a2b8: f7ff ffde bl 800a278 + 800a2bc: e7ea b.n 800a294 + if(((itflags & RCC_CRS_FLAG_ERR) != 0U) && ((itsources & RCC_CRS_IT_ERR) != 0U)) + 800a2be: 0758 lsls r0, r3, #29 + 800a2c0: d5e8 bpl.n 800a294 + 800a2c2: 0751 lsls r1, r2, #29 + 800a2c4: d5e6 bpl.n 800a294 + crserror |= RCC_CRS_SYNCERR; + 800a2c6: f413 7080 ands.w r0, r3, #256 ; 0x100 + 800a2ca: bf18 it ne + 800a2cc: 2008 movne r0, #8 + if((itflags & RCC_CRS_FLAG_SYNCMISS) != 0U) + 800a2ce: 059a lsls r2, r3, #22 + crserror |= RCC_CRS_SYNCMISS; + 800a2d0: bf48 it mi + 800a2d2: f040 0010 orrmi.w r0, r0, #16 + if((itflags & RCC_CRS_FLAG_TRIMOVF) != 0U) + 800a2d6: 055b lsls r3, r3, #21 + WRITE_REG(CRS->ICR, CRS_ICR_ERRC); + 800a2d8: 4b04 ldr r3, [pc, #16] ; (800a2ec ) + 800a2da: f04f 0204 mov.w r2, #4 + crserror |= RCC_CRS_TRIMOVF; + 800a2de: bf48 it mi + 800a2e0: f040 0020 orrmi.w r0, r0, #32 + WRITE_REG(CRS->ICR, CRS_ICR_ERRC); + 800a2e4: 60da str r2, [r3, #12] + HAL_RCCEx_CRS_ErrorCallback(crserror); + 800a2e6: f7ff ffc8 bl 800a27a +} + 800a2ea: e7d3 b.n 800a294 + 800a2ec: 40006000 .word 0x40006000 + +0800a2f0 : + * processing is suspended when possible and the Peripheral feeding point reached at + * suspension time is stored in the handle for resumption later on. + * @retval HAL status + */ +static HAL_StatusTypeDef HASH_WriteData(HASH_HandleTypeDef *hhash, uint8_t *pInBuffer, uint32_t Size) +{ + 800a2f0: b573 push {r0, r1, r4, r5, r6, lr} + __IO uint32_t inputaddr = (uint32_t) pInBuffer; + + for(buffercounter = 0U; buffercounter < Size; buffercounter+=4U) + { + /* Write input data 4 bytes at a time */ + HASH->DIN = *(uint32_t*)inputaddr; + 800a2f2: 4d1e ldr r5, [pc, #120] ; (800a36c ) + __IO uint32_t inputaddr = (uint32_t) pInBuffer; + 800a2f4: 9101 str r1, [sp, #4] +{ + 800a2f6: 4604 mov r4, r0 + for(buffercounter = 0U; buffercounter < Size; buffercounter+=4U) + 800a2f8: 2100 movs r1, #0 + 800a2fa: 4291 cmp r1, r2 + 800a2fc: d221 bcs.n 800a342 + HASH->DIN = *(uint32_t*)inputaddr; + 800a2fe: 9b01 ldr r3, [sp, #4] + 800a300: 681b ldr r3, [r3, #0] + 800a302: 606b str r3, [r5, #4] + inputaddr+=4U; + 800a304: 9b01 ldr r3, [sp, #4] + + /* If the suspension flag has been raised and if the processing is not about + to end, suspend processing */ + if ((hhash->SuspendRequest == HAL_HASH_SUSPEND) && ((buffercounter+4U) < Size)) + 800a306: f894 0036 ldrb.w r0, [r4, #54] ; 0x36 + inputaddr+=4U; + 800a30a: 3304 adds r3, #4 + if ((hhash->SuspendRequest == HAL_HASH_SUSPEND) && ((buffercounter+4U) < Size)) + 800a30c: 2801 cmp r0, #1 + inputaddr+=4U; + 800a30e: 9301 str r3, [sp, #4] + if ((hhash->SuspendRequest == HAL_HASH_SUSPEND) && ((buffercounter+4U) < Size)) + 800a310: f101 0304 add.w r3, r1, #4 + 800a314: d127 bne.n 800a366 + 800a316: 4293 cmp r3, r2 + 800a318: d225 bcs.n 800a366 + { + /* Wait for DINIS = 1, which occurs when 16 32-bit locations are free + in the input buffer */ + if (__HAL_HASH_GET_FLAG(HASH_FLAG_DINIS)) + 800a31a: 6a6e ldr r6, [r5, #36] ; 0x24 + 800a31c: 07f6 lsls r6, r6, #31 + 800a31e: d522 bpl.n 800a366 + /* Reset SuspendRequest */ + hhash->SuspendRequest = HAL_HASH_SUSPEND_NONE; + + /* Depending whether the key or the input data were fed to the Peripheral, the feeding point + reached at suspension time is not saved in the same handle fields */ + if ((hhash->Phase == HAL_HASH_PHASE_PROCESS) || (hhash->Phase == HAL_HASH_PHASE_HMAC_STEP_2)) + 800a320: f894 302d ldrb.w r3, [r4, #45] ; 0x2d + hhash->SuspendRequest = HAL_HASH_SUSPEND_NONE; + 800a324: 2500 movs r5, #0 + if ((hhash->Phase == HAL_HASH_PHASE_PROCESS) || (hhash->Phase == HAL_HASH_PHASE_HMAC_STEP_2)) + 800a326: 2b02 cmp r3, #2 + hhash->SuspendRequest = HAL_HASH_SUSPEND_NONE; + 800a328: f884 5036 strb.w r5, [r4, #54] ; 0x36 + if ((hhash->Phase == HAL_HASH_PHASE_PROCESS) || (hhash->Phase == HAL_HASH_PHASE_HMAC_STEP_2)) + 800a32c: d001 beq.n 800a332 + 800a32e: 2b04 cmp r3, #4 + 800a330: d109 bne.n 800a346 + { + /* Save current reading and writing locations of Input and Output buffers */ + hhash->pHashInBuffPtr = (uint8_t *)inputaddr; + /* Save the number of bytes that remain to be processed at this point */ + hhash->HashInCount = Size - (buffercounter + 4U); + 800a332: 3a04 subs r2, #4 + hhash->pHashInBuffPtr = (uint8_t *)inputaddr; + 800a334: 9b01 ldr r3, [sp, #4] + 800a336: 60e3 str r3, [r4, #12] + hhash->HashInCount = Size - (buffercounter + 4U); + 800a338: 1a52 subs r2, r2, r1 + 800a33a: 6222 str r2, [r4, #32] + __HAL_UNLOCK(hhash); + return HAL_ERROR; + } + + /* Set the HASH state to Suspended and exit to stop entering data */ + hhash->State = HAL_HASH_STATE_SUSPENDED; + 800a33c: 2308 movs r3, #8 + 800a33e: f884 3035 strb.w r3, [r4, #53] ; 0x35 + } /* if (__HAL_HASH_GET_FLAG(HASH_FLAG_DINIS)) */ + } /* if ((hhash->SuspendRequest == HAL_HASH_SUSPEND) && ((buffercounter+4) < Size)) */ + } /* for(buffercounter = 0; buffercounter < Size; buffercounter+=4) */ + + /* At this point, all the data have been entered to the Peripheral: exit */ + return HAL_OK; + 800a342: 2000 movs r0, #0 + 800a344: e00d b.n 800a362 + else if ((hhash->Phase == HAL_HASH_PHASE_HMAC_STEP_1) || (hhash->Phase == HAL_HASH_PHASE_HMAC_STEP_3)) + 800a346: 2b03 cmp r3, #3 + 800a348: d001 beq.n 800a34e + 800a34a: 2b05 cmp r3, #5 + 800a34c: d105 bne.n 800a35a + hhash->HashKeyCount = Size - (buffercounter + 4U); + 800a34e: 3a04 subs r2, #4 + hhash->pHashKeyBuffPtr = (uint8_t *)inputaddr; + 800a350: 9b01 ldr r3, [sp, #4] + 800a352: 6163 str r3, [r4, #20] + hhash->HashKeyCount = Size - (buffercounter + 4U); + 800a354: 1a52 subs r2, r2, r1 + 800a356: 62a2 str r2, [r4, #40] ; 0x28 + 800a358: e7f0 b.n 800a33c + hhash->State = HAL_HASH_STATE_READY; + 800a35a: f884 0035 strb.w r0, [r4, #53] ; 0x35 + __HAL_UNLOCK(hhash); + 800a35e: f884 5034 strb.w r5, [r4, #52] ; 0x34 +} + 800a362: b002 add sp, #8 + 800a364: bd70 pop {r4, r5, r6, pc} + 800a366: 4619 mov r1, r3 + 800a368: e7c7 b.n 800a2fa + 800a36a: bf00 nop + 800a36c: 50060400 .word 0x50060400 + +0800a370 : + */ +static void HASH_GetDigest(uint8_t *pMsgDigest, uint8_t Size) +{ + uint32_t msgdigest = (uint32_t)pMsgDigest; + + switch(Size) + 800a370: 291c cmp r1, #28 + 800a372: d027 beq.n 800a3c4 + 800a374: d804 bhi.n 800a380 + 800a376: 2910 cmp r1, #16 + 800a378: d005 beq.n 800a386 + 800a37a: 2914 cmp r1, #20 + 800a37c: d011 beq.n 800a3a2 + 800a37e: 4770 bx lr + 800a380: 2920 cmp r1, #32 + 800a382: d037 beq.n 800a3f4 + 800a384: 4770 bx lr + { + /* Read the message digest */ + case 16: /* MD5 */ + *(uint32_t*)(msgdigest) = __REV(HASH->HR[0]); + 800a386: 4b29 ldr r3, [pc, #164] ; (800a42c ) + 800a388: 68da ldr r2, [r3, #12] + \return Reversed value + */ +__STATIC_FORCEINLINE uint32_t __REV(uint32_t value) +{ +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) + return __builtin_bswap32(value); + 800a38a: ba12 rev r2, r2 + 800a38c: 6002 str r2, [r0, #0] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[1]); + 800a38e: 691a ldr r2, [r3, #16] + 800a390: ba12 rev r2, r2 + 800a392: 6042 str r2, [r0, #4] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[2]); + 800a394: 695a ldr r2, [r3, #20] + 800a396: ba12 rev r2, r2 + 800a398: 6082 str r2, [r0, #8] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[3]); + 800a39a: 699b ldr r3, [r3, #24] + 800a39c: ba1b rev r3, r3 + 800a39e: 60c3 str r3, [r0, #12] + break; + 800a3a0: 4770 bx lr + case 20: /* SHA1 */ + *(uint32_t*)(msgdigest) = __REV(HASH->HR[0]); + 800a3a2: 4b22 ldr r3, [pc, #136] ; (800a42c ) + 800a3a4: 68da ldr r2, [r3, #12] + 800a3a6: ba12 rev r2, r2 + 800a3a8: 6002 str r2, [r0, #0] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[1]); + 800a3aa: 691a ldr r2, [r3, #16] + 800a3ac: ba12 rev r2, r2 + 800a3ae: 6042 str r2, [r0, #4] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[2]); + 800a3b0: 695a ldr r2, [r3, #20] + 800a3b2: ba12 rev r2, r2 + 800a3b4: 6082 str r2, [r0, #8] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[3]); + 800a3b6: 699a ldr r2, [r3, #24] + 800a3b8: ba12 rev r2, r2 + 800a3ba: 60c2 str r2, [r0, #12] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[4]); + 800a3bc: 69db ldr r3, [r3, #28] + 800a3be: ba1b rev r3, r3 + 800a3c0: 6103 str r3, [r0, #16] + break; + 800a3c2: 4770 bx lr + case 28: /* SHA224 */ + *(uint32_t*)(msgdigest) = __REV(HASH->HR[0]); + 800a3c4: 4b19 ldr r3, [pc, #100] ; (800a42c ) + 800a3c6: 68da ldr r2, [r3, #12] + 800a3c8: ba12 rev r2, r2 + 800a3ca: 6002 str r2, [r0, #0] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[1]); + 800a3cc: 691a ldr r2, [r3, #16] + 800a3ce: ba12 rev r2, r2 + 800a3d0: 6042 str r2, [r0, #4] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[2]); + 800a3d2: 695a ldr r2, [r3, #20] + 800a3d4: ba12 rev r2, r2 + 800a3d6: 6082 str r2, [r0, #8] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[3]); + 800a3d8: 699a ldr r2, [r3, #24] + 800a3da: ba12 rev r2, r2 + 800a3dc: 60c2 str r2, [r0, #12] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[4]); + 800a3de: 69db ldr r3, [r3, #28] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH_DIGEST->HR[5]); + 800a3e0: 4a13 ldr r2, [pc, #76] ; (800a430 ) + 800a3e2: ba1b rev r3, r3 + *(uint32_t*)(msgdigest) = __REV(HASH->HR[4]); + 800a3e4: 6103 str r3, [r0, #16] + *(uint32_t*)(msgdigest) = __REV(HASH_DIGEST->HR[5]); + 800a3e6: 6a53 ldr r3, [r2, #36] ; 0x24 + 800a3e8: ba1b rev r3, r3 + 800a3ea: 6143 str r3, [r0, #20] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH_DIGEST->HR[6]); + 800a3ec: 6a93 ldr r3, [r2, #40] ; 0x28 + 800a3ee: ba1b rev r3, r3 + 800a3f0: 6183 str r3, [r0, #24] + break; + 800a3f2: 4770 bx lr + case 32: /* SHA256 */ + *(uint32_t*)(msgdigest) = __REV(HASH->HR[0]); + 800a3f4: 4b0d ldr r3, [pc, #52] ; (800a42c ) + 800a3f6: 68da ldr r2, [r3, #12] + 800a3f8: ba12 rev r2, r2 + 800a3fa: 6002 str r2, [r0, #0] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[1]); + 800a3fc: 691a ldr r2, [r3, #16] + 800a3fe: ba12 rev r2, r2 + 800a400: 6042 str r2, [r0, #4] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[2]); + 800a402: 695a ldr r2, [r3, #20] + 800a404: ba12 rev r2, r2 + 800a406: 6082 str r2, [r0, #8] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[3]); + 800a408: 699a ldr r2, [r3, #24] + 800a40a: ba12 rev r2, r2 + 800a40c: 60c2 str r2, [r0, #12] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[4]); + 800a40e: 69db ldr r3, [r3, #28] + 800a410: ba1b rev r3, r3 + 800a412: 6103 str r3, [r0, #16] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH_DIGEST->HR[5]); + 800a414: 4b06 ldr r3, [pc, #24] ; (800a430 ) + 800a416: 6a5a ldr r2, [r3, #36] ; 0x24 + 800a418: ba12 rev r2, r2 + 800a41a: 6142 str r2, [r0, #20] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH_DIGEST->HR[6]); + 800a41c: 6a9a ldr r2, [r3, #40] ; 0x28 + 800a41e: ba12 rev r2, r2 + 800a420: 6182 str r2, [r0, #24] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH_DIGEST->HR[7]); + 800a422: 6adb ldr r3, [r3, #44] ; 0x2c + 800a424: ba1b rev r3, r3 + 800a426: 61c3 str r3, [r0, #28] + break; + default: + break; + } +} + 800a428: 4770 bx lr + 800a42a: bf00 nop + 800a42c: 50060400 .word 0x50060400 + 800a430: 50060700 .word 0x50060700 + +0800a434 : + * @param Status the Flag status (SET or RESET). + * @param Timeout Timeout duration. + * @retval HAL status + */ +static HAL_StatusTypeDef HASH_WaitOnFlagUntilTimeout(HASH_HandleTypeDef *hhash, uint32_t Flag, FlagStatus Status, uint32_t Timeout) +{ + 800a434: e92d 43f8 stmdb sp!, {r3, r4, r5, r6, r7, r8, r9, lr} + 800a438: 4604 mov r4, r0 + 800a43a: 460e mov r6, r1 + 800a43c: 4691 mov r9, r2 + 800a43e: 461d mov r5, r3 + uint32_t tickstart = HAL_GetTick(); + 800a440: f7fc fe54 bl 80070ec + 800a444: f8df 805c ldr.w r8, [pc, #92] ; 800a4a4 + 800a448: 4607 mov r7, r0 + + /* Wait until flag is set */ + if(Status == RESET) + 800a44a: f1b9 0f00 cmp.w r9, #0 + 800a44e: d021 beq.n 800a494 + } + } + } + else + { + while(__HAL_HASH_GET_FLAG(Flag) != RESET) + 800a450: f8d8 3024 ldr.w r3, [r8, #36] ; 0x24 + 800a454: ea36 0303 bics.w r3, r6, r3 + 800a458: d121 bne.n 800a49e + { + /* Check for the Timeout */ + if(Timeout != HAL_MAX_DELAY) + 800a45a: 1c6b adds r3, r5, #1 + 800a45c: d0f8 beq.n 800a450 + { + if(((HAL_GetTick()-tickstart) > Timeout) || (Timeout == 0U)) + 800a45e: f7fc fe45 bl 80070ec + 800a462: 1bc0 subs r0, r0, r7 + 800a464: 42a8 cmp r0, r5 + 800a466: d80a bhi.n 800a47e + 800a468: 2d00 cmp r5, #0 + 800a46a: d1f1 bne.n 800a450 + 800a46c: e007 b.n 800a47e + if(Timeout != HAL_MAX_DELAY) + 800a46e: 1c6a adds r2, r5, #1 + 800a470: d010 beq.n 800a494 + if(((HAL_GetTick()-tickstart) > Timeout) || (Timeout == 0U)) + 800a472: f7fc fe3b bl 80070ec + 800a476: 1bc0 subs r0, r0, r7 + 800a478: 42a8 cmp r0, r5 + 800a47a: d800 bhi.n 800a47e + 800a47c: b955 cbnz r5, 800a494 + { + /* Set State to Ready to be able to restart later on */ + hhash->State = HAL_HASH_STATE_READY; + 800a47e: 2301 movs r3, #1 + 800a480: f884 3035 strb.w r3, [r4, #53] ; 0x35 + /* Store time out issue in handle status */ + hhash->Status = HAL_TIMEOUT; + + /* Process Unlocked */ + __HAL_UNLOCK(hhash); + 800a484: 2200 movs r2, #0 + hhash->Status = HAL_TIMEOUT; + 800a486: 2303 movs r3, #3 + 800a488: f884 302c strb.w r3, [r4, #44] ; 0x2c + __HAL_UNLOCK(hhash); + 800a48c: f884 2034 strb.w r2, [r4, #52] ; 0x34 + + return HAL_TIMEOUT; + 800a490: 4618 mov r0, r3 + 800a492: e005 b.n 800a4a0 + while(__HAL_HASH_GET_FLAG(Flag) == RESET) + 800a494: f8d8 3024 ldr.w r3, [r8, #36] ; 0x24 + 800a498: ea36 0303 bics.w r3, r6, r3 + 800a49c: d1e7 bne.n 800a46e + } + } + } + } + return HAL_OK; + 800a49e: 2000 movs r0, #0 +} + 800a4a0: e8bd 83f8 ldmia.w sp!, {r3, r4, r5, r6, r7, r8, r9, pc} + 800a4a4: 50060400 .word 0x50060400 + +0800a4a8 : +} + 800a4a8: 4770 bx lr + ... + +0800a4ac : +{ + 800a4ac: b538 push {r3, r4, r5, lr} + if(hhash == NULL) + 800a4ae: 4604 mov r4, r0 + 800a4b0: b328 cbz r0, 800a4fe + if(hhash->State == HAL_HASH_STATE_RESET) + 800a4b2: f890 3035 ldrb.w r3, [r0, #53] ; 0x35 + 800a4b6: f003 02ff and.w r2, r3, #255 ; 0xff + 800a4ba: b91b cbnz r3, 800a4c4 + hhash->Lock = HAL_UNLOCKED; + 800a4bc: f880 2034 strb.w r2, [r0, #52] ; 0x34 + HAL_HASH_MspInit(hhash); + 800a4c0: f7ff fff2 bl 800a4a8 + hhash->HashInCount = 0; + 800a4c4: 2000 movs r0, #0 + MODIFY_REG(HASH->CR, HASH_CR_DATATYPE, hhash->Init.DataType); + 800a4c6: 4a0f ldr r2, [pc, #60] ; (800a504 ) + hhash->HashBuffSize = 0; + 800a4c8: 61e0 str r0, [r4, #28] + hhash->State = HAL_HASH_STATE_BUSY; + 800a4ca: 2302 movs r3, #2 + hhash->Phase = HAL_HASH_PHASE_READY; + 800a4cc: 2101 movs r1, #1 + hhash->State = HAL_HASH_STATE_BUSY; + 800a4ce: f884 3035 strb.w r3, [r4, #53] ; 0x35 + hhash->Phase = HAL_HASH_PHASE_READY; + 800a4d2: f884 102d strb.w r1, [r4, #45] ; 0x2d + hhash->HashInCount = 0; + 800a4d6: 6220 str r0, [r4, #32] + hhash->SuspendRequest = HAL_HASH_SUSPEND_NONE; + 800a4d8: 86e0 strh r0, [r4, #54] ; 0x36 + hhash->HashITCounter = 0; + 800a4da: 6260 str r0, [r4, #36] ; 0x24 + hhash->NbWordsAlreadyPushed = 0; + 800a4dc: 63a0 str r0, [r4, #56] ; 0x38 + MODIFY_REG(HASH->CR, HASH_CR_DATATYPE, hhash->Init.DataType); + 800a4de: 6813 ldr r3, [r2, #0] + 800a4e0: 6825 ldr r5, [r4, #0] + 800a4e2: f023 0330 bic.w r3, r3, #48 ; 0x30 + 800a4e6: 432b orrs r3, r5 + 800a4e8: 6013 str r3, [r2, #0] +__HAL_HASH_RESET_MDMAT(); + 800a4ea: 6813 ldr r3, [r2, #0] + 800a4ec: f423 5300 bic.w r3, r3, #8192 ; 0x2000 + 800a4f0: 6013 str r3, [r2, #0] + hhash->State = HAL_HASH_STATE_READY; + 800a4f2: f884 1035 strb.w r1, [r4, #53] ; 0x35 + hhash->Status = HAL_OK; + 800a4f6: f884 002c strb.w r0, [r4, #44] ; 0x2c + hhash->ErrorCode = HAL_HASH_ERROR_NONE; + 800a4fa: 63e0 str r0, [r4, #60] ; 0x3c +} + 800a4fc: bd38 pop {r3, r4, r5, pc} + return HAL_ERROR; + 800a4fe: 2001 movs r0, #1 + 800a500: e7fc b.n 800a4fc + 800a502: bf00 nop + 800a504: 50060400 .word 0x50060400 + +0800a508 : + 800a508: 4770 bx lr + +0800a50a : + 800a50a: 4770 bx lr + +0800a50c : + 800a50c: 4770 bx lr + +0800a50e : + 800a50e: 4770 bx lr + +0800a510 : +{ + 800a510: b570 push {r4, r5, r6, lr} + * suspension time is stored in the handle for resumption later on. + * @retval HAL status + */ +static HAL_StatusTypeDef HASH_IT(HASH_HandleTypeDef *hhash) +{ + if (hhash->State == HAL_HASH_STATE_BUSY) + 800a512: f890 3035 ldrb.w r3, [r0, #53] ; 0x35 + 800a516: 2b02 cmp r3, #2 +{ + 800a518: 4604 mov r4, r0 + if (hhash->State == HAL_HASH_STATE_BUSY) + 800a51a: b2da uxtb r2, r3 + 800a51c: f040 80e7 bne.w 800a6ee + { + /* ITCounter must not be equal to 0 at this point. Report an error if this is the case. */ + if(hhash->HashITCounter == 0U) + 800a520: 6a43 ldr r3, [r0, #36] ; 0x24 + 800a522: 4d74 ldr r5, [pc, #464] ; (800a6f4 ) + 800a524: b94b cbnz r3, 800a53a + { + /* Disable Interrupts */ + __HAL_HASH_DISABLE_IT(HASH_IT_DINI|HASH_IT_DCI); + 800a526: 6a2b ldr r3, [r5, #32] + 800a528: f023 0303 bic.w r3, r3, #3 + 800a52c: 622b str r3, [r5, #32] + /* HASH state set back to Ready to prevent any issue in user code + present in HAL_HASH_ErrorCallback() */ + hhash->State = HAL_HASH_STATE_READY; + 800a52e: 2301 movs r3, #1 + 800a530: f880 3035 strb.w r3, [r0, #53] ; 0x35 + hhash->Status = HASH_IT(hhash); + 800a534: f884 302c strb.w r3, [r4, #44] ; 0x2c + if (hhash->Status != HAL_OK) + 800a538: e099 b.n 800a66e + return HAL_ERROR; + } + else if (hhash->HashITCounter == 1U) + 800a53a: 6a43 ldr r3, [r0, #36] ; 0x24 + 800a53c: 2b01 cmp r3, #1 + } + else + { + /* Cruise speed reached, HashITCounter remains equal to 3 until the end of + the HASH processing or the end of the current step for HMAC processing. */ + hhash->HashITCounter = 3U; + 800a53e: bf16 itet ne + 800a540: 2303 movne r3, #3 + hhash->HashITCounter = 2U; + 800a542: 6242 streq r2, [r0, #36] ; 0x24 + hhash->HashITCounter = 3U; + 800a544: 6243 strne r3, [r0, #36] ; 0x24 + } + + /* If digest is ready */ + if (__HAL_HASH_GET_FLAG(HASH_FLAG_DCIS)) + 800a546: 6a6b ldr r3, [r5, #36] ; 0x24 + 800a548: f013 0302 ands.w r3, r3, #2 + 800a54c: d022 beq.n 800a594 + { + /* Read the digest */ + HASH_GetDigest(hhash->pHashOutBuffPtr, HASH_DIGEST_LENGTH()); + 800a54e: 682a ldr r2, [r5, #0] + 800a550: 4b69 ldr r3, [pc, #420] ; (800a6f8 ) + 800a552: 6900 ldr r0, [r0, #16] + 800a554: 421a tst r2, r3 + 800a556: d019 beq.n 800a58c + 800a558: 682a ldr r2, [r5, #0] + 800a55a: 401a ands r2, r3 + 800a55c: f5b2 2f80 cmp.w r2, #262144 ; 0x40000 + 800a560: d016 beq.n 800a590 + 800a562: 682a ldr r2, [r5, #0] + 800a564: 4393 bics r3, r2 + 800a566: bf0c ite eq + 800a568: 2120 moveq r1, #32 + 800a56a: 2110 movne r1, #16 + 800a56c: f7ff ff00 bl 800a370 + + /* Disable Interrupts */ + __HAL_HASH_DISABLE_IT(HASH_IT_DINI|HASH_IT_DCI); + 800a570: 6a2b ldr r3, [r5, #32] + 800a572: f023 0303 bic.w r3, r3, #3 + 800a576: 622b str r3, [r5, #32] + /* Change the HASH state */ + hhash->State = HAL_HASH_STATE_READY; + 800a578: 2301 movs r3, #1 + 800a57a: f884 3035 strb.w r3, [r4, #53] ; 0x35 + /* Reset HASH state machine */ + hhash->Phase = HAL_HASH_PHASE_READY; + 800a57e: f884 302d strb.w r3, [r4, #45] ; 0x2d + /* Call digest computation complete call back */ +#if (USE_HAL_HASH_REGISTER_CALLBACKS == 1) + hhash->DgstCpltCallback(hhash); +#else + HAL_HASH_DgstCpltCallback(hhash); + 800a582: 4620 mov r0, r4 + 800a584: f7ff ffc2 bl 800a50c + hhash->Status = HAL_OK; + 800a588: 2300 movs r3, #0 + 800a58a: e015 b.n 800a5b8 + HASH_GetDigest(hhash->pHashOutBuffPtr, HASH_DIGEST_LENGTH()); + 800a58c: 2114 movs r1, #20 + 800a58e: e7ed b.n 800a56c + 800a590: 211c movs r1, #28 + 800a592: e7eb b.n 800a56c + + return HAL_OK; + } + + /* If Peripheral ready to accept new data */ + if (__HAL_HASH_GET_FLAG(HASH_FLAG_DINIS)) + 800a594: 6a6a ldr r2, [r5, #36] ; 0x24 + 800a596: 07d2 lsls r2, r2, #31 + 800a598: d5f6 bpl.n 800a588 + { + + /* If the suspension flag has been raised and if the processing is not about + to end, suspend processing */ + if ( (hhash->HashInCount != 0U) && (hhash->SuspendRequest == HAL_HASH_SUSPEND)) + 800a59a: 6a02 ldr r2, [r0, #32] + 800a59c: b17a cbz r2, 800a5be + 800a59e: f890 2036 ldrb.w r2, [r0, #54] ; 0x36 + 800a5a2: 2a01 cmp r2, #1 + 800a5a4: d10b bne.n 800a5be + { + /* Disable Interrupts */ + __HAL_HASH_DISABLE_IT(HASH_IT_DINI|HASH_IT_DCI); + 800a5a6: 6a2a ldr r2, [r5, #32] + 800a5a8: f022 0203 bic.w r2, r2, #3 + 800a5ac: 622a str r2, [r5, #32] + + /* Reset SuspendRequest */ + hhash->SuspendRequest = HAL_HASH_SUSPEND_NONE; + + /* Change the HASH state */ + hhash->State = HAL_HASH_STATE_SUSPENDED; + 800a5ae: 2208 movs r2, #8 + hhash->SuspendRequest = HAL_HASH_SUSPEND_NONE; + 800a5b0: f880 3036 strb.w r3, [r0, #54] ; 0x36 + hhash->State = HAL_HASH_STATE_SUSPENDED; + 800a5b4: f880 2035 strb.w r2, [r0, #53] ; 0x35 + hhash->Status = HAL_OK; + 800a5b8: f884 302c strb.w r3, [r4, #44] ; 0x2c +} + 800a5bc: e076 b.n 800a6ac + uint32_t buffercounter; + uint32_t inputcounter; + uint32_t ret = HASH_DIGEST_CALCULATION_NOT_STARTED; + + /* If there are more than 64 bytes remaining to be entered */ + if(hhash->HashInCount > 64U) + 800a5be: 6a21 ldr r1, [r4, #32] + { + inputaddr = (uint32_t)hhash->pHashInBuffPtr; + 800a5c0: 68e3 ldr r3, [r4, #12] + if(hhash->HashInCount > 64U) + 800a5c2: 2940 cmp r1, #64 ; 0x40 + inputaddr = (uint32_t)hhash->pHashInBuffPtr; + 800a5c4: 461a mov r2, r3 + if(hhash->HashInCount > 64U) + 800a5c6: d91c bls.n 800a602 + 800a5c8: f103 0140 add.w r1, r3, #64 ; 0x40 + /* Write the Input block in the Data IN register + (16 32-bit words, or 64 bytes are entered) */ + for(buffercounter = 0U; buffercounter < 64U; buffercounter+=4U) + { + HASH->DIN = *(uint32_t*)inputaddr; + 800a5cc: f853 0b04 ldr.w r0, [r3], #4 + 800a5d0: 6068 str r0, [r5, #4] + for(buffercounter = 0U; buffercounter < 64U; buffercounter+=4U) + 800a5d2: 4299 cmp r1, r3 + 800a5d4: d1fa bne.n 800a5cc + inputaddr+=4U; + } + /* If this is the start of input data entering, an additional word + must be entered to start up the HASH processing */ + if(hhash->HashITCounter == 2U) + 800a5d6: 6a63 ldr r3, [r4, #36] ; 0x24 + 800a5d8: 2b02 cmp r3, #2 + 800a5da: d10d bne.n 800a5f8 + { + HASH->DIN = *(uint32_t*)inputaddr; + 800a5dc: 680b ldr r3, [r1, #0] + 800a5de: 606b str r3, [r5, #4] + if(hhash->HashInCount >= 68U) + 800a5e0: 6a23 ldr r3, [r4, #32] + 800a5e2: 2b43 cmp r3, #67 ; 0x43 + 800a5e4: d905 bls.n 800a5f2 + { + /* There are still data waiting to be entered in the Peripheral. + Decrement buffer counter and set pointer to the proper + memory location for the next data entering round. */ + hhash->HashInCount -= 68U; + 800a5e6: 6a23 ldr r3, [r4, #32] + 800a5e8: 3b44 subs r3, #68 ; 0x44 + 800a5ea: 6223 str r3, [r4, #32] + hhash->pHashInBuffPtr+= 68U; + 800a5ec: 3244 adds r2, #68 ; 0x44 + { + /* 64 bytes have been entered and there are still some remaining: + Decrement buffer counter and set pointer to the proper + memory location for the next data entering round.*/ + hhash->HashInCount -= 64U; + hhash->pHashInBuffPtr+= 64U; + 800a5ee: 60e2 str r2, [r4, #12] + /* Reset buffer counter */ + hhash->HashInCount = 0; + } + + /* Return whether or digest calculation has started */ + return ret; + 800a5f0: e7ca b.n 800a588 + hhash->HashInCount = 0U; + 800a5f2: 2300 movs r3, #0 + 800a5f4: 6223 str r3, [r4, #32] + return ret; + 800a5f6: e7c7 b.n 800a588 + hhash->HashInCount -= 64U; + 800a5f8: 6a23 ldr r3, [r4, #32] + 800a5fa: 3b40 subs r3, #64 ; 0x40 + 800a5fc: 6223 str r3, [r4, #32] + hhash->pHashInBuffPtr+= 64U; + 800a5fe: 3240 adds r2, #64 ; 0x40 + 800a600: e7f5 b.n 800a5ee + inputcounter = hhash->HashInCount; + 800a602: 6a22 ldr r2, [r4, #32] + __HAL_HASH_DISABLE_IT(HASH_IT_DINI); + 800a604: 6a29 ldr r1, [r5, #32] + for(buffercounter = 0U; buffercounter < ((inputcounter+3U)/4U); buffercounter++) + 800a606: 3203 adds r2, #3 + __HAL_HASH_DISABLE_IT(HASH_IT_DINI); + 800a608: f021 0101 bic.w r1, r1, #1 + 800a60c: f022 0203 bic.w r2, r2, #3 + 800a610: 6229 str r1, [r5, #32] + for(buffercounter = 0U; buffercounter < ((inputcounter+3U)/4U); buffercounter++) + 800a612: 441a add r2, r3 + 800a614: 4293 cmp r3, r2 + 800a616: d10b bne.n 800a630 + if (hhash->Accumulation == 1U) + 800a618: 6c23 ldr r3, [r4, #64] ; 0x40 + 800a61a: 2b01 cmp r3, #1 + 800a61c: d10c bne.n 800a638 + hhash->Accumulation = 0U; + 800a61e: 2500 movs r5, #0 + 800a620: 6425 str r5, [r4, #64] ; 0x40 + HAL_HASH_InCpltCallback(hhash); + 800a622: 4620 mov r0, r4 + hhash->State = HAL_HASH_STATE_READY; + 800a624: f884 3035 strb.w r3, [r4, #53] ; 0x35 + HAL_HASH_InCpltCallback(hhash); + 800a628: f7ff ff6f bl 800a50a + hhash->HashInCount = 0; + 800a62c: 6225 str r5, [r4, #32] + return ret; + 800a62e: e7ab b.n 800a588 + HASH->DIN = *(uint32_t*)inputaddr; + 800a630: f853 1b04 ldr.w r1, [r3], #4 + 800a634: 6069 str r1, [r5, #4] + for(buffercounter = 0U; buffercounter < ((inputcounter+3U)/4U); buffercounter++) + 800a636: e7ed b.n 800a614 + __HAL_HASH_START_DIGEST(); + 800a638: 68ab ldr r3, [r5, #8] + 800a63a: f443 7380 orr.w r3, r3, #256 ; 0x100 + 800a63e: 60ab str r3, [r5, #8] + hhash->HashInCount = 0; + 800a640: 2300 movs r3, #0 + 800a642: 6223 str r3, [r4, #32] + HAL_HASH_InCpltCallback(hhash); + 800a644: 4620 mov r0, r4 + 800a646: f7ff ff60 bl 800a50a + if (hhash->Phase == HAL_HASH_PHASE_HMAC_STEP_1) + 800a64a: f894 602d ldrb.w r6, [r4, #45] ; 0x2d + 800a64e: 2e03 cmp r6, #3 + 800a650: d12d bne.n 800a6ae + if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_BUSY, SET, HASH_TIMEOUTVALUE) != HAL_OK) + 800a652: f44f 737a mov.w r3, #1000 ; 0x3e8 + 800a656: 2201 movs r2, #1 + 800a658: 2108 movs r1, #8 + 800a65a: 4620 mov r0, r4 + 800a65c: f7ff feea bl 800a434 + 800a660: b168 cbz r0, 800a67e + __HAL_HASH_DISABLE_IT(HASH_IT_DINI|HASH_IT_DCI); + 800a662: 6a2b ldr r3, [r5, #32] + 800a664: f023 0303 bic.w r3, r3, #3 + 800a668: 622b str r3, [r5, #32] + hhash->Status = HASH_IT(hhash); + 800a66a: f884 602c strb.w r6, [r4, #44] ; 0x2c + hhash->ErrorCode |= HAL_HASH_ERROR_IT; + 800a66e: 6be3 ldr r3, [r4, #60] ; 0x3c + 800a670: f043 0301 orr.w r3, r3, #1 + 800a674: 63e3 str r3, [r4, #60] ; 0x3c + HAL_HASH_ErrorCallback(hhash); + 800a676: 4620 mov r0, r4 + 800a678: f7ff ff49 bl 800a50e + 800a67c: e784 b.n 800a588 + hhash->Phase = HAL_HASH_PHASE_HMAC_STEP_2; /* Move phase from Step 1 to Step 2 */ + 800a67e: 2304 movs r3, #4 + 800a680: f884 302d strb.w r3, [r4, #45] ; 0x2d + __HAL_HASH_SET_NBVALIDBITS(hhash->HashBuffSize); /* Set NBLW for the input message */ + 800a684: 68ab ldr r3, [r5, #8] + 800a686: 69e2 ldr r2, [r4, #28] + 800a688: f023 031f bic.w r3, r3, #31 + 800a68c: f002 0103 and.w r1, r2, #3 + 800a690: ea43 03c1 orr.w r3, r3, r1, lsl #3 + 800a694: 60ab str r3, [r5, #8] + hhash->pHashInBuffPtr = hhash->pHashMsgBuffPtr; /* Set the input data address */ + 800a696: 69a3 ldr r3, [r4, #24] + hhash->HashInCount = hhash->HashBuffSize; /* Set the input data size (in bytes) */ + 800a698: 6222 str r2, [r4, #32] + hhash->pHashInBuffPtr = hhash->Init.pKey; /* Set the key address */ + 800a69a: 60e3 str r3, [r4, #12] + hhash->HashITCounter = 1; /* Set ITCounter to 1 to indicate the start of a new phase */ + 800a69c: 2301 movs r3, #1 + 800a69e: 6263 str r3, [r4, #36] ; 0x24 + __HAL_HASH_ENABLE_IT(HASH_IT_DINI); /* Enable IT (was disabled in HASH_Write_Block_Data) */ + 800a6a0: 6a2b ldr r3, [r5, #32] + 800a6a2: f043 0301 orr.w r3, r3, #1 + 800a6a6: 622b str r3, [r5, #32] + hhash->Status = HASH_IT(hhash); + 800a6a8: f884 002c strb.w r0, [r4, #44] ; 0x2c +} + 800a6ac: bd70 pop {r4, r5, r6, pc} + else if (hhash->Phase == HAL_HASH_PHASE_HMAC_STEP_2) + 800a6ae: 2e04 cmp r6, #4 + 800a6b0: f47f af6a bne.w 800a588 + if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_BUSY, SET, HASH_TIMEOUTVALUE) != HAL_OK) + 800a6b4: f44f 737a mov.w r3, #1000 ; 0x3e8 + 800a6b8: 2201 movs r2, #1 + 800a6ba: 2108 movs r1, #8 + 800a6bc: 4620 mov r0, r4 + 800a6be: f7ff feb9 bl 800a434 + 800a6c2: b128 cbz r0, 800a6d0 + __HAL_HASH_DISABLE_IT(HASH_IT_DINI|HASH_IT_DCI); + 800a6c4: 6a2b ldr r3, [r5, #32] + 800a6c6: f023 0303 bic.w r3, r3, #3 + 800a6ca: 622b str r3, [r5, #32] + hhash->Status = HASH_IT(hhash); + 800a6cc: 2303 movs r3, #3 + 800a6ce: e731 b.n 800a534 + hhash->Phase = HAL_HASH_PHASE_HMAC_STEP_3; /* Move phase from Step 2 to Step 3 */ + 800a6d0: 2305 movs r3, #5 + 800a6d2: f884 302d strb.w r3, [r4, #45] ; 0x2d + __HAL_HASH_SET_NBVALIDBITS(hhash->Init.KeySize); /* Set NBLW for the key */ + 800a6d6: 68ab ldr r3, [r5, #8] + 800a6d8: 6862 ldr r2, [r4, #4] + 800a6da: f023 031f bic.w r3, r3, #31 + 800a6de: f002 0103 and.w r1, r2, #3 + 800a6e2: ea43 03c1 orr.w r3, r3, r1, lsl #3 + 800a6e6: 60ab str r3, [r5, #8] + hhash->pHashInBuffPtr = hhash->Init.pKey; /* Set the key address */ + 800a6e8: 68a3 ldr r3, [r4, #8] + hhash->HashInCount = hhash->Init.KeySize; /* Set the key size (in bytes) */ + 800a6ea: 6222 str r2, [r4, #32] + hhash->pHashInBuffPtr = hhash->Init.pKey; /* Set the key address */ + 800a6ec: e7d5 b.n 800a69a + hhash->Status = HASH_IT(hhash); + 800a6ee: 2302 movs r3, #2 + 800a6f0: e720 b.n 800a534 + 800a6f2: bf00 nop + 800a6f4: 50060400 .word 0x50060400 + 800a6f8: 00040080 .word 0x00040080 + +0800a6fc : + return hhash->State; + 800a6fc: f890 0035 ldrb.w r0, [r0, #53] ; 0x35 +} + 800a700: 4770 bx lr + +0800a702 : +} + 800a702: f890 002c ldrb.w r0, [r0, #44] ; 0x2c + 800a706: 4770 bx lr + +0800a708 : + *(uint32_t*)(mem_ptr) = READ_BIT(HASH->IMR,HASH_IT_DINI|HASH_IT_DCI); + 800a708: 4b0e ldr r3, [pc, #56] ; (800a744 ) + 800a70a: 6a1a ldr r2, [r3, #32] + 800a70c: f002 0203 and.w r2, r2, #3 + 800a710: 600a str r2, [r1, #0] + *(uint32_t*)(mem_ptr) = READ_BIT(HASH->STR,HASH_STR_NBLW); + 800a712: 689a ldr r2, [r3, #8] + 800a714: f002 021f and.w r2, r2, #31 + 800a718: 604a str r2, [r1, #4] + *(uint32_t*)(mem_ptr) = READ_BIT(HASH->CR,HASH_CR_DMAE|HASH_CR_DATATYPE|HASH_CR_MODE|HASH_CR_ALGO|HASH_CR_LKEY|HASH_CR_MDMAT); + 800a71a: 681b ldr r3, [r3, #0] + for (i = HASH_NUMBER_OF_CSR_REGISTERS; i >0U; i--) + 800a71c: 4a0a ldr r2, [pc, #40] ; (800a748 ) + *(uint32_t*)(mem_ptr) = READ_BIT(HASH->CR,HASH_CR_DMAE|HASH_CR_DATATYPE|HASH_CR_MODE|HASH_CR_ALGO|HASH_CR_LKEY|HASH_CR_MDMAT); + 800a71e: f023 437f bic.w r3, r3, #4278190080 ; 0xff000000 + 800a722: f423 037a bic.w r3, r3, #16384000 ; 0xfa0000 + 800a726: f423 435f bic.w r3, r3, #57088 ; 0xdf00 + 800a72a: f023 0307 bic.w r3, r3, #7 + 800a72e: 608b str r3, [r1, #8] + uint32_t csr_ptr = (uint32_t)HASH->CSR; + 800a730: 4b06 ldr r3, [pc, #24] ; (800a74c ) + mem_ptr+=4U; + 800a732: 310c adds r1, #12 + *(uint32_t*)(mem_ptr) = *(uint32_t*)(csr_ptr); + 800a734: f853 0b04 ldr.w r0, [r3], #4 + 800a738: f841 0b04 str.w r0, [r1], #4 + for (i = HASH_NUMBER_OF_CSR_REGISTERS; i >0U; i--) + 800a73c: 4293 cmp r3, r2 + 800a73e: d1f9 bne.n 800a734 +} + 800a740: 4770 bx lr + 800a742: bf00 nop + 800a744: 50060400 .word 0x50060400 + 800a748: 500605d0 .word 0x500605d0 + 800a74c: 500604f8 .word 0x500604f8 + +0800a750 : + WRITE_REG(HASH->IMR, (*(uint32_t*)(mem_ptr))); + 800a750: 4b0a ldr r3, [pc, #40] ; (800a77c ) + 800a752: 680a ldr r2, [r1, #0] + 800a754: 621a str r2, [r3, #32] + WRITE_REG(HASH->STR, (*(uint32_t*)(mem_ptr))); + 800a756: 684a ldr r2, [r1, #4] + 800a758: 609a str r2, [r3, #8] + WRITE_REG(HASH->CR, (*(uint32_t*)(mem_ptr))); + 800a75a: 688a ldr r2, [r1, #8] + 800a75c: 601a str r2, [r3, #0] + __HAL_HASH_INIT(); + 800a75e: 681a ldr r2, [r3, #0] + 800a760: f042 0204 orr.w r2, r2, #4 + 800a764: 601a str r2, [r3, #0] + for (i = HASH_NUMBER_OF_CSR_REGISTERS; i >0U; i--) + 800a766: 4a06 ldr r2, [pc, #24] ; (800a780 ) + mem_ptr+=4U; + 800a768: 310c adds r1, #12 + uint32_t csr_ptr = (uint32_t)HASH->CSR; + 800a76a: 33f8 adds r3, #248 ; 0xf8 + WRITE_REG((*(uint32_t*)(csr_ptr)), (*(uint32_t*)(mem_ptr))); + 800a76c: f851 0b04 ldr.w r0, [r1], #4 + 800a770: f843 0b04 str.w r0, [r3], #4 + for (i = HASH_NUMBER_OF_CSR_REGISTERS; i >0U; i--) + 800a774: 4293 cmp r3, r2 + 800a776: d1f9 bne.n 800a76c +} + 800a778: 4770 bx lr + 800a77a: bf00 nop + 800a77c: 50060400 .word 0x50060400 + 800a780: 500605d0 .word 0x500605d0 + +0800a784 : + hhash->SuspendRequest = HAL_HASH_SUSPEND; + 800a784: 2301 movs r3, #1 + 800a786: f880 3036 strb.w r3, [r0, #54] ; 0x36 +} + 800a78a: 4770 bx lr + +0800a78c : + return hhash->ErrorCode; + 800a78c: 6bc0 ldr r0, [r0, #60] ; 0x3c +} + 800a78e: 4770 bx lr + +0800a790 : + * @param Timeout Timeout value. + * @param Algorithm HASH algorithm. + * @retval HAL status + */ +HAL_StatusTypeDef HASH_Start(HASH_HandleTypeDef *hhash, uint8_t *pInBuffer, uint32_t Size, uint8_t* pOutBuffer, uint32_t Timeout, uint32_t Algorithm) +{ + 800a790: b5f8 push {r3, r4, r5, r6, r7, lr} + 800a792: 461e mov r6, r3 + uint8_t *pInBuffer_tmp; /* input data address, input parameter of HASH_WriteData() */ + uint32_t Size_tmp; /* input data size (in bytes), input parameter of HASH_WriteData() */ + HAL_HASH_StateTypeDef State_tmp = hhash->State; + 800a794: f890 3035 ldrb.w r3, [r0, #53] ; 0x35 + + + /* Initiate HASH processing in case of start or resumption */ +if((State_tmp == HAL_HASH_STATE_READY) || (State_tmp == HAL_HASH_STATE_SUSPENDED)) + 800a798: 2b01 cmp r3, #1 +{ + 800a79a: 4604 mov r4, r0 + HAL_HASH_StateTypeDef State_tmp = hhash->State; + 800a79c: b2d8 uxtb r0, r3 +if((State_tmp == HAL_HASH_STATE_READY) || (State_tmp == HAL_HASH_STATE_SUSPENDED)) + 800a79e: d001 beq.n 800a7a4 + 800a7a0: 2808 cmp r0, #8 + 800a7a2: d17a bne.n 800a89a + { + /* Check input parameters */ + if ((pInBuffer == NULL) || (pOutBuffer == NULL)) + 800a7a4: b101 cbz r1, 800a7a8 + 800a7a6: b926 cbnz r6, 800a7b2 + { + hhash->State = HAL_HASH_STATE_READY; + 800a7a8: 2501 movs r5, #1 + 800a7aa: f884 5035 strb.w r5, [r4, #53] ; 0x35 + } + else + { + return HAL_BUSY; + } +} + 800a7ae: 4628 mov r0, r5 + 800a7b0: bdf8 pop {r3, r4, r5, r6, r7, pc} + __HAL_LOCK(hhash); + 800a7b2: f894 3034 ldrb.w r3, [r4, #52] ; 0x34 + 800a7b6: 2b01 cmp r3, #1 + 800a7b8: d06f beq.n 800a89a + if(hhash->Phase == HAL_HASH_PHASE_READY) + 800a7ba: f894 302d ldrb.w r3, [r4, #45] ; 0x2d + __HAL_LOCK(hhash); + 800a7be: 2501 movs r5, #1 + if(hhash->Phase == HAL_HASH_PHASE_READY) + 800a7c0: 42ab cmp r3, r5 + __HAL_LOCK(hhash); + 800a7c2: f884 5034 strb.w r5, [r4, #52] ; 0x34 + if(hhash->Phase == HAL_HASH_PHASE_READY) + 800a7c6: d148 bne.n 800a85a + MODIFY_REG(HASH->CR, HASH_CR_LKEY|HASH_CR_ALGO|HASH_CR_MODE|HASH_CR_INIT, Algorithm | HASH_CR_INIT); + 800a7c8: 4f36 ldr r7, [pc, #216] ; (800a8a4 ) + 800a7ca: 9b07 ldr r3, [sp, #28] + hhash->State = HAL_HASH_STATE_BUSY; + 800a7cc: f04f 0c02 mov.w ip, #2 + 800a7d0: f884 c035 strb.w ip, [r4, #53] ; 0x35 + MODIFY_REG(HASH->CR, HASH_CR_LKEY|HASH_CR_ALGO|HASH_CR_MODE|HASH_CR_INIT, Algorithm | HASH_CR_INIT); + 800a7d4: 683d ldr r5, [r7, #0] + 800a7d6: f425 25a0 bic.w r5, r5, #327680 ; 0x50000 + 800a7da: f025 05c4 bic.w r5, r5, #196 ; 0xc4 + 800a7de: 431d orrs r5, r3 + 800a7e0: f045 0504 orr.w r5, r5, #4 + 800a7e4: 603d str r5, [r7, #0] + __HAL_HASH_SET_NBVALIDBITS(Size); + 800a7e6: 68b8 ldr r0, [r7, #8] + 800a7e8: f002 0303 and.w r3, r2, #3 + 800a7ec: f020 001f bic.w r0, r0, #31 + 800a7f0: ea40 03c3 orr.w r3, r0, r3, lsl #3 + 800a7f4: 60bb str r3, [r7, #8] + hhash->Phase = HAL_HASH_PHASE_PROCESS; + 800a7f6: f884 c02d strb.w ip, [r4, #45] ; 0x2d + hhash->Status = HASH_WriteData(hhash, pInBuffer_tmp, Size_tmp); + 800a7fa: 4620 mov r0, r4 + 800a7fc: f7ff fd78 bl 800a2f0 + 800a800: 4605 mov r5, r0 + 800a802: f884 002c strb.w r0, [r4, #44] ; 0x2c + if (hhash->Status != HAL_OK) + 800a806: 2800 cmp r0, #0 + 800a808: d1d1 bne.n 800a7ae + if (hhash->State != HAL_HASH_STATE_SUSPENDED) + 800a80a: f894 3035 ldrb.w r3, [r4, #53] ; 0x35 + 800a80e: 2b08 cmp r3, #8 + 800a810: d03b beq.n 800a88a + __HAL_HASH_START_DIGEST(); + 800a812: 4f24 ldr r7, [pc, #144] ; (800a8a4 ) + 800a814: 68bb ldr r3, [r7, #8] + 800a816: f443 7380 orr.w r3, r3, #256 ; 0x100 + 800a81a: 60bb str r3, [r7, #8] + if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_DCIS, RESET, Timeout) != HAL_OK) + 800a81c: 4602 mov r2, r0 + 800a81e: 9b06 ldr r3, [sp, #24] + 800a820: 2102 movs r1, #2 + 800a822: 4620 mov r0, r4 + 800a824: f7ff fe06 bl 800a434 + 800a828: 2800 cmp r0, #0 + 800a82a: d138 bne.n 800a89e + HASH_GetDigest(pOutBuffer, HASH_DIGEST_LENGTH()); + 800a82c: 683a ldr r2, [r7, #0] + 800a82e: 4b1e ldr r3, [pc, #120] ; (800a8a8 ) + 800a830: 421a tst r2, r3 + 800a832: d02e beq.n 800a892 + 800a834: 683a ldr r2, [r7, #0] + 800a836: 401a ands r2, r3 + 800a838: f5b2 2f80 cmp.w r2, #262144 ; 0x40000 + 800a83c: d02b beq.n 800a896 + 800a83e: 683a ldr r2, [r7, #0] + 800a840: 4393 bics r3, r2 + 800a842: bf0c ite eq + 800a844: 2120 moveq r1, #32 + 800a846: 2110 movne r1, #16 + 800a848: 4630 mov r0, r6 + 800a84a: f7ff fd91 bl 800a370 + hhash->State = HAL_HASH_STATE_READY; + 800a84e: 2301 movs r3, #1 + 800a850: f884 3035 strb.w r3, [r4, #53] ; 0x35 + hhash->Phase = HAL_HASH_PHASE_READY; + 800a854: f884 302d strb.w r3, [r4, #45] ; 0x2d + 800a858: e017 b.n 800a88a + else if (hhash->Phase == HAL_HASH_PHASE_PROCESS) + 800a85a: 2b02 cmp r3, #2 + 800a85c: d113 bne.n 800a886 + if (hhash->State == HAL_HASH_STATE_SUSPENDED) + 800a85e: f894 3035 ldrb.w r3, [r4, #53] ; 0x35 + 800a862: 2b08 cmp r3, #8 + __HAL_HASH_SET_NBVALIDBITS(Size); + 800a864: bf15 itete ne + 800a866: 4d0f ldrne r5, [pc, #60] ; (800a8a4 ) + Size_tmp = hhash->HashInCount; + 800a868: 6a22 ldreq r2, [r4, #32] + __HAL_HASH_SET_NBVALIDBITS(Size); + 800a86a: 68a8 ldrne r0, [r5, #8] + pInBuffer_tmp = hhash->pHashInBuffPtr; + 800a86c: 68e1 ldreq r1, [r4, #12] + __HAL_HASH_SET_NBVALIDBITS(Size); + 800a86e: bf1f itttt ne + 800a870: f002 0303 andne.w r3, r2, #3 + 800a874: f020 001f bicne.w r0, r0, #31 + 800a878: ea40 03c3 orrne.w r3, r0, r3, lsl #3 + 800a87c: 60ab strne r3, [r5, #8] + hhash->State = HAL_HASH_STATE_BUSY; + 800a87e: 2302 movs r3, #2 + 800a880: f884 3035 strb.w r3, [r4, #53] ; 0x35 + 800a884: e7b9 b.n 800a7fa + hhash->State = HAL_HASH_STATE_READY; + 800a886: f884 5035 strb.w r5, [r4, #53] ; 0x35 + __HAL_UNLOCK(hhash); + 800a88a: 2300 movs r3, #0 + 800a88c: f884 3034 strb.w r3, [r4, #52] ; 0x34 + return HAL_OK; + 800a890: e78d b.n 800a7ae + HASH_GetDigest(pOutBuffer, HASH_DIGEST_LENGTH()); + 800a892: 2114 movs r1, #20 + 800a894: e7d8 b.n 800a848 + 800a896: 211c movs r1, #28 + 800a898: e7d6 b.n 800a848 + return HAL_BUSY; + 800a89a: 2502 movs r5, #2 + 800a89c: e787 b.n 800a7ae + return HAL_TIMEOUT; + 800a89e: 2503 movs r5, #3 + 800a8a0: e785 b.n 800a7ae + 800a8a2: bf00 nop + 800a8a4: 50060400 .word 0x50060400 + 800a8a8: 00040080 .word 0x00040080 + +0800a8ac : +{ + 800a8ac: b513 push {r0, r1, r4, lr} + return HASH_Start(hhash, pInBuffer, Size, pOutBuffer, Timeout, HASH_ALGOSELECTION_MD5); + 800a8ae: 2480 movs r4, #128 ; 0x80 + 800a8b0: 9401 str r4, [sp, #4] + 800a8b2: 9c04 ldr r4, [sp, #16] + 800a8b4: 9400 str r4, [sp, #0] + 800a8b6: f7ff ff6b bl 800a790 +} + 800a8ba: b002 add sp, #8 + 800a8bc: bd10 pop {r4, pc} + +0800a8be : + 800a8be: f7ff bff5 b.w 800a8ac + +0800a8c2 : +{ + 800a8c2: b513 push {r0, r1, r4, lr} + return HASH_Start(hhash, pInBuffer, Size, pOutBuffer, Timeout, HASH_ALGOSELECTION_SHA1); + 800a8c4: 2400 movs r4, #0 + 800a8c6: 9401 str r4, [sp, #4] + 800a8c8: 9c04 ldr r4, [sp, #16] + 800a8ca: 9400 str r4, [sp, #0] + 800a8cc: f7ff ff60 bl 800a790 +} + 800a8d0: b002 add sp, #8 + 800a8d2: bd10 pop {r4, pc} + +0800a8d4 : + 800a8d4: f7ff bff5 b.w 800a8c2 + +0800a8d8 : + * @param Size length of the input buffer in bytes, must be a multiple of 4. + * @param Algorithm HASH algorithm. + * @retval HAL status + */ +HAL_StatusTypeDef HASH_Accumulate(HASH_HandleTypeDef *hhash, uint8_t *pInBuffer, uint32_t Size, uint32_t Algorithm) +{ + 800a8d8: b570 push {r4, r5, r6, lr} + uint8_t *pInBuffer_tmp; /* input data address, input parameter of HASH_WriteData() */ + uint32_t Size_tmp; /* input data size (in bytes), input parameter of HASH_WriteData() */ + HAL_HASH_StateTypeDef State_tmp = hhash->State; + 800a8da: f890 5035 ldrb.w r5, [r0, #53] ; 0x35 +{ + 800a8de: 4604 mov r4, r0 + + /* Make sure the input buffer size (in bytes) is a multiple of 4 */ + if ((Size % 4U) != 0U) + 800a8e0: 0790 lsls r0, r2, #30 + HAL_HASH_StateTypeDef State_tmp = hhash->State; + 800a8e2: b2ed uxtb r5, r5 + if ((Size % 4U) != 0U) + 800a8e4: d13e bne.n 800a964 + { + return HAL_ERROR; + } + + /* Initiate HASH processing in case of start or resumption */ +if((State_tmp == HAL_HASH_STATE_READY) || (State_tmp == HAL_HASH_STATE_SUSPENDED)) + 800a8e6: 2d01 cmp r5, #1 + 800a8e8: d001 beq.n 800a8ee + 800a8ea: 2d08 cmp r5, #8 + 800a8ec: d13c bne.n 800a968 + { + /* Check input parameters */ + if ((pInBuffer == NULL) || (Size == 0U)) + 800a8ee: b101 cbz r1, 800a8f2 + 800a8f0: b91a cbnz r2, 800a8fa + { + hhash->State = HAL_HASH_STATE_READY; + 800a8f2: 2001 movs r0, #1 + 800a8f4: f884 0035 strb.w r0, [r4, #53] ; 0x35 + { + return HAL_BUSY; + } + + +} + 800a8f8: bd70 pop {r4, r5, r6, pc} + __HAL_LOCK(hhash); + 800a8fa: f894 0034 ldrb.w r0, [r4, #52] ; 0x34 + 800a8fe: 2801 cmp r0, #1 + 800a900: d032 beq.n 800a968 + 800a902: 2001 movs r0, #1 + 800a904: f884 0034 strb.w r0, [r4, #52] ; 0x34 + if (hhash->State == HAL_HASH_STATE_SUSPENDED) + 800a908: f894 0035 ldrb.w r0, [r4, #53] ; 0x35 + 800a90c: 2808 cmp r0, #8 + 800a90e: f04f 0002 mov.w r0, #2 + hhash->State = HAL_HASH_STATE_BUSY; + 800a912: f884 0035 strb.w r0, [r4, #53] ; 0x35 + if (hhash->State == HAL_HASH_STATE_SUSPENDED) + 800a916: d113 bne.n 800a940 + pInBuffer_tmp = hhash->pHashInBuffPtr; /* pInBuffer_tmp is set to the input data address */ + 800a918: 68e1 ldr r1, [r4, #12] + Size_tmp = hhash->HashInCount; /* Size_tmp contains the input data size in bytes */ + 800a91a: 6a22 ldr r2, [r4, #32] + hhash->Status = HASH_WriteData(hhash, pInBuffer_tmp, Size_tmp); + 800a91c: 4620 mov r0, r4 + 800a91e: f7ff fce7 bl 800a2f0 + 800a922: f884 002c strb.w r0, [r4, #44] ; 0x2c + if (hhash->Status != HAL_OK) + 800a926: 2800 cmp r0, #0 + 800a928: d1e6 bne.n 800a8f8 + if (hhash->State != HAL_HASH_STATE_SUSPENDED) + 800a92a: f894 3035 ldrb.w r3, [r4, #53] ; 0x35 + 800a92e: 2b08 cmp r3, #8 + hhash->State = HAL_HASH_STATE_READY; + 800a930: bf1c itt ne + 800a932: 2301 movne r3, #1 + 800a934: f884 3035 strbne.w r3, [r4, #53] ; 0x35 + __HAL_UNLOCK(hhash); + 800a938: 2300 movs r3, #0 + 800a93a: f884 3034 strb.w r3, [r4, #52] ; 0x34 + return HAL_OK; + 800a93e: e7db b.n 800a8f8 + if(hhash->Phase == HAL_HASH_PHASE_READY) + 800a940: f894 002d ldrb.w r0, [r4, #45] ; 0x2d + 800a944: 2801 cmp r0, #1 + 800a946: d109 bne.n 800a95c + MODIFY_REG(HASH->CR, HASH_CR_LKEY|HASH_CR_ALGO|HASH_CR_MODE|HASH_CR_INIT, Algorithm | HASH_CR_INIT); + 800a948: 4e08 ldr r6, [pc, #32] ; (800a96c ) + 800a94a: 6830 ldr r0, [r6, #0] + 800a94c: f420 20a0 bic.w r0, r0, #327680 ; 0x50000 + 800a950: f020 00c4 bic.w r0, r0, #196 ; 0xc4 + 800a954: 4318 orrs r0, r3 + 800a956: f040 0004 orr.w r0, r0, #4 + 800a95a: 6030 str r0, [r6, #0] + hhash->Phase = HAL_HASH_PHASE_PROCESS; + 800a95c: 2302 movs r3, #2 + 800a95e: f884 302d strb.w r3, [r4, #45] ; 0x2d + 800a962: e7db b.n 800a91c + return HAL_ERROR; + 800a964: 2001 movs r0, #1 + 800a966: e7c7 b.n 800a8f8 + return HAL_BUSY; + 800a968: 2002 movs r0, #2 + 800a96a: e7c5 b.n 800a8f8 + 800a96c: 50060400 .word 0x50060400 + +0800a970 : + return HASH_Accumulate(hhash, pInBuffer, Size,HASH_ALGOSELECTION_MD5); + 800a970: 2380 movs r3, #128 ; 0x80 + 800a972: f7ff bfb1 b.w 800a8d8 + +0800a976 : + return HASH_Accumulate(hhash, pInBuffer, Size,HASH_ALGOSELECTION_SHA1); + 800a976: 2300 movs r3, #0 + 800a978: f7ff bfae b.w 800a8d8 + +0800a97c : + * @param Size length of the input buffer in bytes, must be a multiple of 4. + * @param Algorithm HASH algorithm. + * @retval HAL status + */ +HAL_StatusTypeDef HASH_Accumulate_IT(HASH_HandleTypeDef *hhash, uint8_t *pInBuffer, uint32_t Size, uint32_t Algorithm) +{ + 800a97c: b567 push {r0, r1, r2, r5, r6, lr} + HAL_HASH_StateTypeDef State_tmp = hhash->State; + 800a97e: f890 5035 ldrb.w r5, [r0, #53] ; 0x35 + __IO uint32_t inputaddr = (uint32_t) pInBuffer; + 800a982: 9101 str r1, [sp, #4] + uint32_t SizeVar = Size; + + /* Make sure the input buffer size (in bytes) is a multiple of 4 */ + if ((Size % 4U) != 0U) + 800a984: 0796 lsls r6, r2, #30 + HAL_HASH_StateTypeDef State_tmp = hhash->State; + 800a986: b2ed uxtb r5, r5 + if ((Size % 4U) != 0U) + 800a988: d154 bne.n 800aa34 + { + return HAL_ERROR; + } + + /* Initiate HASH processing in case of start or resumption */ + if((State_tmp == HAL_HASH_STATE_READY) || (State_tmp == HAL_HASH_STATE_SUSPENDED)) + 800a98a: 2d01 cmp r5, #1 + 800a98c: d001 beq.n 800a992 + 800a98e: 2d08 cmp r5, #8 + 800a990: d152 bne.n 800aa38 + { + /* Check input parameters */ + if ((pInBuffer == NULL) || (Size == 0U)) + 800a992: b101 cbz r1, 800a996 + 800a994: b92a cbnz r2, 800a9a2 + { + hhash->State = HAL_HASH_STATE_READY; + 800a996: 2301 movs r3, #1 + 800a998: f880 3035 strb.w r3, [r0, #53] ; 0x35 + else + { + return HAL_BUSY; + } + +} + 800a99c: 4618 mov r0, r3 + 800a99e: b003 add sp, #12 + 800a9a0: bd60 pop {r5, r6, pc} + __HAL_LOCK(hhash); + 800a9a2: f890 1034 ldrb.w r1, [r0, #52] ; 0x34 + 800a9a6: 2901 cmp r1, #1 + 800a9a8: d046 beq.n 800aa38 + 800a9aa: 2101 movs r1, #1 + 800a9ac: f880 1034 strb.w r1, [r0, #52] ; 0x34 + if (hhash->State == HAL_HASH_STATE_SUSPENDED) + 800a9b0: f890 1035 ldrb.w r1, [r0, #53] ; 0x35 + 800a9b4: 4d21 ldr r5, [pc, #132] ; (800aa3c ) + 800a9b6: 2908 cmp r1, #8 + 800a9b8: f04f 0102 mov.w r1, #2 + hhash->State = HAL_HASH_STATE_BUSY; + 800a9bc: f880 1035 strb.w r1, [r0, #53] ; 0x35 + if (hhash->State == HAL_HASH_STATE_SUSPENDED) + 800a9c0: d109 bne.n 800a9d6 + hhash->Accumulation = 1U; + 800a9c2: 2301 movs r3, #1 + 800a9c4: 6403 str r3, [r0, #64] ; 0x40 + __HAL_UNLOCK(hhash); + 800a9c6: 2300 movs r3, #0 + 800a9c8: f880 3034 strb.w r3, [r0, #52] ; 0x34 + __HAL_HASH_ENABLE_IT(HASH_IT_DINI); + 800a9cc: 6a2a ldr r2, [r5, #32] + 800a9ce: f042 0201 orr.w r2, r2, #1 + 800a9d2: 622a str r2, [r5, #32] + return HAL_OK; + 800a9d4: e7e2 b.n 800a99c + if(hhash->Phase == HAL_HASH_PHASE_READY) + 800a9d6: f890 602d ldrb.w r6, [r0, #45] ; 0x2d + 800a9da: 2e01 cmp r6, #1 + 800a9dc: d11b bne.n 800aa16 + MODIFY_REG(HASH->CR, HASH_CR_LKEY|HASH_CR_ALGO|HASH_CR_MODE|HASH_CR_INIT, Algorithm | HASH_CR_INIT); + 800a9de: 6829 ldr r1, [r5, #0] + 800a9e0: f421 21a0 bic.w r1, r1, #327680 ; 0x50000 + 800a9e4: f021 01c4 bic.w r1, r1, #196 ; 0xc4 + 800a9e8: 4319 orrs r1, r3 + 800a9ea: f041 0104 orr.w r1, r1, #4 + 800a9ee: 6029 str r1, [r5, #0] + hhash->HashITCounter = 1; + 800a9f0: 6246 str r6, [r0, #36] ; 0x24 + hhash->Phase = HAL_HASH_PHASE_PROCESS; + 800a9f2: 2302 movs r3, #2 + 800a9f4: f880 302d strb.w r3, [r0, #45] ; 0x2d + while((!(__HAL_HASH_GET_FLAG(HASH_FLAG_DINIS))) && (SizeVar > 0U)) + 800a9f8: 6a6b ldr r3, [r5, #36] ; 0x24 + 800a9fa: 07d9 lsls r1, r3, #31 + 800a9fc: d400 bmi.n 800aa00 + 800a9fe: b96a cbnz r2, 800aa1c + if ((!(__HAL_HASH_GET_FLAG(HASH_FLAG_DINIS))) || (SizeVar == 0U)) + 800aa00: 6a6b ldr r3, [r5, #36] ; 0x24 + 800aa02: 07db lsls r3, r3, #31 + 800aa04: d500 bpl.n 800aa08 + 800aa06: b98a cbnz r2, 800aa2c + hhash->State = HAL_HASH_STATE_READY; + 800aa08: 2301 movs r3, #1 + 800aa0a: f880 3035 strb.w r3, [r0, #53] ; 0x35 + __HAL_UNLOCK(hhash); + 800aa0e: 2300 movs r3, #0 + 800aa10: f880 3034 strb.w r3, [r0, #52] ; 0x34 + return HAL_OK; + 800aa14: e7c2 b.n 800a99c + hhash->HashITCounter = 3; /* 'cruise-speed' reached during a previous buffer processing */ + 800aa16: 2303 movs r3, #3 + 800aa18: 6243 str r3, [r0, #36] ; 0x24 + 800aa1a: e7ea b.n 800a9f2 + HASH->DIN = *(uint32_t*)inputaddr; + 800aa1c: 9b01 ldr r3, [sp, #4] + 800aa1e: 681b ldr r3, [r3, #0] + 800aa20: 606b str r3, [r5, #4] + inputaddr+=4U; + 800aa22: 9b01 ldr r3, [sp, #4] + 800aa24: 3304 adds r3, #4 + 800aa26: 9301 str r3, [sp, #4] + SizeVar-=4U; + 800aa28: 3a04 subs r2, #4 + 800aa2a: e7e5 b.n 800a9f8 + hhash->HashInCount = SizeVar; /* Counter used to keep track of number of data + 800aa2c: 6202 str r2, [r0, #32] + hhash->pHashInBuffPtr = (uint8_t *)inputaddr; /* Points at data which will be fed to the Peripheral at + 800aa2e: 9b01 ldr r3, [sp, #4] + 800aa30: 60c3 str r3, [r0, #12] + 800aa32: e7c6 b.n 800a9c2 + return HAL_ERROR; + 800aa34: 2301 movs r3, #1 + 800aa36: e7b1 b.n 800a99c + return HAL_BUSY; + 800aa38: 2302 movs r3, #2 + 800aa3a: e7af b.n 800a99c + 800aa3c: 50060400 .word 0x50060400 + +0800aa40 : + return HASH_Accumulate_IT(hhash, pInBuffer, Size,HASH_ALGOSELECTION_MD5); + 800aa40: 2380 movs r3, #128 ; 0x80 + 800aa42: f7ff bf9b b.w 800a97c + +0800aa46 : + return HASH_Accumulate_IT(hhash, pInBuffer, Size,HASH_ALGOSELECTION_SHA1); + 800aa46: 2300 movs r3, #0 + 800aa48: f7ff bf98 b.w 800a97c + +0800aa4c : + * @param pOutBuffer pointer to the computed digest. + * @param Algorithm HASH algorithm. + * @retval HAL status + */ +HAL_StatusTypeDef HASH_Start_IT(HASH_HandleTypeDef *hhash, uint8_t *pInBuffer, uint32_t Size, uint8_t* pOutBuffer, uint32_t Algorithm) +{ + 800aa4c: b573 push {r0, r1, r4, r5, r6, lr} + HAL_HASH_StateTypeDef State_tmp = hhash->State; + 800aa4e: f890 4035 ldrb.w r4, [r0, #53] ; 0x35 + __IO uint32_t inputaddr = (uint32_t) pInBuffer; + 800aa52: 9101 str r1, [sp, #4] + uint32_t polling_step = 0U; + uint32_t initialization_skipped = 0U; + uint32_t SizeVar = Size; + + /* If State is ready or suspended, start or resume IT-based HASH processing */ +if((State_tmp == HAL_HASH_STATE_READY) || (State_tmp == HAL_HASH_STATE_SUSPENDED)) + 800aa54: 2c01 cmp r4, #1 + HAL_HASH_StateTypeDef State_tmp = hhash->State; + 800aa56: b2e5 uxtb r5, r4 +if((State_tmp == HAL_HASH_STATE_READY) || (State_tmp == HAL_HASH_STATE_SUSPENDED)) + 800aa58: d001 beq.n 800aa5e + 800aa5a: 2d08 cmp r5, #8 + 800aa5c: d17f bne.n 800ab5e + { + /* Check input parameters */ + if ((pInBuffer == NULL) || (Size == 0U) || (pOutBuffer == NULL)) + 800aa5e: b109 cbz r1, 800aa64 + 800aa60: b102 cbz r2, 800aa64 + 800aa62: b92b cbnz r3, 800aa70 + { + hhash->State = HAL_HASH_STATE_READY; + 800aa64: 2201 movs r2, #1 + 800aa66: f880 2035 strb.w r2, [r0, #53] ; 0x35 + else + { + return HAL_BUSY; + } + +} + 800aa6a: 4610 mov r0, r2 + 800aa6c: b002 add sp, #8 + 800aa6e: bd70 pop {r4, r5, r6, pc} + __HAL_LOCK(hhash); + 800aa70: f890 4034 ldrb.w r4, [r0, #52] ; 0x34 + 800aa74: 2c01 cmp r4, #1 + 800aa76: f04f 0402 mov.w r4, #2 + 800aa7a: d072 beq.n 800ab62 + hhash->State = HAL_HASH_STATE_BUSY; + 800aa7c: f880 4035 strb.w r4, [r0, #53] ; 0x35 + if(hhash->Phase == HAL_HASH_PHASE_READY) + 800aa80: f890 402d ldrb.w r4, [r0, #45] ; 0x2d + __HAL_LOCK(hhash); + 800aa84: 2601 movs r6, #1 + if(hhash->Phase == HAL_HASH_PHASE_READY) + 800aa86: 42b4 cmp r4, r6 + __HAL_LOCK(hhash); + 800aa88: f880 6034 strb.w r6, [r0, #52] ; 0x34 + hhash->HashITCounter = 1; + 800aa8c: 4c36 ldr r4, [pc, #216] ; (800ab68 ) + 800aa8e: 6246 str r6, [r0, #36] ; 0x24 + if(hhash->Phase == HAL_HASH_PHASE_READY) + 800aa90: d115 bne.n 800aabe + MODIFY_REG(HASH->CR, HASH_CR_LKEY|HASH_CR_ALGO|HASH_CR_MODE|HASH_CR_INIT, Algorithm | HASH_CR_INIT); + 800aa92: 6825 ldr r5, [r4, #0] + 800aa94: 9e06 ldr r6, [sp, #24] + 800aa96: f425 25a0 bic.w r5, r5, #327680 ; 0x50000 + 800aa9a: f025 05c4 bic.w r5, r5, #196 ; 0xc4 + 800aa9e: 4335 orrs r5, r6 + 800aaa0: f045 0504 orr.w r5, r5, #4 + 800aaa4: 6025 str r5, [r4, #0] + __HAL_HASH_SET_NBVALIDBITS(SizeVar); + 800aaa6: 68a6 ldr r6, [r4, #8] + 800aaa8: f002 0503 and.w r5, r2, #3 + 800aaac: f026 061f bic.w r6, r6, #31 + 800aab0: ea46 05c5 orr.w r5, r6, r5, lsl #3 + 800aab4: 60a5 str r5, [r4, #8] + hhash->pHashOutBuffPtr = pOutBuffer; /* Points at the computed digest */ + 800aab6: e9c0 1303 strd r1, r3, [r0, #12] + hhash->HashInCount = SizeVar; /* Counter used to keep track of number of data + 800aaba: 6202 str r2, [r0, #32] + uint32_t initialization_skipped = 0U; + 800aabc: 2600 movs r6, #0 + hhash->Phase = HAL_HASH_PHASE_PROCESS; + 800aabe: 2102 movs r1, #2 + 800aac0: f880 102d strb.w r1, [r0, #45] ; 0x2d + uint32_t polling_step = 0U; + 800aac4: 2100 movs r1, #0 + while((!(__HAL_HASH_GET_FLAG(HASH_FLAG_DINIS))) && (SizeVar > 3U)) + 800aac6: 6a65 ldr r5, [r4, #36] ; 0x24 + 800aac8: 07ed lsls r5, r5, #31 + 800aaca: d401 bmi.n 800aad0 + 800aacc: 2a03 cmp r2, #3 + 800aace: d80d bhi.n 800aaec + if (polling_step == 1U) + 800aad0: b349 cbz r1, 800ab26 + if (SizeVar == 0U) + 800aad2: b9a2 cbnz r2, 800aafe + hhash->pHashOutBuffPtr = pOutBuffer; /* Points at the computed digest */ + 800aad4: 6103 str r3, [r0, #16] + __HAL_HASH_START_DIGEST(); + 800aad6: 68a3 ldr r3, [r4, #8] + 800aad8: f443 7380 orr.w r3, r3, #256 ; 0x100 + 800aadc: 60a3 str r3, [r4, #8] + __HAL_UNLOCK(hhash); + 800aade: f880 2034 strb.w r2, [r0, #52] ; 0x34 + __HAL_HASH_ENABLE_IT(HASH_IT_DCI); + 800aae2: 6a23 ldr r3, [r4, #32] + 800aae4: f043 0302 orr.w r3, r3, #2 + __HAL_HASH_ENABLE_IT(HASH_IT_DINI|HASH_IT_DCI); + 800aae8: 6223 str r3, [r4, #32] + return HAL_OK; + 800aaea: e7be b.n 800aa6a + HASH->DIN = *(uint32_t*)inputaddr; + 800aaec: 9901 ldr r1, [sp, #4] + 800aaee: 6809 ldr r1, [r1, #0] + 800aaf0: 6061 str r1, [r4, #4] + inputaddr+=4U; + 800aaf2: 9901 ldr r1, [sp, #4] + 800aaf4: 3104 adds r1, #4 + 800aaf6: 9101 str r1, [sp, #4] + SizeVar-=4U; + 800aaf8: 3a04 subs r2, #4 + polling_step = 1U; /* note that some words are entered before enabling the interrupt */ + 800aafa: 2101 movs r1, #1 + 800aafc: e7e3 b.n 800aac6 + else if (__HAL_HASH_GET_FLAG(HASH_FLAG_DINIS)) + 800aafe: 6a61 ldr r1, [r4, #36] ; 0x24 + __HAL_HASH_SET_NBVALIDBITS(SizeVar); /* Update the configuration of the number of valid bits in last word of the message */ + 800ab00: f002 0503 and.w r5, r2, #3 + else if (__HAL_HASH_GET_FLAG(HASH_FLAG_DINIS)) + 800ab04: f011 0101 ands.w r1, r1, #1 + __HAL_HASH_SET_NBVALIDBITS(SizeVar); /* Update the configuration of the number of valid bits in last word of the message */ + 800ab08: ea4f 05c5 mov.w r5, r5, lsl #3 + else if (__HAL_HASH_GET_FLAG(HASH_FLAG_DINIS)) + 800ab0c: d012 beq.n 800ab34 + hhash->HashInCount = SizeVar; + 800ab0e: 6202 str r2, [r0, #32] + hhash->pHashInBuffPtr = (uint8_t *)inputaddr; + 800ab10: 9a01 ldr r2, [sp, #4] + 800ab12: 60c2 str r2, [r0, #12] + __HAL_HASH_SET_NBVALIDBITS(SizeVar); /* Update the configuration of the number of valid bits in last word of the message */ + 800ab14: 68a2 ldr r2, [r4, #8] + 800ab16: f022 021f bic.w r2, r2, #31 + 800ab1a: 432a orrs r2, r5 + 800ab1c: 60a2 str r2, [r4, #8] + hhash->pHashOutBuffPtr = pOutBuffer; /* Points at the computed digest */ + 800ab1e: 6103 str r3, [r0, #16] + if (initialization_skipped == 1U) + 800ab20: b10e cbz r6, 800ab26 + hhash->HashITCounter = 3; /* 'cruise-speed' reached during a previous buffer processing */ + 800ab22: 2303 movs r3, #3 + 800ab24: 6243 str r3, [r0, #36] ; 0x24 + __HAL_UNLOCK(hhash); + 800ab26: 2200 movs r2, #0 + 800ab28: f880 2034 strb.w r2, [r0, #52] ; 0x34 + __HAL_HASH_ENABLE_IT(HASH_IT_DINI|HASH_IT_DCI); + 800ab2c: 6a23 ldr r3, [r4, #32] + 800ab2e: f043 0303 orr.w r3, r3, #3 + 800ab32: e7d9 b.n 800aae8 + __HAL_HASH_SET_NBVALIDBITS(SizeVar); + 800ab34: 68a2 ldr r2, [r4, #8] + 800ab36: f022 021f bic.w r2, r2, #31 + 800ab3a: 432a orrs r2, r5 + 800ab3c: 60a2 str r2, [r4, #8] + HASH->DIN = *(uint32_t*)inputaddr; + 800ab3e: 9a01 ldr r2, [sp, #4] + 800ab40: 6812 ldr r2, [r2, #0] + 800ab42: 6062 str r2, [r4, #4] + hhash->pHashOutBuffPtr = pOutBuffer; /* Points at the computed digest */ + 800ab44: 6103 str r3, [r0, #16] + __HAL_HASH_START_DIGEST(); + 800ab46: 68a3 ldr r3, [r4, #8] + 800ab48: f443 7380 orr.w r3, r3, #256 ; 0x100 + 800ab4c: 60a3 str r3, [r4, #8] + __HAL_UNLOCK(hhash); + 800ab4e: f880 1034 strb.w r1, [r0, #52] ; 0x34 + __HAL_HASH_ENABLE_IT(HASH_IT_DCI); + 800ab52: 6a23 ldr r3, [r4, #32] + 800ab54: f043 0302 orr.w r3, r3, #2 + 800ab58: 6223 str r3, [r4, #32] + return HAL_OK; + 800ab5a: 460a mov r2, r1 + 800ab5c: e785 b.n 800aa6a + return HAL_BUSY; + 800ab5e: 2202 movs r2, #2 + 800ab60: e783 b.n 800aa6a + 800ab62: 4622 mov r2, r4 + 800ab64: e781 b.n 800aa6a + 800ab66: bf00 nop + 800ab68: 50060400 .word 0x50060400 + +0800ab6c : +{ + 800ab6c: b513 push {r0, r1, r4, lr} + return HASH_Start_IT(hhash, pInBuffer, Size, pOutBuffer,HASH_ALGOSELECTION_MD5); + 800ab6e: 2480 movs r4, #128 ; 0x80 + 800ab70: 9400 str r4, [sp, #0] + 800ab72: f7ff ff6b bl 800aa4c +} + 800ab76: b002 add sp, #8 + 800ab78: bd10 pop {r4, pc} + +0800ab7a : + 800ab7a: f7ff bff7 b.w 800ab6c + +0800ab7e : +{ + 800ab7e: b513 push {r0, r1, r4, lr} + return HASH_Start_IT(hhash, pInBuffer, Size, pOutBuffer,HASH_ALGOSELECTION_SHA1); + 800ab80: 2400 movs r4, #0 + 800ab82: 9400 str r4, [sp, #0] + 800ab84: f7ff ff62 bl 800aa4c +} + 800ab88: b002 add sp, #8 + 800ab8a: bd10 pop {r4, pc} + +0800ab8c : + 800ab8c: f7ff bff7 b.w 800ab7e + +0800ab90 : + * @param pOutBuffer pointer to the computed digest. + * @param Timeout Timeout value. + * @retval HAL status + */ +HAL_StatusTypeDef HASH_Finish(HASH_HandleTypeDef *hhash, uint8_t* pOutBuffer, uint32_t Timeout) +{ + 800ab90: b570 push {r4, r5, r6, lr} + 800ab92: 4613 mov r3, r2 + + if(hhash->State == HAL_HASH_STATE_READY) + 800ab94: f890 2035 ldrb.w r2, [r0, #53] ; 0x35 + 800ab98: 2a01 cmp r2, #1 +{ + 800ab9a: 4605 mov r5, r0 + 800ab9c: 460e mov r6, r1 + if(hhash->State == HAL_HASH_STATE_READY) + 800ab9e: b2d4 uxtb r4, r2 + 800aba0: d12f bne.n 800ac02 + { + /* Check parameter */ + if (pOutBuffer == NULL) + 800aba2: b341 cbz r1, 800abf6 + { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(hhash); + 800aba4: f890 2034 ldrb.w r2, [r0, #52] ; 0x34 + 800aba8: 2a01 cmp r2, #1 + 800abaa: f04f 0102 mov.w r1, #2 + 800abae: d028 beq.n 800ac02 + 800abb0: f880 4034 strb.w r4, [r0, #52] ; 0x34 + + /* Change the HASH state to busy */ + hhash->State = HAL_HASH_STATE_BUSY; + 800abb4: f880 1035 strb.w r1, [r0, #53] ; 0x35 + + /* Wait for DCIS flag to be set */ + if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_DCIS, RESET, Timeout) != HAL_OK) + 800abb8: 2200 movs r2, #0 + 800abba: f7ff fc3b bl 800a434 + 800abbe: 4604 mov r4, r0 + 800abc0: bb08 cbnz r0, 800ac06 + { + return HAL_TIMEOUT; + } + + /* Read the message digest */ + HASH_GetDigest(pOutBuffer, HASH_DIGEST_LENGTH()); + 800abc2: 4a12 ldr r2, [pc, #72] ; (800ac0c ) + 800abc4: 4b12 ldr r3, [pc, #72] ; (800ac10 ) + 800abc6: 6811 ldr r1, [r2, #0] + 800abc8: 4219 tst r1, r3 + 800abca: d016 beq.n 800abfa + 800abcc: 6811 ldr r1, [r2, #0] + 800abce: 4019 ands r1, r3 + 800abd0: f5b1 2f80 cmp.w r1, #262144 ; 0x40000 + 800abd4: d013 beq.n 800abfe + 800abd6: 6812 ldr r2, [r2, #0] + 800abd8: 4393 bics r3, r2 + 800abda: bf0c ite eq + 800abdc: 2120 moveq r1, #32 + 800abde: 2110 movne r1, #16 + 800abe0: 4630 mov r0, r6 + 800abe2: f7ff fbc5 bl 800a370 + + /* Change the HASH state to ready */ + hhash->State = HAL_HASH_STATE_READY; + 800abe6: 2301 movs r3, #1 + 800abe8: f885 3035 strb.w r3, [r5, #53] ; 0x35 + + /* Reset HASH state machine */ + hhash->Phase = HAL_HASH_PHASE_READY; + 800abec: f885 302d strb.w r3, [r5, #45] ; 0x2d + + /* Process UnLock */ + __HAL_UNLOCK(hhash); + 800abf0: 2300 movs r3, #0 + 800abf2: f885 3034 strb.w r3, [r5, #52] ; 0x34 + else + { + return HAL_BUSY; + } + +} + 800abf6: 4620 mov r0, r4 + 800abf8: bd70 pop {r4, r5, r6, pc} + HASH_GetDigest(pOutBuffer, HASH_DIGEST_LENGTH()); + 800abfa: 2114 movs r1, #20 + 800abfc: e7f0 b.n 800abe0 + 800abfe: 211c movs r1, #28 + 800ac00: e7ee b.n 800abe0 + return HAL_BUSY; + 800ac02: 2402 movs r4, #2 + 800ac04: e7f7 b.n 800abf6 + return HAL_TIMEOUT; + 800ac06: 2403 movs r4, #3 + 800ac08: e7f5 b.n 800abf6 + 800ac0a: bf00 nop + 800ac0c: 50060400 .word 0x50060400 + 800ac10: 00040080 .word 0x00040080 + +0800ac14 : + * @param Timeout Timeout value. + * @param Algorithm HASH algorithm. + * @retval HAL status + */ +HAL_StatusTypeDef HMAC_Start(HASH_HandleTypeDef *hhash, uint8_t *pInBuffer, uint32_t Size, uint8_t* pOutBuffer, uint32_t Timeout, uint32_t Algorithm) +{ + 800ac14: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + 800ac18: 4604 mov r4, r0 + HAL_HASH_StateTypeDef State_tmp = hhash->State; + 800ac1a: f890 0035 ldrb.w r0, [r0, #53] ; 0x35 + + /* If State is ready or suspended, start or resume polling-based HASH processing */ +if((State_tmp == HAL_HASH_STATE_READY) || (State_tmp == HAL_HASH_STATE_SUSPENDED)) + 800ac1e: 2801 cmp r0, #1 +{ + 800ac20: e9dd 7e06 ldrd r7, lr, [sp, #24] + HAL_HASH_StateTypeDef State_tmp = hhash->State; + 800ac24: b2c5 uxtb r5, r0 +if((State_tmp == HAL_HASH_STATE_READY) || (State_tmp == HAL_HASH_STATE_SUSPENDED)) + 800ac26: d002 beq.n 800ac2e + 800ac28: 2d08 cmp r5, #8 + 800ac2a: f040 80df bne.w 800adec + { + /* Check input parameters */ + if ((pInBuffer == NULL) || /*(Size == 0U) ||*/ (hhash->Init.pKey == NULL) || (hhash->Init.KeySize == 0U) || (pOutBuffer == NULL)) + 800ac2e: b139 cbz r1, 800ac40 + 800ac30: f8d4 c008 ldr.w ip, [r4, #8] + 800ac34: f1bc 0f00 cmp.w ip, #0 + 800ac38: d002 beq.n 800ac40 + 800ac3a: 6865 ldr r5, [r4, #4] + 800ac3c: b105 cbz r5, 800ac40 + 800ac3e: b923 cbnz r3, 800ac4a + { + hhash->State = HAL_HASH_STATE_READY; + 800ac40: 2001 movs r0, #1 + 800ac42: f884 0035 strb.w r0, [r4, #53] ; 0x35 + return HMAC_Processing(hhash, Timeout); + + } + else + { + return HAL_BUSY; + 800ac46: 4605 mov r5, r0 + 800ac48: e05b b.n 800ad02 + __HAL_LOCK(hhash); + 800ac4a: f894 0034 ldrb.w r0, [r4, #52] ; 0x34 + 800ac4e: 2801 cmp r0, #1 + 800ac50: f04f 0002 mov.w r0, #2 + 800ac54: d0f7 beq.n 800ac46 + hhash->State = HAL_HASH_STATE_BUSY; + 800ac56: f884 0035 strb.w r0, [r4, #53] ; 0x35 + if(hhash->Phase == HAL_HASH_PHASE_READY) + 800ac5a: f894 002d ldrb.w r0, [r4, #45] ; 0x2d + __HAL_LOCK(hhash); + 800ac5e: 2601 movs r6, #1 + if(hhash->Phase == HAL_HASH_PHASE_READY) + 800ac60: 42b0 cmp r0, r6 + __HAL_LOCK(hhash); + 800ac62: f884 6034 strb.w r6, [r4, #52] ; 0x34 + if(hhash->Phase == HAL_HASH_PHASE_READY) + 800ac66: d118 bne.n 800ac9a + if(hhash->Init.KeySize > 64U) + 800ac68: 4e61 ldr r6, [pc, #388] ; (800adf0 ) + 800ac6a: f8df 818c ldr.w r8, [pc, #396] ; 800adf8 + MODIFY_REG(HASH->CR, HASH_CR_LKEY|HASH_CR_ALGO|HASH_CR_MODE|HASH_CR_INIT, Algorithm | HASH_ALGOMODE_HMAC | HASH_HMAC_KEYTYPE_LONGKEY | HASH_CR_INIT); + 800ac6e: 6830 ldr r0, [r6, #0] + 800ac70: ea00 0008 and.w r0, r0, r8 + 800ac74: ea40 000e orr.w r0, r0, lr + if(hhash->Init.KeySize > 64U) + 800ac78: 2d40 cmp r5, #64 ; 0x40 + MODIFY_REG(HASH->CR, HASH_CR_LKEY|HASH_CR_ALGO|HASH_CR_MODE|HASH_CR_INIT, Algorithm | HASH_ALGOMODE_HMAC | HASH_HMAC_KEYTYPE_LONGKEY | HASH_CR_INIT); + 800ac7a: bf88 it hi + 800ac7c: f440 3080 orrhi.w r0, r0, #65536 ; 0x10000 + MODIFY_REG(HASH->CR, HASH_CR_LKEY|HASH_CR_ALGO|HASH_CR_MODE|HASH_CR_INIT, Algorithm | HASH_ALGOMODE_HMAC | HASH_CR_INIT); + 800ac80: f040 0044 orr.w r0, r0, #68 ; 0x44 + 800ac84: 6030 str r0, [r6, #0] + hhash->pHashInBuffPtr = pInBuffer; /* Input data address, HMAC_Processing input parameter for Step 2 */ + 800ac86: e9c4 1303 strd r1, r3, [r4, #12] + hhash->Phase = HAL_HASH_PHASE_HMAC_STEP_1; + 800ac8a: 2003 movs r0, #3 + hhash->HashInCount = Size; /* Input data size, HMAC_Processing input parameter for Step 2 */ + 800ac8c: 6222 str r2, [r4, #32] + hhash->Phase = HAL_HASH_PHASE_HMAC_STEP_1; + 800ac8e: f884 002d strb.w r0, [r4, #45] ; 0x2d + hhash->HashBuffSize = Size; /* Store the input buffer size for the whole HMAC process */ + 800ac92: 61e2 str r2, [r4, #28] + hhash->pHashKeyBuffPtr = hhash->Init.pKey; /* Key address, HMAC_Processing input parameter for Step 1 and Step 3 */ + 800ac94: f8c4 c014 str.w ip, [r4, #20] + hhash->HashKeyCount = hhash->Init.KeySize; /* Key size, HMAC_Processing input parameter for Step 1 and Step 3 */ + 800ac98: 62a5 str r5, [r4, #40] ; 0x28 + if ((hhash->Phase != HAL_HASH_PHASE_HMAC_STEP_1) && (hhash->Phase != HAL_HASH_PHASE_HMAC_STEP_2) && (hhash->Phase != HAL_HASH_PHASE_HMAC_STEP_3)) + 800ac9a: f894 302d ldrb.w r3, [r4, #45] ; 0x2d + 800ac9e: 1eda subs r2, r3, #3 + 800aca0: 2a02 cmp r2, #2 + 800aca2: d906 bls.n 800acb2 + hhash->State = HAL_HASH_STATE_READY; + 800aca4: 2001 movs r0, #1 + __HAL_UNLOCK(hhash); + 800aca6: 2300 movs r3, #0 + hhash->State = HAL_HASH_STATE_READY; + 800aca8: f884 0035 strb.w r0, [r4, #53] ; 0x35 + __HAL_UNLOCK(hhash); + 800acac: f884 3034 strb.w r3, [r4, #52] ; 0x34 + return HAL_ERROR; + 800acb0: e7c9 b.n 800ac46 + if (hhash->Phase == HAL_HASH_PHASE_HMAC_STEP_1) + 800acb2: 2b03 cmp r3, #3 + 800acb4: 4e4e ldr r6, [pc, #312] ; (800adf0 ) + 800acb6: d155 bne.n 800ad64 + __HAL_HASH_SET_NBVALIDBITS(hhash->Init.KeySize); + 800acb8: 68b3 ldr r3, [r6, #8] + hhash->Status = HASH_WriteData(hhash, hhash->pHashKeyBuffPtr, hhash->HashKeyCount); + 800acba: 6961 ldr r1, [r4, #20] + __HAL_HASH_SET_NBVALIDBITS(hhash->Init.KeySize); + 800acbc: f023 031f bic.w r3, r3, #31 + 800acc0: f005 0503 and.w r5, r5, #3 + 800acc4: ea43 05c5 orr.w r5, r3, r5, lsl #3 + 800acc8: 60b5 str r5, [r6, #8] + hhash->Status = HASH_WriteData(hhash, hhash->pHashKeyBuffPtr, hhash->HashKeyCount); + 800acca: 6aa2 ldr r2, [r4, #40] ; 0x28 + 800accc: 4620 mov r0, r4 + 800acce: f7ff fb0f bl 800a2f0 + 800acd2: 4605 mov r5, r0 + 800acd4: f884 002c strb.w r0, [r4, #44] ; 0x2c + if (hhash->Status != HAL_OK) + 800acd8: b998 cbnz r0, 800ad02 + if (hhash->State == HAL_HASH_STATE_SUSPENDED) + 800acda: f894 3035 ldrb.w r3, [r4, #53] ; 0x35 + 800acde: 2b08 cmp r3, #8 + 800ace0: d103 bne.n 800acea + __HAL_UNLOCK(hhash); + 800ace2: 2000 movs r0, #0 + 800ace4: f884 0034 strb.w r0, [r4, #52] ; 0x34 + return HAL_OK; + 800ace8: e7ad b.n 800ac46 + __HAL_HASH_START_DIGEST(); + 800acea: 68b3 ldr r3, [r6, #8] + 800acec: f443 7380 orr.w r3, r3, #256 ; 0x100 + 800acf0: 60b3 str r3, [r6, #8] + if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_BUSY, SET, Timeout) != HAL_OK) + 800acf2: 2201 movs r2, #1 + 800acf4: 463b mov r3, r7 + 800acf6: 2108 movs r1, #8 + 800acf8: 4620 mov r0, r4 + 800acfa: f7ff fb9b bl 800a434 + 800acfe: b118 cbz r0, 800ad08 + return HAL_TIMEOUT; + 800ad00: 2503 movs r5, #3 + } +} + 800ad02: 4628 mov r0, r5 + 800ad04: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + hhash->Phase = HAL_HASH_PHASE_HMAC_STEP_2; + 800ad08: 2304 movs r3, #4 + 800ad0a: f884 302d strb.w r3, [r4, #45] ; 0x2d + __HAL_HASH_SET_NBVALIDBITS(hhash->HashBuffSize); + 800ad0e: 68b3 ldr r3, [r6, #8] + 800ad10: 69e2 ldr r2, [r4, #28] + hhash->Status = HASH_WriteData(hhash, hhash->pHashInBuffPtr, hhash->HashInCount); + 800ad12: 68e1 ldr r1, [r4, #12] + __HAL_HASH_SET_NBVALIDBITS(hhash->HashBuffSize); + 800ad14: f002 0203 and.w r2, r2, #3 + 800ad18: f023 031f bic.w r3, r3, #31 + 800ad1c: ea43 03c2 orr.w r3, r3, r2, lsl #3 + 800ad20: 60b3 str r3, [r6, #8] + hhash->Status = HASH_WriteData(hhash, hhash->pHashInBuffPtr, hhash->HashInCount); + 800ad22: 6a22 ldr r2, [r4, #32] + 800ad24: 4620 mov r0, r4 + 800ad26: f7ff fae3 bl 800a2f0 + 800ad2a: 4605 mov r5, r0 + 800ad2c: f884 002c strb.w r0, [r4, #44] ; 0x2c + if (hhash->Status != HAL_OK) + 800ad30: 2800 cmp r0, #0 + 800ad32: d1e6 bne.n 800ad02 + if (hhash->State == HAL_HASH_STATE_SUSPENDED) + 800ad34: f894 3035 ldrb.w r3, [r4, #53] ; 0x35 + 800ad38: 2b08 cmp r3, #8 + 800ad3a: d0d2 beq.n 800ace2 + __HAL_HASH_START_DIGEST(); + 800ad3c: 68b3 ldr r3, [r6, #8] + 800ad3e: f443 7380 orr.w r3, r3, #256 ; 0x100 + 800ad42: 60b3 str r3, [r6, #8] + if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_BUSY, SET, Timeout) != HAL_OK) + 800ad44: 2201 movs r2, #1 + 800ad46: 463b mov r3, r7 + 800ad48: 2108 movs r1, #8 + 800ad4a: 4620 mov r0, r4 + 800ad4c: f7ff fb72 bl 800a434 + 800ad50: 2800 cmp r0, #0 + 800ad52: d1d5 bne.n 800ad00 + hhash->Phase = HAL_HASH_PHASE_HMAC_STEP_3; + 800ad54: 2305 movs r3, #5 + 800ad56: f884 302d strb.w r3, [r4, #45] ; 0x2d + hhash->pHashKeyBuffPtr = hhash->Init.pKey; + 800ad5a: 68a3 ldr r3, [r4, #8] + 800ad5c: 6163 str r3, [r4, #20] + hhash->HashKeyCount = hhash->Init.KeySize; + 800ad5e: 6863 ldr r3, [r4, #4] + 800ad60: 62a3 str r3, [r4, #40] ; 0x28 + if (hhash->Phase == HAL_HASH_PHASE_HMAC_STEP_3) + 800ad62: e001 b.n 800ad68 + if (hhash->Phase == HAL_HASH_PHASE_HMAC_STEP_2) + 800ad64: 2b04 cmp r3, #4 + 800ad66: d0d2 beq.n 800ad0e + __HAL_HASH_SET_NBVALIDBITS(hhash->Init.KeySize); + 800ad68: 68b3 ldr r3, [r6, #8] + 800ad6a: 6862 ldr r2, [r4, #4] + hhash->Status = HASH_WriteData(hhash, hhash->pHashKeyBuffPtr, hhash->HashKeyCount); + 800ad6c: 6961 ldr r1, [r4, #20] + __HAL_HASH_SET_NBVALIDBITS(hhash->Init.KeySize); + 800ad6e: f002 0203 and.w r2, r2, #3 + 800ad72: f023 031f bic.w r3, r3, #31 + 800ad76: ea43 03c2 orr.w r3, r3, r2, lsl #3 + 800ad7a: 60b3 str r3, [r6, #8] + hhash->Status = HASH_WriteData(hhash, hhash->pHashKeyBuffPtr, hhash->HashKeyCount); + 800ad7c: 6aa2 ldr r2, [r4, #40] ; 0x28 + 800ad7e: 4620 mov r0, r4 + 800ad80: f7ff fab6 bl 800a2f0 + 800ad84: 4605 mov r5, r0 + 800ad86: f884 002c strb.w r0, [r4, #44] ; 0x2c + if (hhash->Status != HAL_OK) + 800ad8a: 2800 cmp r0, #0 + 800ad8c: d1b9 bne.n 800ad02 + if (hhash->State == HAL_HASH_STATE_SUSPENDED) + 800ad8e: f894 3035 ldrb.w r3, [r4, #53] ; 0x35 + 800ad92: 2b08 cmp r3, #8 + 800ad94: d0a5 beq.n 800ace2 + __HAL_HASH_START_DIGEST(); + 800ad96: 68b3 ldr r3, [r6, #8] + 800ad98: f443 7380 orr.w r3, r3, #256 ; 0x100 + 800ad9c: 60b3 str r3, [r6, #8] + if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_DCIS, RESET, Timeout) != HAL_OK) + 800ad9e: 4602 mov r2, r0 + 800ada0: 463b mov r3, r7 + 800ada2: 2102 movs r1, #2 + 800ada4: 4620 mov r0, r4 + 800ada6: f7ff fb45 bl 800a434 + 800adaa: 4605 mov r5, r0 + 800adac: 2800 cmp r0, #0 + 800adae: d1a7 bne.n 800ad00 + HASH_GetDigest(hhash->pHashOutBuffPtr, HASH_DIGEST_LENGTH()); + 800adb0: 6832 ldr r2, [r6, #0] + 800adb2: 4b10 ldr r3, [pc, #64] ; (800adf4 ) + 800adb4: 6920 ldr r0, [r4, #16] + 800adb6: 421a tst r2, r3 + 800adb8: d014 beq.n 800ade4 + 800adba: 6832 ldr r2, [r6, #0] + 800adbc: 401a ands r2, r3 + 800adbe: f5b2 2f80 cmp.w r2, #262144 ; 0x40000 + 800adc2: d011 beq.n 800ade8 + 800adc4: 6832 ldr r2, [r6, #0] + 800adc6: 4393 bics r3, r2 + 800adc8: bf0c ite eq + 800adca: 2120 moveq r1, #32 + 800adcc: 2110 movne r1, #16 + 800adce: f7ff facf bl 800a370 + hhash->Phase = HAL_HASH_PHASE_READY; + 800add2: 2301 movs r3, #1 + 800add4: f884 302d strb.w r3, [r4, #45] ; 0x2d + hhash->State = HAL_HASH_STATE_READY; + 800add8: f884 3035 strb.w r3, [r4, #53] ; 0x35 + __HAL_UNLOCK(hhash); + 800addc: 2300 movs r3, #0 + 800adde: f884 3034 strb.w r3, [r4, #52] ; 0x34 + return HAL_OK; + 800ade2: e78e b.n 800ad02 + HASH_GetDigest(hhash->pHashOutBuffPtr, HASH_DIGEST_LENGTH()); + 800ade4: 2114 movs r1, #20 + 800ade6: e7f2 b.n 800adce + 800ade8: 211c movs r1, #28 + 800adea: e7f0 b.n 800adce + return HAL_BUSY; + 800adec: 2502 movs r5, #2 + 800adee: e788 b.n 800ad02 + 800adf0: 50060400 .word 0x50060400 + 800adf4: 00040080 .word 0x00040080 + 800adf8: fffaff3b .word 0xfffaff3b + +0800adfc : + * @param Tickstart : Tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef OSPI_WaitFlagStateUntilTimeout(OSPI_HandleTypeDef *hospi, uint32_t Flag, + FlagStatus State, uint32_t Tickstart, uint32_t Timeout) +{ + 800adfc: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + 800ae00: f8dd 8018 ldr.w r8, [sp, #24] + 800ae04: 4604 mov r4, r0 + 800ae06: 460e mov r6, r1 + 800ae08: 4615 mov r5, r2 + 800ae0a: 461f mov r7, r3 + /* Wait until flag is in expected state */ + while((__HAL_OSPI_GET_FLAG(hospi, Flag)) != State) + 800ae0c: 6822 ldr r2, [r4, #0] + 800ae0e: 6a13 ldr r3, [r2, #32] + 800ae10: 4233 tst r3, r6 + 800ae12: bf14 ite ne + 800ae14: 2301 movne r3, #1 + 800ae16: 2300 moveq r3, #0 + 800ae18: 42ab cmp r3, r5 + 800ae1a: d101 bne.n 800ae20 + + return HAL_ERROR; + } + } + } + return HAL_OK; + 800ae1c: 2000 movs r0, #0 + 800ae1e: e012 b.n 800ae46 + if (Timeout != HAL_MAX_DELAY) + 800ae20: f1b8 3fff cmp.w r8, #4294967295 ; 0xffffffff + 800ae24: d0f3 beq.n 800ae0e + if(((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U)) + 800ae26: f7fc f961 bl 80070ec + 800ae2a: 1bc0 subs r0, r0, r7 + 800ae2c: 4540 cmp r0, r8 + 800ae2e: d802 bhi.n 800ae36 + 800ae30: f1b8 0f00 cmp.w r8, #0 + 800ae34: d1ea bne.n 800ae0c + hospi->State = HAL_OSPI_STATE_ERROR; + 800ae36: f44f 7300 mov.w r3, #512 ; 0x200 + 800ae3a: 6463 str r3, [r4, #68] ; 0x44 + hospi->ErrorCode |= HAL_OSPI_ERROR_TIMEOUT; + 800ae3c: 6ca3 ldr r3, [r4, #72] ; 0x48 + 800ae3e: f043 0301 orr.w r3, r3, #1 + 800ae42: 64a3 str r3, [r4, #72] ; 0x48 + 800ae44: 2001 movs r0, #1 +} + 800ae46: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + +0800ae4a : +} + 800ae4a: 4770 bx lr + +0800ae4c : +{ + 800ae4c: b5f0 push {r4, r5, r6, r7, lr} + 800ae4e: b085 sub sp, #20 + 800ae50: 4604 mov r4, r0 + uint32_t tickstart = HAL_GetTick(); + 800ae52: f7fc f94b bl 80070ec + 800ae56: 4603 mov r3, r0 + if (hospi == NULL) + 800ae58: 2c00 cmp r4, #0 + 800ae5a: d05d beq.n 800af18 + hospi->ErrorCode = HAL_OSPI_ERROR_NONE; + 800ae5c: 2000 movs r0, #0 + 800ae5e: 64a0 str r0, [r4, #72] ; 0x48 + if (hospi->State == HAL_OSPI_STATE_RESET) + 800ae60: 6c66 ldr r6, [r4, #68] ; 0x44 + 800ae62: 2e00 cmp r6, #0 + 800ae64: d156 bne.n 800af14 + HAL_OSPI_MspInit(hospi); + 800ae66: 4620 mov r0, r4 + 800ae68: 9303 str r3, [sp, #12] + 800ae6a: f7ff ffee bl 800ae4a + MODIFY_REG(hospi->Instance->DCR1, + 800ae6e: 6b20 ldr r0, [r4, #48] ; 0x30 + 800ae70: 68e1 ldr r1, [r4, #12] + 800ae72: 6825 ldr r5, [r4, #0] + status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_BUSY, RESET, tickstart, hospi->Timeout); + 800ae74: 9b03 ldr r3, [sp, #12] + MODIFY_REG(hospi->Instance->DCR1, + 800ae76: 68af ldr r7, [r5, #8] + 800ae78: 4301 orrs r1, r0 + 800ae7a: 69e0 ldr r0, [r4, #28] + 800ae7c: 4301 orrs r1, r0 + 800ae7e: 4827 ldr r0, [pc, #156] ; (800af1c ) + 800ae80: 4038 ands r0, r7 + 800ae82: 4301 orrs r1, r0 + 800ae84: 6920 ldr r0, [r4, #16] + 800ae86: 3801 subs r0, #1 + 800ae88: ea41 4100 orr.w r1, r1, r0, lsl #16 + 800ae8c: 6960 ldr r0, [r4, #20] + 800ae8e: 3801 subs r0, #1 + hospi->Timeout = Timeout; + 800ae90: f241 3288 movw r2, #5000 ; 0x1388 + MODIFY_REG(hospi->Instance->DCR1, + 800ae94: ea41 2100 orr.w r1, r1, r0, lsl #8 + hospi->Timeout = Timeout; + 800ae98: 64e2 str r2, [r4, #76] ; 0x4c + MODIFY_REG(hospi->Instance->DCR1, + 800ae9a: 60a9 str r1, [r5, #8] + hospi->Instance->DCR3 = (hospi->Init.ChipSelectBoundary << OCTOSPI_DCR3_CSBOUND_Pos); + 800ae9c: 6ae1 ldr r1, [r4, #44] ; 0x2c + MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FTHRES, ((hospi->Init.FifoThreshold - 1U) << OCTOSPI_CR_FTHRES_Pos)); + 800ae9e: 6860 ldr r0, [r4, #4] + hospi->Instance->DCR3 = (hospi->Init.ChipSelectBoundary << OCTOSPI_DCR3_CSBOUND_Pos); + 800aea0: 0409 lsls r1, r1, #16 + 800aea2: 6129 str r1, [r5, #16] + MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FTHRES, ((hospi->Init.FifoThreshold - 1U) << OCTOSPI_CR_FTHRES_Pos)); + 800aea4: 6829 ldr r1, [r5, #0] + 800aea6: 3801 subs r0, #1 + 800aea8: f421 51f8 bic.w r1, r1, #7936 ; 0x1f00 + 800aeac: ea41 2100 orr.w r1, r1, r0, lsl #8 + 800aeb0: 6029 str r1, [r5, #0] + status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_BUSY, RESET, tickstart, hospi->Timeout); + 800aeb2: 4620 mov r0, r4 + 800aeb4: 9200 str r2, [sp, #0] + 800aeb6: 2120 movs r1, #32 + 800aeb8: 4632 mov r2, r6 + 800aeba: f7ff ff9f bl 800adfc + if (status == HAL_OK) + 800aebe: bb48 cbnz r0, 800af14 + MODIFY_REG(hospi->Instance->DCR2, OCTOSPI_DCR2_PRESCALER, ((hospi->Init.ClockPrescaler - 1U) << OCTOSPI_DCR2_PRESCALER_Pos)); + 800aec0: 6823 ldr r3, [r4, #0] + 800aec2: 6a22 ldr r2, [r4, #32] + 800aec4: 68d9 ldr r1, [r3, #12] + 800aec6: 3a01 subs r2, #1 + 800aec8: f021 01ff bic.w r1, r1, #255 ; 0xff + 800aecc: 430a orrs r2, r1 + 800aece: 60da str r2, [r3, #12] + MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_DQM, hospi->Init.DualQuad); + 800aed0: 681a ldr r2, [r3, #0] + 800aed2: 68a1 ldr r1, [r4, #8] + 800aed4: f022 0240 bic.w r2, r2, #64 ; 0x40 + 800aed8: 430a orrs r2, r1 + 800aeda: 601a str r2, [r3, #0] + MODIFY_REG(hospi->Instance->TCR, (OCTOSPI_TCR_SSHIFT | OCTOSPI_TCR_DHQC), (hospi->Init.SampleShifting | hospi->Init.DelayHoldQuarterCycle)); + 800aedc: e9d4 2509 ldrd r2, r5, [r4, #36] ; 0x24 + 800aee0: f8d3 1108 ldr.w r1, [r3, #264] ; 0x108 + 800aee4: 432a orrs r2, r5 + 800aee6: f021 41a0 bic.w r1, r1, #1342177280 ; 0x50000000 + 800aeea: 430a orrs r2, r1 + 800aeec: f8c3 2108 str.w r2, [r3, #264] ; 0x108 + __HAL_OSPI_ENABLE(hospi); + 800aef0: 681a ldr r2, [r3, #0] + 800aef2: f042 0201 orr.w r2, r2, #1 + 800aef6: 601a str r2, [r3, #0] + if (hospi->Init.FreeRunningClock == HAL_OSPI_FREERUNCLK_ENABLE) + 800aef8: 69a2 ldr r2, [r4, #24] + 800aefa: 2a02 cmp r2, #2 + SET_BIT(hospi->Instance->DCR1, OCTOSPI_DCR1_FRCK); + 800aefc: bf02 ittt eq + 800aefe: 689a ldreq r2, [r3, #8] + 800af00: f042 0202 orreq.w r2, r2, #2 + 800af04: 609a streq r2, [r3, #8] + if (hospi->Init.MemoryType == HAL_OSPI_MEMTYPE_HYPERBUS) + 800af06: 68e3 ldr r3, [r4, #12] + 800af08: f1b3 6f80 cmp.w r3, #67108864 ; 0x4000000 + hospi->State = HAL_OSPI_STATE_HYPERBUS_INIT; + 800af0c: bf0c ite eq + 800af0e: 2301 moveq r3, #1 + hospi->State = HAL_OSPI_STATE_READY; + 800af10: 2302 movne r3, #2 + 800af12: 6463 str r3, [r4, #68] ; 0x44 +} + 800af14: b005 add sp, #20 + 800af16: bdf0 pop {r4, r5, r6, r7, pc} + status = HAL_ERROR; + 800af18: 2001 movs r0, #1 + 800af1a: e7fb b.n 800af14 + 800af1c: f8e0f8f4 .word 0xf8e0f8f4 + +0800af20 : +{ + 800af20: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + 800af24: 4605 mov r5, r0 + 800af26: b085 sub sp, #20 + 800af28: 460c mov r4, r1 + 800af2a: 9202 str r2, [sp, #8] + uint32_t tickstart = HAL_GetTick(); + 800af2c: f7fc f8de bl 80070ec + state = hospi->State; + 800af30: 6c6a ldr r2, [r5, #68] ; 0x44 + if (((state == HAL_OSPI_STATE_READY) && (hospi->Init.MemoryType != HAL_OSPI_MEMTYPE_HYPERBUS)) || + 800af32: 2a02 cmp r2, #2 + uint32_t tickstart = HAL_GetTick(); + 800af34: ee07 0a90 vmov s15, r0 + if (((state == HAL_OSPI_STATE_READY) && (hospi->Init.MemoryType != HAL_OSPI_MEMTYPE_HYPERBUS)) || + 800af38: d105 bne.n 800af46 + 800af3a: 68ea ldr r2, [r5, #12] + 800af3c: f1b2 6f80 cmp.w r2, #67108864 ; 0x4000000 + 800af40: d107 bne.n 800af52 + hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; + 800af42: 2310 movs r3, #16 + 800af44: e109 b.n 800b15a + if (((state == HAL_OSPI_STATE_READY) && (hospi->Init.MemoryType != HAL_OSPI_MEMTYPE_HYPERBUS)) || + 800af46: 2a14 cmp r2, #20 + 800af48: f040 8084 bne.w 800b054 + ((state == HAL_OSPI_STATE_READ_CMD_CFG) && (cmd->OperationType == HAL_OSPI_OPTYPE_WRITE_CFG)) || + 800af4c: 6822 ldr r2, [r4, #0] + 800af4e: 2a02 cmp r2, #2 + ((state == HAL_OSPI_STATE_WRITE_CMD_CFG) && (cmd->OperationType == HAL_OSPI_OPTYPE_READ_CFG))) + 800af50: d1f7 bne.n 800af42 + status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_BUSY, RESET, tickstart, Timeout); + 800af52: 9a02 ldr r2, [sp, #8] + 800af54: 9200 str r2, [sp, #0] + 800af56: ee17 3a90 vmov r3, s15 + 800af5a: 2200 movs r2, #0 + 800af5c: 2120 movs r1, #32 + 800af5e: 4628 mov r0, r5 + 800af60: edcd 7a03 vstr s15, [sp, #12] + 800af64: f7ff ff4a bl 800adfc + if (status == HAL_OK) + 800af68: eddd 7a03 vldr s15, [sp, #12] + 800af6c: 2800 cmp r0, #0 + 800af6e: f040 80b9 bne.w 800b0e4 +{ + HAL_StatusTypeDef status = HAL_OK; + __IO uint32_t *ccr_reg, *tcr_reg, *ir_reg, *abr_reg; + + /* Re-initialize the value of the functional mode */ + MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FMODE, 0U); + 800af72: 6829 ldr r1, [r5, #0] + hospi->ErrorCode = HAL_OSPI_ERROR_NONE; + 800af74: 64a8 str r0, [r5, #72] ; 0x48 + MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FMODE, 0U); + 800af76: 680a ldr r2, [r1, #0] + 800af78: f022 5240 bic.w r2, r2, #805306368 ; 0x30000000 + 800af7c: 600a str r2, [r1, #0] + + /* Configure the flash ID */ + if (hospi->Init.DualQuad == HAL_OSPI_DUALQUAD_DISABLE) + 800af7e: 68aa ldr r2, [r5, #8] + 800af80: b92a cbnz r2, 800af8e + { + MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FSEL, cmd->FlashId); + 800af82: 680a ldr r2, [r1, #0] + 800af84: 6866 ldr r6, [r4, #4] + 800af86: f022 0280 bic.w r2, r2, #128 ; 0x80 + 800af8a: 4332 orrs r2, r6 + 800af8c: 600a str r2, [r1, #0] + } + + if (cmd->OperationType == HAL_OSPI_OPTYPE_WRITE_CFG) + 800af8e: 6822 ldr r2, [r4, #0] + ir_reg = &(hospi->Instance->IR); + abr_reg = &(hospi->Instance->ABR); + } + + /* Configure the CCR register with DQS and SIOO modes */ + *ccr_reg = (cmd->DQSMode | cmd->SIOOMode); + 800af90: e9d4 6712 ldrd r6, r7, [r4, #72] ; 0x48 + if (cmd->OperationType == HAL_OSPI_OPTYPE_WRITE_CFG) + 800af94: 2a02 cmp r2, #2 + ccr_reg = &(hospi->Instance->WCCR); + 800af96: bf0c ite eq + 800af98: f501 72c0 addeq.w r2, r1, #384 ; 0x180 + ccr_reg = &(hospi->Instance->CCR); + 800af9c: f501 7280 addne.w r2, r1, #256 ; 0x100 + *ccr_reg = (cmd->DQSMode | cmd->SIOOMode); + 800afa0: ea46 0607 orr.w r6, r6, r7 + 800afa4: 6016 str r6, [r2, #0] + + if (cmd->AlternateBytesMode != HAL_OSPI_ALTERNATE_BYTES_NONE) + 800afa6: 6ae6 ldr r6, [r4, #44] ; 0x2c + tcr_reg = &(hospi->Instance->WTCR); + 800afa8: bf03 ittte eq + 800afaa: f501 7cc4 addeq.w ip, r1, #392 ; 0x188 + ir_reg = &(hospi->Instance->WIR); + 800afae: f501 7ec8 addeq.w lr, r1, #400 ; 0x190 + abr_reg = &(hospi->Instance->WABR); + 800afb2: f501 78d0 addeq.w r8, r1, #416 ; 0x1a0 + tcr_reg = &(hospi->Instance->TCR); + 800afb6: f501 7c84 addne.w ip, r1, #264 ; 0x108 + ir_reg = &(hospi->Instance->IR); + 800afba: bf1c itt ne + 800afbc: f501 7e88 addne.w lr, r1, #272 ; 0x110 + abr_reg = &(hospi->Instance->ABR); + 800afc0: f501 7890 addne.w r8, r1, #288 ; 0x120 + if (cmd->AlternateBytesMode != HAL_OSPI_ALTERNATE_BYTES_NONE) + 800afc4: b16e cbz r6, 800afe2 + { + /* Configure the ABR register with alternate bytes value */ + *abr_reg = cmd->AlternateBytes; + 800afc6: 6aa6 ldr r6, [r4, #40] ; 0x28 + 800afc8: f8c8 6000 str.w r6, [r8] + + /* Configure the CCR register with alternate bytes communication parameters */ + MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_ABMODE | OCTOSPI_CCR_ABDTR | OCTOSPI_CCR_ABSIZE), + 800afcc: 6ae3 ldr r3, [r4, #44] ; 0x2c + 800afce: 6b67 ldr r7, [r4, #52] ; 0x34 + 800afd0: 6816 ldr r6, [r2, #0] + 800afd2: 431f orrs r7, r3 + 800afd4: 6b23 ldr r3, [r4, #48] ; 0x30 + 800afd6: f426 187c bic.w r8, r6, #4128768 ; 0x3f0000 + 800afda: 431f orrs r7, r3 + 800afdc: ea47 0708 orr.w r7, r7, r8 + 800afe0: 6017 str r7, [r2, #0] + (cmd->AlternateBytesMode | cmd->AlternateBytesDtrMode | cmd->AlternateBytesSize)); + } + + /* Configure the TCR register with the number of dummy cycles */ + MODIFY_REG((*tcr_reg), OCTOSPI_TCR_DCYC, cmd->DummyCycles); + 800afe2: f8dc 7000 ldr.w r7, [ip] + 800afe6: 6c66 ldr r6, [r4, #68] ; 0x44 + 800afe8: f027 071f bic.w r7, r7, #31 + 800afec: 433e orrs r6, r7 + 800afee: f8cc 6000 str.w r6, [ip] + + if (cmd->DataMode != HAL_OSPI_DATA_NONE) + 800aff2: f8d4 c038 ldr.w ip, [r4, #56] ; 0x38 + 800aff6: f1bc 0f00 cmp.w ip, #0 + 800affa: d004 beq.n 800b006 + { + if (cmd->OperationType == HAL_OSPI_OPTYPE_COMMON_CFG) + 800affc: 6827 ldr r7, [r4, #0] + 800affe: b917 cbnz r7, 800b006 + { + /* Configure the DLR register with the number of data */ + hospi->Instance->DLR = (cmd->NbData - 1U); + 800b000: 6be7 ldr r7, [r4, #60] ; 0x3c + 800b002: 3f01 subs r7, #1 + 800b004: 640f str r7, [r1, #64] ; 0x40 + } + } + + if (cmd->InstructionMode != HAL_OSPI_INSTRUCTION_NONE) + 800b006: 68e6 ldr r6, [r4, #12] + { + if (cmd->AddressMode != HAL_OSPI_ADDRESS_NONE) + 800b008: 69e7 ldr r7, [r4, #28] + if (cmd->InstructionMode != HAL_OSPI_INSTRUCTION_NONE) + 800b00a: 2e00 cmp r6, #0 + 800b00c: f000 8082 beq.w 800b114 + if (cmd->DataMode != HAL_OSPI_DATA_NONE) + { + /* ---- Command with instruction, address and data ---- */ + + /* Configure the CCR register with all communication parameters */ + MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_IMODE | OCTOSPI_CCR_IDTR | OCTOSPI_CCR_ISIZE | + 800b010: e9d4 8904 ldrd r8, r9, [r4, #16] + if (cmd->AddressMode != HAL_OSPI_ADDRESS_NONE) + 800b014: 2f00 cmp r7, #0 + 800b016: d040 beq.n 800b09a + MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_IMODE | OCTOSPI_CCR_IDTR | OCTOSPI_CCR_ISIZE | + 800b018: e9d4 ab08 ldrd sl, fp, [r4, #32] + if (cmd->DataMode != HAL_OSPI_DATA_NONE) + 800b01c: f1bc 0f00 cmp.w ip, #0 + 800b020: d01e beq.n 800b060 + MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_IMODE | OCTOSPI_CCR_IDTR | OCTOSPI_CCR_ISIZE | + 800b022: ea4c 0606 orr.w r6, ip, r6 + 800b026: 433e orrs r6, r7 + 800b028: ea46 0909 orr.w r9, r6, r9 + 800b02c: ea49 0808 orr.w r8, r9, r8 + 800b030: 6813 ldr r3, [r2, #0] + 800b032: 6c26 ldr r6, [r4, #64] ; 0x40 + 800b034: 4f52 ldr r7, [pc, #328] ; (800b180 ) + 800b036: ea48 0b0b orr.w fp, r8, fp + 800b03a: ea4b 0b0a orr.w fp, fp, sl + 800b03e: ea4b 0606 orr.w r6, fp, r6 + 800b042: 401f ands r7, r3 + 800b044: 433e orrs r6, r7 + + /* The DHQC bit is linked with DDTR bit which should be activated */ + if ((hospi->Init.DelayHoldQuarterCycle == HAL_OSPI_DHQC_ENABLE) && + (cmd->InstructionDtrMode == HAL_OSPI_INSTRUCTION_DTR_ENABLE)) + { + MODIFY_REG((*ccr_reg), OCTOSPI_CCR_DDTR, HAL_OSPI_DATA_DTR_ENABLE); + 800b046: 6016 str r6, [r2, #0] + } + } + + /* Configure the IR register with the instruction value */ + *ir_reg = cmd->Instruction; + 800b048: 68a2 ldr r2, [r4, #8] + 800b04a: f8ce 2000 str.w r2, [lr] + MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_ADMODE | OCTOSPI_CCR_ADDTR | OCTOSPI_CCR_ADSIZE), + (cmd->AddressMode | cmd->AddressDtrMode | cmd->AddressSize)); + } + + /* Configure the AR register with the instruction value */ + hospi->Instance->AR = cmd->Address; + 800b04e: 69a2 ldr r2, [r4, #24] + 800b050: 648a str r2, [r1, #72] ; 0x48 + if (status == HAL_OK) + 800b052: e038 b.n 800b0c6 + ((state == HAL_OSPI_STATE_READ_CMD_CFG) && (cmd->OperationType == HAL_OSPI_OPTYPE_WRITE_CFG)) || + 800b054: 2a24 cmp r2, #36 ; 0x24 + 800b056: f47f af74 bne.w 800af42 + ((state == HAL_OSPI_STATE_WRITE_CMD_CFG) && (cmd->OperationType == HAL_OSPI_OPTYPE_READ_CFG))) + 800b05a: 6822 ldr r2, [r4, #0] + 800b05c: 2a01 cmp r2, #1 + 800b05e: e777 b.n 800af50 + MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_IMODE | OCTOSPI_CCR_IDTR | OCTOSPI_CCR_ISIZE | + 800b060: 433e orrs r6, r7 + 800b062: f8d2 c000 ldr.w ip, [r2] + 800b066: ea46 0609 orr.w r6, r6, r9 + 800b06a: ea46 0608 orr.w r6, r6, r8 + 800b06e: ea46 060b orr.w r6, r6, fp + 800b072: f42c 5c7c bic.w ip, ip, #16128 ; 0x3f00 + 800b076: ea46 060a orr.w r6, r6, sl + 800b07a: f02c 0c3f bic.w ip, ip, #63 ; 0x3f + 800b07e: ea46 060c orr.w r6, r6, ip + 800b082: 6016 str r6, [r2, #0] + if ((hospi->Init.DelayHoldQuarterCycle == HAL_OSPI_DHQC_ENABLE) && + 800b084: 6aae ldr r6, [r5, #40] ; 0x28 + 800b086: f1b6 5f80 cmp.w r6, #268435456 ; 0x10000000 + 800b08a: d1dd bne.n 800b048 + 800b08c: 6966 ldr r6, [r4, #20] + 800b08e: 2e08 cmp r6, #8 + 800b090: d1da bne.n 800b048 + MODIFY_REG((*ccr_reg), OCTOSPI_CCR_DDTR, HAL_OSPI_DATA_DTR_ENABLE); + 800b092: 6816 ldr r6, [r2, #0] + 800b094: f046 6600 orr.w r6, r6, #134217728 ; 0x8000000 + 800b098: e7d5 b.n 800b046 + if (cmd->DataMode != HAL_OSPI_DATA_NONE) + 800b09a: f1bc 0f00 cmp.w ip, #0 + 800b09e: d024 beq.n 800b0ea + MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_IMODE | OCTOSPI_CCR_IDTR | OCTOSPI_CCR_ISIZE | + 800b0a0: ea4c 0106 orr.w r1, ip, r6 + 800b0a4: 6817 ldr r7, [r2, #0] + 800b0a6: 6c26 ldr r6, [r4, #64] ; 0x40 + 800b0a8: ea41 0109 orr.w r1, r1, r9 + 800b0ac: ea41 0108 orr.w r1, r1, r8 + 800b0b0: f027 6a70 bic.w sl, r7, #251658240 ; 0xf000000 + 800b0b4: 4331 orrs r1, r6 + 800b0b6: f02a 0a3f bic.w sl, sl, #63 ; 0x3f + 800b0ba: ea41 010a orr.w r1, r1, sl + MODIFY_REG((*ccr_reg), OCTOSPI_CCR_DDTR, HAL_OSPI_DATA_DTR_ENABLE); + 800b0be: 6011 str r1, [r2, #0] + *ir_reg = cmd->Instruction; + 800b0c0: 68a2 ldr r2, [r4, #8] + 800b0c2: f8ce 2000 str.w r2, [lr] + if (cmd->DataMode == HAL_OSPI_DATA_NONE) + 800b0c6: 6ba2 ldr r2, [r4, #56] ; 0x38 + 800b0c8: 2a00 cmp r2, #0 + 800b0ca: d149 bne.n 800b160 + status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_TC, SET, tickstart, Timeout); + 800b0cc: 9b02 ldr r3, [sp, #8] + 800b0ce: 9300 str r3, [sp, #0] + 800b0d0: 2201 movs r2, #1 + 800b0d2: ee17 3a90 vmov r3, s15 + 800b0d6: 2102 movs r1, #2 + 800b0d8: 4628 mov r0, r5 + 800b0da: f7ff fe8f bl 800adfc + __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_TC); + 800b0de: 682b ldr r3, [r5, #0] + 800b0e0: 2202 movs r2, #2 + 800b0e2: 625a str r2, [r3, #36] ; 0x24 +} + 800b0e4: b005 add sp, #20 + 800b0e6: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_IMODE | OCTOSPI_CCR_IDTR | OCTOSPI_CCR_ISIZE), + 800b0ea: 6811 ldr r1, [r2, #0] + 800b0ec: ea46 0609 orr.w r6, r6, r9 + 800b0f0: ea46 0808 orr.w r8, r6, r8 + 800b0f4: f021 063f bic.w r6, r1, #63 ; 0x3f + 800b0f8: ea48 0606 orr.w r6, r8, r6 + 800b0fc: 6016 str r6, [r2, #0] + if ((hospi->Init.DelayHoldQuarterCycle == HAL_OSPI_DHQC_ENABLE) && + 800b0fe: 6aa9 ldr r1, [r5, #40] ; 0x28 + 800b100: f1b1 5f80 cmp.w r1, #268435456 ; 0x10000000 + 800b104: d1dc bne.n 800b0c0 + 800b106: 6961 ldr r1, [r4, #20] + 800b108: 2908 cmp r1, #8 + 800b10a: d1d9 bne.n 800b0c0 + MODIFY_REG((*ccr_reg), OCTOSPI_CCR_DDTR, HAL_OSPI_DATA_DTR_ENABLE); + 800b10c: 6811 ldr r1, [r2, #0] + 800b10e: f041 6100 orr.w r1, r1, #134217728 ; 0x8000000 + 800b112: e7d4 b.n 800b0be + if (cmd->AddressMode != HAL_OSPI_ADDRESS_NONE) + 800b114: b307 cbz r7, 800b158 + MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_IMODE | OCTOSPI_CCR_IDTR | OCTOSPI_CCR_ISIZE | + 800b116: e9d4 9808 ldrd r9, r8, [r4, #32] + if (cmd->DataMode != HAL_OSPI_DATA_NONE) + 800b11a: f1bc 0f00 cmp.w ip, #0 + 800b11e: d011 beq.n 800b144 + MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_ADMODE | OCTOSPI_CCR_ADDTR | OCTOSPI_CCR_ADSIZE | + 800b120: f8d2 e000 ldr.w lr, [r2] + 800b124: 6c23 ldr r3, [r4, #64] ; 0x40 + 800b126: ea4c 0607 orr.w r6, ip, r7 + 800b12a: ea46 0608 orr.w r6, r6, r8 + 800b12e: ea46 0609 orr.w r6, r6, r9 + 800b132: f02e 6e70 bic.w lr, lr, #251658240 ; 0xf000000 + 800b136: 431e orrs r6, r3 + 800b138: f42e 5e7c bic.w lr, lr, #16128 ; 0x3f00 + 800b13c: ea46 060e orr.w r6, r6, lr + MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_ADMODE | OCTOSPI_CCR_ADDTR | OCTOSPI_CCR_ADSIZE), + 800b140: 6016 str r6, [r2, #0] + 800b142: e784 b.n 800b04e + 800b144: f8d2 c000 ldr.w ip, [r2] + 800b148: ea48 0607 orr.w r6, r8, r7 + 800b14c: ea46 0609 orr.w r6, r6, r9 + 800b150: f42c 577c bic.w r7, ip, #16128 ; 0x3f00 + 800b154: 433e orrs r6, r7 + 800b156: e7f3 b.n 800b140 + } + else + { + /* ---- Invalid command configuration (no instruction, no address) ---- */ + status = HAL_ERROR; + hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_PARAM; + 800b158: 2308 movs r3, #8 + hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; + 800b15a: 64ab str r3, [r5, #72] ; 0x48 + status = HAL_ERROR; + 800b15c: 2001 movs r0, #1 + 800b15e: e7c1 b.n 800b0e4 + if (cmd->OperationType == HAL_OSPI_OPTYPE_COMMON_CFG) + 800b160: 6823 ldr r3, [r4, #0] + 800b162: b90b cbnz r3, 800b168 + hospi->State = HAL_OSPI_STATE_CMD_CFG; + 800b164: 2304 movs r3, #4 + 800b166: e005 b.n 800b174 + else if (cmd->OperationType == HAL_OSPI_OPTYPE_READ_CFG) + 800b168: 2b01 cmp r3, #1 + if (hospi->State == HAL_OSPI_STATE_WRITE_CMD_CFG) + 800b16a: 6c6b ldr r3, [r5, #68] ; 0x44 + else if (cmd->OperationType == HAL_OSPI_OPTYPE_READ_CFG) + 800b16c: d104 bne.n 800b178 + if (hospi->State == HAL_OSPI_STATE_WRITE_CMD_CFG) + 800b16e: 2b24 cmp r3, #36 ; 0x24 + 800b170: d0f8 beq.n 800b164 + hospi->State = HAL_OSPI_STATE_READ_CMD_CFG; + 800b172: 2314 movs r3, #20 + hospi->State = HAL_OSPI_STATE_WRITE_CMD_CFG; + 800b174: 646b str r3, [r5, #68] ; 0x44 + 800b176: e7b5 b.n 800b0e4 + if (hospi->State == HAL_OSPI_STATE_READ_CMD_CFG) + 800b178: 2b14 cmp r3, #20 + 800b17a: d0f3 beq.n 800b164 + hospi->State = HAL_OSPI_STATE_WRITE_CMD_CFG; + 800b17c: 2324 movs r3, #36 ; 0x24 + 800b17e: e7f9 b.n 800b174 + 800b180: f0ffc0c0 .word 0xf0ffc0c0 + +0800b184 : +{ + 800b184: b5f0 push {r4, r5, r6, r7, lr} + 800b186: 4604 mov r4, r0 + 800b188: b085 sub sp, #20 + 800b18a: 460f mov r7, r1 + 800b18c: 4616 mov r6, r2 + uint32_t tickstart = HAL_GetTick(); + 800b18e: f7fb ffad bl 80070ec + __IO uint32_t *data_reg = &hospi->Instance->DR; + 800b192: 6825 ldr r5, [r4, #0] + uint32_t tickstart = HAL_GetTick(); + 800b194: 4603 mov r3, r0 + uint32_t addr_reg = hospi->Instance->AR; + 800b196: 6ca8 ldr r0, [r5, #72] ; 0x48 + uint32_t ir_reg = hospi->Instance->IR; + 800b198: f8d5 c110 ldr.w ip, [r5, #272] ; 0x110 + if (pData == NULL) + 800b19c: b91f cbnz r7, 800b1a6 + hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_PARAM; + 800b19e: 2308 movs r3, #8 + hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; + 800b1a0: 64a3 str r3, [r4, #72] ; 0x48 + status = HAL_ERROR; + 800b1a2: 2001 movs r0, #1 + 800b1a4: e034 b.n 800b210 + if (hospi->State == HAL_OSPI_STATE_CMD_CFG) + 800b1a6: 6c62 ldr r2, [r4, #68] ; 0x44 + 800b1a8: 2a04 cmp r2, #4 + 800b1aa: d13b bne.n 800b224 + hospi->XferCount = READ_REG(hospi->Instance->DLR) + 1U; + 800b1ac: 6c2a ldr r2, [r5, #64] ; 0x40 + hospi->pBuffPtr = pData; + 800b1ae: 6367 str r7, [r4, #52] ; 0x34 + hospi->XferCount = READ_REG(hospi->Instance->DLR) + 1U; + 800b1b0: 3201 adds r2, #1 + 800b1b2: 63e2 str r2, [r4, #60] ; 0x3c + hospi->XferSize = hospi->XferCount; + 800b1b4: 6be2 ldr r2, [r4, #60] ; 0x3c + 800b1b6: 63a2 str r2, [r4, #56] ; 0x38 + MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FMODE, OSPI_FUNCTIONAL_MODE_INDIRECT_READ); + 800b1b8: 6829 ldr r1, [r5, #0] + if (hospi->Init.MemoryType == HAL_OSPI_MEMTYPE_HYPERBUS) + 800b1ba: 68e2 ldr r2, [r4, #12] + MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FMODE, OSPI_FUNCTIONAL_MODE_INDIRECT_READ); + 800b1bc: f021 5140 bic.w r1, r1, #805306368 ; 0x30000000 + 800b1c0: f041 5180 orr.w r1, r1, #268435456 ; 0x10000000 + if (hospi->Init.MemoryType == HAL_OSPI_MEMTYPE_HYPERBUS) + 800b1c4: f1b2 6f80 cmp.w r2, #67108864 ; 0x4000000 + MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FMODE, OSPI_FUNCTIONAL_MODE_INDIRECT_READ); + 800b1c8: 6029 str r1, [r5, #0] + if (hospi->Init.MemoryType == HAL_OSPI_MEMTYPE_HYPERBUS) + 800b1ca: d123 bne.n 800b214 + WRITE_REG(hospi->Instance->AR, addr_reg); + 800b1cc: 64a8 str r0, [r5, #72] ; 0x48 + status = OSPI_WaitFlagStateUntilTimeout(hospi, (HAL_OSPI_FLAG_FT | HAL_OSPI_FLAG_TC), SET, tickstart, Timeout); + 800b1ce: 9600 str r6, [sp, #0] + 800b1d0: 2201 movs r2, #1 + 800b1d2: 2106 movs r1, #6 + 800b1d4: 4620 mov r0, r4 + 800b1d6: 9303 str r3, [sp, #12] + 800b1d8: f7ff fe10 bl 800adfc + if (status != HAL_OK) + 800b1dc: b9c0 cbnz r0, 800b210 + *hospi->pBuffPtr = *((__IO uint8_t *)data_reg); + 800b1de: 6b62 ldr r2, [r4, #52] ; 0x34 + 800b1e0: f895 1050 ldrb.w r1, [r5, #80] ; 0x50 + 800b1e4: 7011 strb r1, [r2, #0] + hospi->pBuffPtr++; + 800b1e6: 6b62 ldr r2, [r4, #52] ; 0x34 + } while(hospi->XferCount > 0U); + 800b1e8: 9b03 ldr r3, [sp, #12] + hospi->pBuffPtr++; + 800b1ea: 3201 adds r2, #1 + 800b1ec: 6362 str r2, [r4, #52] ; 0x34 + hospi->XferCount--; + 800b1ee: 6be2 ldr r2, [r4, #60] ; 0x3c + 800b1f0: 3a01 subs r2, #1 + 800b1f2: 63e2 str r2, [r4, #60] ; 0x3c + } while(hospi->XferCount > 0U); + 800b1f4: 6be2 ldr r2, [r4, #60] ; 0x3c + 800b1f6: 2a00 cmp r2, #0 + 800b1f8: d1e9 bne.n 800b1ce + status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_TC, SET, tickstart, Timeout); + 800b1fa: 9600 str r6, [sp, #0] + 800b1fc: 2201 movs r2, #1 + 800b1fe: 2102 movs r1, #2 + 800b200: 4620 mov r0, r4 + 800b202: f7ff fdfb bl 800adfc + if (status == HAL_OK) + 800b206: b918 cbnz r0, 800b210 + __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_TC); + 800b208: 6822 ldr r2, [r4, #0] + 800b20a: 2302 movs r3, #2 + 800b20c: 6253 str r3, [r2, #36] ; 0x24 + hospi->State = HAL_OSPI_STATE_READY; + 800b20e: 6463 str r3, [r4, #68] ; 0x44 +} + 800b210: b005 add sp, #20 + 800b212: bdf0 pop {r4, r5, r6, r7, pc} + if (READ_BIT(hospi->Instance->CCR, OCTOSPI_CCR_ADMODE) != HAL_OSPI_ADDRESS_NONE) + 800b214: f8d5 2100 ldr.w r2, [r5, #256] ; 0x100 + 800b218: f412 6fe0 tst.w r2, #1792 ; 0x700 + 800b21c: d1d6 bne.n 800b1cc + WRITE_REG(hospi->Instance->IR, ir_reg); + 800b21e: f8c5 c110 str.w ip, [r5, #272] ; 0x110 + 800b222: e7d4 b.n 800b1ce + hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; + 800b224: 2310 movs r3, #16 + 800b226: e7bb b.n 800b1a0 + +0800b228 : +{ + 800b228: e92d 41ff stmdb sp!, {r0, r1, r2, r3, r4, r5, r6, r7, r8, lr} + 800b22c: 4604 mov r4, r0 + 800b22e: 4616 mov r6, r2 + 800b230: 460d mov r5, r1 + uint32_t tickstart = HAL_GetTick(); + 800b232: f7fb ff5b bl 80070ec + uint32_t addr_reg = hospi->Instance->AR; + 800b236: 6822 ldr r2, [r4, #0] + 800b238: 6c97 ldr r7, [r2, #72] ; 0x48 + uint32_t ir_reg = hospi->Instance->IR; + 800b23a: f8d2 8110 ldr.w r8, [r2, #272] ; 0x110 + if ((hospi->State == HAL_OSPI_STATE_CMD_CFG) && (cfg->AutomaticStop == HAL_OSPI_AUTOMATIC_STOP_ENABLE)) + 800b23e: 6c62 ldr r2, [r4, #68] ; 0x44 + 800b240: 2a04 cmp r2, #4 + uint32_t tickstart = HAL_GetTick(); + 800b242: 4603 mov r3, r0 + if ((hospi->State == HAL_OSPI_STATE_CMD_CFG) && (cfg->AutomaticStop == HAL_OSPI_AUTOMATIC_STOP_ENABLE)) + 800b244: d13c bne.n 800b2c0 + 800b246: 68ea ldr r2, [r5, #12] + 800b248: f5b2 0f80 cmp.w r2, #4194304 ; 0x400000 + 800b24c: d138 bne.n 800b2c0 + status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_BUSY, RESET, tickstart, Timeout); + 800b24e: 9003 str r0, [sp, #12] + 800b250: 9600 str r6, [sp, #0] + 800b252: 2200 movs r2, #0 + 800b254: 2120 movs r1, #32 + 800b256: 4620 mov r0, r4 + 800b258: f7ff fdd0 bl 800adfc + if (status == HAL_OK) + 800b25c: bb28 cbnz r0, 800b2aa + WRITE_REG (hospi->Instance->PSMAR, cfg->Match); + 800b25e: 6822 ldr r2, [r4, #0] + 800b260: 6829 ldr r1, [r5, #0] + 800b262: f8c2 1088 str.w r1, [r2, #136] ; 0x88 + WRITE_REG (hospi->Instance->PSMKR, cfg->Mask); + 800b266: 6869 ldr r1, [r5, #4] + 800b268: f8c2 1080 str.w r1, [r2, #128] ; 0x80 + WRITE_REG (hospi->Instance->PIR, cfg->Interval); + 800b26c: 6929 ldr r1, [r5, #16] + 800b26e: f8c2 1090 str.w r1, [r2, #144] ; 0x90 + MODIFY_REG(hospi->Instance->CR, (OCTOSPI_CR_PMM | OCTOSPI_CR_APMS | OCTOSPI_CR_FMODE), + 800b272: e9d5 1502 ldrd r1, r5, [r5, #8] + 800b276: 6810 ldr r0, [r2, #0] + if (hospi->Init.MemoryType == HAL_OSPI_MEMTYPE_HYPERBUS) + 800b278: 9b03 ldr r3, [sp, #12] + MODIFY_REG(hospi->Instance->CR, (OCTOSPI_CR_PMM | OCTOSPI_CR_APMS | OCTOSPI_CR_FMODE), + 800b27a: 4329 orrs r1, r5 + 800b27c: f020 5043 bic.w r0, r0, #817889280 ; 0x30c00000 + 800b280: 4301 orrs r1, r0 + 800b282: f041 5100 orr.w r1, r1, #536870912 ; 0x20000000 + 800b286: 6011 str r1, [r2, #0] + if (hospi->Init.MemoryType == HAL_OSPI_MEMTYPE_HYPERBUS) + 800b288: 68e1 ldr r1, [r4, #12] + 800b28a: f1b1 6f80 cmp.w r1, #67108864 ; 0x4000000 + 800b28e: d10f bne.n 800b2b0 + WRITE_REG(hospi->Instance->AR, addr_reg); + 800b290: 6497 str r7, [r2, #72] ; 0x48 + status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_SM, SET, tickstart, Timeout); + 800b292: 9600 str r6, [sp, #0] + 800b294: 2201 movs r2, #1 + 800b296: 2108 movs r1, #8 + 800b298: 4620 mov r0, r4 + 800b29a: f7ff fdaf bl 800adfc + if (status == HAL_OK) + 800b29e: b920 cbnz r0, 800b2aa + __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_SM); + 800b2a0: 6823 ldr r3, [r4, #0] + 800b2a2: 2208 movs r2, #8 + 800b2a4: 625a str r2, [r3, #36] ; 0x24 + hospi->State = HAL_OSPI_STATE_READY; + 800b2a6: 2302 movs r3, #2 + 800b2a8: 6463 str r3, [r4, #68] ; 0x44 +} + 800b2aa: b004 add sp, #16 + 800b2ac: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + if (READ_BIT(hospi->Instance->CCR, OCTOSPI_CCR_ADMODE) != HAL_OSPI_ADDRESS_NONE) + 800b2b0: f8d2 1100 ldr.w r1, [r2, #256] ; 0x100 + 800b2b4: f411 6fe0 tst.w r1, #1792 ; 0x700 + 800b2b8: d1ea bne.n 800b290 + WRITE_REG(hospi->Instance->IR, ir_reg); + 800b2ba: f8c2 8110 str.w r8, [r2, #272] ; 0x110 + 800b2be: e7e8 b.n 800b292 + hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; + 800b2c0: 2310 movs r3, #16 + 800b2c2: 64a3 str r3, [r4, #72] ; 0x48 + status = HAL_ERROR; + 800b2c4: 2001 movs r0, #1 + 800b2c6: e7f0 b.n 800b2aa + +0800b2c8 : +{ + 800b2c8: b5f7 push {r0, r1, r2, r4, r5, r6, r7, lr} + 800b2ca: 4604 mov r4, r0 + 800b2cc: 460f mov r7, r1 + uint32_t tickstart = HAL_GetTick(); + 800b2ce: f7fb ff0d bl 80070ec + uint32_t addr_reg = hospi->Instance->AR; + 800b2d2: 6822 ldr r2, [r4, #0] + 800b2d4: 6c95 ldr r5, [r2, #72] ; 0x48 + uint32_t ir_reg = hospi->Instance->IR; + 800b2d6: f8d2 6110 ldr.w r6, [r2, #272] ; 0x110 + if (hospi->State == HAL_OSPI_STATE_CMD_CFG) + 800b2da: 6c62 ldr r2, [r4, #68] ; 0x44 + 800b2dc: 2a04 cmp r2, #4 + uint32_t tickstart = HAL_GetTick(); + 800b2de: 4603 mov r3, r0 + if (hospi->State == HAL_OSPI_STATE_CMD_CFG) + 800b2e0: d132 bne.n 800b348 + status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_BUSY, RESET, tickstart, hospi->Timeout); + 800b2e2: 6ce2 ldr r2, [r4, #76] ; 0x4c + 800b2e4: 9200 str r2, [sp, #0] + 800b2e6: 2120 movs r1, #32 + 800b2e8: 2200 movs r2, #0 + 800b2ea: 4620 mov r0, r4 + 800b2ec: f7ff fd86 bl 800adfc + if (status == HAL_OK) + 800b2f0: bb00 cbnz r0, 800b334 + WRITE_REG (hospi->Instance->PSMAR, cfg->Match); + 800b2f2: 6823 ldr r3, [r4, #0] + 800b2f4: 683a ldr r2, [r7, #0] + 800b2f6: f8c3 2088 str.w r2, [r3, #136] ; 0x88 + WRITE_REG (hospi->Instance->PSMKR, cfg->Mask); + 800b2fa: 687a ldr r2, [r7, #4] + 800b2fc: f8c3 2080 str.w r2, [r3, #128] ; 0x80 + WRITE_REG (hospi->Instance->PIR, cfg->Interval); + 800b300: 693a ldr r2, [r7, #16] + 800b302: f8c3 2090 str.w r2, [r3, #144] ; 0x90 + MODIFY_REG(hospi->Instance->CR, (OCTOSPI_CR_PMM | OCTOSPI_CR_APMS | OCTOSPI_CR_FMODE), + 800b306: e9d7 2702 ldrd r2, r7, [r7, #8] + 800b30a: 6819 ldr r1, [r3, #0] + 800b30c: 433a orrs r2, r7 + 800b30e: f021 5143 bic.w r1, r1, #817889280 ; 0x30c00000 + 800b312: 430a orrs r2, r1 + 800b314: f042 5200 orr.w r2, r2, #536870912 ; 0x20000000 + 800b318: 601a str r2, [r3, #0] + __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_TE | HAL_OSPI_FLAG_SM); + 800b31a: 2209 movs r2, #9 + 800b31c: 625a str r2, [r3, #36] ; 0x24 + hospi->State = HAL_OSPI_STATE_BUSY_AUTO_POLLING; + 800b31e: 2248 movs r2, #72 ; 0x48 + 800b320: 6462 str r2, [r4, #68] ; 0x44 + __HAL_OSPI_ENABLE_IT(hospi, HAL_OSPI_IT_SM | HAL_OSPI_IT_TE); + 800b322: 681a ldr r2, [r3, #0] + 800b324: f442 2210 orr.w r2, r2, #589824 ; 0x90000 + 800b328: 601a str r2, [r3, #0] + if (hospi->Init.MemoryType == HAL_OSPI_MEMTYPE_HYPERBUS) + 800b32a: 68e2 ldr r2, [r4, #12] + 800b32c: f1b2 6f80 cmp.w r2, #67108864 ; 0x4000000 + 800b330: d102 bne.n 800b338 + WRITE_REG(hospi->Instance->AR, addr_reg); + 800b332: 649d str r5, [r3, #72] ; 0x48 +} + 800b334: b003 add sp, #12 + 800b336: bdf0 pop {r4, r5, r6, r7, pc} + if (READ_BIT(hospi->Instance->CCR, OCTOSPI_CCR_ADMODE) != HAL_OSPI_ADDRESS_NONE) + 800b338: f8d3 2100 ldr.w r2, [r3, #256] ; 0x100 + 800b33c: f412 6fe0 tst.w r2, #1792 ; 0x700 + 800b340: d1f7 bne.n 800b332 + WRITE_REG(hospi->Instance->IR, ir_reg); + 800b342: f8c3 6110 str.w r6, [r3, #272] ; 0x110 + 800b346: e7f5 b.n 800b334 + hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; + 800b348: 2310 movs r3, #16 + 800b34a: 64a3 str r3, [r4, #72] ; 0x48 + status = HAL_ERROR; + 800b34c: 2001 movs r0, #1 + 800b34e: e7f1 b.n 800b334 + +0800b350 : +{ + 800b350: b573 push {r0, r1, r4, r5, r6, lr} + 800b352: 4604 mov r4, r0 + 800b354: 460d mov r5, r1 + uint32_t tickstart = HAL_GetTick(); + 800b356: f7fb fec9 bl 80070ec + if (hospi->State == HAL_OSPI_STATE_CMD_CFG) + 800b35a: 6c62 ldr r2, [r4, #68] ; 0x44 + 800b35c: 2a04 cmp r2, #4 + uint32_t tickstart = HAL_GetTick(); + 800b35e: 4603 mov r3, r0 + if (hospi->State == HAL_OSPI_STATE_CMD_CFG) + 800b360: d121 bne.n 800b3a6 + status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_BUSY, RESET, tickstart, hospi->Timeout); + 800b362: 6ce2 ldr r2, [r4, #76] ; 0x4c + 800b364: 9200 str r2, [sp, #0] + 800b366: 2120 movs r1, #32 + 800b368: 2200 movs r2, #0 + 800b36a: 4620 mov r0, r4 + 800b36c: f7ff fd46 bl 800adfc + if (status == HAL_OK) + 800b370: b9b8 cbnz r0, 800b3a2 + if (cfg->TimeOutActivation == HAL_OSPI_TIMEOUT_COUNTER_ENABLE) + 800b372: 682e ldr r6, [r5, #0] + WRITE_REG(hospi->Instance->LPTR, cfg->TimeOutPeriod); + 800b374: 6822 ldr r2, [r4, #0] + hospi->State = HAL_OSPI_STATE_BUSY_MEM_MAPPED; + 800b376: 2388 movs r3, #136 ; 0x88 + if (cfg->TimeOutActivation == HAL_OSPI_TIMEOUT_COUNTER_ENABLE) + 800b378: 2e08 cmp r6, #8 + hospi->State = HAL_OSPI_STATE_BUSY_MEM_MAPPED; + 800b37a: 6463 str r3, [r4, #68] ; 0x44 + if (cfg->TimeOutActivation == HAL_OSPI_TIMEOUT_COUNTER_ENABLE) + 800b37c: d108 bne.n 800b390 + WRITE_REG(hospi->Instance->LPTR, cfg->TimeOutPeriod); + 800b37e: 686b ldr r3, [r5, #4] + 800b380: f8c2 3130 str.w r3, [r2, #304] ; 0x130 + __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_TO); + 800b384: 2310 movs r3, #16 + 800b386: 6253 str r3, [r2, #36] ; 0x24 + __HAL_OSPI_ENABLE_IT(hospi, HAL_OSPI_IT_TO); + 800b388: 6811 ldr r1, [r2, #0] + 800b38a: f441 1180 orr.w r1, r1, #1048576 ; 0x100000 + 800b38e: 6011 str r1, [r2, #0] + MODIFY_REG(hospi->Instance->CR, (OCTOSPI_CR_TCEN | OCTOSPI_CR_FMODE), + 800b390: 6813 ldr r3, [r2, #0] + 800b392: f023 5340 bic.w r3, r3, #805306368 ; 0x30000000 + 800b396: f023 0308 bic.w r3, r3, #8 + 800b39a: 4333 orrs r3, r6 + 800b39c: f043 5340 orr.w r3, r3, #805306368 ; 0x30000000 + 800b3a0: 6013 str r3, [r2, #0] +} + 800b3a2: b002 add sp, #8 + 800b3a4: bd70 pop {r4, r5, r6, pc} + hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; + 800b3a6: 2310 movs r3, #16 + 800b3a8: 64a3 str r3, [r4, #72] ; 0x48 + status = HAL_ERROR; + 800b3aa: 2001 movs r0, #1 + 800b3ac: e7f9 b.n 800b3a2 + +0800b3ae : + if ((hospi->State & OSPI_BUSY_STATE_MASK) == 0U) + 800b3ae: 6c43 ldr r3, [r0, #68] ; 0x44 + 800b3b0: f013 0308 ands.w r3, r3, #8 + 800b3b4: d10a bne.n 800b3cc + hospi->Init.FifoThreshold = Threshold; + 800b3b6: 6041 str r1, [r0, #4] + MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FTHRES, ((hospi->Init.FifoThreshold-1U) << OCTOSPI_CR_FTHRES_Pos)); + 800b3b8: 6800 ldr r0, [r0, #0] + 800b3ba: 6802 ldr r2, [r0, #0] + 800b3bc: 3901 subs r1, #1 + 800b3be: f422 52f8 bic.w r2, r2, #7936 ; 0x1f00 + 800b3c2: ea42 2101 orr.w r1, r2, r1, lsl #8 + 800b3c6: 6001 str r1, [r0, #0] + HAL_StatusTypeDef status = HAL_OK; + 800b3c8: 4618 mov r0, r3 + 800b3ca: 4770 bx lr + hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; + 800b3cc: 2310 movs r3, #16 + 800b3ce: 6483 str r3, [r0, #72] ; 0x48 + status = HAL_ERROR; + 800b3d0: 2001 movs r0, #1 +} + 800b3d2: 4770 bx lr + +0800b3d4 : + return ((READ_BIT(hospi->Instance->CR, OCTOSPI_CR_FTHRES) >> OCTOSPI_CR_FTHRES_Pos) + 1U); + 800b3d4: 6803 ldr r3, [r0, #0] + 800b3d6: 6818 ldr r0, [r3, #0] + 800b3d8: f3c0 2004 ubfx r0, r0, #8, #5 +} + 800b3dc: 3001 adds r0, #1 + 800b3de: 4770 bx lr + +0800b3e0 : + hospi->Timeout = Timeout; + 800b3e0: 64c1 str r1, [r0, #76] ; 0x4c +} + 800b3e2: 2000 movs r0, #0 + 800b3e4: 4770 bx lr + +0800b3e6 : + return hospi->ErrorCode; + 800b3e6: 6c80 ldr r0, [r0, #72] ; 0x48 +} + 800b3e8: 4770 bx lr + +0800b3ea : + return hospi->State; + 800b3ea: 6c40 ldr r0, [r0, #68] ; 0x44 +} + 800b3ec: 4770 bx lr + ... + +0800b3f0 : +{ + 800b3f0: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + if (hospi->Instance == OCTOSPI1) + 800b3f4: 6802 ldr r2, [r0, #0] + other_instance = 0U; + 800b3f6: 4bbf ldr r3, [pc, #764] ; (800b6f4 ) + * @retval HAL status + */ +static HAL_StatusTypeDef OSPIM_GetConfig(uint8_t instance_nb, OSPIM_CfgTypeDef *cfg) +{ + HAL_StatusTypeDef status = HAL_OK; + uint32_t reg, value = 0U; + 800b3f8: f8df 8304 ldr.w r8, [pc, #772] ; 800b700 + other_instance = 0U; + 800b3fc: 429a cmp r2, r3 +{ + 800b3fe: b08b sub sp, #44 ; 0x2c + } + + /* Get the information about the instance */ + for (index = 0U; index < OSPI_IOM_NB_PORTS; index ++) + { + reg = OCTOSPIM->PCR[index]; + 800b400: 4bbd ldr r3, [pc, #756] ; (800b6f8 ) + other_instance = 0U; + 800b402: bf0b itete eq + 800b404: f04f 0a01 moveq.w sl, #1 + 800b408: f04f 0a00 movne.w sl, #0 + 800b40c: 2000 moveq r0, #0 + 800b40e: 2001 movne r0, #1 + for (index = 0U; index < OSPI_NB_INSTANCE; index++) + 800b410: 466a mov r2, sp + instance = 1U; + 800b412: 2501 movs r5, #1 + cfg->ClkPort = 0U; + 800b414: 2700 movs r7, #0 + cfg->DQSPort = 0U; + 800b416: e9c2 7700 strd r7, r7, [r2] + cfg->IOLowPort = 0U; + 800b41a: e9c2 7702 strd r7, r7, [r2, #8] + uint32_t reg, value = 0U; + 800b41e: 2d02 cmp r5, #2 + 800b420: bf0c ite eq + 800b422: 46c4 moveq ip, r8 + 800b424: f04f 0c00 movne.w ip, #0 + cfg->IOHighPort = 0U; + 800b428: 6117 str r7, [r2, #16] + for (index = 0U; index < OSPI_IOM_NB_PORTS; index ++) + 800b42a: f04f 0e00 mov.w lr, #0 + reg = OCTOSPIM->PCR[index]; + 800b42e: eb03 048e add.w r4, r3, lr, lsl #2 + { + /* The clock is enabled on this port */ + if ((reg & OCTOSPIM_PCR_CLKSRC) == (value & OCTOSPIM_PCR_CLKSRC)) + { + /* The clock correspond to the instance passed as parameter */ + cfg->ClkPort = index+1U; + 800b432: f10e 0601 add.w r6, lr, #1 + reg = OCTOSPIM->PCR[index]; + 800b436: 6864 ldr r4, [r4, #4] + if ((reg & OCTOSPIM_PCR_CLKEN) != 0U) + 800b438: f014 0f01 tst.w r4, #1 + 800b43c: d005 beq.n 800b44a + if ((reg & OCTOSPIM_PCR_CLKSRC) == (value & OCTOSPIM_PCR_CLKSRC)) + 800b43e: ea84 0e0c eor.w lr, r4, ip + 800b442: f01e 0f02 tst.w lr, #2 + cfg->ClkPort = index+1U; + 800b446: bf08 it eq + 800b448: 6016 streq r6, [r2, #0] + } + } + + if ((reg & OCTOSPIM_PCR_DQSEN) != 0U) + 800b44a: f014 0f10 tst.w r4, #16 + 800b44e: d005 beq.n 800b45c + { + /* The DQS is enabled on this port */ + if ((reg & OCTOSPIM_PCR_DQSSRC) == (value & OCTOSPIM_PCR_DQSSRC)) + 800b450: ea84 0e0c eor.w lr, r4, ip + 800b454: f01e 0f20 tst.w lr, #32 + { + /* The DQS correspond to the instance passed as parameter */ + cfg->DQSPort = index+1U; + 800b458: bf08 it eq + 800b45a: 6056 streq r6, [r2, #4] + } + } + + if ((reg & OCTOSPIM_PCR_NCSEN) != 0U) + 800b45c: f414 7f80 tst.w r4, #256 ; 0x100 + 800b460: d005 beq.n 800b46e + { + /* The nCS is enabled on this port */ + if ((reg & OCTOSPIM_PCR_NCSSRC) == (value & OCTOSPIM_PCR_NCSSRC)) + 800b462: ea84 0e0c eor.w lr, r4, ip + 800b466: f41e 7f00 tst.w lr, #512 ; 0x200 + { + /* The nCS correspond to the instance passed as parameter */ + cfg->NCSPort = index+1U; + 800b46a: bf08 it eq + 800b46c: 6096 streq r6, [r2, #8] + } + } + + if ((reg & OCTOSPIM_PCR_IOLEN) != 0U) + 800b46e: f414 3f80 tst.w r4, #65536 ; 0x10000 + 800b472: d00d beq.n 800b490 + { + /* The IO Low is enabled on this port */ + if ((reg & OCTOSPIM_PCR_IOLSRC_1) == (value & OCTOSPIM_PCR_IOLSRC_1)) + 800b474: ea84 0e0c eor.w lr, r4, ip + 800b478: f41e 2f80 tst.w lr, #262144 ; 0x40000 + 800b47c: d108 bne.n 800b490 + { + /* The IO Low correspond to the instance passed as parameter */ + if ((reg & OCTOSPIM_PCR_IOLSRC_0) == 0U) + 800b47e: f414 3f00 tst.w r4, #131072 ; 0x20000 + { + cfg->IOLowPort = (OCTOSPIM_PCR_IOLEN | (index+1U)); + 800b482: bf0c ite eq + 800b484: f446 3e80 orreq.w lr, r6, #65536 ; 0x10000 + } + else + { + cfg->IOLowPort = (OCTOSPIM_PCR_IOHEN | (index+1U)); + 800b488: f046 7e80 orrne.w lr, r6, #16777216 ; 0x1000000 + 800b48c: f8c2 e00c str.w lr, [r2, #12] + } + } + } + + if ((reg & OCTOSPIM_PCR_IOHEN) != 0U) + 800b490: f014 7f80 tst.w r4, #16777216 ; 0x1000000 + 800b494: d00b beq.n 800b4ae + { + /* The IO High is enabled on this port */ + if ((reg & OCTOSPIM_PCR_IOHSRC_1) == (value & OCTOSPIM_PCR_IOHSRC_1)) + 800b496: ea84 0e0c eor.w lr, r4, ip + 800b49a: f01e 6f80 tst.w lr, #67108864 ; 0x4000000 + 800b49e: d106 bne.n 800b4ae + { + /* The IO High correspond to the instance passed as parameter */ + if ((reg & OCTOSPIM_PCR_IOHSRC_0) == 0U) + 800b4a0: 01a4 lsls r4, r4, #6 + { + cfg->IOHighPort = (OCTOSPIM_PCR_IOLEN | (index+1U)); + 800b4a2: bf54 ite pl + 800b4a4: f446 3480 orrpl.w r4, r6, #65536 ; 0x10000 + } + else + { + cfg->IOHighPort = (OCTOSPIM_PCR_IOHEN | (index+1U)); + 800b4a8: f046 7480 orrmi.w r4, r6, #16777216 ; 0x1000000 + 800b4ac: 6114 str r4, [r2, #16] + for (index = 0U; index < OSPI_IOM_NB_PORTS; index ++) + 800b4ae: 2e02 cmp r6, #2 + 800b4b0: f04f 0e01 mov.w lr, #1 + 800b4b4: d1bb bne.n 800b42e + for (index = 0U; index < OSPI_NB_INSTANCE; index++) + 800b4b6: 2d02 cmp r5, #2 + 800b4b8: f102 0214 add.w r2, r2, #20 + 800b4bc: f040 8117 bne.w 800b6ee + if ((OCTOSPI1->CR & OCTOSPI_CR_EN) != 0U) + 800b4c0: 4c8c ldr r4, [pc, #560] ; (800b6f4 ) + 800b4c2: 6825 ldr r5, [r4, #0] + 800b4c4: ea15 050e ands.w r5, r5, lr + CLEAR_BIT(OCTOSPI1->CR, OCTOSPI_CR_EN); + 800b4c8: bf1e ittt ne + 800b4ca: 6822 ldrne r2, [r4, #0] + 800b4cc: f022 0201 bicne.w r2, r2, #1 + 800b4d0: 6022 strne r2, [r4, #0] + if ((OCTOSPI2->CR & OCTOSPI_CR_EN) != 0U) + 800b4d2: 4a8a ldr r2, [pc, #552] ; (800b6fc ) + 800b4d4: 6814 ldr r4, [r2, #0] + ospi_enabled |= 0x1U; + 800b4d6: bf18 it ne + 800b4d8: 4675 movne r5, lr + if ((OCTOSPI2->CR & OCTOSPI_CR_EN) != 0U) + 800b4da: 07e6 lsls r6, r4, #31 + CLEAR_BIT(OCTOSPI2->CR, OCTOSPI_CR_EN); + 800b4dc: bf42 ittt mi + 800b4de: 6814 ldrmi r4, [r2, #0] + 800b4e0: f024 0401 bicmi.w r4, r4, #1 + 800b4e4: 6014 strmi r4, [r2, #0] + CLEAR_BIT(OCTOSPIM->PCR[(IOM_cfg[instance].NCSPort-1U)], OCTOSPIM_PCR_NCSEN); + 800b4e6: aa0a add r2, sp, #40 ; 0x28 + 800b4e8: f04f 0414 mov.w r4, #20 + 800b4ec: fb04 2400 mla r4, r4, r0, r2 + ospi_enabled |= 0x2U; + 800b4f0: bf48 it mi + 800b4f2: f045 0b02 orrmi.w fp, r5, #2 + CLEAR_BIT(OCTOSPIM->PCR[(IOM_cfg[instance].NCSPort-1U)], OCTOSPIM_PCR_NCSEN); + 800b4f6: f854 2c20 ldr.w r2, [r4, #-32] + 800b4fa: f102 32ff add.w r2, r2, #4294967295 ; 0xffffffff + 800b4fe: eb03 0282 add.w r2, r3, r2, lsl #2 + 800b502: bf58 it pl + 800b504: 46ab movpl fp, r5 + 800b506: 6856 ldr r6, [r2, #4] + 800b508: f426 7680 bic.w r6, r6, #256 ; 0x100 + 800b50c: 6056 str r6, [r2, #4] + if (IOM_cfg[instance].ClkPort != 0U) + 800b50e: f854 2c28 ldr.w r2, [r4, #-40] + 800b512: b382 cbz r2, 800b576 + CLEAR_BIT(OCTOSPIM->PCR[(IOM_cfg[instance].ClkPort-1U)], OCTOSPIM_PCR_CLKEN); + 800b514: 3a01 subs r2, #1 + 800b516: eb03 0282 add.w r2, r3, r2, lsl #2 + 800b51a: 6856 ldr r6, [r2, #4] + 800b51c: f026 0601 bic.w r6, r6, #1 + 800b520: 6056 str r6, [r2, #4] + if (IOM_cfg[instance].DQSPort != 0U) + 800b522: f854 2c24 ldr.w r2, [r4, #-36] + 800b526: b132 cbz r2, 800b536 + CLEAR_BIT(OCTOSPIM->PCR[(IOM_cfg[instance].DQSPort-1U)], OCTOSPIM_PCR_DQSEN); + 800b528: 3a01 subs r2, #1 + 800b52a: eb03 0282 add.w r2, r3, r2, lsl #2 + 800b52e: 6854 ldr r4, [r2, #4] + 800b530: f024 0410 bic.w r4, r4, #16 + 800b534: 6054 str r4, [r2, #4] + if (IOM_cfg[instance].IOLowPort != HAL_OSPIM_IOPORT_NONE) + 800b536: 2214 movs r2, #20 + 800b538: ac0a add r4, sp, #40 ; 0x28 + 800b53a: fb02 4200 mla r2, r2, r0, r4 + 800b53e: f852 2c1c ldr.w r2, [r2, #-28] + 800b542: b142 cbz r2, 800b556 + CLEAR_BIT(OCTOSPIM->PCR[((IOM_cfg[instance].IOLowPort-1U)& OSPI_IOM_PORT_MASK)], OCTOSPIM_PCR_IOLEN); + 800b544: 3a01 subs r2, #1 + 800b546: f002 0201 and.w r2, r2, #1 + 800b54a: eb03 0282 add.w r2, r3, r2, lsl #2 + 800b54e: 6854 ldr r4, [r2, #4] + 800b550: f424 3480 bic.w r4, r4, #65536 ; 0x10000 + 800b554: 6054 str r4, [r2, #4] + if (IOM_cfg[instance].IOHighPort != HAL_OSPIM_IOPORT_NONE) + 800b556: 2214 movs r2, #20 + 800b558: ac0a add r4, sp, #40 ; 0x28 + 800b55a: fb02 4200 mla r2, r2, r0, r4 + 800b55e: f852 2c18 ldr.w r2, [r2, #-24] + 800b562: b142 cbz r2, 800b576 + CLEAR_BIT(OCTOSPIM->PCR[((IOM_cfg[instance].IOHighPort-1U)& OSPI_IOM_PORT_MASK)], OCTOSPIM_PCR_IOHEN); + 800b564: 3a01 subs r2, #1 + 800b566: f002 0201 and.w r2, r2, #1 + 800b56a: eb03 0282 add.w r2, r3, r2, lsl #2 + 800b56e: 6854 ldr r4, [r2, #4] + 800b570: f024 7480 bic.w r4, r4, #16777216 ; 0x1000000 + 800b574: 6054 str r4, [r2, #4] + if ((cfg->ClkPort == IOM_cfg[other_instance].ClkPort) || (cfg->DQSPort == IOM_cfg[other_instance].DQSPort) || + 800b576: aa0a add r2, sp, #40 ; 0x28 + 800b578: f04f 0914 mov.w r9, #20 + 800b57c: fb09 290a mla r9, r9, sl, r2 + 800b580: f8d1 c000 ldr.w ip, [r1] + 800b584: f859 8c28 ldr.w r8, [r9, #-40] + (cfg->IOHighPort == IOM_cfg[other_instance].IOHighPort)) + 800b588: f859 4c18 ldr.w r4, [r9, #-24] + if ((cfg->ClkPort == IOM_cfg[other_instance].ClkPort) || (cfg->DQSPort == IOM_cfg[other_instance].DQSPort) || + 800b58c: 45c4 cmp ip, r8 + (cfg->NCSPort == IOM_cfg[other_instance].NCSPort) || (cfg->IOLowPort == IOM_cfg[other_instance].IOLowPort) || + 800b58e: e9d1 6e01 ldrd r6, lr, [r1, #4] + (cfg->IOHighPort == IOM_cfg[other_instance].IOHighPort)) + 800b592: e9d1 2103 ldrd r2, r1, [r1, #12] + if ((cfg->ClkPort == IOM_cfg[other_instance].ClkPort) || (cfg->DQSPort == IOM_cfg[other_instance].DQSPort) || + 800b596: d00d beq.n 800b5b4 + 800b598: f859 7c24 ldr.w r7, [r9, #-36] + 800b59c: 42b7 cmp r7, r6 + 800b59e: d009 beq.n 800b5b4 + 800b5a0: f859 7c20 ldr.w r7, [r9, #-32] + 800b5a4: 45be cmp lr, r7 + 800b5a6: d005 beq.n 800b5b4 + (cfg->NCSPort == IOM_cfg[other_instance].NCSPort) || (cfg->IOLowPort == IOM_cfg[other_instance].IOLowPort) || + 800b5a8: f859 7c1c ldr.w r7, [r9, #-28] + 800b5ac: 4297 cmp r7, r2 + 800b5ae: d001 beq.n 800b5b4 + 800b5b0: 428c cmp r4, r1 + 800b5b2: d142 bne.n 800b63a + CLEAR_BIT(OCTOSPIM->PCR[(IOM_cfg[other_instance].ClkPort-1U)], OCTOSPIM_PCR_CLKEN); + 800b5b4: f108 38ff add.w r8, r8, #4294967295 ; 0xffffffff + 800b5b8: eb03 0888 add.w r8, r3, r8, lsl #2 + 800b5bc: f8d8 7004 ldr.w r7, [r8, #4] + 800b5c0: f027 0701 bic.w r7, r7, #1 + 800b5c4: f8c8 7004 str.w r7, [r8, #4] + if (IOM_cfg[other_instance].DQSPort != 0U) + 800b5c8: 2714 movs r7, #20 + 800b5ca: f10d 0828 add.w r8, sp, #40 ; 0x28 + 800b5ce: fb07 870a mla r7, r7, sl, r8 + 800b5d2: f857 7c24 ldr.w r7, [r7, #-36] + 800b5d6: b147 cbz r7, 800b5ea + CLEAR_BIT(OCTOSPIM->PCR[(IOM_cfg[other_instance].DQSPort-1U)], OCTOSPIM_PCR_DQSEN); + 800b5d8: 3f01 subs r7, #1 + 800b5da: eb03 0787 add.w r7, r3, r7, lsl #2 + 800b5de: f8d7 8004 ldr.w r8, [r7, #4] + 800b5e2: f028 0810 bic.w r8, r8, #16 + 800b5e6: f8c7 8004 str.w r8, [r7, #4] + CLEAR_BIT(OCTOSPIM->PCR[(IOM_cfg[other_instance].NCSPort-1U)], OCTOSPIM_PCR_NCSEN); + 800b5ea: 2714 movs r7, #20 + 800b5ec: f10d 0828 add.w r8, sp, #40 ; 0x28 + 800b5f0: fb07 8a0a mla sl, r7, sl, r8 + 800b5f4: f85a 7c20 ldr.w r7, [sl, #-32] + 800b5f8: 3f01 subs r7, #1 + 800b5fa: eb03 0787 add.w r7, r3, r7, lsl #2 + 800b5fe: f8d7 8004 ldr.w r8, [r7, #4] + 800b602: f428 7880 bic.w r8, r8, #256 ; 0x100 + 800b606: f8c7 8004 str.w r8, [r7, #4] + if (IOM_cfg[other_instance].IOLowPort != HAL_OSPIM_IOPORT_NONE) + 800b60a: f85a 7c1c ldr.w r7, [sl, #-28] + 800b60e: b157 cbz r7, 800b626 + CLEAR_BIT(OCTOSPIM->PCR[((IOM_cfg[other_instance].IOLowPort-1U)& OSPI_IOM_PORT_MASK)], OCTOSPIM_PCR_IOLEN); + 800b610: 3f01 subs r7, #1 + 800b612: f007 0701 and.w r7, r7, #1 + 800b616: eb03 0787 add.w r7, r3, r7, lsl #2 + 800b61a: f8d7 8004 ldr.w r8, [r7, #4] + 800b61e: f428 3880 bic.w r8, r8, #65536 ; 0x10000 + 800b622: f8c7 8004 str.w r8, [r7, #4] + if (IOM_cfg[other_instance].IOHighPort != HAL_OSPIM_IOPORT_NONE) + 800b626: b144 cbz r4, 800b63a + CLEAR_BIT(OCTOSPIM->PCR[((IOM_cfg[other_instance].IOHighPort-1U)& OSPI_IOM_PORT_MASK)], OCTOSPIM_PCR_IOHEN); + 800b628: 3c01 subs r4, #1 + 800b62a: f004 0401 and.w r4, r4, #1 + 800b62e: eb03 0484 add.w r4, r3, r4, lsl #2 + 800b632: 6867 ldr r7, [r4, #4] + 800b634: f027 7780 bic.w r7, r7, #16777216 ; 0x1000000 + 800b638: 6067 str r7, [r4, #4] + MODIFY_REG(OCTOSPIM->PCR[(cfg->NCSPort-1U)], (OCTOSPIM_PCR_NCSEN | OCTOSPIM_PCR_NCSSRC), (OCTOSPIM_PCR_NCSEN | (instance << OCTOSPIM_PCR_NCSSRC_Pos))); + 800b63a: f10e 3eff add.w lr, lr, #4294967295 ; 0xffffffff + 800b63e: eb03 0e8e add.w lr, r3, lr, lsl #2 + MODIFY_REG(OCTOSPIM->PCR[(cfg->ClkPort-1U)], (OCTOSPIM_PCR_CLKEN | OCTOSPIM_PCR_CLKSRC), (OCTOSPIM_PCR_CLKEN | (instance << OCTOSPIM_PCR_CLKSRC_Pos))); + 800b642: f10c 3cff add.w ip, ip, #4294967295 ; 0xffffffff + MODIFY_REG(OCTOSPIM->PCR[(cfg->NCSPort-1U)], (OCTOSPIM_PCR_NCSEN | OCTOSPIM_PCR_NCSSRC), (OCTOSPIM_PCR_NCSEN | (instance << OCTOSPIM_PCR_NCSSRC_Pos))); + 800b646: f8de 4004 ldr.w r4, [lr, #4] + 800b64a: f424 7440 bic.w r4, r4, #768 ; 0x300 + 800b64e: ea44 2440 orr.w r4, r4, r0, lsl #9 + 800b652: f444 7480 orr.w r4, r4, #256 ; 0x100 + MODIFY_REG(OCTOSPIM->PCR[(cfg->ClkPort-1U)], (OCTOSPIM_PCR_CLKEN | OCTOSPIM_PCR_CLKSRC), (OCTOSPIM_PCR_CLKEN | (instance << OCTOSPIM_PCR_CLKSRC_Pos))); + 800b656: eb03 0c8c add.w ip, r3, ip, lsl #2 + MODIFY_REG(OCTOSPIM->PCR[(cfg->NCSPort-1U)], (OCTOSPIM_PCR_NCSEN | OCTOSPIM_PCR_NCSSRC), (OCTOSPIM_PCR_NCSEN | (instance << OCTOSPIM_PCR_NCSSRC_Pos))); + 800b65a: f8ce 4004 str.w r4, [lr, #4] + MODIFY_REG(OCTOSPIM->PCR[(cfg->ClkPort-1U)], (OCTOSPIM_PCR_CLKEN | OCTOSPIM_PCR_CLKSRC), (OCTOSPIM_PCR_CLKEN | (instance << OCTOSPIM_PCR_CLKSRC_Pos))); + 800b65e: f8dc 4004 ldr.w r4, [ip, #4] + 800b662: f024 0403 bic.w r4, r4, #3 + 800b666: ea44 0440 orr.w r4, r4, r0, lsl #1 + 800b66a: f044 0401 orr.w r4, r4, #1 + 800b66e: f8cc 4004 str.w r4, [ip, #4] + if (cfg->DQSPort != 0U) + 800b672: b156 cbz r6, 800b68a + MODIFY_REG(OCTOSPIM->PCR[(cfg->DQSPort-1U)], (OCTOSPIM_PCR_DQSEN | OCTOSPIM_PCR_DQSSRC), (OCTOSPIM_PCR_DQSEN | (instance << OCTOSPIM_PCR_DQSSRC_Pos))); + 800b674: 3e01 subs r6, #1 + 800b676: eb03 0686 add.w r6, r3, r6, lsl #2 + 800b67a: 6874 ldr r4, [r6, #4] + 800b67c: f024 0430 bic.w r4, r4, #48 ; 0x30 + 800b680: ea44 1440 orr.w r4, r4, r0, lsl #5 + 800b684: f044 0410 orr.w r4, r4, #16 + 800b688: 6074 str r4, [r6, #4] + if ((cfg->IOLowPort & OCTOSPIM_PCR_IOLEN) != 0U) + 800b68a: 03d4 lsls r4, r2, #15 + 800b68c: d53a bpl.n 800b704 + MODIFY_REG(OCTOSPIM->PCR[((cfg->IOLowPort-1U)& OSPI_IOM_PORT_MASK)], (OCTOSPIM_PCR_IOLEN | OCTOSPIM_PCR_IOLSRC), + 800b68e: 3a01 subs r2, #1 + 800b690: f002 0201 and.w r2, r2, #1 + 800b694: eb03 0282 add.w r2, r3, r2, lsl #2 + 800b698: 6854 ldr r4, [r2, #4] + 800b69a: f424 24e0 bic.w r4, r4, #458752 ; 0x70000 + 800b69e: ea44 4480 orr.w r4, r4, r0, lsl #18 + 800b6a2: f444 3480 orr.w r4, r4, #65536 ; 0x10000 + MODIFY_REG(OCTOSPIM->PCR[((cfg->IOLowPort-1U)& OSPI_IOM_PORT_MASK)], (OCTOSPIM_PCR_IOHEN | OCTOSPIM_PCR_IOHSRC), + 800b6a6: 6054 str r4, [r2, #4] + if ((cfg->IOHighPort & OCTOSPIM_PCR_IOLEN) != 0U) + 800b6a8: 03ca lsls r2, r1, #15 + 800b6aa: d53a bpl.n 800b722 + MODIFY_REG(OCTOSPIM->PCR[((cfg->IOHighPort-1U)& OSPI_IOM_PORT_MASK)], (OCTOSPIM_PCR_IOLEN | OCTOSPIM_PCR_IOLSRC), + 800b6ac: 3901 subs r1, #1 + 800b6ae: f001 0101 and.w r1, r1, #1 + 800b6b2: eb03 0381 add.w r3, r3, r1, lsl #2 + 800b6b6: 685a ldr r2, [r3, #4] + 800b6b8: f422 22e0 bic.w r2, r2, #458752 ; 0x70000 + 800b6bc: ea42 4080 orr.w r0, r2, r0, lsl #18 + 800b6c0: f440 3040 orr.w r0, r0, #196608 ; 0x30000 + MODIFY_REG(OCTOSPIM->PCR[((cfg->IOHighPort-1U)& OSPI_IOM_PORT_MASK)], (OCTOSPIM_PCR_IOHEN | OCTOSPIM_PCR_IOHSRC), + 800b6c4: 6058 str r0, [r3, #4] + if ((ospi_enabled & 0x1U) != 0U) + 800b6c6: b125 cbz r5, 800b6d2 + SET_BIT(OCTOSPI1->CR, OCTOSPI_CR_EN); + 800b6c8: 4a0a ldr r2, [pc, #40] ; (800b6f4 ) + 800b6ca: 6813 ldr r3, [r2, #0] + 800b6cc: f043 0301 orr.w r3, r3, #1 + 800b6d0: 6013 str r3, [r2, #0] + if ((ospi_enabled & 0x2U) != 0U) + 800b6d2: f01b 0f02 tst.w fp, #2 + SET_BIT(OCTOSPI2->CR, OCTOSPI_CR_EN); + 800b6d6: bf1c itt ne + 800b6d8: 4a08 ldrne r2, [pc, #32] ; (800b6fc ) + 800b6da: 6813 ldrne r3, [r2, #0] +} + 800b6dc: f04f 0000 mov.w r0, #0 + SET_BIT(OCTOSPI2->CR, OCTOSPI_CR_EN); + 800b6e0: bf1c itt ne + 800b6e2: f043 0301 orrne.w r3, r3, #1 + 800b6e6: 6013 strne r3, [r2, #0] +} + 800b6e8: b00b add sp, #44 ; 0x2c + 800b6ea: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + 800b6ee: 4635 mov r5, r6 + 800b6f0: e691 b.n 800b416 + 800b6f2: bf00 nop + 800b6f4: a0001000 .word 0xa0001000 + 800b6f8: 50061c00 .word 0x50061c00 + 800b6fc: a0001400 .word 0xa0001400 + 800b700: 04040222 .word 0x04040222 + else if (cfg->IOLowPort != HAL_OSPIM_IOPORT_NONE) + 800b704: 2a00 cmp r2, #0 + 800b706: d0cf beq.n 800b6a8 + MODIFY_REG(OCTOSPIM->PCR[((cfg->IOLowPort-1U)& OSPI_IOM_PORT_MASK)], (OCTOSPIM_PCR_IOHEN | OCTOSPIM_PCR_IOHSRC), + 800b708: 3a01 subs r2, #1 + 800b70a: f002 0201 and.w r2, r2, #1 + 800b70e: eb03 0282 add.w r2, r3, r2, lsl #2 + 800b712: 6854 ldr r4, [r2, #4] + 800b714: f024 64e0 bic.w r4, r4, #117440512 ; 0x7000000 + 800b718: ea44 6480 orr.w r4, r4, r0, lsl #26 + 800b71c: f044 7480 orr.w r4, r4, #16777216 ; 0x1000000 + 800b720: e7c1 b.n 800b6a6 + else if (cfg->IOHighPort != HAL_OSPIM_IOPORT_NONE) + 800b722: 2900 cmp r1, #0 + 800b724: d0cf beq.n 800b6c6 + MODIFY_REG(OCTOSPIM->PCR[((cfg->IOHighPort-1U)& OSPI_IOM_PORT_MASK)], (OCTOSPIM_PCR_IOHEN | OCTOSPIM_PCR_IOHSRC), + 800b726: 3901 subs r1, #1 + 800b728: f001 0101 and.w r1, r1, #1 + 800b72c: eb03 0381 add.w r3, r3, r1, lsl #2 + 800b730: 685a ldr r2, [r3, #4] + 800b732: f022 62e0 bic.w r2, r2, #117440512 ; 0x7000000 + 800b736: ea42 6080 orr.w r0, r2, r0, lsl #26 + 800b73a: f040 7040 orr.w r0, r0, #50331648 ; 0x3000000 + 800b73e: e7c1 b.n 800b6c4 + +0800b740 : + * @arg @ref I2C_GENERATE_START_WRITE Generate Restart for write request. + * @retval None + */ +static void I2C_TransferConfig(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t Size, uint32_t Mode, + uint32_t Request) +{ + 800b740: b530 push {r4, r5, lr} + 800b742: 9d03 ldr r5, [sp, #12] + assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance)); + assert_param(IS_TRANSFER_MODE(Mode)); + assert_param(IS_TRANSFER_REQUEST(Request)); + + /* update CR2 register */ + MODIFY_REG(hi2c->Instance->CR2, + 800b744: 6804 ldr r4, [r0, #0] + 800b746: ea45 4202 orr.w r2, r5, r2, lsl #16 + 800b74a: 431a orrs r2, r3 + 800b74c: 4b05 ldr r3, [pc, #20] ; (800b764 ) + 800b74e: 6860 ldr r0, [r4, #4] + 800b750: f3c1 0109 ubfx r1, r1, #0, #10 + 800b754: ea43 5355 orr.w r3, r3, r5, lsr #21 + 800b758: 430a orrs r2, r1 + 800b75a: ea20 0003 bic.w r0, r0, r3 + 800b75e: 4302 orrs r2, r0 + 800b760: 6062 str r2, [r4, #4] + ((I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_AUTOEND | \ + (I2C_CR2_RD_WRN & (uint32_t)(Request >> (31U - I2C_CR2_RD_WRN_Pos))) | I2C_CR2_START | I2C_CR2_STOP)), \ + (uint32_t)(((uint32_t)DevAddress & I2C_CR2_SADD) | + (((uint32_t)Size << I2C_CR2_NBYTES_Pos) & I2C_CR2_NBYTES) | (uint32_t)Mode | (uint32_t)Request)); +} + 800b762: bd30 pop {r4, r5, pc} + 800b764: 03ff63ff .word 0x03ff63ff + +0800b768 : + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) + 800b768: 6803 ldr r3, [r0, #0] +{ + 800b76a: b570 push {r4, r5, r6, lr} + 800b76c: 4604 mov r4, r0 + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) + 800b76e: 6998 ldr r0, [r3, #24] + 800b770: f010 0010 ands.w r0, r0, #16 +{ + 800b774: 460d mov r5, r1 + 800b776: 4616 mov r6, r2 + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) + 800b778: d116 bne.n 800b7a8 +} + 800b77a: bd70 pop {r4, r5, r6, pc} + if (Timeout != HAL_MAX_DELAY) + 800b77c: 1c6a adds r2, r5, #1 + 800b77e: d014 beq.n 800b7aa + if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U)) + 800b780: f7fb fcb4 bl 80070ec + 800b784: 1b80 subs r0, r0, r6 + 800b786: 4285 cmp r5, r0 + 800b788: d300 bcc.n 800b78c + 800b78a: b96d cbnz r5, 800b7a8 + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + 800b78c: 6c63 ldr r3, [r4, #68] ; 0x44 + 800b78e: f043 0320 orr.w r3, r3, #32 + hi2c->ErrorCode |= HAL_I2C_ERROR_AF; + 800b792: 6463 str r3, [r4, #68] ; 0x44 + hi2c->State = HAL_I2C_STATE_READY; + 800b794: 2320 movs r3, #32 + 800b796: f884 3041 strb.w r3, [r4, #65] ; 0x41 + hi2c->Mode = HAL_I2C_MODE_NONE; + 800b79a: 2300 movs r3, #0 + 800b79c: f884 3042 strb.w r3, [r4, #66] ; 0x42 + __HAL_UNLOCK(hi2c); + 800b7a0: f884 3040 strb.w r3, [r4, #64] ; 0x40 + return HAL_ERROR; + 800b7a4: 2001 movs r0, #1 + 800b7a6: e7e8 b.n 800b77a + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == RESET) + 800b7a8: 6823 ldr r3, [r4, #0] + 800b7aa: 699a ldr r2, [r3, #24] + 800b7ac: 0690 lsls r0, r2, #26 + 800b7ae: d5e5 bpl.n 800b77c + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); + 800b7b0: 2210 movs r2, #16 + 800b7b2: 61da str r2, [r3, #28] + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF); + 800b7b4: 2220 movs r2, #32 + 800b7b6: 61da str r2, [r3, #28] + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXIS) != RESET) + 800b7b8: 699a ldr r2, [r3, #24] + 800b7ba: 0791 lsls r1, r2, #30 + hi2c->Instance->TXDR = 0x00U; + 800b7bc: bf44 itt mi + 800b7be: 2200 movmi r2, #0 + 800b7c0: 629a strmi r2, [r3, #40] ; 0x28 + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXE) == RESET) + 800b7c2: 699a ldr r2, [r3, #24] + 800b7c4: 07d2 lsls r2, r2, #31 + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_TXE); + 800b7c6: bf5e ittt pl + 800b7c8: 699a ldrpl r2, [r3, #24] + 800b7ca: f042 0201 orrpl.w r2, r2, #1 + 800b7ce: 619a strpl r2, [r3, #24] + I2C_RESET_CR2(hi2c); + 800b7d0: 685a ldr r2, [r3, #4] + 800b7d2: f022 72ff bic.w r2, r2, #33423360 ; 0x1fe0000 + 800b7d6: f422 328b bic.w r2, r2, #71168 ; 0x11600 + 800b7da: f422 72ff bic.w r2, r2, #510 ; 0x1fe + 800b7de: f022 0201 bic.w r2, r2, #1 + 800b7e2: 605a str r2, [r3, #4] + hi2c->ErrorCode |= HAL_I2C_ERROR_AF; + 800b7e4: 6c63 ldr r3, [r4, #68] ; 0x44 + 800b7e6: f043 0304 orr.w r3, r3, #4 + 800b7ea: e7d2 b.n 800b792 + +0800b7ec : +{ + 800b7ec: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + 800b7f0: 9f06 ldr r7, [sp, #24] + 800b7f2: 4604 mov r4, r0 + 800b7f4: 4688 mov r8, r1 + 800b7f6: 4616 mov r6, r2 + 800b7f8: 461d mov r5, r3 + while (__HAL_I2C_GET_FLAG(hi2c, Flag) == Status) + 800b7fa: 6822 ldr r2, [r4, #0] + 800b7fc: 6993 ldr r3, [r2, #24] + 800b7fe: ea38 0303 bics.w r3, r8, r3 + 800b802: bf0c ite eq + 800b804: 2301 moveq r3, #1 + 800b806: 2300 movne r3, #0 + 800b808: 42b3 cmp r3, r6 + 800b80a: d001 beq.n 800b810 + return HAL_OK; + 800b80c: 2000 movs r0, #0 + 800b80e: e015 b.n 800b83c + if (Timeout != HAL_MAX_DELAY) + 800b810: 1c6b adds r3, r5, #1 + 800b812: d0f3 beq.n 800b7fc + if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U)) + 800b814: f7fb fc6a bl 80070ec + 800b818: 1bc0 subs r0, r0, r7 + 800b81a: 42a8 cmp r0, r5 + 800b81c: d801 bhi.n 800b822 + 800b81e: 2d00 cmp r5, #0 + 800b820: d1eb bne.n 800b7fa + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + 800b822: 6c63 ldr r3, [r4, #68] ; 0x44 + 800b824: f043 0320 orr.w r3, r3, #32 + 800b828: 6463 str r3, [r4, #68] ; 0x44 + hi2c->State = HAL_I2C_STATE_READY; + 800b82a: 2320 movs r3, #32 + 800b82c: f884 3041 strb.w r3, [r4, #65] ; 0x41 + hi2c->Mode = HAL_I2C_MODE_NONE; + 800b830: 2300 movs r3, #0 + 800b832: f884 3042 strb.w r3, [r4, #66] ; 0x42 + __HAL_UNLOCK(hi2c); + 800b836: f884 3040 strb.w r3, [r4, #64] ; 0x40 + 800b83a: 2001 movs r0, #1 +} + 800b83c: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + +0800b840 : +{ + 800b840: b570 push {r4, r5, r6, lr} + 800b842: 4604 mov r4, r0 + 800b844: 460d mov r5, r1 + 800b846: 4616 mov r6, r2 + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == RESET) + 800b848: 6823 ldr r3, [r4, #0] + 800b84a: 699b ldr r3, [r3, #24] + 800b84c: 069b lsls r3, r3, #26 + 800b84e: d501 bpl.n 800b854 + return HAL_OK; + 800b850: 2000 movs r0, #0 +} + 800b852: bd70 pop {r4, r5, r6, pc} + if (I2C_IsAcknowledgeFailed(hi2c, Timeout, Tickstart) != HAL_OK) + 800b854: 4632 mov r2, r6 + 800b856: 4629 mov r1, r5 + 800b858: 4620 mov r0, r4 + 800b85a: f7ff ff85 bl 800b768 + 800b85e: b990 cbnz r0, 800b886 + if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U)) + 800b860: f7fb fc44 bl 80070ec + 800b864: 1b80 subs r0, r0, r6 + 800b866: 42a8 cmp r0, r5 + 800b868: d801 bhi.n 800b86e + 800b86a: 2d00 cmp r5, #0 + 800b86c: d1ec bne.n 800b848 + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + 800b86e: 6c63 ldr r3, [r4, #68] ; 0x44 + 800b870: f043 0320 orr.w r3, r3, #32 + 800b874: 6463 str r3, [r4, #68] ; 0x44 + hi2c->State = HAL_I2C_STATE_READY; + 800b876: 2320 movs r3, #32 + 800b878: f884 3041 strb.w r3, [r4, #65] ; 0x41 + hi2c->Mode = HAL_I2C_MODE_NONE; + 800b87c: 2300 movs r3, #0 + 800b87e: f884 3042 strb.w r3, [r4, #66] ; 0x42 + __HAL_UNLOCK(hi2c); + 800b882: f884 3040 strb.w r3, [r4, #64] ; 0x40 + return HAL_ERROR; + 800b886: 2001 movs r0, #1 + 800b888: e7e3 b.n 800b852 + +0800b88a : +} + 800b88a: 4770 bx lr + +0800b88c : +{ + 800b88c: b510 push {r4, lr} + if (hi2c == NULL) + 800b88e: 4604 mov r4, r0 + 800b890: 2800 cmp r0, #0 + 800b892: d04a beq.n 800b92a + if (hi2c->State == HAL_I2C_STATE_RESET) + 800b894: f890 3041 ldrb.w r3, [r0, #65] ; 0x41 + 800b898: f003 02ff and.w r2, r3, #255 ; 0xff + 800b89c: b91b cbnz r3, 800b8a6 + hi2c->Lock = HAL_UNLOCKED; + 800b89e: f880 2040 strb.w r2, [r0, #64] ; 0x40 + HAL_I2C_MspInit(hi2c); + 800b8a2: f7ff fff2 bl 800b88a + hi2c->State = HAL_I2C_STATE_BUSY; + 800b8a6: 2324 movs r3, #36 ; 0x24 + 800b8a8: f884 3041 strb.w r3, [r4, #65] ; 0x41 + __HAL_I2C_DISABLE(hi2c); + 800b8ac: 6823 ldr r3, [r4, #0] + 800b8ae: 681a ldr r2, [r3, #0] + 800b8b0: f022 0201 bic.w r2, r2, #1 + 800b8b4: 601a str r2, [r3, #0] + hi2c->Instance->TIMINGR = hi2c->Init.Timing & TIMING_CLEAR_MASK; + 800b8b6: 6862 ldr r2, [r4, #4] + 800b8b8: f022 6270 bic.w r2, r2, #251658240 ; 0xf000000 + 800b8bc: 611a str r2, [r3, #16] + hi2c->Instance->OAR1 &= ~I2C_OAR1_OA1EN; + 800b8be: 689a ldr r2, [r3, #8] + 800b8c0: f422 4200 bic.w r2, r2, #32768 ; 0x8000 + 800b8c4: 609a str r2, [r3, #8] + hi2c->Instance->OAR1 = (I2C_OAR1_OA1EN | hi2c->Init.OwnAddress1); + 800b8c6: e9d4 2102 ldrd r2, r1, [r4, #8] + if (hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_7BIT) + 800b8ca: 2901 cmp r1, #1 + 800b8cc: d124 bne.n 800b918 + hi2c->Instance->OAR1 = (I2C_OAR1_OA1EN | hi2c->Init.OwnAddress1); + 800b8ce: f442 4200 orr.w r2, r2, #32768 ; 0x8000 + 800b8d2: 609a str r2, [r3, #8] + hi2c->Instance->CR2 |= (I2C_CR2_AUTOEND | I2C_CR2_NACK); + 800b8d4: 685a ldr r2, [r3, #4] + 800b8d6: f042 7200 orr.w r2, r2, #33554432 ; 0x2000000 + 800b8da: f442 4200 orr.w r2, r2, #32768 ; 0x8000 + 800b8de: 605a str r2, [r3, #4] + hi2c->Instance->OAR2 &= ~I2C_DUALADDRESS_ENABLE; + 800b8e0: 68da ldr r2, [r3, #12] + 800b8e2: f422 4200 bic.w r2, r2, #32768 ; 0x8000 + 800b8e6: 60da str r2, [r3, #12] + hi2c->Instance->OAR2 = (hi2c->Init.DualAddressMode | hi2c->Init.OwnAddress2 | (hi2c->Init.OwnAddress2Masks << 8)); + 800b8e8: e9d4 2104 ldrd r2, r1, [r4, #16] + 800b8ec: 430a orrs r2, r1 + 800b8ee: 69a1 ldr r1, [r4, #24] + 800b8f0: ea42 2201 orr.w r2, r2, r1, lsl #8 + 800b8f4: 60da str r2, [r3, #12] + hi2c->Instance->CR1 = (hi2c->Init.GeneralCallMode | hi2c->Init.NoStretchMode); + 800b8f6: e9d4 2107 ldrd r2, r1, [r4, #28] + 800b8fa: 430a orrs r2, r1 + 800b8fc: 601a str r2, [r3, #0] + __HAL_I2C_ENABLE(hi2c); + 800b8fe: 681a ldr r2, [r3, #0] + 800b900: f042 0201 orr.w r2, r2, #1 + 800b904: 601a str r2, [r3, #0] + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + 800b906: 2000 movs r0, #0 + hi2c->State = HAL_I2C_STATE_READY; + 800b908: 2320 movs r3, #32 + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + 800b90a: 6460 str r0, [r4, #68] ; 0x44 + hi2c->State = HAL_I2C_STATE_READY; + 800b90c: f884 3041 strb.w r3, [r4, #65] ; 0x41 + hi2c->PreviousState = I2C_STATE_NONE; + 800b910: 6320 str r0, [r4, #48] ; 0x30 + hi2c->Mode = HAL_I2C_MODE_NONE; + 800b912: f884 0042 strb.w r0, [r4, #66] ; 0x42 +} + 800b916: bd10 pop {r4, pc} + hi2c->Instance->OAR1 = (I2C_OAR1_OA1EN | I2C_OAR1_OA1MODE | hi2c->Init.OwnAddress1); + 800b918: f442 4204 orr.w r2, r2, #33792 ; 0x8400 + if (hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_10BIT) + 800b91c: 2902 cmp r1, #2 + hi2c->Instance->OAR1 = (I2C_OAR1_OA1EN | I2C_OAR1_OA1MODE | hi2c->Init.OwnAddress1); + 800b91e: 609a str r2, [r3, #8] + hi2c->Instance->CR2 = (I2C_CR2_ADD10); + 800b920: bf04 itt eq + 800b922: f44f 6200 moveq.w r2, #2048 ; 0x800 + 800b926: 605a streq r2, [r3, #4] + 800b928: e7d4 b.n 800b8d4 + return HAL_ERROR; + 800b92a: 2001 movs r0, #1 + 800b92c: e7f3 b.n 800b916 + +0800b92e : + 800b92e: 4770 bx lr + +0800b930 : +{ + 800b930: e92d 47f3 stmdb sp!, {r0, r1, r4, r5, r6, r7, r8, r9, sl, lr} + 800b934: 4698 mov r8, r3 + if (hi2c->State == HAL_I2C_STATE_READY) + 800b936: f890 3041 ldrb.w r3, [r0, #65] ; 0x41 +{ + 800b93a: 9f0a ldr r7, [sp, #40] ; 0x28 + if (hi2c->State == HAL_I2C_STATE_READY) + 800b93c: 2b20 cmp r3, #32 +{ + 800b93e: 4604 mov r4, r0 + 800b940: 460e mov r6, r1 + 800b942: 4691 mov r9, r2 + if (hi2c->State == HAL_I2C_STATE_READY) + 800b944: f040 80a3 bne.w 800ba8e + __HAL_LOCK(hi2c); + 800b948: f890 3040 ldrb.w r3, [r0, #64] ; 0x40 + 800b94c: 2b01 cmp r3, #1 + 800b94e: f000 809e beq.w 800ba8e + 800b952: f04f 0a01 mov.w sl, #1 + 800b956: f880 a040 strb.w sl, [r0, #64] ; 0x40 + tickstart = HAL_GetTick(); + 800b95a: f7fb fbc7 bl 80070ec + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY, tickstart) != HAL_OK) + 800b95e: 2319 movs r3, #25 + tickstart = HAL_GetTick(); + 800b960: 4605 mov r5, r0 + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY, tickstart) != HAL_OK) + 800b962: 9000 str r0, [sp, #0] + 800b964: 4652 mov r2, sl + 800b966: f44f 4100 mov.w r1, #32768 ; 0x8000 + 800b96a: 4620 mov r0, r4 + 800b96c: f7ff ff3e bl 800b7ec + 800b970: b118 cbz r0, 800b97a + return HAL_ERROR; + 800b972: 2001 movs r0, #1 +} + 800b974: b002 add sp, #8 + 800b976: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + hi2c->State = HAL_I2C_STATE_BUSY_TX; + 800b97a: 2321 movs r3, #33 ; 0x21 + 800b97c: f884 3041 strb.w r3, [r4, #65] ; 0x41 + hi2c->Mode = HAL_I2C_MODE_MASTER; + 800b980: 2310 movs r3, #16 + 800b982: f884 3042 strb.w r3, [r4, #66] ; 0x42 + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + 800b986: 6460 str r0, [r4, #68] ; 0x44 + hi2c->XferCount = Size; + 800b988: f8a4 802a strh.w r8, [r4, #42] ; 0x2a + if (hi2c->XferCount > MAX_NBYTE_SIZE) + 800b98c: 8d63 ldrh r3, [r4, #42] ; 0x2a + hi2c->pBuffPtr = pData; + 800b98e: f8c4 9024 str.w r9, [r4, #36] ; 0x24 + if (hi2c->XferCount > MAX_NBYTE_SIZE) + 800b992: b29b uxth r3, r3 + 800b994: 2bff cmp r3, #255 ; 0xff + hi2c->XferISR = NULL; + 800b996: 6360 str r0, [r4, #52] ; 0x34 + if (hi2c->XferCount > MAX_NBYTE_SIZE) + 800b998: 4b3e ldr r3, [pc, #248] ; (800ba94 ) + 800b99a: d927 bls.n 800b9ec + hi2c->XferSize = MAX_NBYTE_SIZE; + 800b99c: 22ff movs r2, #255 ; 0xff + 800b99e: 8522 strh r2, [r4, #40] ; 0x28 + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_RELOAD_MODE, I2C_GENERATE_START_WRITE); + 800b9a0: 9300 str r3, [sp, #0] + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_RELOAD_MODE, I2C_NO_STARTSTOP); + 800b9a2: f04f 7380 mov.w r3, #16777216 ; 0x1000000 + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); + 800b9a6: 4631 mov r1, r6 + 800b9a8: 4620 mov r0, r4 + 800b9aa: f7ff fec9 bl 800b740 + while (hi2c->XferCount > 0U) + 800b9ae: 8d63 ldrh r3, [r4, #42] ; 0x2a + 800b9b0: b29b uxth r3, r3 + 800b9b2: 2b00 cmp r3, #0 + 800b9b4: d13e bne.n 800ba34 + if (I2C_WaitOnSTOPFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + 800b9b6: 462a mov r2, r5 + 800b9b8: 4639 mov r1, r7 + 800b9ba: 4620 mov r0, r4 + 800b9bc: f7ff ff40 bl 800b840 + 800b9c0: 2800 cmp r0, #0 + 800b9c2: d1d6 bne.n 800b972 + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF); + 800b9c4: 6823 ldr r3, [r4, #0] + 800b9c6: 2120 movs r1, #32 + 800b9c8: 61d9 str r1, [r3, #28] + I2C_RESET_CR2(hi2c); + 800b9ca: 685a ldr r2, [r3, #4] + 800b9cc: f022 72ff bic.w r2, r2, #33423360 ; 0x1fe0000 + 800b9d0: f422 328b bic.w r2, r2, #71168 ; 0x11600 + 800b9d4: f422 72ff bic.w r2, r2, #510 ; 0x1fe + 800b9d8: f022 0201 bic.w r2, r2, #1 + 800b9dc: 605a str r2, [r3, #4] + hi2c->State = HAL_I2C_STATE_READY; + 800b9de: f884 1041 strb.w r1, [r4, #65] ; 0x41 + __HAL_UNLOCK(hi2c); + 800b9e2: f884 0040 strb.w r0, [r4, #64] ; 0x40 + hi2c->Mode = HAL_I2C_MODE_NONE; + 800b9e6: f884 0042 strb.w r0, [r4, #66] ; 0x42 + return HAL_OK; + 800b9ea: e7c3 b.n 800b974 + hi2c->XferSize = hi2c->XferCount; + 800b9ec: 8d62 ldrh r2, [r4, #42] ; 0x2a + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_GENERATE_START_WRITE); + 800b9ee: 9300 str r3, [sp, #0] + hi2c->XferSize = hi2c->XferCount; + 800b9f0: b292 uxth r2, r2 + 800b9f2: 8522 strh r2, [r4, #40] ; 0x28 + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); + 800b9f4: f04f 7300 mov.w r3, #33554432 ; 0x2000000 + 800b9f8: b2d2 uxtb r2, r2 + 800b9fa: e7d4 b.n 800b9a6 + if (I2C_IsAcknowledgeFailed(hi2c, Timeout, Tickstart) != HAL_OK) + 800b9fc: 462a mov r2, r5 + 800b9fe: 4639 mov r1, r7 + 800ba00: 4620 mov r0, r4 + 800ba02: f7ff feb1 bl 800b768 + 800ba06: 2800 cmp r0, #0 + 800ba08: d1b3 bne.n 800b972 + if (Timeout != HAL_MAX_DELAY) + 800ba0a: 1c7a adds r2, r7, #1 + 800ba0c: d012 beq.n 800ba34 + if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U)) + 800ba0e: f7fb fb6d bl 80070ec + 800ba12: 1b40 subs r0, r0, r5 + 800ba14: 4287 cmp r7, r0 + 800ba16: d300 bcc.n 800ba1a + 800ba18: b967 cbnz r7, 800ba34 + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + 800ba1a: 6c63 ldr r3, [r4, #68] ; 0x44 + 800ba1c: f043 0320 orr.w r3, r3, #32 + 800ba20: 6463 str r3, [r4, #68] ; 0x44 + hi2c->State = HAL_I2C_STATE_READY; + 800ba22: 2320 movs r3, #32 + 800ba24: f884 3041 strb.w r3, [r4, #65] ; 0x41 + hi2c->Mode = HAL_I2C_MODE_NONE; + 800ba28: 2300 movs r3, #0 + 800ba2a: f884 3042 strb.w r3, [r4, #66] ; 0x42 + __HAL_UNLOCK(hi2c); + 800ba2e: f884 3040 strb.w r3, [r4, #64] ; 0x40 + 800ba32: e79e b.n 800b972 + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXIS) == RESET) + 800ba34: 6822 ldr r2, [r4, #0] + 800ba36: 6993 ldr r3, [r2, #24] + 800ba38: 079b lsls r3, r3, #30 + 800ba3a: d5df bpl.n 800b9fc + hi2c->Instance->TXDR = *hi2c->pBuffPtr; + 800ba3c: 6a63 ldr r3, [r4, #36] ; 0x24 + 800ba3e: f813 1b01 ldrb.w r1, [r3], #1 + 800ba42: 6291 str r1, [r2, #40] ; 0x28 + hi2c->pBuffPtr++; + 800ba44: 6263 str r3, [r4, #36] ; 0x24 + hi2c->XferCount--; + 800ba46: 8d63 ldrh r3, [r4, #42] ; 0x2a + hi2c->XferSize--; + 800ba48: 8d22 ldrh r2, [r4, #40] ; 0x28 + hi2c->XferCount--; + 800ba4a: 3b01 subs r3, #1 + 800ba4c: b29b uxth r3, r3 + 800ba4e: 8563 strh r3, [r4, #42] ; 0x2a + if ((hi2c->XferCount != 0U) && (hi2c->XferSize == 0U)) + 800ba50: 8d63 ldrh r3, [r4, #42] ; 0x2a + hi2c->XferSize--; + 800ba52: 3a01 subs r2, #1 + 800ba54: b292 uxth r2, r2 + if ((hi2c->XferCount != 0U) && (hi2c->XferSize == 0U)) + 800ba56: b29b uxth r3, r3 + hi2c->XferSize--; + 800ba58: 8522 strh r2, [r4, #40] ; 0x28 + if ((hi2c->XferCount != 0U) && (hi2c->XferSize == 0U)) + 800ba5a: 2b00 cmp r3, #0 + 800ba5c: d0a7 beq.n 800b9ae + 800ba5e: 2a00 cmp r2, #0 + 800ba60: d1a5 bne.n 800b9ae + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_TCR, RESET, Timeout, tickstart) != HAL_OK) + 800ba62: 9500 str r5, [sp, #0] + 800ba64: 463b mov r3, r7 + 800ba66: 2180 movs r1, #128 ; 0x80 + 800ba68: 4620 mov r0, r4 + 800ba6a: f7ff febf bl 800b7ec + 800ba6e: 2800 cmp r0, #0 + 800ba70: f47f af7f bne.w 800b972 + if (hi2c->XferCount > MAX_NBYTE_SIZE) + 800ba74: 8d63 ldrh r3, [r4, #42] ; 0x2a + 800ba76: b29b uxth r3, r3 + 800ba78: 2bff cmp r3, #255 ; 0xff + 800ba7a: d903 bls.n 800ba84 + hi2c->XferSize = MAX_NBYTE_SIZE; + 800ba7c: 22ff movs r2, #255 ; 0xff + 800ba7e: 8522 strh r2, [r4, #40] ; 0x28 + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_RELOAD_MODE, I2C_NO_STARTSTOP); + 800ba80: 9000 str r0, [sp, #0] + 800ba82: e78e b.n 800b9a2 + hi2c->XferSize = hi2c->XferCount; + 800ba84: 8d62 ldrh r2, [r4, #42] ; 0x2a + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); + 800ba86: 9000 str r0, [sp, #0] + hi2c->XferSize = hi2c->XferCount; + 800ba88: b292 uxth r2, r2 + 800ba8a: 8522 strh r2, [r4, #40] ; 0x28 + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); + 800ba8c: e7b2 b.n 800b9f4 + return HAL_BUSY; + 800ba8e: 2002 movs r0, #2 + 800ba90: e770 b.n 800b974 + 800ba92: bf00 nop + 800ba94: 80002000 .word 0x80002000 + +0800ba98 : +{ + 800ba98: e92d 47f3 stmdb sp!, {r0, r1, r4, r5, r6, r7, r8, r9, sl, lr} + 800ba9c: 4698 mov r8, r3 + if (hi2c->State == HAL_I2C_STATE_READY) + 800ba9e: f890 3041 ldrb.w r3, [r0, #65] ; 0x41 +{ + 800baa2: 9f0a ldr r7, [sp, #40] ; 0x28 + if (hi2c->State == HAL_I2C_STATE_READY) + 800baa4: 2b20 cmp r3, #32 +{ + 800baa6: 4604 mov r4, r0 + 800baa8: 460e mov r6, r1 + 800baaa: 4691 mov r9, r2 + if (hi2c->State == HAL_I2C_STATE_READY) + 800baac: f040 80be bne.w 800bc2c + __HAL_LOCK(hi2c); + 800bab0: f890 3040 ldrb.w r3, [r0, #64] ; 0x40 + 800bab4: 2b01 cmp r3, #1 + 800bab6: f000 80b9 beq.w 800bc2c + 800baba: f04f 0a01 mov.w sl, #1 + 800babe: f880 a040 strb.w sl, [r0, #64] ; 0x40 + tickstart = HAL_GetTick(); + 800bac2: f7fb fb13 bl 80070ec + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY, tickstart) != HAL_OK) + 800bac6: 2319 movs r3, #25 + tickstart = HAL_GetTick(); + 800bac8: 4605 mov r5, r0 + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY, tickstart) != HAL_OK) + 800baca: 9000 str r0, [sp, #0] + 800bacc: 4652 mov r2, sl + 800bace: f44f 4100 mov.w r1, #32768 ; 0x8000 + 800bad2: 4620 mov r0, r4 + 800bad4: f7ff fe8a bl 800b7ec + 800bad8: b118 cbz r0, 800bae2 + return HAL_ERROR; + 800bada: 2001 movs r0, #1 +} + 800badc: b002 add sp, #8 + 800bade: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + hi2c->State = HAL_I2C_STATE_BUSY_RX; + 800bae2: 2322 movs r3, #34 ; 0x22 + 800bae4: f884 3041 strb.w r3, [r4, #65] ; 0x41 + hi2c->Mode = HAL_I2C_MODE_MASTER; + 800bae8: 2310 movs r3, #16 + 800baea: f884 3042 strb.w r3, [r4, #66] ; 0x42 + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + 800baee: 6460 str r0, [r4, #68] ; 0x44 + hi2c->XferCount = Size; + 800baf0: f8a4 802a strh.w r8, [r4, #42] ; 0x2a + if (hi2c->XferCount > MAX_NBYTE_SIZE) + 800baf4: 8d63 ldrh r3, [r4, #42] ; 0x2a + hi2c->pBuffPtr = pData; + 800baf6: f8c4 9024 str.w r9, [r4, #36] ; 0x24 + if (hi2c->XferCount > MAX_NBYTE_SIZE) + 800bafa: b29b uxth r3, r3 + 800bafc: 2bff cmp r3, #255 ; 0xff + hi2c->XferISR = NULL; + 800bafe: 6360 str r0, [r4, #52] ; 0x34 + if (hi2c->XferCount > MAX_NBYTE_SIZE) + 800bb00: 4b4b ldr r3, [pc, #300] ; (800bc30 ) + 800bb02: d909 bls.n 800bb18 + hi2c->XferSize = MAX_NBYTE_SIZE; + 800bb04: 22ff movs r2, #255 ; 0xff + 800bb06: 8522 strh r2, [r4, #40] ; 0x28 + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_RELOAD_MODE, I2C_GENERATE_START_READ); + 800bb08: 9300 str r3, [sp, #0] + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_RELOAD_MODE, I2C_NO_STARTSTOP); + 800bb0a: f04f 7380 mov.w r3, #16777216 ; 0x1000000 + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); + 800bb0e: 4631 mov r1, r6 + 800bb10: 4620 mov r0, r4 + 800bb12: f7ff fe15 bl 800b740 + 800bb16: e052 b.n 800bbbe + hi2c->XferSize = hi2c->XferCount; + 800bb18: 8d62 ldrh r2, [r4, #42] ; 0x2a + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_GENERATE_START_READ); + 800bb1a: 9300 str r3, [sp, #0] + hi2c->XferSize = hi2c->XferCount; + 800bb1c: b292 uxth r2, r2 + 800bb1e: 8522 strh r2, [r4, #40] ; 0x28 + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); + 800bb20: f04f 7300 mov.w r3, #33554432 ; 0x2000000 + 800bb24: b2d2 uxtb r2, r2 + 800bb26: e7f2 b.n 800bb0e + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF); + 800bb28: 2120 movs r1, #32 + 800bb2a: 61d9 str r1, [r3, #28] + I2C_RESET_CR2(hi2c); + 800bb2c: 685a ldr r2, [r3, #4] + 800bb2e: f022 72ff bic.w r2, r2, #33423360 ; 0x1fe0000 + 800bb32: f422 328b bic.w r2, r2, #71168 ; 0x11600 + 800bb36: f422 72ff bic.w r2, r2, #510 ; 0x1fe + 800bb3a: f022 0201 bic.w r2, r2, #1 + 800bb3e: 605a str r2, [r3, #4] + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + 800bb40: 2300 movs r3, #0 + 800bb42: 6463 str r3, [r4, #68] ; 0x44 + hi2c->State = HAL_I2C_STATE_READY; + 800bb44: f884 1041 strb.w r1, [r4, #65] ; 0x41 + hi2c->Mode = HAL_I2C_MODE_NONE; + 800bb48: f884 3042 strb.w r3, [r4, #66] ; 0x42 + __HAL_UNLOCK(hi2c); + 800bb4c: f884 3040 strb.w r3, [r4, #64] ; 0x40 + 800bb50: e7c3 b.n 800bada + if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U)) + 800bb52: f7fb facb bl 80070ec + 800bb56: 1b40 subs r0, r0, r5 + 800bb58: 4287 cmp r7, r0 + 800bb5a: d300 bcc.n 800bb5e + 800bb5c: b947 cbnz r7, 800bb70 + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + 800bb5e: 6c63 ldr r3, [r4, #68] ; 0x44 + 800bb60: f043 0320 orr.w r3, r3, #32 + 800bb64: 6463 str r3, [r4, #68] ; 0x44 + hi2c->State = HAL_I2C_STATE_READY; + 800bb66: 2320 movs r3, #32 + 800bb68: f884 3041 strb.w r3, [r4, #65] ; 0x41 + __HAL_UNLOCK(hi2c); + 800bb6c: 2300 movs r3, #0 + 800bb6e: e7ed b.n 800bb4c + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == RESET) + 800bb70: 6823 ldr r3, [r4, #0] + 800bb72: 699b ldr r3, [r3, #24] + 800bb74: 075b lsls r3, r3, #29 + 800bb76: d410 bmi.n 800bb9a + if (I2C_IsAcknowledgeFailed(hi2c, Timeout, Tickstart) != HAL_OK) + 800bb78: 462a mov r2, r5 + 800bb7a: 4639 mov r1, r7 + 800bb7c: 4620 mov r0, r4 + 800bb7e: f7ff fdf3 bl 800b768 + 800bb82: 2800 cmp r0, #0 + 800bb84: d1a9 bne.n 800bada + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == SET) + 800bb86: 6823 ldr r3, [r4, #0] + 800bb88: 699a ldr r2, [r3, #24] + 800bb8a: 0691 lsls r1, r2, #26 + 800bb8c: d5e1 bpl.n 800bb52 + if ((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == SET) && (hi2c->XferSize > 0U)) + 800bb8e: 699a ldr r2, [r3, #24] + 800bb90: 0752 lsls r2, r2, #29 + 800bb92: d5c9 bpl.n 800bb28 + 800bb94: 8d22 ldrh r2, [r4, #40] ; 0x28 + 800bb96: 2a00 cmp r2, #0 + 800bb98: d0c6 beq.n 800bb28 + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->RXDR; + 800bb9a: 6823 ldr r3, [r4, #0] + 800bb9c: 6a5a ldr r2, [r3, #36] ; 0x24 + 800bb9e: 6a63 ldr r3, [r4, #36] ; 0x24 + 800bba0: 701a strb r2, [r3, #0] + hi2c->pBuffPtr++; + 800bba2: 6a63 ldr r3, [r4, #36] ; 0x24 + hi2c->XferSize--; + 800bba4: 8d22 ldrh r2, [r4, #40] ; 0x28 + hi2c->pBuffPtr++; + 800bba6: 3301 adds r3, #1 + 800bba8: 6263 str r3, [r4, #36] ; 0x24 + hi2c->XferCount--; + 800bbaa: 8d63 ldrh r3, [r4, #42] ; 0x2a + 800bbac: 3b01 subs r3, #1 + 800bbae: b29b uxth r3, r3 + 800bbb0: 8563 strh r3, [r4, #42] ; 0x2a + if ((hi2c->XferCount != 0U) && (hi2c->XferSize == 0U)) + 800bbb2: 8d63 ldrh r3, [r4, #42] ; 0x2a + hi2c->XferSize--; + 800bbb4: 3a01 subs r2, #1 + 800bbb6: b292 uxth r2, r2 + if ((hi2c->XferCount != 0U) && (hi2c->XferSize == 0U)) + 800bbb8: b29b uxth r3, r3 + hi2c->XferSize--; + 800bbba: 8522 strh r2, [r4, #40] ; 0x28 + if ((hi2c->XferCount != 0U) && (hi2c->XferSize == 0U)) + 800bbbc: b9f3 cbnz r3, 800bbfc + while (hi2c->XferCount > 0U) + 800bbbe: 8d63 ldrh r3, [r4, #42] ; 0x2a + 800bbc0: b29b uxth r3, r3 + 800bbc2: 2b00 cmp r3, #0 + 800bbc4: d1d4 bne.n 800bb70 + if (I2C_WaitOnSTOPFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + 800bbc6: 462a mov r2, r5 + 800bbc8: 4639 mov r1, r7 + 800bbca: 4620 mov r0, r4 + 800bbcc: f7ff fe38 bl 800b840 + 800bbd0: 2800 cmp r0, #0 + 800bbd2: d182 bne.n 800bada + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF); + 800bbd4: 6823 ldr r3, [r4, #0] + 800bbd6: 2120 movs r1, #32 + 800bbd8: 61d9 str r1, [r3, #28] + I2C_RESET_CR2(hi2c); + 800bbda: 685a ldr r2, [r3, #4] + 800bbdc: f022 72ff bic.w r2, r2, #33423360 ; 0x1fe0000 + 800bbe0: f422 328b bic.w r2, r2, #71168 ; 0x11600 + 800bbe4: f422 72ff bic.w r2, r2, #510 ; 0x1fe + 800bbe8: f022 0201 bic.w r2, r2, #1 + 800bbec: 605a str r2, [r3, #4] + hi2c->State = HAL_I2C_STATE_READY; + 800bbee: f884 1041 strb.w r1, [r4, #65] ; 0x41 + __HAL_UNLOCK(hi2c); + 800bbf2: f884 0040 strb.w r0, [r4, #64] ; 0x40 + hi2c->Mode = HAL_I2C_MODE_NONE; + 800bbf6: f884 0042 strb.w r0, [r4, #66] ; 0x42 + return HAL_OK; + 800bbfa: e76f b.n 800badc + if ((hi2c->XferCount != 0U) && (hi2c->XferSize == 0U)) + 800bbfc: 2a00 cmp r2, #0 + 800bbfe: d1de bne.n 800bbbe + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_TCR, RESET, Timeout, tickstart) != HAL_OK) + 800bc00: 9500 str r5, [sp, #0] + 800bc02: 463b mov r3, r7 + 800bc04: 2180 movs r1, #128 ; 0x80 + 800bc06: 4620 mov r0, r4 + 800bc08: f7ff fdf0 bl 800b7ec + 800bc0c: 2800 cmp r0, #0 + 800bc0e: f47f af64 bne.w 800bada + if (hi2c->XferCount > MAX_NBYTE_SIZE) + 800bc12: 8d63 ldrh r3, [r4, #42] ; 0x2a + 800bc14: b29b uxth r3, r3 + 800bc16: 2bff cmp r3, #255 ; 0xff + 800bc18: d903 bls.n 800bc22 + hi2c->XferSize = MAX_NBYTE_SIZE; + 800bc1a: 22ff movs r2, #255 ; 0xff + 800bc1c: 8522 strh r2, [r4, #40] ; 0x28 + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_RELOAD_MODE, I2C_NO_STARTSTOP); + 800bc1e: 9000 str r0, [sp, #0] + 800bc20: e773 b.n 800bb0a + hi2c->XferSize = hi2c->XferCount; + 800bc22: 8d62 ldrh r2, [r4, #42] ; 0x2a + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); + 800bc24: 9000 str r0, [sp, #0] + hi2c->XferSize = hi2c->XferCount; + 800bc26: b292 uxth r2, r2 + 800bc28: 8522 strh r2, [r4, #40] ; 0x28 + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); + 800bc2a: e779 b.n 800bb20 + return HAL_BUSY; + 800bc2c: 2002 movs r0, #2 + 800bc2e: e755 b.n 800badc + 800bc30: 80002400 .word 0x80002400 + +0800bc34 : + * @param hsd Pointer to SD handle + * @param pSCR pointer to the buffer that will contain the SCR value + * @retval error state + */ +static uint32_t SD_FindSCR(SD_HandleTypeDef *hsd, uint32_t *pSCR) +{ + 800bc34: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + 800bc38: b086 sub sp, #24 + 800bc3a: 4605 mov r5, r0 + 800bc3c: 4688 mov r8, r1 + SDMMC_DataInitTypeDef config; + uint32_t errorstate; + uint32_t tickstart = HAL_GetTick(); + 800bc3e: f7fb fa55 bl 80070ec + uint32_t index = 0U; + uint32_t tempscr[2U] = {0UL, 0UL}; + uint32_t *scr = pSCR; + + /* Set Block Size To 8 Bytes */ + errorstate = SDMMC_CmdBlockLength(hsd->Instance, 8U); + 800bc42: 2108 movs r1, #8 + uint32_t tickstart = HAL_GetTick(); + 800bc44: 4681 mov r9, r0 + errorstate = SDMMC_CmdBlockLength(hsd->Instance, 8U); + 800bc46: 6828 ldr r0, [r5, #0] + 800bc48: f001 f996 bl 800cf78 + if(errorstate != HAL_SD_ERROR_NONE) + 800bc4c: 4604 mov r4, r0 + 800bc4e: bb48 cbnz r0, 800bca4 + { + return errorstate; + } + + /* Send CMD55 APP_CMD with argument as card's RCA */ + errorstate = SDMMC_CmdAppCommand(hsd->Instance, (uint32_t)((hsd->SdCard.RelCardAdd) << 16U)); + 800bc50: 6ca9 ldr r1, [r5, #72] ; 0x48 + 800bc52: 6828 ldr r0, [r5, #0] + 800bc54: 0409 lsls r1, r1, #16 + 800bc56: f001 fac8 bl 800d1ea + if(errorstate != HAL_SD_ERROR_NONE) + 800bc5a: 4604 mov r4, r0 + 800bc5c: bb10 cbnz r0, 800bca4 + { + return errorstate; + } + + config.DataTimeOut = SDMMC_DATATIMEOUT; + config.DataLength = 8U; + 800bc5e: f04f 30ff mov.w r0, #4294967295 ; 0xffffffff + 800bc62: 2308 movs r3, #8 + 800bc64: e9cd 0300 strd r0, r3, [sp] + config.DataBlockSize = SDMMC_DATABLOCK_SIZE_8B; + config.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + 800bc68: 2630 movs r6, #48 ; 0x30 + 800bc6a: 2302 movs r3, #2 + 800bc6c: e9cd 6302 strd r6, r3, [sp, #8] + config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + config.DPSM = SDMMC_DPSM_ENABLE; + (void)SDMMC_ConfigData(hsd->Instance, &config); + 800bc70: 4669 mov r1, sp + config.DPSM = SDMMC_DPSM_ENABLE; + 800bc72: 2301 movs r3, #1 + (void)SDMMC_ConfigData(hsd->Instance, &config); + 800bc74: 6828 ldr r0, [r5, #0] + config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + 800bc76: 9404 str r4, [sp, #16] + config.DPSM = SDMMC_DPSM_ENABLE; + 800bc78: 9305 str r3, [sp, #20] + (void)SDMMC_ConfigData(hsd->Instance, &config); + 800bc7a: f001 f8a1 bl 800cdc0 + + /* Send ACMD51 SD_APP_SEND_SCR with argument as 0 */ + errorstate = SDMMC_CmdSendSCR(hsd->Instance); + 800bc7e: 6828 ldr r0, [r5, #0] + 800bc80: f001 fae7 bl 800d252 + if(errorstate != HAL_SD_ERROR_NONE) + 800bc84: 4604 mov r4, r0 + 800bc86: b968 cbnz r0, 800bca4 + uint32_t tempscr[2U] = {0UL, 0UL}; + 800bc88: 4607 mov r7, r0 + 800bc8a: 4606 mov r6, r0 + { + return errorstate; + } + +#if defined(STM32L4P5xx) || defined(STM32L4Q5xx) || defined(STM32L4R5xx) || defined(STM32L4R7xx) || defined(STM32L4R9xx) || defined(STM32L4S5xx) || defined(STM32L4S7xx) || defined(STM32L4S9xx) + while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND | SDMMC_FLAG_DATAEND)) + 800bc8c: f240 5a2a movw sl, #1322 ; 0x52a + 800bc90: 6828 ldr r0, [r5, #0] + 800bc92: 6b42 ldr r2, [r0, #52] ; 0x34 + 800bc94: ea12 0f0a tst.w r2, sl + { + if((!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOE)) && (index == 0U)) + 800bc98: 6b42 ldr r2, [r0, #52] ; 0x34 + while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND | SDMMC_FLAG_DATAEND)) + 800bc9a: d007 beq.n 800bcac + return HAL_SD_ERROR_TIMEOUT; + } + } +#endif /* STM32L4P5xx || STM32L4Q5xx || STM32L4R5xx || STM32L4R7xx || STM32L4R9xx || STM32L4S5xx || STM32L4S7xx || STM32L4S9xx */ + + if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT)) + 800bc9c: 0712 lsls r2, r2, #28 + 800bc9e: d519 bpl.n 800bcd4 + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DTIMEOUT); + 800bca0: 2408 movs r4, #8 + + return HAL_SD_ERROR_DATA_CRC_FAIL; + } + else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)) + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_RXOVERR); + 800bca2: 6384 str r4, [r0, #56] ; 0x38 + ((tempscr[0] & SDMMC_16TO23BITS) >> 8) | ((tempscr[0] & SDMMC_24TO31BITS) >> 24)); + + } + + return HAL_SD_ERROR_NONE; +} + 800bca4: 4620 mov r0, r4 + 800bca6: b006 add sp, #24 + 800bca8: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + if((!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOE)) && (index == 0U)) + 800bcac: 0311 lsls r1, r2, #12 + 800bcae: d408 bmi.n 800bcc2 + 800bcb0: b93c cbnz r4, 800bcc2 + tempscr[0] = SDMMC_ReadFIFO(hsd->Instance); + 800bcb2: f001 f849 bl 800cd48 + 800bcb6: 4606 mov r6, r0 + tempscr[1] = SDMMC_ReadFIFO(hsd->Instance); + 800bcb8: 6828 ldr r0, [r5, #0] + 800bcba: f001 f845 bl 800cd48 + index++; + 800bcbe: 2401 movs r4, #1 + tempscr[1] = SDMMC_ReadFIFO(hsd->Instance); + 800bcc0: 4607 mov r7, r0 + if((HAL_GetTick() - tickstart) >= SDMMC_DATATIMEOUT) + 800bcc2: f7fb fa13 bl 80070ec + 800bcc6: eba0 0009 sub.w r0, r0, r9 + 800bcca: 3001 adds r0, #1 + 800bccc: d1e0 bne.n 800bc90 + return HAL_SD_ERROR_TIMEOUT; + 800bcce: f04f 4400 mov.w r4, #2147483648 ; 0x80000000 + 800bcd2: e7e7 b.n 800bca4 + else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL)) + 800bcd4: 6b42 ldr r2, [r0, #52] ; 0x34 + 800bcd6: 0793 lsls r3, r2, #30 + 800bcd8: d501 bpl.n 800bcde + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DCRCFAIL); + 800bcda: 2402 movs r4, #2 + 800bcdc: e7e1 b.n 800bca2 + else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)) + 800bcde: 6b44 ldr r4, [r0, #52] ; 0x34 + 800bce0: f014 0420 ands.w r4, r4, #32 + 800bce4: d001 beq.n 800bcea + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_RXOVERR); + 800bce6: 2420 movs r4, #32 + 800bce8: e7db b.n 800bca2 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + 800bcea: 4a04 ldr r2, [pc, #16] ; (800bcfc ) + 800bcec: 6382 str r2, [r0, #56] ; 0x38 + *scr = (((tempscr[1] & SDMMC_0TO7BITS) << 24) | ((tempscr[1] & SDMMC_8TO15BITS) << 8) |\ + 800bcee: ba3f rev r7, r7 + 800bcf0: ba36 rev r6, r6 + 800bcf2: f8c8 7000 str.w r7, [r8] + *scr = (((tempscr[0] & SDMMC_0TO7BITS) << 24) | ((tempscr[0] & SDMMC_8TO15BITS) << 8) |\ + 800bcf6: f8c8 6004 str.w r6, [r8, #4] + return HAL_SD_ERROR_NONE; + 800bcfa: e7d3 b.n 800bca4 + 800bcfc: 18000f3a .word 0x18000f3a + +0800bd00 : + * of PLL to have SDMMCCK clock between 50 and 120 MHz + * @param hsd SD handle + * @retval SD Card error state + */ +static uint32_t SD_UltraHighSpeed(SD_HandleTypeDef *hsd) +{ + 800bd00: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + uint32_t errorstate = HAL_SD_ERROR_NONE; + SDMMC_DataInitTypeDef sdmmc_datainitstructure; + uint32_t SD_hs[16] = {0}; + 800bd04: 2640 movs r6, #64 ; 0x40 +{ + 800bd06: b096 sub sp, #88 ; 0x58 + 800bd08: 4605 mov r5, r0 + uint32_t SD_hs[16] = {0}; + 800bd0a: 4632 mov r2, r6 + 800bd0c: 2100 movs r1, #0 + 800bd0e: a806 add r0, sp, #24 + 800bd10: f001 fcb0 bl 800d674 + uint32_t count, loop = 0 ; + uint32_t Timeout = HAL_GetTick(); + 800bd14: f7fb f9ea bl 80070ec + + if(hsd->SdCard.CardSpeed == CARD_NORMAL_SPEED) + 800bd18: 6deb ldr r3, [r5, #92] ; 0x5c + uint32_t Timeout = HAL_GetTick(); + 800bd1a: 4680 mov r8, r0 + if(hsd->SdCard.CardSpeed == CARD_NORMAL_SPEED) + 800bd1c: 2b00 cmp r3, #0 + 800bd1e: d067 beq.n 800bdf0 + { + /* Standard Speed Card <= 12.5Mhz */ + return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE; + } + + if((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) && + 800bd20: f5b3 7f00 cmp.w r3, #512 ; 0x200 + 800bd24: d167 bne.n 800bdf6 + 800bd26: 69af ldr r7, [r5, #24] + 800bd28: 2f01 cmp r7, #1 + 800bd2a: d164 bne.n 800bdf6 + (hsd->Init.Transceiver == SDMMC_TRANSCEIVER_ENABLE)) + { + /* Initialize the Data control register */ + hsd->Instance->DCTRL = 0; + 800bd2c: 6828 ldr r0, [r5, #0] + 800bd2e: 2300 movs r3, #0 + 800bd30: 62c3 str r3, [r0, #44] ; 0x2c + errorstate = SDMMC_CmdBlockLength(hsd->Instance, 64U); + 800bd32: 4631 mov r1, r6 + 800bd34: f001 f920 bl 800cf78 + + if (errorstate != HAL_SD_ERROR_NONE) + 800bd38: 4604 mov r4, r0 + 800bd3a: 2800 cmp r0, #0 + 800bd3c: d13e bne.n 800bdbc + { + return errorstate; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + sdmmc_datainitstructure.DataTimeOut = SDMMC_DATATIMEOUT; + 800bd3e: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + sdmmc_datainitstructure.DataLength = 64U; + 800bd42: e9cd 3600 strd r3, r6, [sp] + sdmmc_datainitstructure.DataBlockSize = SDMMC_DATABLOCK_SIZE_64B ; + sdmmc_datainitstructure.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + sdmmc_datainitstructure.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + sdmmc_datainitstructure.DPSM = SDMMC_DPSM_ENABLE; + 800bd46: e9cd 0704 strd r0, r7, [sp, #16] + sdmmc_datainitstructure.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + 800bd4a: 2660 movs r6, #96 ; 0x60 + 800bd4c: 2302 movs r3, #2 + + if ( SDMMC_ConfigData(hsd->Instance, &sdmmc_datainitstructure) != HAL_OK) + 800bd4e: 6828 ldr r0, [r5, #0] + 800bd50: 4669 mov r1, sp + sdmmc_datainitstructure.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + 800bd52: e9cd 6302 strd r6, r3, [sp, #8] + if ( SDMMC_ConfigData(hsd->Instance, &sdmmc_datainitstructure) != HAL_OK) + 800bd56: f001 f833 bl 800cdc0 + 800bd5a: 2800 cmp r0, #0 + 800bd5c: d14d bne.n 800bdfa + { + return (HAL_SD_ERROR_GENERAL_UNKNOWN_ERR); + } + + errorstate = SDMMC_CmdSwitch(hsd->Instance, SDMMC_SDR104_SWITCH_PATTERN); + 800bd5e: 492a ldr r1, [pc, #168] ; (800be08 ) + 800bd60: 6828 ldr r0, [r5, #0] + 800bd62: f001 fa74 bl 800d24e + if(errorstate != HAL_SD_ERROR_NONE) + 800bd66: 4604 mov r4, r0 + 800bd68: bb40 cbnz r0, 800bdbc + uint32_t count, loop = 0 ; + 800bd6a: 4607 mov r7, r0 + { + return errorstate; + } + + while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND| SDMMC_FLAG_DATAEND )) + 800bd6c: f240 592a movw r9, #1322 ; 0x52a + 800bd70: 682b ldr r3, [r5, #0] + 800bd72: 6b5e ldr r6, [r3, #52] ; 0x34 + 800bd74: ea16 0609 ands.w r6, r6, r9 + 800bd78: d005 beq.n 800bd86 + hsd->State= HAL_SD_STATE_READY; + return HAL_SD_ERROR_TIMEOUT; + } + } + + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT)) + 800bd7a: 6b5a ldr r2, [r3, #52] ; 0x34 + 800bd7c: 0711 lsls r1, r2, #28 + 800bd7e: d521 bpl.n 800bdc4 + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DTIMEOUT); + 800bd80: 2208 movs r2, #8 + 800bd82: 639a str r2, [r3, #56] ; 0x38 + + return errorstate; + 800bd84: e01a b.n 800bdbc + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOHF)) + 800bd86: 6b5b ldr r3, [r3, #52] ; 0x34 + 800bd88: 0418 lsls r0, r3, #16 + 800bd8a: d50b bpl.n 800bda4 + 800bd8c: ab06 add r3, sp, #24 + 800bd8e: eb03 1a47 add.w sl, r3, r7, lsl #5 + SD_hs[(8U*loop)+count] = SDMMC_ReadFIFO(hsd->Instance); + 800bd92: 6828 ldr r0, [r5, #0] + 800bd94: f000 ffd8 bl 800cd48 + for (count = 0U; count < 8U; count++) + 800bd98: 3601 adds r6, #1 + 800bd9a: 2e08 cmp r6, #8 + SD_hs[(8U*loop)+count] = SDMMC_ReadFIFO(hsd->Instance); + 800bd9c: f84a 0b04 str.w r0, [sl], #4 + for (count = 0U; count < 8U; count++) + 800bda0: d1f7 bne.n 800bd92 + loop ++; + 800bda2: 3701 adds r7, #1 + if((HAL_GetTick()-Timeout) >= SDMMC_DATATIMEOUT) + 800bda4: f7fb f9a2 bl 80070ec + 800bda8: eba0 0008 sub.w r0, r0, r8 + 800bdac: 3001 adds r0, #1 + 800bdae: d1df bne.n 800bd70 + hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT; + 800bdb0: f04f 4400 mov.w r4, #2147483648 ; 0x80000000 + hsd->State= HAL_SD_STATE_READY; + 800bdb4: 2301 movs r3, #1 + hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT; + 800bdb6: 63ac str r4, [r5, #56] ; 0x38 + hsd->State= HAL_SD_STATE_READY; + 800bdb8: f885 3034 strb.w r3, [r5, #52] ; 0x34 +#endif /* (DLYB_SDMMC1) || (DLYB_SDMMC2) */ + } + } + + return errorstate; +} + 800bdbc: 4620 mov r0, r4 + 800bdbe: b016 add sp, #88 ; 0x58 + 800bdc0: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL)) + 800bdc4: 6b5a ldr r2, [r3, #52] ; 0x34 + 800bdc6: 0792 lsls r2, r2, #30 + 800bdc8: d502 bpl.n 800bdd0 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DCRCFAIL); + 800bdca: 2402 movs r4, #2 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_RXOVERR); + 800bdcc: 639c str r4, [r3, #56] ; 0x38 + return errorstate; + 800bdce: e7f5 b.n 800bdbc + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)) + 800bdd0: 6b5c ldr r4, [r3, #52] ; 0x34 + 800bdd2: f014 0420 ands.w r4, r4, #32 + 800bdd6: d001 beq.n 800bddc + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_RXOVERR); + 800bdd8: 2420 movs r4, #32 + 800bdda: e7f7 b.n 800bdcc + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + 800bddc: 4a0b ldr r2, [pc, #44] ; (800be0c ) + 800bdde: 639a str r2, [r3, #56] ; 0x38 + if ((((uint8_t*)SD_hs)[13] & 2U) != 2U) + 800bde0: f89d 3025 ldrb.w r3, [sp, #37] ; 0x25 + 800bde4: 079b lsls r3, r3, #30 + 800bde6: d50b bpl.n 800be00 + HAL_SDEx_DriveTransceiver_1_8V_Callback(SET); + 800bde8: 2001 movs r0, #1 + 800bdea: f7fb f9ef bl 80071cc + 800bdee: e7e5 b.n 800bdbc + return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE; + 800bdf0: f04f 6480 mov.w r4, #67108864 ; 0x4000000 + 800bdf4: e7e2 b.n 800bdbc + uint32_t errorstate = HAL_SD_ERROR_NONE; + 800bdf6: 2400 movs r4, #0 + 800bdf8: e7e0 b.n 800bdbc + return (HAL_SD_ERROR_GENERAL_UNKNOWN_ERR); + 800bdfa: f44f 3480 mov.w r4, #65536 ; 0x10000 + 800bdfe: e7dd b.n 800bdbc + errorstate = SDMMC_ERROR_UNSUPPORTED_FEATURE; + 800be00: f04f 5480 mov.w r4, #268435456 ; 0x10000000 + 800be04: e7da b.n 800bdbc + 800be06: bf00 nop + 800be08: 80ff1f03 .word 0x80ff1f03 + 800be0c: 18000f3a .word 0x18000f3a + +0800be10 : +} + 800be10: 4770 bx lr + +0800be12 : + 800be12: 4770 bx lr + +0800be14 : +{ + 800be14: b510 push {r4, lr} + if(hsd == NULL) + 800be16: 4604 mov r4, r0 + 800be18: b198 cbz r0, 800be42 + hsd->State = HAL_SD_STATE_BUSY; + 800be1a: 2303 movs r3, #3 + 800be1c: f880 3034 strb.w r3, [r0, #52] ; 0x34 + if(hsd->Init.Transceiver == SDMMC_TRANSCEIVER_ENABLE) + 800be20: 6983 ldr r3, [r0, #24] + 800be22: 2b01 cmp r3, #1 + 800be24: d102 bne.n 800be2c + HAL_SDEx_DriveTransceiver_1_8V_Callback(RESET); + 800be26: 2000 movs r0, #0 + 800be28: f7fb f9d0 bl 80071cc + (void)SDMMC_PowerState_OFF(hsd->Instance); + 800be2c: 6820 ldr r0, [r4, #0] + 800be2e: f000 ffa3 bl 800cd78 + HAL_SD_MspDeInit(hsd); + 800be32: 4620 mov r0, r4 + 800be34: f7ff ffed bl 800be12 + hsd->ErrorCode = HAL_SD_ERROR_NONE; + 800be38: 2000 movs r0, #0 + 800be3a: 63a0 str r0, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_RESET; + 800be3c: f884 0034 strb.w r0, [r4, #52] ; 0x34 +} + 800be40: bd10 pop {r4, pc} + return HAL_ERROR; + 800be42: 2001 movs r0, #1 + 800be44: e7fc b.n 800be40 + ... + +0800be48 : +{ + 800be48: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + 800be4c: b087 sub sp, #28 + 800be4e: 4604 mov r4, r0 + 800be50: 460e mov r6, r1 + 800be52: 4692 mov sl, r2 + 800be54: 461f mov r7, r3 + uint32_t tickstart = HAL_GetTick(); + 800be56: f7fb f949 bl 80070ec + 800be5a: 4681 mov r9, r0 + if(NULL == pData) + 800be5c: b936 cbnz r6, 800be6c + hsd->ErrorCode |= HAL_SD_ERROR_PARAM; + 800be5e: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800be60: f043 6300 orr.w r3, r3, #134217728 ; 0x8000000 + hsd->ErrorCode |= HAL_SD_ERROR_BUSY; + 800be64: 63a3 str r3, [r4, #56] ; 0x38 + return HAL_ERROR; + 800be66: f04f 0801 mov.w r8, #1 + 800be6a: e011 b.n 800be90 + if(hsd->State == HAL_SD_STATE_READY) + 800be6c: f894 3034 ldrb.w r3, [r4, #52] ; 0x34 + 800be70: 2b01 cmp r3, #1 + 800be72: fa5f f883 uxtb.w r8, r3 + 800be76: f040 80c3 bne.w 800c000 + if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr)) + 800be7a: 6d62 ldr r2, [r4, #84] ; 0x54 + 800be7c: eb0a 0307 add.w r3, sl, r7 + hsd->ErrorCode = HAL_SD_ERROR_NONE; + 800be80: 2100 movs r1, #0 + if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr)) + 800be82: 4293 cmp r3, r2 + hsd->ErrorCode = HAL_SD_ERROR_NONE; + 800be84: 63a1 str r1, [r4, #56] ; 0x38 + if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr)) + 800be86: d907 bls.n 800be98 + hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE; + 800be88: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800be8a: f043 7300 orr.w r3, r3, #33554432 ; 0x2000000 + 800be8e: 63a3 str r3, [r4, #56] ; 0x38 +} + 800be90: 4640 mov r0, r8 + 800be92: b007 add sp, #28 + 800be94: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + hsd->State = HAL_SD_STATE_BUSY; + 800be98: 2303 movs r3, #3 + 800be9a: f884 3034 strb.w r3, [r4, #52] ; 0x34 + if(hsd->SdCard.CardType != CARD_SDHC_SDXC) + 800be9e: 6be3 ldr r3, [r4, #60] ; 0x3c + hsd->Instance->DCTRL = 0U; + 800bea0: 6820 ldr r0, [r4, #0] + if(hsd->SdCard.CardType != CARD_SDHC_SDXC) + 800bea2: 2b01 cmp r3, #1 + config.DataTimeOut = SDMMC_DATATIMEOUT; + 800bea4: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 800bea8: 9300 str r3, [sp, #0] + config.DataLength = NumberOfBlocks * BLOCKSIZE; + 800beaa: ea4f 2347 mov.w r3, r7, lsl #9 + 800beae: 9301 str r3, [sp, #4] + config.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + 800beb0: f04f 0502 mov.w r5, #2 + 800beb4: f04f 0390 mov.w r3, #144 ; 0x90 + 800beb8: e9cd 3502 strd r3, r5, [sp, #8] + hsd->Instance->DCTRL = 0U; + 800bebc: 62c1 str r1, [r0, #44] ; 0x2c + config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + 800bebe: f04f 0300 mov.w r3, #0 + (void)SDMMC_ConfigData(hsd->Instance, &config); + 800bec2: 4669 mov r1, sp + config.DPSM = SDMMC_DPSM_DISABLE; + 800bec4: e9cd 3304 strd r3, r3, [sp, #16] + add *= 512U; + 800bec8: bf18 it ne + 800beca: ea4f 2a4a movne.w sl, sl, lsl #9 + (void)SDMMC_ConfigData(hsd->Instance, &config); + 800bece: f000 ff77 bl 800cdc0 + __SDMMC_CMDTRANS_ENABLE( hsd->Instance); + 800bed2: 6820 ldr r0, [r4, #0] + 800bed4: 68c3 ldr r3, [r0, #12] + if(NumberOfBlocks > 1U) + 800bed6: 2f01 cmp r7, #1 + __SDMMC_CMDTRANS_ENABLE( hsd->Instance); + 800bed8: f043 0340 orr.w r3, r3, #64 ; 0x40 + 800bedc: 60c3 str r3, [r0, #12] + if(NumberOfBlocks > 1U) + 800bede: d910 bls.n 800bf02 + hsd->Context = SD_CONTEXT_READ_MULTIPLE_BLOCK; + 800bee0: 6325 str r5, [r4, #48] ; 0x30 + errorstate = SDMMC_CmdReadMultiBlock(hsd->Instance, add); + 800bee2: 4651 mov r1, sl + 800bee4: f001 f87a bl 800cfdc + if(errorstate != HAL_SD_ERROR_NONE) + 800bee8: b188 cbz r0, 800bf0e + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800beea: 6823 ldr r3, [r4, #0] + 800beec: 4a46 ldr r2, [pc, #280] ; (800c008 ) + 800beee: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= errorstate; + 800bef0: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800bef2: 4318 orrs r0, r3 + 800bef4: 63a0 str r0, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800bef6: 2301 movs r3, #1 + 800bef8: f884 3034 strb.w r3, [r4, #52] ; 0x34 + hsd->Context = SD_CONTEXT_NONE; + 800befc: 2300 movs r3, #0 + 800befe: 6323 str r3, [r4, #48] ; 0x30 + return HAL_ERROR; + 800bf00: e7c6 b.n 800be90 + hsd->Context = SD_CONTEXT_READ_SINGLE_BLOCK; + 800bf02: 2301 movs r3, #1 + 800bf04: 6323 str r3, [r4, #48] ; 0x30 + errorstate = SDMMC_CmdReadSingleBlock(hsd->Instance, add); + 800bf06: 4651 mov r1, sl + 800bf08: f001 f84f bl 800cfaa + 800bf0c: e7ec b.n 800bee8 + dataremaining = config.DataLength; + 800bf0e: 9d01 ldr r5, [sp, #4] + while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DATAEND)) + 800bf10: 6820 ldr r0, [r4, #0] + 800bf12: 6b43 ldr r3, [r0, #52] ; 0x34 + 800bf14: f413 7f95 tst.w r3, #298 ; 0x12a + 800bf18: d01b beq.n 800bf52 + __SDMMC_CMDTRANS_DISABLE( hsd->Instance); + 800bf1a: 68c3 ldr r3, [r0, #12] + 800bf1c: f023 0340 bic.w r3, r3, #64 ; 0x40 + 800bf20: 60c3 str r3, [r0, #12] + if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DATAEND) && (NumberOfBlocks > 1U)) + 800bf22: 6b43 ldr r3, [r0, #52] ; 0x34 + 800bf24: 05db lsls r3, r3, #23 + 800bf26: d508 bpl.n 800bf3a + 800bf28: 2f01 cmp r7, #1 + 800bf2a: d906 bls.n 800bf3a + if(hsd->SdCard.CardType != CARD_SECURED) + 800bf2c: 6be3 ldr r3, [r4, #60] ; 0x3c + 800bf2e: 2b03 cmp r3, #3 + 800bf30: d003 beq.n 800bf3a + errorstate = SDMMC_CmdStopTransfer(hsd->Instance); + 800bf32: f001 f91b bl 800d16c + if(errorstate != HAL_SD_ERROR_NONE) + 800bf36: 2800 cmp r0, #0 + 800bf38: d1d7 bne.n 800beea + if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT)) + 800bf3a: 6823 ldr r3, [r4, #0] + 800bf3c: 6b58 ldr r0, [r3, #52] ; 0x34 + 800bf3e: f010 0008 ands.w r0, r0, #8 + 800bf42: d038 beq.n 800bfb6 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800bf44: 4a30 ldr r2, [pc, #192] ; (800c008 ) + 800bf46: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= HAL_SD_ERROR_DATA_TIMEOUT; + 800bf48: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800bf4a: f043 0308 orr.w r3, r3, #8 + 800bf4e: 63a3 str r3, [r4, #56] ; 0x38 + 800bf50: e7d1 b.n 800bef6 + if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOHF) && (dataremaining > 0U)) + 800bf52: 6b43 ldr r3, [r0, #52] ; 0x34 + 800bf54: 041a lsls r2, r3, #16 + 800bf56: d518 bpl.n 800bf8a + 800bf58: b1bd cbz r5, 800bf8a + 800bf5a: f106 0a04 add.w sl, r6, #4 + 800bf5e: f106 0b24 add.w fp, r6, #36 ; 0x24 + data = SDMMC_ReadFIFO(hsd->Instance); + 800bf62: 6820 ldr r0, [r4, #0] + 800bf64: f000 fef0 bl 800cd48 + *tempbuff = (uint8_t)((data >> 8U) & 0xFFU); + 800bf68: 0a02 lsrs r2, r0, #8 + 800bf6a: f80a 2c03 strb.w r2, [sl, #-3] + *tempbuff = (uint8_t)((data >> 16U) & 0xFFU); + 800bf6e: 0c02 lsrs r2, r0, #16 + 800bf70: f80a 2c02 strb.w r2, [sl, #-2] + *tempbuff = (uint8_t)((data >> 24U) & 0xFFU); + 800bf74: 0e02 lsrs r2, r0, #24 + *tempbuff = (uint8_t)(data & 0xFFU); + 800bf76: f80a 0c04 strb.w r0, [sl, #-4] + *tempbuff = (uint8_t)((data >> 24U) & 0xFFU); + 800bf7a: f80a 2c01 strb.w r2, [sl, #-1] + for(count = 0U; count < 8U; count++) + 800bf7e: f10a 0a04 add.w sl, sl, #4 + 800bf82: 45d3 cmp fp, sl + 800bf84: d1ed bne.n 800bf62 + tempbuff++; + 800bf86: 3620 adds r6, #32 + dataremaining--; + 800bf88: 3d20 subs r5, #32 + if(((HAL_GetTick()-tickstart) >= Timeout) || (Timeout == 0U)) + 800bf8a: f7fb f8af bl 80070ec + 800bf8e: 9b10 ldr r3, [sp, #64] ; 0x40 + 800bf90: eba0 0009 sub.w r0, r0, r9 + 800bf94: 4298 cmp r0, r3 + 800bf96: d3bb bcc.n 800bf10 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800bf98: 6823 ldr r3, [r4, #0] + 800bf9a: 4a1b ldr r2, [pc, #108] ; (800c008 ) + 800bf9c: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= HAL_SD_ERROR_TIMEOUT; + 800bf9e: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800bfa0: f043 4300 orr.w r3, r3, #2147483648 ; 0x80000000 + 800bfa4: 63a3 str r3, [r4, #56] ; 0x38 + hsd->State= HAL_SD_STATE_READY; + 800bfa6: 2301 movs r3, #1 + 800bfa8: f884 3034 strb.w r3, [r4, #52] ; 0x34 + hsd->Context = SD_CONTEXT_NONE; + 800bfac: 2300 movs r3, #0 + 800bfae: 6323 str r3, [r4, #48] ; 0x30 + return HAL_TIMEOUT; + 800bfb0: f04f 0803 mov.w r8, #3 + 800bfb4: e76c b.n 800be90 + else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL)) + 800bfb6: 6b59 ldr r1, [r3, #52] ; 0x34 + 800bfb8: f011 0102 ands.w r1, r1, #2 + 800bfbc: d00a beq.n 800bfd4 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800bfbe: 4a12 ldr r2, [pc, #72] ; (800c008 ) + 800bfc0: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= HAL_SD_ERROR_DATA_CRC_FAIL; + 800bfc2: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800bfc4: f043 0302 orr.w r3, r3, #2 + 800bfc8: 63a3 str r3, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800bfca: 2301 movs r3, #1 + 800bfcc: f884 3034 strb.w r3, [r4, #52] ; 0x34 + hsd->Context = SD_CONTEXT_NONE; + 800bfd0: 6320 str r0, [r4, #48] ; 0x30 + return HAL_ERROR; + 800bfd2: e75d b.n 800be90 + else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)) + 800bfd4: 6b5a ldr r2, [r3, #52] ; 0x34 + 800bfd6: f012 0220 ands.w r2, r2, #32 + 800bfda: d00a beq.n 800bff2 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800bfdc: 4a0a ldr r2, [pc, #40] ; (800c008 ) + 800bfde: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= HAL_SD_ERROR_RX_OVERRUN; + 800bfe0: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800bfe2: f043 0320 orr.w r3, r3, #32 + 800bfe6: 63a3 str r3, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800bfe8: 2301 movs r3, #1 + 800bfea: f884 3034 strb.w r3, [r4, #52] ; 0x34 + hsd->Context = SD_CONTEXT_NONE; + 800bfee: 6321 str r1, [r4, #48] ; 0x30 + return HAL_ERROR; + 800bff0: e74e b.n 800be90 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + 800bff2: 4906 ldr r1, [pc, #24] ; (800c00c ) + 800bff4: 6399 str r1, [r3, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800bff6: 2301 movs r3, #1 + 800bff8: f884 3034 strb.w r3, [r4, #52] ; 0x34 + return HAL_OK; + 800bffc: 4690 mov r8, r2 + 800bffe: e747 b.n 800be90 + hsd->ErrorCode |= HAL_SD_ERROR_BUSY; + 800c000: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c002: f043 5300 orr.w r3, r3, #536870912 ; 0x20000000 + 800c006: e72d b.n 800be64 + 800c008: 1fe00fff .word 0x1fe00fff + 800c00c: 18000f3a .word 0x18000f3a + +0800c010 : +{ + 800c010: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + 800c014: b089 sub sp, #36 ; 0x24 + 800c016: 4604 mov r4, r0 + 800c018: 460d mov r5, r1 + 800c01a: 4692 mov sl, r2 + 800c01c: 461f mov r7, r3 + uint32_t tickstart = HAL_GetTick(); + 800c01e: f7fb f865 bl 80070ec + 800c022: 4681 mov r9, r0 + if(NULL == pData) + 800c024: b935 cbnz r5, 800c034 + hsd->ErrorCode |= HAL_SD_ERROR_PARAM; + 800c026: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c028: f043 6300 orr.w r3, r3, #134217728 ; 0x8000000 + hsd->ErrorCode |= HAL_SD_ERROR_BUSY; + 800c02c: 63a3 str r3, [r4, #56] ; 0x38 + return HAL_ERROR; + 800c02e: f04f 0801 mov.w r8, #1 + 800c032: e011 b.n 800c058 + if(hsd->State == HAL_SD_STATE_READY) + 800c034: f894 3034 ldrb.w r3, [r4, #52] ; 0x34 + 800c038: 2b01 cmp r3, #1 + 800c03a: fa5f f883 uxtb.w r8, r3 + 800c03e: f040 80b4 bne.w 800c1aa + if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr)) + 800c042: 6d62 ldr r2, [r4, #84] ; 0x54 + 800c044: eb0a 0307 add.w r3, sl, r7 + hsd->ErrorCode = HAL_SD_ERROR_NONE; + 800c048: 2100 movs r1, #0 + if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr)) + 800c04a: 4293 cmp r3, r2 + hsd->ErrorCode = HAL_SD_ERROR_NONE; + 800c04c: 63a1 str r1, [r4, #56] ; 0x38 + if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr)) + 800c04e: d907 bls.n 800c060 + hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE; + 800c050: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c052: f043 7300 orr.w r3, r3, #33554432 ; 0x2000000 + 800c056: 63a3 str r3, [r4, #56] ; 0x38 +} + 800c058: 4640 mov r0, r8 + 800c05a: b009 add sp, #36 ; 0x24 + 800c05c: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + hsd->State = HAL_SD_STATE_BUSY; + 800c060: 2303 movs r3, #3 + 800c062: f884 3034 strb.w r3, [r4, #52] ; 0x34 + if(hsd->SdCard.CardType != CARD_SDHC_SDXC) + 800c066: 6be3 ldr r3, [r4, #60] ; 0x3c + hsd->Instance->DCTRL = 0U; + 800c068: 6820 ldr r0, [r4, #0] + if(hsd->SdCard.CardType != CARD_SDHC_SDXC) + 800c06a: 2b01 cmp r3, #1 + config.DataTimeOut = SDMMC_DATATIMEOUT; + 800c06c: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 800c070: 9302 str r3, [sp, #8] + config.DataLength = NumberOfBlocks * BLOCKSIZE; + 800c072: ea4f 2347 mov.w r3, r7, lsl #9 + hsd->Instance->DCTRL = 0U; + 800c076: 62c1 str r1, [r0, #44] ; 0x2c + config.DataLength = NumberOfBlocks * BLOCKSIZE; + 800c078: 9303 str r3, [sp, #12] + config.TransferDir = SDMMC_TRANSFER_DIR_TO_CARD; + 800c07a: f04f 0190 mov.w r1, #144 ; 0x90 + 800c07e: f04f 0300 mov.w r3, #0 + 800c082: e9cd 1304 strd r1, r3, [sp, #16] + (void)SDMMC_ConfigData(hsd->Instance, &config); + 800c086: a902 add r1, sp, #8 + config.DPSM = SDMMC_DPSM_DISABLE; + 800c088: e9cd 3306 strd r3, r3, [sp, #24] + add *= 512U; + 800c08c: bf18 it ne + 800c08e: ea4f 2a4a movne.w sl, sl, lsl #9 + (void)SDMMC_ConfigData(hsd->Instance, &config); + 800c092: f000 fe95 bl 800cdc0 + __SDMMC_CMDTRANS_ENABLE( hsd->Instance); + 800c096: 6820 ldr r0, [r4, #0] + 800c098: 68c3 ldr r3, [r0, #12] + if(NumberOfBlocks > 1U) + 800c09a: 2f01 cmp r7, #1 + __SDMMC_CMDTRANS_ENABLE( hsd->Instance); + 800c09c: f043 0340 orr.w r3, r3, #64 ; 0x40 + 800c0a0: 60c3 str r3, [r0, #12] + if(NumberOfBlocks > 1U) + 800c0a2: d911 bls.n 800c0c8 + hsd->Context = SD_CONTEXT_WRITE_MULTIPLE_BLOCK; + 800c0a4: 2320 movs r3, #32 + 800c0a6: 6323 str r3, [r4, #48] ; 0x30 + errorstate = SDMMC_CmdWriteMultiBlock(hsd->Instance, add); + 800c0a8: 4651 mov r1, sl + 800c0aa: f000 ffc9 bl 800d040 + if(errorstate != HAL_SD_ERROR_NONE) + 800c0ae: b188 cbz r0, 800c0d4 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c0b0: 6823 ldr r3, [r4, #0] + 800c0b2: 4a40 ldr r2, [pc, #256] ; (800c1b4 ) + 800c0b4: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= errorstate; + 800c0b6: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c0b8: 4318 orrs r0, r3 + 800c0ba: 63a0 str r0, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c0bc: 2301 movs r3, #1 + 800c0be: f884 3034 strb.w r3, [r4, #52] ; 0x34 + hsd->Context = SD_CONTEXT_NONE; + 800c0c2: 2300 movs r3, #0 + 800c0c4: 6323 str r3, [r4, #48] ; 0x30 + return HAL_ERROR; + 800c0c6: e7c7 b.n 800c058 + hsd->Context = SD_CONTEXT_WRITE_SINGLE_BLOCK; + 800c0c8: 2310 movs r3, #16 + 800c0ca: 6323 str r3, [r4, #48] ; 0x30 + errorstate = SDMMC_CmdWriteSingleBlock(hsd->Instance, add); + 800c0cc: 4651 mov r1, sl + 800c0ce: f000 ff9e bl 800d00e + 800c0d2: e7ec b.n 800c0ae + dataremaining = config.DataLength; + 800c0d4: 9e03 ldr r6, [sp, #12] + while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_TXUNDERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DATAEND)) + 800c0d6: 6820 ldr r0, [r4, #0] + 800c0d8: 6b43 ldr r3, [r0, #52] ; 0x34 + 800c0da: f413 7f8d tst.w r3, #282 ; 0x11a + 800c0de: d01b beq.n 800c118 + __SDMMC_CMDTRANS_DISABLE( hsd->Instance); + 800c0e0: 68c3 ldr r3, [r0, #12] + 800c0e2: f023 0340 bic.w r3, r3, #64 ; 0x40 + 800c0e6: 60c3 str r3, [r0, #12] + if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DATAEND) && (NumberOfBlocks > 1U)) + 800c0e8: 6b43 ldr r3, [r0, #52] ; 0x34 + 800c0ea: 05db lsls r3, r3, #23 + 800c0ec: d508 bpl.n 800c100 + 800c0ee: 2f01 cmp r7, #1 + 800c0f0: d906 bls.n 800c100 + if(hsd->SdCard.CardType != CARD_SECURED) + 800c0f2: 6be3 ldr r3, [r4, #60] ; 0x3c + 800c0f4: 2b03 cmp r3, #3 + 800c0f6: d003 beq.n 800c100 + errorstate = SDMMC_CmdStopTransfer(hsd->Instance); + 800c0f8: f001 f838 bl 800d16c + if(errorstate != HAL_SD_ERROR_NONE) + 800c0fc: 2800 cmp r0, #0 + 800c0fe: d1d7 bne.n 800c0b0 + if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT)) + 800c100: 6823 ldr r3, [r4, #0] + 800c102: 6b58 ldr r0, [r3, #52] ; 0x34 + 800c104: f010 0008 ands.w r0, r0, #8 + 800c108: d02a beq.n 800c160 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c10a: 4a2a ldr r2, [pc, #168] ; (800c1b4 ) + 800c10c: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= HAL_SD_ERROR_DATA_TIMEOUT; + 800c10e: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c110: f043 0308 orr.w r3, r3, #8 + 800c114: 63a3 str r3, [r4, #56] ; 0x38 + 800c116: e7d1 b.n 800c0bc + if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_TXFIFOHE) && (dataremaining > 0U)) + 800c118: 6b43 ldr r3, [r0, #52] ; 0x34 + 800c11a: 045a lsls r2, r3, #17 + 800c11c: d50c bpl.n 800c138 + 800c11e: b15e cbz r6, 800c138 + 800c120: f105 0b20 add.w fp, r5, #32 + data |= ((uint32_t)(*tempbuff) << 24U); + 800c124: f855 3b04 ldr.w r3, [r5], #4 + (void)SDMMC_WriteFIFO(hsd->Instance, &data); + 800c128: 6820 ldr r0, [r4, #0] + data |= ((uint32_t)(*tempbuff) << 24U); + 800c12a: 9301 str r3, [sp, #4] + (void)SDMMC_WriteFIFO(hsd->Instance, &data); + 800c12c: a901 add r1, sp, #4 + 800c12e: f000 fe0e bl 800cd4e + for(count = 0U; count < 8U; count++) + 800c132: 45ab cmp fp, r5 + 800c134: d1f6 bne.n 800c124 + dataremaining--; + 800c136: 3e20 subs r6, #32 + if(((HAL_GetTick()-tickstart) >= Timeout) || (Timeout == 0U)) + 800c138: f7fa ffd8 bl 80070ec + 800c13c: 9b12 ldr r3, [sp, #72] ; 0x48 + 800c13e: eba0 0009 sub.w r0, r0, r9 + 800c142: 4298 cmp r0, r3 + 800c144: d3c7 bcc.n 800c0d6 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c146: 6823 ldr r3, [r4, #0] + 800c148: 4a1a ldr r2, [pc, #104] ; (800c1b4 ) + 800c14a: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= errorstate; + 800c14c: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c14e: 63a3 str r3, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c150: 2301 movs r3, #1 + 800c152: f884 3034 strb.w r3, [r4, #52] ; 0x34 + hsd->Context = SD_CONTEXT_NONE; + 800c156: 2300 movs r3, #0 + 800c158: 6323 str r3, [r4, #48] ; 0x30 + return HAL_TIMEOUT; + 800c15a: f04f 0803 mov.w r8, #3 + 800c15e: e77b b.n 800c058 + else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL)) + 800c160: 6b59 ldr r1, [r3, #52] ; 0x34 + 800c162: f011 0102 ands.w r1, r1, #2 + 800c166: d00a beq.n 800c17e + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c168: 4a12 ldr r2, [pc, #72] ; (800c1b4 ) + 800c16a: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= HAL_SD_ERROR_DATA_CRC_FAIL; + 800c16c: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c16e: f043 0302 orr.w r3, r3, #2 + 800c172: 63a3 str r3, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c174: 2301 movs r3, #1 + 800c176: f884 3034 strb.w r3, [r4, #52] ; 0x34 + hsd->Context = SD_CONTEXT_NONE; + 800c17a: 6320 str r0, [r4, #48] ; 0x30 + return HAL_ERROR; + 800c17c: e76c b.n 800c058 + else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_TXUNDERR)) + 800c17e: 6b5a ldr r2, [r3, #52] ; 0x34 + 800c180: f012 0210 ands.w r2, r2, #16 + 800c184: d00a beq.n 800c19c + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c186: 4a0b ldr r2, [pc, #44] ; (800c1b4 ) + 800c188: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= HAL_SD_ERROR_TX_UNDERRUN; + 800c18a: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c18c: f043 0310 orr.w r3, r3, #16 + 800c190: 63a3 str r3, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c192: 2301 movs r3, #1 + 800c194: f884 3034 strb.w r3, [r4, #52] ; 0x34 + hsd->Context = SD_CONTEXT_NONE; + 800c198: 6321 str r1, [r4, #48] ; 0x30 + return HAL_ERROR; + 800c19a: e75d b.n 800c058 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + 800c19c: 4906 ldr r1, [pc, #24] ; (800c1b8 ) + 800c19e: 6399 str r1, [r3, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c1a0: 2301 movs r3, #1 + 800c1a2: f884 3034 strb.w r3, [r4, #52] ; 0x34 + return HAL_OK; + 800c1a6: 4690 mov r8, r2 + 800c1a8: e756 b.n 800c058 + hsd->ErrorCode |= HAL_SD_ERROR_BUSY; + 800c1aa: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c1ac: f043 5300 orr.w r3, r3, #536870912 ; 0x20000000 + 800c1b0: e73c b.n 800c02c + 800c1b2: bf00 nop + 800c1b4: 1fe00fff .word 0x1fe00fff + 800c1b8: 18000f3a .word 0x18000f3a + +0800c1bc : + return hsd->State; + 800c1bc: f890 0034 ldrb.w r0, [r0, #52] ; 0x34 +} + 800c1c0: 4770 bx lr + +0800c1c2 : + return hsd->ErrorCode; + 800c1c2: 6b80 ldr r0, [r0, #56] ; 0x38 +} + 800c1c4: 4770 bx lr + +0800c1c6 : + 800c1c6: 4770 bx lr + +0800c1c8 : + 800c1c8: 4770 bx lr + +0800c1ca : + 800c1ca: 4770 bx lr + +0800c1cc : + 800c1cc: 4770 bx lr + ... + +0800c1d0 : + pCSD->CSDStruct = (uint8_t)((hsd->CSD[0] & 0xC0000000U) >> 30U); + 800c1d0: 6e03 ldr r3, [r0, #96] ; 0x60 + 800c1d2: 0f9a lsrs r2, r3, #30 + 800c1d4: 700a strb r2, [r1, #0] + pCSD->SysSpecVersion = (uint8_t)((hsd->CSD[0] & 0x3C000000U) >> 26U); + 800c1d6: f3c3 6283 ubfx r2, r3, #26, #4 + 800c1da: 704a strb r2, [r1, #1] + pCSD->Reserved1 = (uint8_t)((hsd->CSD[0] & 0x03000000U) >> 24U); + 800c1dc: f3c3 6201 ubfx r2, r3, #24, #2 + 800c1e0: 708a strb r2, [r1, #2] + pCSD->TAAC = (uint8_t)((hsd->CSD[0] & 0x00FF0000U) >> 16U); + 800c1e2: f3c3 4207 ubfx r2, r3, #16, #8 + 800c1e6: 70ca strb r2, [r1, #3] + pCSD->NSAC = (uint8_t)((hsd->CSD[0] & 0x0000FF00U) >> 8U); + 800c1e8: f3c3 2207 ubfx r2, r3, #8, #8 + pCSD->MaxBusClkFrec = (uint8_t)(hsd->CSD[0] & 0x000000FFU); + 800c1ec: b2db uxtb r3, r3 + pCSD->NSAC = (uint8_t)((hsd->CSD[0] & 0x0000FF00U) >> 8U); + 800c1ee: 710a strb r2, [r1, #4] + pCSD->MaxBusClkFrec = (uint8_t)(hsd->CSD[0] & 0x000000FFU); + 800c1f0: 714b strb r3, [r1, #5] + pCSD->CardComdClasses = (uint16_t)((hsd->CSD[1] & 0xFFF00000U) >> 20U); + 800c1f2: 6e43 ldr r3, [r0, #100] ; 0x64 + 800c1f4: 0d1a lsrs r2, r3, #20 + 800c1f6: 80ca strh r2, [r1, #6] + pCSD->RdBlockLen = (uint8_t)((hsd->CSD[1] & 0x000F0000U) >> 16U); + 800c1f8: f3c3 4203 ubfx r2, r3, #16, #4 + 800c1fc: 720a strb r2, [r1, #8] + pCSD->PartBlockRead = (uint8_t)((hsd->CSD[1] & 0x00008000U) >> 15U); + 800c1fe: f3c3 32c0 ubfx r2, r3, #15, #1 + 800c202: 724a strb r2, [r1, #9] + pCSD->WrBlockMisalign = (uint8_t)((hsd->CSD[1] & 0x00004000U) >> 14U); + 800c204: f3c3 3280 ubfx r2, r3, #14, #1 + 800c208: 728a strb r2, [r1, #10] + pCSD->RdBlockMisalign = (uint8_t)((hsd->CSD[1] & 0x00002000U) >> 13U); + 800c20a: f3c3 3240 ubfx r2, r3, #13, #1 + 800c20e: 72ca strb r2, [r1, #11] + pCSD->DSRImpl = (uint8_t)((hsd->CSD[1] & 0x00001000U) >> 12U); + 800c210: f3c3 3200 ubfx r2, r3, #12, #1 + 800c214: 730a strb r2, [r1, #12] + pCSD->Reserved2 = 0U; /*!< Reserved */ + 800c216: 2200 movs r2, #0 + 800c218: 734a strb r2, [r1, #13] + if(hsd->SdCard.CardType == CARD_SDSC) + 800c21a: 6bc2 ldr r2, [r0, #60] ; 0x3c +{ + 800c21c: b510 push {r4, lr} + if(hsd->SdCard.CardType == CARD_SDSC) + 800c21e: 2a00 cmp r2, #0 + 800c220: d16c bne.n 800c2fc + pCSD->DeviceSize = (((hsd->CSD[1] & 0x000003FFU) << 2U) | ((hsd->CSD[2] & 0xC0000000U) >> 30U)); + 800c222: 6e82 ldr r2, [r0, #104] ; 0x68 + 800c224: f640 74fc movw r4, #4092 ; 0xffc + 800c228: ea04 0383 and.w r3, r4, r3, lsl #2 + 800c22c: ea43 7392 orr.w r3, r3, r2, lsr #30 + 800c230: 610b str r3, [r1, #16] + pCSD->MaxRdCurrentVDDMin = (uint8_t)((hsd->CSD[2] & 0x38000000U) >> 27U); + 800c232: f3c2 63c2 ubfx r3, r2, #27, #3 + 800c236: 750b strb r3, [r1, #20] + pCSD->MaxRdCurrentVDDMax = (uint8_t)((hsd->CSD[2] & 0x07000000U) >> 24U); + 800c238: f3c2 6302 ubfx r3, r2, #24, #3 + 800c23c: 754b strb r3, [r1, #21] + pCSD->MaxWrCurrentVDDMin = (uint8_t)((hsd->CSD[2] & 0x00E00000U) >> 21U); + 800c23e: f3c2 5342 ubfx r3, r2, #21, #3 + 800c242: 758b strb r3, [r1, #22] + pCSD->MaxWrCurrentVDDMax = (uint8_t)((hsd->CSD[2] & 0x001C0000U) >> 18U); + 800c244: f3c2 4382 ubfx r3, r2, #18, #3 + pCSD->DeviceSizeMul = (uint8_t)((hsd->CSD[2] & 0x00038000U) >> 15U); + 800c248: f3c2 32c2 ubfx r2, r2, #15, #3 + pCSD->MaxWrCurrentVDDMax = (uint8_t)((hsd->CSD[2] & 0x001C0000U) >> 18U); + 800c24c: 75cb strb r3, [r1, #23] + pCSD->DeviceSizeMul = (uint8_t)((hsd->CSD[2] & 0x00038000U) >> 15U); + 800c24e: 760a strb r2, [r1, #24] + hsd->SdCard.BlockNbr = (pCSD->DeviceSize + 1U) ; + 800c250: 690b ldr r3, [r1, #16] + hsd->SdCard.BlockNbr *= (1UL << ((pCSD->DeviceSizeMul & 0x07U) + 2U)); + 800c252: 7e0a ldrb r2, [r1, #24] + 800c254: f002 0207 and.w r2, r2, #7 + hsd->SdCard.BlockNbr = (pCSD->DeviceSize + 1U) ; + 800c258: 3301 adds r3, #1 + hsd->SdCard.BlockNbr *= (1UL << ((pCSD->DeviceSizeMul & 0x07U) + 2U)); + 800c25a: 3202 adds r2, #2 + 800c25c: fa03 f202 lsl.w r2, r3, r2 + 800c260: 64c2 str r2, [r0, #76] ; 0x4c + hsd->SdCard.BlockSize = (1UL << (pCSD->RdBlockLen & 0x0FU)); + 800c262: 7a0b ldrb r3, [r1, #8] + 800c264: f003 040f and.w r4, r3, #15 + 800c268: 2301 movs r3, #1 + 800c26a: 40a3 lsls r3, r4 + 800c26c: 6503 str r3, [r0, #80] ; 0x50 + hsd->SdCard.LogBlockNbr = (hsd->SdCard.BlockNbr) * ((hsd->SdCard.BlockSize) / 512U); + 800c26e: 0a5b lsrs r3, r3, #9 + 800c270: 4353 muls r3, r2 + 800c272: 6543 str r3, [r0, #84] ; 0x54 + hsd->SdCard.LogBlockSize = 512U; + 800c274: f44f 7300 mov.w r3, #512 ; 0x200 + hsd->SdCard.LogBlockSize = hsd->SdCard.BlockSize; + 800c278: 6583 str r3, [r0, #88] ; 0x58 + pCSD->EraseGrSize = (uint8_t)((hsd->CSD[2] & 0x00004000U) >> 14U); + 800c27a: 6e83 ldr r3, [r0, #104] ; 0x68 + 800c27c: f3c3 3280 ubfx r2, r3, #14, #1 + 800c280: 764a strb r2, [r1, #25] + pCSD->EraseGrMul = (uint8_t)((hsd->CSD[2] & 0x00003F80U) >> 7U); + 800c282: f3c3 12c6 ubfx r2, r3, #7, #7 + pCSD->WrProtectGrSize = (uint8_t)(hsd->CSD[2] & 0x0000007FU); + 800c286: f003 037f and.w r3, r3, #127 ; 0x7f + pCSD->EraseGrMul = (uint8_t)((hsd->CSD[2] & 0x00003F80U) >> 7U); + 800c28a: 768a strb r2, [r1, #26] + pCSD->WrProtectGrSize = (uint8_t)(hsd->CSD[2] & 0x0000007FU); + 800c28c: 76cb strb r3, [r1, #27] + pCSD->WrProtectGrEnable = (uint8_t)((hsd->CSD[3] & 0x80000000U) >> 31U); + 800c28e: 6ec3 ldr r3, [r0, #108] ; 0x6c + 800c290: 0fda lsrs r2, r3, #31 + 800c292: 770a strb r2, [r1, #28] + pCSD->ManDeflECC = (uint8_t)((hsd->CSD[3] & 0x60000000U) >> 29U); + 800c294: f3c3 7241 ubfx r2, r3, #29, #2 + 800c298: 774a strb r2, [r1, #29] + pCSD->WrSpeedFact = (uint8_t)((hsd->CSD[3] & 0x1C000000U) >> 26U); + 800c29a: f3c3 6282 ubfx r2, r3, #26, #3 + 800c29e: 778a strb r2, [r1, #30] + pCSD->MaxWrBlockLen= (uint8_t)((hsd->CSD[3] & 0x03C00000U) >> 22U); + 800c2a0: f3c3 5283 ubfx r2, r3, #22, #4 + 800c2a4: 77ca strb r2, [r1, #31] + pCSD->WriteBlockPaPartial = (uint8_t)((hsd->CSD[3] & 0x00200000U) >> 21U); + 800c2a6: f3c3 5240 ubfx r2, r3, #21, #1 + 800c2aa: f881 2020 strb.w r2, [r1, #32] + pCSD->Reserved3 = 0; + 800c2ae: 2000 movs r0, #0 + pCSD->ContentProtectAppli = (uint8_t)((hsd->CSD[3] & 0x00010000U) >> 16U); + 800c2b0: f3c3 4200 ubfx r2, r3, #16, #1 + pCSD->Reserved3 = 0; + 800c2b4: f881 0021 strb.w r0, [r1, #33] ; 0x21 + pCSD->ContentProtectAppli = (uint8_t)((hsd->CSD[3] & 0x00010000U) >> 16U); + 800c2b8: f881 2022 strb.w r2, [r1, #34] ; 0x22 + pCSD->FileFormatGroup = (uint8_t)((hsd->CSD[3] & 0x00008000U) >> 15U); + 800c2bc: f3c3 32c0 ubfx r2, r3, #15, #1 + 800c2c0: f881 2023 strb.w r2, [r1, #35] ; 0x23 + pCSD->CopyFlag = (uint8_t)((hsd->CSD[3] & 0x00004000U) >> 14U); + 800c2c4: f3c3 3280 ubfx r2, r3, #14, #1 + 800c2c8: f881 2024 strb.w r2, [r1, #36] ; 0x24 + pCSD->PermWrProtect = (uint8_t)((hsd->CSD[3] & 0x00002000U) >> 13U); + 800c2cc: f3c3 3240 ubfx r2, r3, #13, #1 + 800c2d0: f881 2025 strb.w r2, [r1, #37] ; 0x25 + pCSD->TempWrProtect = (uint8_t)((hsd->CSD[3] & 0x00001000U) >> 12U); + 800c2d4: f3c3 3200 ubfx r2, r3, #12, #1 + 800c2d8: f881 2026 strb.w r2, [r1, #38] ; 0x26 + pCSD->FileFormat = (uint8_t)((hsd->CSD[3] & 0x00000C00U) >> 10U); + 800c2dc: f3c3 2281 ubfx r2, r3, #10, #2 + 800c2e0: f881 2027 strb.w r2, [r1, #39] ; 0x27 + pCSD->ECC= (uint8_t)((hsd->CSD[3] & 0x00000300U) >> 8U); + 800c2e4: f3c3 2201 ubfx r2, r3, #8, #2 + pCSD->CSD_CRC = (uint8_t)((hsd->CSD[3] & 0x000000FEU) >> 1U); + 800c2e8: f3c3 0346 ubfx r3, r3, #1, #7 + pCSD->ECC= (uint8_t)((hsd->CSD[3] & 0x00000300U) >> 8U); + 800c2ec: f881 2028 strb.w r2, [r1, #40] ; 0x28 + pCSD->CSD_CRC = (uint8_t)((hsd->CSD[3] & 0x000000FEU) >> 1U); + 800c2f0: f881 3029 strb.w r3, [r1, #41] ; 0x29 + pCSD->Reserved4 = 1; + 800c2f4: 2301 movs r3, #1 + 800c2f6: f881 302a strb.w r3, [r1, #42] ; 0x2a +} + 800c2fa: bd10 pop {r4, pc} + else if(hsd->SdCard.CardType == CARD_SDHC_SDXC) + 800c2fc: 2a01 cmp r2, #1 + 800c2fe: d10f bne.n 800c320 + pCSD->DeviceSize = (((hsd->CSD[1] & 0x0000003FU) << 16U) | ((hsd->CSD[2] & 0xFFFF0000U) >> 16U)); + 800c300: f8b0 206a ldrh.w r2, [r0, #106] ; 0x6a + 800c304: 041b lsls r3, r3, #16 + 800c306: f403 137c and.w r3, r3, #4128768 ; 0x3f0000 + 800c30a: 4313 orrs r3, r2 + 800c30c: 610b str r3, [r1, #16] + hsd->SdCard.BlockNbr = ((pCSD->DeviceSize + 1U) * 1024U); + 800c30e: 690b ldr r3, [r1, #16] + 800c310: 3301 adds r3, #1 + 800c312: 029b lsls r3, r3, #10 + 800c314: 64c3 str r3, [r0, #76] ; 0x4c + hsd->SdCard.LogBlockNbr = hsd->SdCard.BlockNbr; + 800c316: 6543 str r3, [r0, #84] ; 0x54 + hsd->SdCard.BlockSize = 512U; + 800c318: f44f 7300 mov.w r3, #512 ; 0x200 + 800c31c: 6503 str r3, [r0, #80] ; 0x50 + 800c31e: e7ab b.n 800c278 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c320: 6803 ldr r3, [r0, #0] + 800c322: 4a05 ldr r2, [pc, #20] ; (800c338 ) + 800c324: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + 800c326: 6b83 ldr r3, [r0, #56] ; 0x38 + 800c328: f043 5380 orr.w r3, r3, #268435456 ; 0x10000000 + 800c32c: 6383 str r3, [r0, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c32e: 2301 movs r3, #1 + 800c330: f880 3034 strb.w r3, [r0, #52] ; 0x34 + return HAL_ERROR; + 800c334: 4618 mov r0, r3 + 800c336: e7e0 b.n 800c2fa + 800c338: 1fe00fff .word 0x1fe00fff + +0800c33c : +{ + 800c33c: e92d 43f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, lr} + Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING; + 800c340: 2300 movs r3, #0 +{ + 800c342: b099 sub sp, #100 ; 0x64 + 800c344: 4604 mov r4, r0 + sdmmc_clk = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SDMMC1); + 800c346: f44f 2000 mov.w r0, #524288 ; 0x80000 + Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; + 800c34a: e9cd 3307 strd r3, r3, [sp, #28] + Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; + 800c34e: e9cd 3309 strd r3, r3, [sp, #36] ; 0x24 + sdmmc_clk = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SDMMC1); + 800c352: f7fd fb2d bl 80099b0 + if (sdmmc_clk == 0U) + 800c356: 4605 mov r5, r0 + 800c358: b948 cbnz r0, 800c36e + hsd->State = HAL_SD_STATE_READY; + 800c35a: 2501 movs r5, #1 + hsd->ErrorCode = SDMMC_ERROR_INVALID_PARAMETER; + 800c35c: f04f 6300 mov.w r3, #134217728 ; 0x8000000 + hsd->State = HAL_SD_STATE_READY; + 800c360: f884 5034 strb.w r5, [r4, #52] ; 0x34 + hsd->ErrorCode = SDMMC_ERROR_INVALID_PARAMETER; + 800c364: 63a3 str r3, [r4, #56] ; 0x38 +} + 800c366: 4628 mov r0, r5 + 800c368: b019 add sp, #100 ; 0x64 + 800c36a: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + Init.Transceiver = hsd->Init.Transceiver; + 800c36e: 69a3 ldr r3, [r4, #24] + hsd->Instance->POWER |= SDMMC_POWER_DIRPOL; + 800c370: 6827 ldr r7, [r4, #0] + Init.Transceiver = hsd->Init.Transceiver; + 800c372: 930c str r3, [sp, #48] ; 0x30 + if(hsd->Init.Transceiver == SDMMC_TRANSCEIVER_ENABLE) + 800c374: 2b01 cmp r3, #1 + hsd->Instance->POWER |= SDMMC_POWER_DIRPOL; + 800c376: bf08 it eq + 800c378: 683b ldreq r3, [r7, #0] + Init.ClockDiv = sdmmc_clk / (2U * SD_INIT_FREQ); + 800c37a: 4e99 ldr r6, [pc, #612] ; (800c5e0 ) + 800c37c: fbb0 f6f6 udiv r6, r0, r6 + hsd->Instance->POWER |= SDMMC_POWER_DIRPOL; + 800c380: bf04 itt eq + 800c382: f043 0310 orreq.w r3, r3, #16 + 800c386: 603b streq r3, [r7, #0] + status = SDMMC_Init(hsd->Instance, Init); + 800c388: 960b str r6, [sp, #44] ; 0x2c + 800c38a: ab0a add r3, sp, #40 ; 0x28 + 800c38c: e893 0007 ldmia.w r3, {r0, r1, r2} + 800c390: e88d 0007 stmia.w sp, {r0, r1, r2} + 800c394: ab07 add r3, sp, #28 + 800c396: cb0e ldmia r3, {r1, r2, r3} + 800c398: 4638 mov r0, r7 + 800c39a: f000 fcbb bl 800cd14 + if(status != HAL_OK) + 800c39e: b108 cbz r0, 800c3a4 + return HAL_ERROR; + 800c3a0: 2501 movs r5, #1 + 800c3a2: e7e0 b.n 800c366 + status = SDMMC_PowerState_ON(hsd->Instance); + 800c3a4: 6820 ldr r0, [r4, #0] + 800c3a6: f000 fcd7 bl 800cd58 + if(status != HAL_OK) + 800c3aa: 4607 mov r7, r0 + 800c3ac: 2800 cmp r0, #0 + 800c3ae: d1f7 bne.n 800c3a0 + sdmmc_clk = sdmmc_clk/(2U*Init.ClockDiv); + 800c3b0: 0076 lsls r6, r6, #1 + HAL_Delay(1U+ (74U*1000U/(sdmmc_clk))); + 800c3b2: 488c ldr r0, [pc, #560] ; (800c5e4 ) + sdmmc_clk = sdmmc_clk/(2U*Init.ClockDiv); + 800c3b4: fbb5 f5f6 udiv r5, r5, r6 + HAL_Delay(1U+ (74U*1000U/(sdmmc_clk))); + 800c3b8: fbb0 f0f5 udiv r0, r0, r5 + 800c3bc: 3001 adds r0, #1 + 800c3be: f7f7 faa8 bl 8003912 + __IO uint32_t count = 0U; + 800c3c2: 9706 str r7, [sp, #24] + uint32_t tickstart = HAL_GetTick(); + 800c3c4: f7fa fe92 bl 80070ec + 800c3c8: 4606 mov r6, r0 + errorstate = SDMMC_CmdGoIdleState(hsd->Instance); + 800c3ca: 6820 ldr r0, [r4, #0] + 800c3cc: f000 fd18 bl 800ce00 + if(errorstate != HAL_SD_ERROR_NONE) + 800c3d0: 4605 mov r5, r0 + 800c3d2: b940 cbnz r0, 800c3e6 + errorstate = SDMMC_CmdOperCond(hsd->Instance); + 800c3d4: 6820 ldr r0, [r4, #0] + 800c3d6: f001 f8fd bl 800d5d4 + if(errorstate != HAL_SD_ERROR_NONE) + 800c3da: b158 cbz r0, 800c3f4 + errorstate = SDMMC_CmdGoIdleState(hsd->Instance); + 800c3dc: 6820 ldr r0, [r4, #0] + hsd->SdCard.CardVersion = CARD_V1_X; + 800c3de: 6425 str r5, [r4, #64] ; 0x40 + errorstate = SDMMC_CmdGoIdleState(hsd->Instance); + 800c3e0: f000 fd0e bl 800ce00 + if(errorstate != HAL_SD_ERROR_NONE) + 800c3e4: b180 cbz r0, 800c408 + hsd->State = HAL_SD_STATE_READY; + 800c3e6: 2501 movs r5, #1 + 800c3e8: f884 5034 strb.w r5, [r4, #52] ; 0x34 + hsd->ErrorCode |= errorstate; + 800c3ec: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c3ee: 4318 orrs r0, r3 + 800c3f0: 63a0 str r0, [r4, #56] ; 0x38 + return HAL_ERROR; + 800c3f2: e7b8 b.n 800c366 + hsd->SdCard.CardVersion = CARD_V2_X; + 800c3f4: 2301 movs r3, #1 + 800c3f6: 6423 str r3, [r4, #64] ; 0x40 + errorstate = SDMMC_CmdAppCommand(hsd->Instance, 0); + 800c3f8: 6820 ldr r0, [r4, #0] + 800c3fa: 2100 movs r1, #0 + 800c3fc: f000 fef5 bl 800d1ea + if(errorstate != HAL_SD_ERROR_NONE) + 800c400: b128 cbz r0, 800c40e + return HAL_SD_ERROR_UNSUPPORTED_FEATURE; + 800c402: f04f 5080 mov.w r0, #268435456 ; 0x10000000 + 800c406: e7ee b.n 800c3e6 + if( hsd->SdCard.CardVersion == CARD_V2_X) + 800c408: 6c23 ldr r3, [r4, #64] ; 0x40 + 800c40a: 2b01 cmp r3, #1 + 800c40c: d0f4 beq.n 800c3f8 + errorstate = SDMMC_CmdAppOperCommand(hsd->Instance, SDMMC_VOLTAGE_WINDOW_SD | SDMMC_HIGH_CAPACITY | SD_SWITCH_1_8V_CAPACITY); + 800c40e: f8df 91dc ldr.w r9, [pc, #476] ; 800c5ec +{ + 800c412: 2700 movs r7, #0 + while((count < SDMMC_MAX_VOLT_TRIAL) && (validvoltage == 0U)) + 800c414: f64f 78fe movw r8, #65534 ; 0xfffe + 800c418: 9b06 ldr r3, [sp, #24] + 800c41a: 4543 cmp r3, r8 + 800c41c: d800 bhi.n 800c420 + 800c41e: b12f cbz r7, 800c42c + if(count >= SDMMC_MAX_VOLT_TRIAL) + 800c420: 9b06 ldr r3, [sp, #24] + 800c422: 4543 cmp r3, r8 + 800c424: d918 bls.n 800c458 + return HAL_SD_ERROR_INVALID_VOLTRANGE; + 800c426: f04f 7080 mov.w r0, #16777216 ; 0x1000000 + 800c42a: e7dc b.n 800c3e6 + errorstate = SDMMC_CmdAppCommand(hsd->Instance, 0); + 800c42c: 6820 ldr r0, [r4, #0] + 800c42e: 4639 mov r1, r7 + 800c430: f000 fedb bl 800d1ea + if(errorstate != HAL_SD_ERROR_NONE) + 800c434: 2800 cmp r0, #0 + 800c436: d1d6 bne.n 800c3e6 + errorstate = SDMMC_CmdAppOperCommand(hsd->Instance, SDMMC_VOLTAGE_WINDOW_SD | SDMMC_HIGH_CAPACITY | SD_SWITCH_1_8V_CAPACITY); + 800c438: 6820 ldr r0, [r4, #0] + 800c43a: 4649 mov r1, r9 + 800c43c: f001 f816 bl 800d46c + if(errorstate != HAL_SD_ERROR_NONE) + 800c440: 2800 cmp r0, #0 + 800c442: d1de bne.n 800c402 + response = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1); + 800c444: 4639 mov r1, r7 + 800c446: 6820 ldr r0, [r4, #0] + 800c448: f000 fcb7 bl 800cdba + count++; + 800c44c: 9b06 ldr r3, [sp, #24] + 800c44e: 3301 adds r3, #1 + response = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1); + 800c450: 4605 mov r5, r0 + validvoltage = (((response >> 31U) == 1U) ? 1U : 0U); + 800c452: 0fc7 lsrs r7, r0, #31 + count++; + 800c454: 9306 str r3, [sp, #24] + 800c456: e7df b.n 800c418 + if((response & SDMMC_HIGH_CAPACITY) == SDMMC_HIGH_CAPACITY) /* (response &= SD_HIGH_CAPACITY) */ + 800c458: f015 4380 ands.w r3, r5, #1073741824 ; 0x40000000 + 800c45c: d04b beq.n 800c4f6 + hsd->SdCard.CardType = CARD_SDHC_SDXC; + 800c45e: 2301 movs r3, #1 + 800c460: 63e3 str r3, [r4, #60] ; 0x3c + if(hsd->Init.Transceiver == SDMMC_TRANSCEIVER_ENABLE) + 800c462: 69a3 ldr r3, [r4, #24] + errorstate = SDMMC_CmdAppCommand(hsd->Instance, 0); + 800c464: 6820 ldr r0, [r4, #0] + if(hsd->Init.Transceiver == SDMMC_TRANSCEIVER_ENABLE) + 800c466: 2b01 cmp r3, #1 + 800c468: d12d bne.n 800c4c6 + if((response & SD_SWITCH_1_8V_CAPACITY) == SD_SWITCH_1_8V_CAPACITY) + 800c46a: 01ef lsls r7, r5, #7 + 800c46c: d52b bpl.n 800c4c6 + hsd->SdCard.CardSpeed = CARD_ULTRA_HIGH_SPEED; + 800c46e: f44f 7300 mov.w r3, #512 ; 0x200 + 800c472: 65e3 str r3, [r4, #92] ; 0x5c + hsd->Instance->POWER |= SDMMC_POWER_VSWITCHEN; + 800c474: 6803 ldr r3, [r0, #0] + 800c476: f043 0308 orr.w r3, r3, #8 + 800c47a: 6003 str r3, [r0, #0] + errorstate = SDMMC_CmdVoltageSwitch(hsd->Instance); + 800c47c: f000 ff4e bl 800d31c + if(errorstate != HAL_SD_ERROR_NONE) + 800c480: 2800 cmp r0, #0 + 800c482: d1b0 bne.n 800c3e6 + while(( hsd->Instance->STA & SDMMC_FLAG_CKSTOP) != SDMMC_FLAG_CKSTOP) + 800c484: 6823 ldr r3, [r4, #0] + 800c486: 6b5a ldr r2, [r3, #52] ; 0x34 + 800c488: 0155 lsls r5, r2, #5 + 800c48a: d526 bpl.n 800c4da + hsd->Instance->ICR = SDMMC_FLAG_CKSTOP; + 800c48c: f04f 6280 mov.w r2, #67108864 ; 0x4000000 + 800c490: 639a str r2, [r3, #56] ; 0x38 + if(( hsd->Instance->STA & SDMMC_FLAG_BUSYD0) != SDMMC_FLAG_BUSYD0) + 800c492: 6b5b ldr r3, [r3, #52] ; 0x34 + 800c494: 02d8 lsls r0, r3, #11 + 800c496: d5b4 bpl.n 800c402 + HAL_SDEx_DriveTransceiver_1_8V_Callback(SET); + 800c498: 2001 movs r0, #1 + 800c49a: f7fa fe97 bl 80071cc + hsd->Instance->POWER |= SDMMC_POWER_VSWITCH; + 800c49e: 6822 ldr r2, [r4, #0] + 800c4a0: 6813 ldr r3, [r2, #0] + 800c4a2: f043 0304 orr.w r3, r3, #4 + 800c4a6: 6013 str r3, [r2, #0] + while(( hsd->Instance->STA & SDMMC_FLAG_VSWEND) != SDMMC_FLAG_VSWEND) + 800c4a8: 6823 ldr r3, [r4, #0] + 800c4aa: 6b5a ldr r2, [r3, #52] ; 0x34 + 800c4ac: 0191 lsls r1, r2, #6 + 800c4ae: d51c bpl.n 800c4ea + hsd->Instance->ICR = SDMMC_FLAG_VSWEND; + 800c4b0: f04f 7200 mov.w r2, #33554432 ; 0x2000000 + 800c4b4: 639a str r2, [r3, #56] ; 0x38 + if(( hsd->Instance->STA & SDMMC_FLAG_BUSYD0) == SDMMC_FLAG_BUSYD0) + 800c4b6: 6b5a ldr r2, [r3, #52] ; 0x34 + 800c4b8: 02d2 lsls r2, r2, #11 + 800c4ba: d4b4 bmi.n 800c426 + hsd->Instance->POWER = 0x13U; + 800c4bc: 2213 movs r2, #19 + 800c4be: 601a str r2, [r3, #0] + hsd->Instance->ICR = 0xFFFFFFFFU; + 800c4c0: f04f 32ff mov.w r2, #4294967295 ; 0xffffffff + 800c4c4: 639a str r2, [r3, #56] ; 0x38 + uint16_t sd_rca = 1U; + 800c4c6: 2301 movs r3, #1 + if(SDMMC_GetPowerState(hsd->Instance) == 0U) + 800c4c8: 6820 ldr r0, [r4, #0] + uint16_t sd_rca = 1U; + 800c4ca: f8ad 3016 strh.w r3, [sp, #22] + if(SDMMC_GetPowerState(hsd->Instance) == 0U) + 800c4ce: f000 fc59 bl 800cd84 + 800c4d2: b990 cbnz r0, 800c4fa + return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE; + 800c4d4: f04f 6080 mov.w r0, #67108864 ; 0x4000000 + 800c4d8: e785 b.n 800c3e6 + if((HAL_GetTick() - tickstart) >= SDMMC_DATATIMEOUT) + 800c4da: f7fa fe07 bl 80070ec + 800c4de: 1b80 subs r0, r0, r6 + 800c4e0: 3001 adds r0, #1 + 800c4e2: d1cf bne.n 800c484 + return HAL_SD_ERROR_TIMEOUT; + 800c4e4: f04f 4000 mov.w r0, #2147483648 ; 0x80000000 + 800c4e8: e77d b.n 800c3e6 + if((HAL_GetTick() - tickstart) >= SDMMC_DATATIMEOUT) + 800c4ea: f7fa fdff bl 80070ec + 800c4ee: 1b80 subs r0, r0, r6 + 800c4f0: 3001 adds r0, #1 + 800c4f2: d1d9 bne.n 800c4a8 + 800c4f4: e7f6 b.n 800c4e4 + hsd->SdCard.CardType = CARD_SDSC; + 800c4f6: 63e3 str r3, [r4, #60] ; 0x3c + if(errorstate != HAL_SD_ERROR_NONE) + 800c4f8: e7e5 b.n 800c4c6 + if(hsd->SdCard.CardType != CARD_SECURED) + 800c4fa: 6be3 ldr r3, [r4, #60] ; 0x3c + 800c4fc: 2b03 cmp r3, #3 + 800c4fe: d045 beq.n 800c58c + errorstate = SDMMC_CmdSendCID(hsd->Instance); + 800c500: 6820 ldr r0, [r4, #0] + 800c502: f000 ff65 bl 800d3d0 + if(errorstate != HAL_SD_ERROR_NONE) + 800c506: 2800 cmp r0, #0 + 800c508: f47f af6d bne.w 800c3e6 + hsd->CID[0U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1); + 800c50c: 4601 mov r1, r0 + 800c50e: 6820 ldr r0, [r4, #0] + 800c510: f000 fc53 bl 800cdba + hsd->CID[1U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP2); + 800c514: 2104 movs r1, #4 + hsd->CID[0U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1); + 800c516: 6720 str r0, [r4, #112] ; 0x70 + hsd->CID[1U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP2); + 800c518: 6820 ldr r0, [r4, #0] + 800c51a: f000 fc4e bl 800cdba + hsd->CID[2U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP3); + 800c51e: 2108 movs r1, #8 + hsd->CID[1U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP2); + 800c520: 6760 str r0, [r4, #116] ; 0x74 + hsd->CID[2U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP3); + 800c522: 6820 ldr r0, [r4, #0] + 800c524: f000 fc49 bl 800cdba + hsd->CID[3U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP4); + 800c528: 210c movs r1, #12 + hsd->CID[2U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP3); + 800c52a: 67a0 str r0, [r4, #120] ; 0x78 + hsd->CID[3U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP4); + 800c52c: 6820 ldr r0, [r4, #0] + 800c52e: f000 fc44 bl 800cdba + if(hsd->SdCard.CardType != CARD_SECURED) + 800c532: 6be3 ldr r3, [r4, #60] ; 0x3c + hsd->CID[3U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP4); + 800c534: 67e0 str r0, [r4, #124] ; 0x7c + if(hsd->SdCard.CardType != CARD_SECURED) + 800c536: 2b03 cmp r3, #3 + 800c538: d028 beq.n 800c58c + errorstate = SDMMC_CmdSetRelAdd(hsd->Instance, &sd_rca); + 800c53a: 6820 ldr r0, [r4, #0] + 800c53c: f10d 0116 add.w r1, sp, #22 + 800c540: f001 f804 bl 800d54c + if(errorstate != HAL_SD_ERROR_NONE) + 800c544: 2800 cmp r0, #0 + 800c546: f47f af4e bne.w 800c3e6 + if(hsd->SdCard.CardType != CARD_SECURED) + 800c54a: 6be3 ldr r3, [r4, #60] ; 0x3c + errorstate = SDMMC_CmdSendCSD(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); + 800c54c: 6820 ldr r0, [r4, #0] + if(hsd->SdCard.CardType != CARD_SECURED) + 800c54e: 2b03 cmp r3, #3 + 800c550: d01c beq.n 800c58c + hsd->SdCard.RelCardAdd = sd_rca; + 800c552: f8bd 1016 ldrh.w r1, [sp, #22] + 800c556: 64a1 str r1, [r4, #72] ; 0x48 + errorstate = SDMMC_CmdSendCSD(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); + 800c558: 0409 lsls r1, r1, #16 + 800c55a: f000 ff4f bl 800d3fc + if(errorstate != HAL_SD_ERROR_NONE) + 800c55e: 2800 cmp r0, #0 + 800c560: f47f af41 bne.w 800c3e6 + hsd->CSD[0U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1); + 800c564: 4601 mov r1, r0 + 800c566: 6820 ldr r0, [r4, #0] + 800c568: f000 fc27 bl 800cdba + hsd->CSD[1U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP2); + 800c56c: 2104 movs r1, #4 + hsd->CSD[0U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1); + 800c56e: 6620 str r0, [r4, #96] ; 0x60 + hsd->CSD[1U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP2); + 800c570: 6820 ldr r0, [r4, #0] + 800c572: f000 fc22 bl 800cdba + hsd->CSD[2U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP3); + 800c576: 2108 movs r1, #8 + hsd->CSD[1U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP2); + 800c578: 6660 str r0, [r4, #100] ; 0x64 + hsd->CSD[2U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP3); + 800c57a: 6820 ldr r0, [r4, #0] + 800c57c: f000 fc1d bl 800cdba + hsd->CSD[3U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP4); + 800c580: 210c movs r1, #12 + hsd->CSD[2U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP3); + 800c582: 66a0 str r0, [r4, #104] ; 0x68 + hsd->CSD[3U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP4); + 800c584: 6820 ldr r0, [r4, #0] + 800c586: f000 fc18 bl 800cdba + 800c58a: 66e0 str r0, [r4, #108] ; 0x6c + hsd->SdCard.Class = (SDMMC_GetResponse(hsd->Instance, SDMMC_RESP2) >> 20U); + 800c58c: 2104 movs r1, #4 + 800c58e: 6820 ldr r0, [r4, #0] + 800c590: f000 fc13 bl 800cdba + 800c594: 0d00 lsrs r0, r0, #20 + 800c596: 6460 str r0, [r4, #68] ; 0x44 + if (HAL_SD_GetCardCSD(hsd, &CSD) != HAL_OK) + 800c598: a90d add r1, sp, #52 ; 0x34 + 800c59a: 4620 mov r0, r4 + 800c59c: f7ff fe18 bl 800c1d0 + 800c5a0: 4605 mov r5, r0 + 800c5a2: 2800 cmp r0, #0 + 800c5a4: f47f af2d bne.w 800c402 + errorstate = SDMMC_CmdSelDesel(hsd->Instance, (uint32_t)(((uint32_t)hsd->SdCard.RelCardAdd) << 16U)); + 800c5a8: 6ca2 ldr r2, [r4, #72] ; 0x48 + 800c5aa: 4603 mov r3, r0 + 800c5ac: 0412 lsls r2, r2, #16 + 800c5ae: 6820 ldr r0, [r4, #0] + 800c5b0: f000 fe02 bl 800d1b8 + if(errorstate != HAL_SD_ERROR_NONE) + 800c5b4: 2800 cmp r0, #0 + 800c5b6: f47f af16 bne.w 800c3e6 + errorstate = SDMMC_CmdBlockLength(hsd->Instance, BLOCKSIZE); + 800c5ba: 6820 ldr r0, [r4, #0] + 800c5bc: f44f 7100 mov.w r1, #512 ; 0x200 + 800c5c0: f000 fcda bl 800cf78 + if(errorstate != HAL_SD_ERROR_NONE) + 800c5c4: 2800 cmp r0, #0 + 800c5c6: f43f aece beq.w 800c366 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c5ca: 6823 ldr r3, [r4, #0] + 800c5cc: 4a06 ldr r2, [pc, #24] ; (800c5e8 ) + 800c5ce: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= errorstate; + 800c5d0: 6ba3 ldr r3, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c5d2: 2501 movs r5, #1 + hsd->ErrorCode |= errorstate; + 800c5d4: 4318 orrs r0, r3 + 800c5d6: 63a0 str r0, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c5d8: f884 5034 strb.w r5, [r4, #52] ; 0x34 + return HAL_ERROR; + 800c5dc: e6c3 b.n 800c366 + 800c5de: bf00 nop + 800c5e0: 000c3500 .word 0x000c3500 + 800c5e4: 00012110 .word 0x00012110 + 800c5e8: 1fe00fff .word 0x1fe00fff + 800c5ec: c1100000 .word 0xc1100000 + +0800c5f0 : +{ + 800c5f0: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + 800c5f4: b096 sub sp, #88 ; 0x58 + 800c5f6: 4604 mov r4, r0 + 800c5f8: 460d mov r5, r1 + uint32_t tickstart = HAL_GetTick(); + 800c5fa: f7fa fd77 bl 80070ec + if((SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED) + 800c5fe: 2100 movs r1, #0 + uint32_t tickstart = HAL_GetTick(); + 800c600: 4606 mov r6, r0 + if((SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED) + 800c602: 6820 ldr r0, [r4, #0] + 800c604: f000 fbd9 bl 800cdba + 800c608: 0183 lsls r3, r0, #6 + 800c60a: d50b bpl.n 800c624 + return HAL_SD_ERROR_LOCK_UNLOCK_FAILED; + 800c60c: f44f 6000 mov.w r0, #2048 ; 0x800 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c610: 6823 ldr r3, [r4, #0] + 800c612: 4a54 ldr r2, [pc, #336] ; (800c764 ) + 800c614: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= errorstate; + 800c616: 6ba3 ldr r3, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c618: 2501 movs r5, #1 + hsd->ErrorCode |= errorstate; + 800c61a: 4318 orrs r0, r3 + 800c61c: 63a0 str r0, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c61e: f884 5034 strb.w r5, [r4, #52] ; 0x34 + status = HAL_ERROR; + 800c622: e08a b.n 800c73a + errorstate = SDMMC_CmdBlockLength(hsd->Instance, 64U); + 800c624: 6820 ldr r0, [r4, #0] + 800c626: 2140 movs r1, #64 ; 0x40 + 800c628: f000 fca6 bl 800cf78 + if(errorstate != HAL_SD_ERROR_NONE) + 800c62c: b110 cbz r0, 800c634 + hsd->ErrorCode |= HAL_SD_ERROR_NONE; + 800c62e: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c630: 63a3 str r3, [r4, #56] ; 0x38 + return errorstate; + 800c632: e7ed b.n 800c610 + errorstate = SDMMC_CmdAppCommand(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); + 800c634: 6ca1 ldr r1, [r4, #72] ; 0x48 + 800c636: 6820 ldr r0, [r4, #0] + 800c638: 0409 lsls r1, r1, #16 + 800c63a: f000 fdd6 bl 800d1ea + if(errorstate != HAL_SD_ERROR_NONE) + 800c63e: 2800 cmp r0, #0 + 800c640: d1f5 bne.n 800c62e + config.DataLength = 64U; + 800c642: 2340 movs r3, #64 ; 0x40 + 800c644: f04f 37ff mov.w r7, #4294967295 ; 0xffffffff + 800c648: e9cd 7300 strd r7, r3, [sp] + config.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + 800c64c: f04f 0c60 mov.w ip, #96 ; 0x60 + 800c650: 2302 movs r3, #2 + 800c652: e9cd c302 strd ip, r3, [sp, #8] + config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + 800c656: 9004 str r0, [sp, #16] + config.DPSM = SDMMC_DPSM_ENABLE; + 800c658: 2301 movs r3, #1 + (void)SDMMC_ConfigData(hsd->Instance, &config); + 800c65a: 6820 ldr r0, [r4, #0] + config.DPSM = SDMMC_DPSM_ENABLE; + 800c65c: 9305 str r3, [sp, #20] + (void)SDMMC_ConfigData(hsd->Instance, &config); + 800c65e: 4669 mov r1, sp + 800c660: f000 fbae bl 800cdc0 + errorstate = SDMMC_CmdStatusRegister(hsd->Instance); + 800c664: 6820 ldr r0, [r4, #0] + 800c666: f000 fe40 bl 800d2ea + if(errorstate != HAL_SD_ERROR_NONE) + 800c66a: 2800 cmp r0, #0 + 800c66c: d1df bne.n 800c62e + uint32_t *pData = pSDstatus; + 800c66e: af06 add r7, sp, #24 + while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DATAEND)) + 800c670: 6823 ldr r3, [r4, #0] + 800c672: 6b5a ldr r2, [r3, #52] ; 0x34 + 800c674: f412 7f95 tst.w r2, #298 ; 0x12a + 800c678: d00a beq.n 800c690 + if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT)) + 800c67a: 6b5a ldr r2, [r3, #52] ; 0x34 + 800c67c: 0711 lsls r1, r2, #28 + 800c67e: d46f bmi.n 800c760 + else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL)) + 800c680: 6b5a ldr r2, [r3, #52] ; 0x34 + 800c682: 0792 lsls r2, r2, #30 + 800c684: d46a bmi.n 800c75c + else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)) + 800c686: 6b5b ldr r3, [r3, #52] ; 0x34 + 800c688: 069b lsls r3, r3, #26 + 800c68a: d51e bpl.n 800c6ca + return HAL_SD_ERROR_RX_OVERRUN; + 800c68c: 2020 movs r0, #32 + 800c68e: e7bf b.n 800c610 + if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOHF)) + 800c690: 6b5b ldr r3, [r3, #52] ; 0x34 + 800c692: 0418 lsls r0, r3, #16 + 800c694: d508 bpl.n 800c6a8 + 800c696: f107 0820 add.w r8, r7, #32 + *pData = SDMMC_ReadFIFO(hsd->Instance); + 800c69a: 6820 ldr r0, [r4, #0] + 800c69c: f000 fb54 bl 800cd48 + 800c6a0: f847 0b04 str.w r0, [r7], #4 + for(count = 0U; count < 8U; count++) + 800c6a4: 45b8 cmp r8, r7 + 800c6a6: d1f8 bne.n 800c69a + if((HAL_GetTick() - tickstart) >= SDMMC_DATATIMEOUT) + 800c6a8: f7fa fd20 bl 80070ec + 800c6ac: 1b80 subs r0, r0, r6 + 800c6ae: 3001 adds r0, #1 + 800c6b0: d1de bne.n 800c670 + return HAL_SD_ERROR_TIMEOUT; + 800c6b2: f04f 4000 mov.w r0, #2147483648 ; 0x80000000 + if(errorstate != HAL_SD_ERROR_NONE) + 800c6b6: e7ab b.n 800c610 + *pData = SDMMC_ReadFIFO(hsd->Instance); + 800c6b8: f000 fb46 bl 800cd48 + 800c6bc: f847 0b04 str.w r0, [r7], #4 + if((HAL_GetTick() - tickstart) >= SDMMC_DATATIMEOUT) + 800c6c0: f7fa fd14 bl 80070ec + 800c6c4: 1b80 subs r0, r0, r6 + 800c6c6: 3001 adds r0, #1 + 800c6c8: d0f3 beq.n 800c6b2 + while ((__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DPSMACT))) + 800c6ca: 6820 ldr r0, [r4, #0] + 800c6cc: 6b43 ldr r3, [r0, #52] ; 0x34 + 800c6ce: f413 5380 ands.w r3, r3, #4096 ; 0x1000 + 800c6d2: d1f1 bne.n 800c6b8 + pStatus->DataBusWidth = (uint8_t)((sd_status[0] & 0xC0U) >> 6U); + 800c6d4: 9906 ldr r1, [sp, #24] + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + 800c6d6: 4a24 ldr r2, [pc, #144] ; (800c768 ) + 800c6d8: 6382 str r2, [r0, #56] ; 0x38 + pStatus->DataBusWidth = (uint8_t)((sd_status[0] & 0xC0U) >> 6U); + 800c6da: f3c1 1281 ubfx r2, r1, #6, #2 + 800c6de: 702a strb r2, [r5, #0] + pStatus->SecuredMode = (uint8_t)((sd_status[0] & 0x20U) >> 5U); + 800c6e0: f3c1 1240 ubfx r2, r1, #5, #1 + 800c6e4: 706a strb r2, [r5, #1] + pStatus->CardType = (uint16_t)(((sd_status[0] & 0x00FF0000U) >> 8U) | ((sd_status[0] & 0xFF000000U) >> 24U)); + 800c6e6: 0a0a lsrs r2, r1, #8 + 800c6e8: f022 02ff bic.w r2, r2, #255 ; 0xff + 800c6ec: ea42 6211 orr.w r2, r2, r1, lsr #24 + 800c6f0: b292 uxth r2, r2 + 800c6f2: 806a strh r2, [r5, #2] + pStatus->ProtectedAreaSize = (((sd_status[1] & 0xFFU) << 24U) | ((sd_status[1] & 0xFF00U) << 8U) | + 800c6f4: 9a07 ldr r2, [sp, #28] + 800c6f6: ba12 rev r2, r2 + 800c6f8: 606a str r2, [r5, #4] + pStatus->SpeedClass = (uint8_t)(sd_status[2] & 0xFFU); + 800c6fa: 9a08 ldr r2, [sp, #32] + 800c6fc: b2d1 uxtb r1, r2 + 800c6fe: 7229 strb r1, [r5, #8] + pStatus->PerformanceMove = (uint8_t)((sd_status[2] & 0xFF00U) >> 8U); + 800c700: f3c2 2107 ubfx r1, r2, #8, #8 + 800c704: 7269 strb r1, [r5, #9] + pStatus->AllocationUnitSize = (uint8_t)((sd_status[2] & 0xF00000U) >> 20U); + 800c706: f3c2 5103 ubfx r1, r2, #20, #4 + 800c70a: 72a9 strb r1, [r5, #10] + pStatus->EraseSize = (uint16_t)(((sd_status[2] & 0xFF000000U) >> 16U) | (sd_status[3] & 0xFFU)); + 800c70c: 9909 ldr r1, [sp, #36] ; 0x24 + 800c70e: 0c12 lsrs r2, r2, #16 + 800c710: b2c8 uxtb r0, r1 + 800c712: f022 02ff bic.w r2, r2, #255 ; 0xff + 800c716: 4302 orrs r2, r0 + 800c718: 81aa strh r2, [r5, #12] + pStatus->EraseTimeout = (uint8_t)((sd_status[3] & 0xFC00U) >> 10U); + 800c71a: f3c1 2285 ubfx r2, r1, #10, #6 + 800c71e: 73aa strb r2, [r5, #14] + pStatus->EraseOffset = (uint8_t)((sd_status[3] & 0x0300U) >> 8U); + 800c720: f3c1 2201 ubfx r2, r1, #8, #2 + 800c724: 73ea strb r2, [r5, #15] + pStatus->UhsSpeedGrade = (uint8_t)((sd_status[3] & 0x00F0U) >> 4U); + 800c726: f3c1 1203 ubfx r2, r1, #4, #4 + 800c72a: 742a strb r2, [r5, #16] + pStatus->UhsAllocationUnitSize = (uint8_t)(sd_status[3] & 0x000FU) ; + 800c72c: f001 010f and.w r1, r1, #15 + pStatus->VideoSpeedClass = (uint8_t)((sd_status[4] & 0xFF000000U) >> 24U); + 800c730: f89d 202b ldrb.w r2, [sp, #43] ; 0x2b + pStatus->UhsAllocationUnitSize = (uint8_t)(sd_status[3] & 0x000FU) ; + 800c734: 7469 strb r1, [r5, #17] + pStatus->VideoSpeedClass = (uint8_t)((sd_status[4] & 0xFF000000U) >> 24U); + 800c736: 74aa strb r2, [r5, #18] + HAL_StatusTypeDef status = HAL_OK; + 800c738: 461d mov r5, r3 + errorstate = SDMMC_CmdBlockLength(hsd->Instance, BLOCKSIZE); + 800c73a: 6820 ldr r0, [r4, #0] + 800c73c: f44f 7100 mov.w r1, #512 ; 0x200 + 800c740: f000 fc1a bl 800cf78 + if(errorstate != HAL_SD_ERROR_NONE) + 800c744: b130 cbz r0, 800c754 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c746: 6823 ldr r3, [r4, #0] + 800c748: 4a06 ldr r2, [pc, #24] ; (800c764 ) + 800c74a: 639a str r2, [r3, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c74c: 2501 movs r5, #1 + hsd->ErrorCode = errorstate; + 800c74e: 63a0 str r0, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c750: f884 5034 strb.w r5, [r4, #52] ; 0x34 +} + 800c754: 4628 mov r0, r5 + 800c756: b016 add sp, #88 ; 0x58 + 800c758: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + return HAL_SD_ERROR_DATA_CRC_FAIL; + 800c75c: 2002 movs r0, #2 + 800c75e: e757 b.n 800c610 + return HAL_SD_ERROR_DATA_TIMEOUT; + 800c760: 2008 movs r0, #8 + 800c762: e755 b.n 800c610 + 800c764: 1fe00fff .word 0x1fe00fff + 800c768: 18000f3a .word 0x18000f3a + +0800c76c : + pCardInfo->CardType = (uint32_t)(hsd->SdCard.CardType); + 800c76c: 6bc3 ldr r3, [r0, #60] ; 0x3c + 800c76e: 600b str r3, [r1, #0] + pCardInfo->CardVersion = (uint32_t)(hsd->SdCard.CardVersion); + 800c770: 6c03 ldr r3, [r0, #64] ; 0x40 + 800c772: 604b str r3, [r1, #4] + pCardInfo->Class = (uint32_t)(hsd->SdCard.Class); + 800c774: 6c43 ldr r3, [r0, #68] ; 0x44 + 800c776: 608b str r3, [r1, #8] + pCardInfo->RelCardAdd = (uint32_t)(hsd->SdCard.RelCardAdd); + 800c778: 6c83 ldr r3, [r0, #72] ; 0x48 + 800c77a: 60cb str r3, [r1, #12] + pCardInfo->BlockNbr = (uint32_t)(hsd->SdCard.BlockNbr); + 800c77c: 6cc3 ldr r3, [r0, #76] ; 0x4c + 800c77e: 610b str r3, [r1, #16] + pCardInfo->BlockSize = (uint32_t)(hsd->SdCard.BlockSize); + 800c780: 6d03 ldr r3, [r0, #80] ; 0x50 + 800c782: 614b str r3, [r1, #20] + pCardInfo->LogBlockNbr = (uint32_t)(hsd->SdCard.LogBlockNbr); + 800c784: 6d43 ldr r3, [r0, #84] ; 0x54 + 800c786: 618b str r3, [r1, #24] + pCardInfo->LogBlockSize = (uint32_t)(hsd->SdCard.LogBlockSize); + 800c788: 6d83 ldr r3, [r0, #88] ; 0x58 + 800c78a: 61cb str r3, [r1, #28] +} + 800c78c: 2000 movs r0, #0 + 800c78e: 4770 bx lr + +0800c790 : +{ + 800c790: b530 push {r4, r5, lr} + hsd->State = HAL_SD_STATE_BUSY; + 800c792: 2303 movs r3, #3 + 800c794: f880 3034 strb.w r3, [r0, #52] ; 0x34 + if(hsd->SdCard.CardType != CARD_SECURED) + 800c798: 6bc3 ldr r3, [r0, #60] ; 0x3c + 800c79a: 2b03 cmp r3, #3 +{ + 800c79c: b08b sub sp, #44 ; 0x2c + 800c79e: 4604 mov r4, r0 + 800c7a0: 460d mov r5, r1 + if(hsd->SdCard.CardType != CARD_SECURED) + 800c7a2: d002 beq.n 800c7aa + if(WideMode == SDMMC_BUS_WIDE_8B) + 800c7a4: f5b1 4f00 cmp.w r1, #32768 ; 0x8000 + 800c7a8: d103 bne.n 800c7b2 + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + 800c7aa: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c7ac: f043 5380 orr.w r3, r3, #268435456 ; 0x10000000 + 800c7b0: e049 b.n 800c846 + else if(WideMode == SDMMC_BUS_WIDE_4B) + 800c7b2: f5b1 4f80 cmp.w r1, #16384 ; 0x4000 + 800c7b6: d123 bne.n 800c800 + uint32_t scr[2U] = {0UL, 0UL}; + 800c7b8: 2100 movs r1, #0 + if((SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED) + 800c7ba: 6800 ldr r0, [r0, #0] + uint32_t scr[2U] = {0UL, 0UL}; + 800c7bc: e9cd 1104 strd r1, r1, [sp, #16] + if((SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED) + 800c7c0: f000 fafb bl 800cdba + 800c7c4: 0180 lsls r0, r0, #6 + 800c7c6: d435 bmi.n 800c834 + errorstate = SD_FindSCR(hsd, scr); + 800c7c8: a904 add r1, sp, #16 + 800c7ca: 4620 mov r0, r4 + 800c7cc: f7ff fa32 bl 800bc34 + if(errorstate != HAL_SD_ERROR_NONE) + 800c7d0: b960 cbnz r0, 800c7ec + if((scr[1U] & SDMMC_WIDE_BUS_SUPPORT) != SDMMC_ALLZERO) + 800c7d2: 9b05 ldr r3, [sp, #20] + 800c7d4: 0359 lsls r1, r3, #13 + 800c7d6: d530 bpl.n 800c83a + errorstate = SDMMC_CmdAppCommand(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); + 800c7d8: 6ca1 ldr r1, [r4, #72] ; 0x48 + 800c7da: 6820 ldr r0, [r4, #0] + 800c7dc: 0409 lsls r1, r1, #16 + 800c7de: f000 fd04 bl 800d1ea + if(errorstate != HAL_SD_ERROR_NONE) + 800c7e2: b918 cbnz r0, 800c7ec + errorstate = SDMMC_CmdBusWidth(hsd->Instance, 2U); + 800c7e4: 2102 movs r1, #2 + errorstate = SDMMC_CmdBusWidth(hsd->Instance, 0U); + 800c7e6: 6820 ldr r0, [r4, #0] + 800c7e8: f000 fd18 bl 800d21c + hsd->ErrorCode |= errorstate; + 800c7ec: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c7ee: 4318 orrs r0, r3 + 800c7f0: 63a0 str r0, [r4, #56] ; 0x38 + if(hsd->ErrorCode != HAL_SD_ERROR_NONE) + 800c7f2: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c7f4: b34b cbz r3, 800c84a + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c7f6: 6823 ldr r3, [r4, #0] + 800c7f8: 4a42 ldr r2, [pc, #264] ; (800c904 ) + 800c7fa: 639a str r2, [r3, #56] ; 0x38 + status = HAL_ERROR; + 800c7fc: 2501 movs r5, #1 + 800c7fe: e054 b.n 800c8aa + else if(WideMode == SDMMC_BUS_WIDE_1B) + 800c800: b9f1 cbnz r1, 800c840 + if((SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED) + 800c802: 6800 ldr r0, [r0, #0] + uint32_t scr[2U] = {0UL, 0UL}; + 800c804: e9cd 1104 strd r1, r1, [sp, #16] + if((SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED) + 800c808: f000 fad7 bl 800cdba + 800c80c: 0182 lsls r2, r0, #6 + 800c80e: d411 bmi.n 800c834 + errorstate = SD_FindSCR(hsd, scr); + 800c810: a904 add r1, sp, #16 + 800c812: 4620 mov r0, r4 + 800c814: f7ff fa0e bl 800bc34 + if(errorstate != HAL_SD_ERROR_NONE) + 800c818: 2800 cmp r0, #0 + 800c81a: d1e7 bne.n 800c7ec + if((scr[1U] & SDMMC_SINGLE_BUS_SUPPORT) != SDMMC_ALLZERO) + 800c81c: 9b05 ldr r3, [sp, #20] + 800c81e: 03db lsls r3, r3, #15 + 800c820: d50b bpl.n 800c83a + errorstate = SDMMC_CmdAppCommand(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); + 800c822: 6ca1 ldr r1, [r4, #72] ; 0x48 + 800c824: 6820 ldr r0, [r4, #0] + 800c826: 0409 lsls r1, r1, #16 + 800c828: f000 fcdf bl 800d1ea + if(errorstate != HAL_SD_ERROR_NONE) + 800c82c: 2800 cmp r0, #0 + 800c82e: d1dd bne.n 800c7ec + errorstate = SDMMC_CmdBusWidth(hsd->Instance, 0U); + 800c830: 4601 mov r1, r0 + 800c832: e7d8 b.n 800c7e6 + return HAL_SD_ERROR_LOCK_UNLOCK_FAILED; + 800c834: f44f 6000 mov.w r0, #2048 ; 0x800 + 800c838: e7d8 b.n 800c7ec + return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE; + 800c83a: f04f 6080 mov.w r0, #67108864 ; 0x4000000 + 800c83e: e7d5 b.n 800c7ec + hsd->ErrorCode |= HAL_SD_ERROR_PARAM; + 800c840: 6b83 ldr r3, [r0, #56] ; 0x38 + 800c842: f043 6300 orr.w r3, r3, #134217728 ; 0x8000000 + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + 800c846: 63a3 str r3, [r4, #56] ; 0x38 + 800c848: e7d3 b.n 800c7f2 + sdmmc_clk = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SDMMC1); + 800c84a: f44f 2000 mov.w r0, #524288 ; 0x80000 + 800c84e: f7fd f8af bl 80099b0 + if (sdmmc_clk != 0U) + 800c852: 2800 cmp r0, #0 + 800c854: d051 beq.n 800c8fa + Init.ClockEdge = hsd->Init.ClockEdge; + 800c856: 6863 ldr r3, [r4, #4] + 800c858: 9304 str r3, [sp, #16] + Init.ClockPowerSave = hsd->Init.ClockPowerSave; + 800c85a: 68a3 ldr r3, [r4, #8] + if (hsd->Init.ClockDiv >= (sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ))) + 800c85c: 492a ldr r1, [pc, #168] ; (800c908 ) + 800c85e: fbb0 f2f1 udiv r2, r0, r1 + Init.BusWide = WideMode; + 800c862: e9cd 3505 strd r3, r5, [sp, #20] + Init.HardwareFlowControl = hsd->Init.HardwareFlowControl; + 800c866: 6923 ldr r3, [r4, #16] + 800c868: 9307 str r3, [sp, #28] + if (hsd->Init.ClockDiv >= (sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ))) + 800c86a: 6963 ldr r3, [r4, #20] + 800c86c: 4293 cmp r3, r2 + 800c86e: d301 bcc.n 800c874 + Init.ClockDiv = sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ); + 800c870: 9308 str r3, [sp, #32] + 800c872: e00d b.n 800c890 + else if (hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) + 800c874: 6de5 ldr r5, [r4, #92] ; 0x5c + 800c876: f5b5 7f00 cmp.w r5, #512 ; 0x200 + 800c87a: d0f9 beq.n 800c870 + else if (hsd->SdCard.CardSpeed == CARD_HIGH_SPEED) + 800c87c: f5b5 7f80 cmp.w r5, #256 ; 0x100 + 800c880: d12e bne.n 800c8e0 + if (hsd->Init.ClockDiv == 0U) + 800c882: bb3b cbnz r3, 800c8d4 + if (sdmmc_clk > SD_HIGH_SPEED_FREQ) + 800c884: 4288 cmp r0, r1 + 800c886: d923 bls.n 800c8d0 + Init.ClockDiv = sdmmc_clk / (2U * SD_HIGH_SPEED_FREQ); + 800c888: 4b20 ldr r3, [pc, #128] ; (800c90c ) + 800c88a: fbb0 f0f3 udiv r0, r0, r3 + 800c88e: 9008 str r0, [sp, #32] + Init.Transceiver = hsd->Init.Transceiver; + 800c890: 69a3 ldr r3, [r4, #24] + 800c892: 9309 str r3, [sp, #36] ; 0x24 + (void)SDMMC_Init(hsd->Instance, Init); + 800c894: ab0a add r3, sp, #40 ; 0x28 + 800c896: e913 0007 ldmdb r3, {r0, r1, r2} + 800c89a: e88d 0007 stmia.w sp, {r0, r1, r2} + 800c89e: ab04 add r3, sp, #16 + 800c8a0: cb0e ldmia r3, {r1, r2, r3} + 800c8a2: 6820 ldr r0, [r4, #0] + 800c8a4: f000 fa36 bl 800cd14 + HAL_StatusTypeDef status = HAL_OK; + 800c8a8: 2500 movs r5, #0 + errorstate = SDMMC_CmdBlockLength(hsd->Instance, BLOCKSIZE); + 800c8aa: 6820 ldr r0, [r4, #0] + 800c8ac: f44f 7100 mov.w r1, #512 ; 0x200 + 800c8b0: f000 fb62 bl 800cf78 + if(errorstate != HAL_SD_ERROR_NONE) + 800c8b4: b130 cbz r0, 800c8c4 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c8b6: 6823 ldr r3, [r4, #0] + 800c8b8: 4a12 ldr r2, [pc, #72] ; (800c904 ) + 800c8ba: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= errorstate; + 800c8bc: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c8be: 4318 orrs r0, r3 + 800c8c0: 63a0 str r0, [r4, #56] ; 0x38 + status = HAL_ERROR; + 800c8c2: 2501 movs r5, #1 + hsd->State = HAL_SD_STATE_READY; + 800c8c4: 2301 movs r3, #1 +} + 800c8c6: 4628 mov r0, r5 + hsd->State = HAL_SD_STATE_READY; + 800c8c8: f884 3034 strb.w r3, [r4, #52] ; 0x34 +} + 800c8cc: b00b add sp, #44 ; 0x2c + 800c8ce: bd30 pop {r4, r5, pc} + Init.ClockDiv = hsd->Init.ClockDiv; + 800c8d0: 2300 movs r3, #0 + 800c8d2: e7cd b.n 800c870 + if ((sdmmc_clk/(2U * hsd->Init.ClockDiv)) > SD_HIGH_SPEED_FREQ) + 800c8d4: 005a lsls r2, r3, #1 + 800c8d6: fbb0 f2f2 udiv r2, r0, r2 + 800c8da: 428a cmp r2, r1 + 800c8dc: d9c8 bls.n 800c870 + 800c8de: e7d3 b.n 800c888 + if (hsd->Init.ClockDiv == 0U) + 800c8e0: 490b ldr r1, [pc, #44] ; (800c910 ) + 800c8e2: b91b cbnz r3, 800c8ec + if (sdmmc_clk > SD_NORMAL_SPEED_FREQ) + 800c8e4: 4288 cmp r0, r1 + 800c8e6: d9f3 bls.n 800c8d0 + Init.ClockDiv = sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ); + 800c8e8: 9208 str r2, [sp, #32] + 800c8ea: e7d1 b.n 800c890 + if ((sdmmc_clk/(2U * hsd->Init.ClockDiv)) > SD_NORMAL_SPEED_FREQ) + 800c8ec: 005d lsls r5, r3, #1 + 800c8ee: fbb0 f0f5 udiv r0, r0, r5 + Init.ClockDiv = sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ); + 800c8f2: 4288 cmp r0, r1 + 800c8f4: bf88 it hi + 800c8f6: 4613 movhi r3, r2 + 800c8f8: e7ba b.n 800c870 + hsd->ErrorCode |= SDMMC_ERROR_INVALID_PARAMETER; + 800c8fa: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c8fc: f043 6300 orr.w r3, r3, #134217728 ; 0x8000000 + 800c900: 63a3 str r3, [r4, #56] ; 0x38 + 800c902: e77b b.n 800c7fc + 800c904: 1fe00fff .word 0x1fe00fff + 800c908: 02faf080 .word 0x02faf080 + 800c90c: 05f5e100 .word 0x05f5e100 + 800c910: 017d7840 .word 0x017d7840 + +0800c914 : + errorstate = SDMMC_CmdSendStatus(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); + 800c914: 6c81 ldr r1, [r0, #72] ; 0x48 +{ + 800c916: b510 push {r4, lr} + errorstate = SDMMC_CmdSendStatus(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); + 800c918: 0409 lsls r1, r1, #16 +{ + 800c91a: 4604 mov r4, r0 + errorstate = SDMMC_CmdSendStatus(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); + 800c91c: 6800 ldr r0, [r0, #0] + 800c91e: f000 fccb bl 800d2b8 + if(errorstate != HAL_SD_ERROR_NONE) + 800c922: 4601 mov r1, r0 + 800c924: b928 cbnz r0, 800c932 + *pCardStatus = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1); + 800c926: 6820 ldr r0, [r4, #0] + 800c928: f000 fa47 bl 800cdba +} + 800c92c: f3c0 2043 ubfx r0, r0, #9, #4 + 800c930: bd10 pop {r4, pc} + hsd->ErrorCode |= errorstate; + 800c932: 6ba0 ldr r0, [r4, #56] ; 0x38 + 800c934: 4308 orrs r0, r1 + 800c936: 63a0 str r0, [r4, #56] ; 0x38 + uint32_t resp1 = 0; + 800c938: 2000 movs r0, #0 + 800c93a: e7f7 b.n 800c92c + +0800c93c : +{ + 800c93c: b570 push {r4, r5, r6, lr} + if(hsd == NULL) + 800c93e: 4604 mov r4, r0 +{ + 800c940: b086 sub sp, #24 + if(hsd == NULL) + 800c942: b918 cbnz r0, 800c94c + return HAL_ERROR; + 800c944: 2501 movs r5, #1 +} + 800c946: 4628 mov r0, r5 + 800c948: b006 add sp, #24 + 800c94a: bd70 pop {r4, r5, r6, pc} + if(hsd->State == HAL_SD_STATE_RESET) + 800c94c: f890 3034 ldrb.w r3, [r0, #52] ; 0x34 + 800c950: f003 02ff and.w r2, r3, #255 ; 0xff + 800c954: b913 cbnz r3, 800c95c + hsd->Lock = HAL_UNLOCKED; + 800c956: 7702 strb r2, [r0, #28] + HAL_SD_MspInit(hsd); + 800c958: f7ff fa5a bl 800be10 + hsd->State = HAL_SD_STATE_BUSY; + 800c95c: 2303 movs r3, #3 + 800c95e: f884 3034 strb.w r3, [r4, #52] ; 0x34 + if (HAL_SD_InitCard(hsd) != HAL_OK) + 800c962: 4620 mov r0, r4 + 800c964: f7ff fcea bl 800c33c + 800c968: 2800 cmp r0, #0 + 800c96a: d1eb bne.n 800c944 + if( HAL_SD_GetCardStatus(hsd, &CardStatus) != HAL_OK) + 800c96c: a901 add r1, sp, #4 + 800c96e: 4620 mov r0, r4 + 800c970: f7ff fe3e bl 800c5f0 + 800c974: 2800 cmp r0, #0 + 800c976: d1e5 bne.n 800c944 + if ((hsd->SdCard.CardType == CARD_SDHC_SDXC) && ((speedgrade != 0U) || (unitsize != 0U))) + 800c978: 6be1 ldr r1, [r4, #60] ; 0x3c + speedgrade = CardStatus.UhsSpeedGrade; + 800c97a: f89d 2014 ldrb.w r2, [sp, #20] + unitsize = CardStatus.UhsAllocationUnitSize; + 800c97e: f89d 3015 ldrb.w r3, [sp, #21] + if ((hsd->SdCard.CardType == CARD_SDHC_SDXC) && ((speedgrade != 0U) || (unitsize != 0U))) + 800c982: 2901 cmp r1, #1 + speedgrade = CardStatus.UhsSpeedGrade; + 800c984: b2d2 uxtb r2, r2 + unitsize = CardStatus.UhsAllocationUnitSize; + 800c986: b2db uxtb r3, r3 + if ((hsd->SdCard.CardType == CARD_SDHC_SDXC) && ((speedgrade != 0U) || (unitsize != 0U))) + 800c988: d11c bne.n 800c9c4 + 800c98a: 4313 orrs r3, r2 + hsd->SdCard.CardSpeed = CARD_ULTRA_HIGH_SPEED; + 800c98c: bf14 ite ne + 800c98e: f44f 7300 movne.w r3, #512 ; 0x200 + hsd->SdCard.CardSpeed = CARD_HIGH_SPEED; + 800c992: f44f 7380 moveq.w r3, #256 ; 0x100 + 800c996: 65e3 str r3, [r4, #92] ; 0x5c + if(HAL_SD_ConfigWideBusOperation(hsd, hsd->Init.BusWide) != HAL_OK) + 800c998: 68e1 ldr r1, [r4, #12] + 800c99a: 4620 mov r0, r4 + 800c99c: f7ff fef8 bl 800c790 + 800c9a0: 4605 mov r5, r0 + 800c9a2: 2800 cmp r0, #0 + 800c9a4: d1ce bne.n 800c944 + tickstart = HAL_GetTick(); + 800c9a6: f7fa fba1 bl 80070ec + 800c9aa: 4606 mov r6, r0 + while((HAL_SD_GetCardState(hsd) != HAL_SD_CARD_TRANSFER)) + 800c9ac: 4620 mov r0, r4 + 800c9ae: f7ff ffb1 bl 800c914 + 800c9b2: 2804 cmp r0, #4 + 800c9b4: d108 bne.n 800c9c8 + hsd->ErrorCode = HAL_SD_ERROR_NONE; + 800c9b6: 2300 movs r3, #0 + 800c9b8: 63a3 str r3, [r4, #56] ; 0x38 + hsd->Context = SD_CONTEXT_NONE; + 800c9ba: 6323 str r3, [r4, #48] ; 0x30 + hsd->State = HAL_SD_STATE_READY; + 800c9bc: 2301 movs r3, #1 + 800c9be: f884 3034 strb.w r3, [r4, #52] ; 0x34 + return HAL_OK; + 800c9c2: e7c0 b.n 800c946 + hsd->SdCard.CardSpeed = CARD_NORMAL_SPEED; + 800c9c4: 65e0 str r0, [r4, #92] ; 0x5c + 800c9c6: e7e7 b.n 800c998 + if((HAL_GetTick()-tickstart) >= SDMMC_DATATIMEOUT) + 800c9c8: f7fa fb90 bl 80070ec + 800c9cc: 1b80 subs r0, r0, r6 + 800c9ce: 3001 adds r0, #1 + 800c9d0: d1ec bne.n 800c9ac + hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT; + 800c9d2: f04f 4300 mov.w r3, #2147483648 ; 0x80000000 + 800c9d6: 63a3 str r3, [r4, #56] ; 0x38 + hsd->State= HAL_SD_STATE_READY; + 800c9d8: 2301 movs r3, #1 + 800c9da: f884 3034 strb.w r3, [r4, #52] ; 0x34 + hsd->Context = SD_CONTEXT_NONE; + 800c9de: 2300 movs r3, #0 + 800c9e0: 6323 str r3, [r4, #48] ; 0x30 + return HAL_TIMEOUT; + 800c9e2: 2503 movs r5, #3 + 800c9e4: e7af b.n 800c946 + ... + +0800c9e8 : +{ + 800c9e8: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + uint32_t SD_hs[16] = {0}; + 800c9ec: 2640 movs r6, #64 ; 0x40 +{ + 800c9ee: b096 sub sp, #88 ; 0x58 + 800c9f0: 4605 mov r5, r0 + uint32_t SD_hs[16] = {0}; + 800c9f2: 4632 mov r2, r6 + 800c9f4: 2100 movs r1, #0 + 800c9f6: a806 add r0, sp, #24 + 800c9f8: f000 fe3c bl 800d674 + uint32_t Timeout = HAL_GetTick(); + 800c9fc: f7fa fb76 bl 80070ec + if(hsd->SdCard.CardSpeed == CARD_NORMAL_SPEED) + 800ca00: 6deb ldr r3, [r5, #92] ; 0x5c + uint32_t Timeout = HAL_GetTick(); + 800ca02: 4680 mov r8, r0 + if(hsd->SdCard.CardSpeed == CARD_NORMAL_SPEED) + 800ca04: 2b00 cmp r3, #0 + 800ca06: d066 beq.n 800cad6 + if(hsd->SdCard.CardSpeed == CARD_HIGH_SPEED) + 800ca08: f5b3 7f80 cmp.w r3, #256 ; 0x100 + 800ca0c: d004 beq.n 800ca18 + uint32_t errorstate = HAL_SD_ERROR_NONE; + 800ca0e: 2400 movs r4, #0 +} + 800ca10: 4620 mov r0, r4 + 800ca12: b016 add sp, #88 ; 0x58 + 800ca14: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + hsd->Instance->DCTRL = 0; + 800ca18: 6828 ldr r0, [r5, #0] + 800ca1a: 2300 movs r3, #0 + 800ca1c: 62c3 str r3, [r0, #44] ; 0x2c + errorstate = SDMMC_CmdBlockLength(hsd->Instance, 64U); + 800ca1e: 4631 mov r1, r6 + 800ca20: f000 faaa bl 800cf78 + if (errorstate != HAL_SD_ERROR_NONE) + 800ca24: 4604 mov r4, r0 + 800ca26: 2800 cmp r0, #0 + 800ca28: d1f2 bne.n 800ca10 + sdmmc_datainitstructure.DataTimeOut = SDMMC_DATATIMEOUT; + 800ca2a: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + sdmmc_datainitstructure.DataLength = 64U; + 800ca2e: e9cd 3600 strd r3, r6, [sp] + sdmmc_datainitstructure.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + 800ca32: 2260 movs r2, #96 ; 0x60 + 800ca34: 2302 movs r3, #2 + 800ca36: e9cd 2302 strd r2, r3, [sp, #8] + sdmmc_datainitstructure.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + 800ca3a: 9004 str r0, [sp, #16] + sdmmc_datainitstructure.DPSM = SDMMC_DPSM_ENABLE; + 800ca3c: 2301 movs r3, #1 + if ( SDMMC_ConfigData(hsd->Instance, &sdmmc_datainitstructure) != HAL_OK) + 800ca3e: 6828 ldr r0, [r5, #0] + sdmmc_datainitstructure.DPSM = SDMMC_DPSM_ENABLE; + 800ca40: 9305 str r3, [sp, #20] + if ( SDMMC_ConfigData(hsd->Instance, &sdmmc_datainitstructure) != HAL_OK) + 800ca42: 4669 mov r1, sp + 800ca44: f000 f9bc bl 800cdc0 + 800ca48: 2800 cmp r0, #0 + 800ca4a: d147 bne.n 800cadc + errorstate = SDMMC_CmdSwitch(hsd->Instance,SDMMC_SDR25_SWITCH_PATTERN); + 800ca4c: 4925 ldr r1, [pc, #148] ; (800cae4 ) + 800ca4e: 6828 ldr r0, [r5, #0] + 800ca50: f000 fbfd bl 800d24e + if(errorstate != HAL_SD_ERROR_NONE) + 800ca54: 4604 mov r4, r0 + 800ca56: 2800 cmp r0, #0 + 800ca58: d1da bne.n 800ca10 + uint32_t count, loop = 0 ; + 800ca5a: 4607 mov r7, r0 + while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND| SDMMC_FLAG_DATAEND )) + 800ca5c: f240 592a movw r9, #1322 ; 0x52a + 800ca60: 682b ldr r3, [r5, #0] + 800ca62: 6b5e ldr r6, [r3, #52] ; 0x34 + 800ca64: ea16 0609 ands.w r6, r6, r9 + 800ca68: d005 beq.n 800ca76 + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT)) + 800ca6a: 6b5a ldr r2, [r3, #52] ; 0x34 + 800ca6c: 0710 lsls r0, r2, #28 + 800ca6e: d51e bpl.n 800caae + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DTIMEOUT); + 800ca70: 2208 movs r2, #8 + 800ca72: 639a str r2, [r3, #56] ; 0x38 + return errorstate; + 800ca74: e7cc b.n 800ca10 + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOHF)) + 800ca76: 6b5b ldr r3, [r3, #52] ; 0x34 + 800ca78: 041b lsls r3, r3, #16 + 800ca7a: d50b bpl.n 800ca94 + 800ca7c: ab06 add r3, sp, #24 + 800ca7e: eb03 1a47 add.w sl, r3, r7, lsl #5 + SD_hs[(8U*loop)+count] = SDMMC_ReadFIFO(hsd->Instance); + 800ca82: 6828 ldr r0, [r5, #0] + 800ca84: f000 f960 bl 800cd48 + for (count = 0U; count < 8U; count++) + 800ca88: 3601 adds r6, #1 + 800ca8a: 2e08 cmp r6, #8 + SD_hs[(8U*loop)+count] = SDMMC_ReadFIFO(hsd->Instance); + 800ca8c: f84a 0b04 str.w r0, [sl], #4 + for (count = 0U; count < 8U; count++) + 800ca90: d1f7 bne.n 800ca82 + loop ++; + 800ca92: 3701 adds r7, #1 + if((HAL_GetTick()-Timeout) >= SDMMC_DATATIMEOUT) + 800ca94: f7fa fb2a bl 80070ec + 800ca98: eba0 0008 sub.w r0, r0, r8 + 800ca9c: 3001 adds r0, #1 + 800ca9e: d1df bne.n 800ca60 + hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT; + 800caa0: f04f 4400 mov.w r4, #2147483648 ; 0x80000000 + hsd->State= HAL_SD_STATE_READY; + 800caa4: 2301 movs r3, #1 + hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT; + 800caa6: 63ac str r4, [r5, #56] ; 0x38 + hsd->State= HAL_SD_STATE_READY; + 800caa8: f885 3034 strb.w r3, [r5, #52] ; 0x34 + return HAL_SD_ERROR_TIMEOUT; + 800caac: e7b0 b.n 800ca10 + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL)) + 800caae: 6b5a ldr r2, [r3, #52] ; 0x34 + 800cab0: 0791 lsls r1, r2, #30 + 800cab2: d502 bpl.n 800caba + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DCRCFAIL); + 800cab4: 2402 movs r4, #2 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_RXOVERR); + 800cab6: 639c str r4, [r3, #56] ; 0x38 + return errorstate; + 800cab8: e7aa b.n 800ca10 + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)) + 800caba: 6b5a ldr r2, [r3, #52] ; 0x34 + 800cabc: 0692 lsls r2, r2, #26 + 800cabe: d501 bpl.n 800cac4 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_RXOVERR); + 800cac0: 2420 movs r4, #32 + 800cac2: e7f8 b.n 800cab6 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + 800cac4: 4a08 ldr r2, [pc, #32] ; (800cae8 ) + 800cac6: 639a str r2, [r3, #56] ; 0x38 + if ((((uint8_t*)SD_hs)[13] & 2U) != 2U) + 800cac8: f89d 3025 ldrb.w r3, [sp, #37] ; 0x25 + 800cacc: 079b lsls r3, r3, #30 + 800cace: d49e bmi.n 800ca0e + errorstate = SDMMC_ERROR_UNSUPPORTED_FEATURE; + 800cad0: f04f 5480 mov.w r4, #268435456 ; 0x10000000 + 800cad4: e79c b.n 800ca10 + return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE; + 800cad6: f04f 6480 mov.w r4, #67108864 ; 0x4000000 + 800cada: e799 b.n 800ca10 + return (HAL_SD_ERROR_GENERAL_UNKNOWN_ERR); + 800cadc: f44f 3480 mov.w r4, #65536 ; 0x10000 + 800cae0: e796 b.n 800ca10 + 800cae2: bf00 nop + 800cae4: 80ffff01 .word 0x80ffff01 + 800cae8: 18000f3a .word 0x18000f3a + +0800caec : +{ + 800caec: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + hsd->State = HAL_SD_STATE_BUSY; + 800caf0: 2303 movs r3, #3 + 800caf2: f880 3034 strb.w r3, [r0, #52] ; 0x34 + if(hsd->Init.Transceiver == SDMMC_TRANSCEIVER_ENABLE) + 800caf6: 6983 ldr r3, [r0, #24] + 800caf8: 2b01 cmp r3, #1 +{ + 800cafa: b096 sub sp, #88 ; 0x58 + 800cafc: 4604 mov r4, r0 + if(hsd->Init.Transceiver == SDMMC_TRANSCEIVER_ENABLE) + 800cafe: f040 80cf bne.w 800cca0 + switch (SpeedMode) + 800cb02: 2904 cmp r1, #4 + 800cb04: f200 80eb bhi.w 800ccde + 800cb08: e8df f011 tbh [pc, r1, lsl #1] + 800cb0c: 00150005 .word 0x00150005 + 800cb10: 001e00dc .word 0x001e00dc + 800cb14: 0031 .short 0x0031 + if ((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) || + 800cb16: 6dc3 ldr r3, [r0, #92] ; 0x5c + 800cb18: f5b3 7f00 cmp.w r3, #512 ; 0x200 + 800cb1c: d002 beq.n 800cb24 + 800cb1e: 6bc2 ldr r2, [r0, #60] ; 0x3c + 800cb20: 2a01 cmp r2, #1 + 800cb22: d10a bne.n 800cb3a + hsd->Instance->CLKCR |= 0x00100000U; + 800cb24: 6822 ldr r2, [r4, #0] + 800cb26: 6853 ldr r3, [r2, #4] + 800cb28: f443 1380 orr.w r3, r3, #1048576 ; 0x100000 + 800cb2c: 6053 str r3, [r2, #4] + if (SD_UltraHighSpeed(hsd) != HAL_SD_ERROR_NONE) + 800cb2e: 4620 mov r0, r4 + 800cb30: f7ff f8e6 bl 800bd00 + 800cb34: b920 cbnz r0, 800cb40 + switch (SpeedMode) + 800cb36: 2500 movs r5, #0 + 800cb38: e063 b.n 800cc02 + else if (hsd->SdCard.CardSpeed == CARD_HIGH_SPEED) + 800cb3a: f5b3 7f80 cmp.w r3, #256 ; 0x100 + (hsd->SdCard.CardSpeed == CARD_HIGH_SPEED) || + 800cb3e: d1fa bne.n 800cb36 + if (SD_HighSpeed(hsd) != HAL_SD_ERROR_NONE) + 800cb40: 4620 mov r0, r4 + 800cb42: f7ff ff51 bl 800c9e8 + 800cb46: e00f b.n 800cb68 + if ((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) || + 800cb48: 6dc3 ldr r3, [r0, #92] ; 0x5c + 800cb4a: f5b3 7f00 cmp.w r3, #512 ; 0x200 + 800cb4e: d003 beq.n 800cb58 + 800cb50: 6bc3 ldr r3, [r0, #60] ; 0x3c + 800cb52: 2b01 cmp r3, #1 + 800cb54: f040 8089 bne.w 800cc6a + hsd->Instance->CLKCR |= 0x00100000U; + 800cb58: 6822 ldr r2, [r4, #0] + 800cb5a: 6853 ldr r3, [r2, #4] + 800cb5c: f443 1380 orr.w r3, r3, #1048576 ; 0x100000 + 800cb60: 6053 str r3, [r2, #4] + if (SD_UltraHighSpeed(hsd) != HAL_SD_ERROR_NONE) + 800cb62: 4620 mov r0, r4 + 800cb64: f7ff f8cc bl 800bd00 + if (SD_HighSpeed(hsd) != HAL_SD_ERROR_NONE) + 800cb68: 2800 cmp r0, #0 + 800cb6a: d0e4 beq.n 800cb36 + 800cb6c: e07d b.n 800cc6a + if ((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) || + 800cb6e: 6dc3 ldr r3, [r0, #92] ; 0x5c + 800cb70: f5b3 7f00 cmp.w r3, #512 ; 0x200 + 800cb74: d002 beq.n 800cb7c + 800cb76: 6bc3 ldr r3, [r0, #60] ; 0x3c + 800cb78: 2b01 cmp r3, #1 + 800cb7a: d176 bne.n 800cc6a + hsd->Instance->CLKCR |= 0x00100000U; + 800cb7c: 6822 ldr r2, [r4, #0] + 800cb7e: 6853 ldr r3, [r2, #4] + */ +static uint32_t SD_DDR_Mode(SD_HandleTypeDef *hsd) +{ + uint32_t errorstate = HAL_SD_ERROR_NONE; + SDMMC_DataInitTypeDef sdmmc_datainitstructure; + uint32_t SD_hs[16] = {0}; + 800cb80: 2540 movs r5, #64 ; 0x40 + hsd->Instance->CLKCR |= 0x00100000U; + 800cb82: f443 1380 orr.w r3, r3, #1048576 ; 0x100000 + 800cb86: 6053 str r3, [r2, #4] + uint32_t SD_hs[16] = {0}; + 800cb88: 2100 movs r1, #0 + 800cb8a: 462a mov r2, r5 + 800cb8c: a806 add r0, sp, #24 + 800cb8e: f000 fd71 bl 800d674 + uint32_t count, loop = 0 ; + uint32_t Timeout = HAL_GetTick(); + 800cb92: f7fa faab bl 80070ec + + if(hsd->SdCard.CardSpeed == CARD_NORMAL_SPEED) + 800cb96: 6de3 ldr r3, [r4, #92] ; 0x5c + uint32_t Timeout = HAL_GetTick(); + 800cb98: 4680 mov r8, r0 + if(hsd->SdCard.CardSpeed == CARD_NORMAL_SPEED) + 800cb9a: 2b00 cmp r3, #0 + 800cb9c: d065 beq.n 800cc6a + { + /* Standard Speed Card <= 12.5Mhz */ + return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE; + } + + if((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) && + 800cb9e: f5b3 7f00 cmp.w r3, #512 ; 0x200 + 800cba2: d1c8 bne.n 800cb36 + 800cba4: 69a6 ldr r6, [r4, #24] + 800cba6: 2e01 cmp r6, #1 + 800cba8: d1c5 bne.n 800cb36 + (hsd->Init.Transceiver == SDMMC_TRANSCEIVER_ENABLE)) + { + /* Initialize the Data control register */ + hsd->Instance->DCTRL = 0; + 800cbaa: 6820 ldr r0, [r4, #0] + 800cbac: 2300 movs r3, #0 + 800cbae: 62c3 str r3, [r0, #44] ; 0x2c + errorstate = SDMMC_CmdBlockLength(hsd->Instance, 64U); + 800cbb0: 4629 mov r1, r5 + 800cbb2: f000 f9e1 bl 800cf78 + + if (errorstate != HAL_SD_ERROR_NONE) + 800cbb6: 2800 cmp r0, #0 + 800cbb8: d157 bne.n 800cc6a + { + return errorstate; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + sdmmc_datainitstructure.DataTimeOut = SDMMC_DATATIMEOUT; + 800cbba: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + sdmmc_datainitstructure.DataLength = 64U; + 800cbbe: e9cd 3500 strd r3, r5, [sp] + sdmmc_datainitstructure.DataBlockSize = SDMMC_DATABLOCK_SIZE_64B ; + sdmmc_datainitstructure.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + sdmmc_datainitstructure.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + sdmmc_datainitstructure.DPSM = SDMMC_DPSM_ENABLE; + 800cbc2: e9cd 0604 strd r0, r6, [sp, #16] + sdmmc_datainitstructure.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + 800cbc6: 2260 movs r2, #96 ; 0x60 + 800cbc8: 2302 movs r3, #2 + + if ( SDMMC_ConfigData(hsd->Instance, &sdmmc_datainitstructure) != HAL_OK) + 800cbca: 6820 ldr r0, [r4, #0] + 800cbcc: 4669 mov r1, sp + sdmmc_datainitstructure.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + 800cbce: e9cd 2302 strd r2, r3, [sp, #8] + if ( SDMMC_ConfigData(hsd->Instance, &sdmmc_datainitstructure) != HAL_OK) + 800cbd2: f000 f8f5 bl 800cdc0 + 800cbd6: 4605 mov r5, r0 + 800cbd8: 2800 cmp r0, #0 + 800cbda: d146 bne.n 800cc6a + { + return (HAL_SD_ERROR_GENERAL_UNKNOWN_ERR); + } + + errorstate = SDMMC_CmdSwitch(hsd->Instance, SDMMC_DDR50_SWITCH_PATTERN); + 800cbdc: 494a ldr r1, [pc, #296] ; (800cd08 ) + 800cbde: 6820 ldr r0, [r4, #0] + 800cbe0: f000 fb35 bl 800d24e + if(errorstate != HAL_SD_ERROR_NONE) + 800cbe4: 4607 mov r7, r0 + 800cbe6: 2800 cmp r0, #0 + 800cbe8: d13f bne.n 800cc6a + { + return errorstate; + } + + while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND| SDMMC_FLAG_DATAEND )) + 800cbea: f240 592a movw r9, #1322 ; 0x52a + 800cbee: 6823 ldr r3, [r4, #0] + 800cbf0: 6b5e ldr r6, [r3, #52] ; 0x34 + 800cbf2: ea16 0609 ands.w r6, r6, r9 + 800cbf6: d01d beq.n 800cc34 + hsd->State= HAL_SD_STATE_READY; + return HAL_SD_ERROR_TIMEOUT; + } + } + + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT)) + 800cbf8: 6b5a ldr r2, [r3, #52] ; 0x34 + 800cbfa: 0710 lsls r0, r2, #28 + 800cbfc: d53b bpl.n 800cc76 + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DTIMEOUT); + 800cbfe: 2208 movs r2, #8 + 800cc00: 639a str r2, [r3, #56] ; 0x38 + tickstart = HAL_GetTick(); + 800cc02: f7fa fa73 bl 80070ec + 800cc06: 4606 mov r6, r0 + while ((HAL_SD_GetCardState(hsd) != HAL_SD_CARD_TRANSFER)) + 800cc08: 4620 mov r0, r4 + 800cc0a: f7ff fe83 bl 800c914 + 800cc0e: 2804 cmp r0, #4 + 800cc10: d169 bne.n 800cce6 + errorstate = SDMMC_CmdBlockLength(hsd->Instance, BLOCKSIZE); + 800cc12: 6820 ldr r0, [r4, #0] + 800cc14: f44f 7100 mov.w r1, #512 ; 0x200 + 800cc18: f000 f9ae bl 800cf78 + if(errorstate != HAL_SD_ERROR_NONE) + 800cc1c: b130 cbz r0, 800cc2c + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800cc1e: 6823 ldr r3, [r4, #0] + 800cc20: 4a3a ldr r2, [pc, #232] ; (800cd0c ) + 800cc22: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= errorstate; + 800cc24: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800cc26: 4318 orrs r0, r3 + 800cc28: 63a0 str r0, [r4, #56] ; 0x38 + status = HAL_ERROR; + 800cc2a: 2501 movs r5, #1 + hsd->State = HAL_SD_STATE_READY; + 800cc2c: 2301 movs r3, #1 + 800cc2e: f884 3034 strb.w r3, [r4, #52] ; 0x34 + return status; + 800cc32: e064 b.n 800ccfe + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOHF)) + 800cc34: 6b5b ldr r3, [r3, #52] ; 0x34 + 800cc36: 041b lsls r3, r3, #16 + 800cc38: d50b bpl.n 800cc52 + 800cc3a: ab06 add r3, sp, #24 + 800cc3c: eb03 1a47 add.w sl, r3, r7, lsl #5 + SD_hs[(8U*loop)+count] = SDMMC_ReadFIFO(hsd->Instance); + 800cc40: 6820 ldr r0, [r4, #0] + 800cc42: f000 f881 bl 800cd48 + for (count = 0U; count < 8U; count++) + 800cc46: 3601 adds r6, #1 + 800cc48: 2e08 cmp r6, #8 + SD_hs[(8U*loop)+count] = SDMMC_ReadFIFO(hsd->Instance); + 800cc4a: f84a 0b04 str.w r0, [sl], #4 + for (count = 0U; count < 8U; count++) + 800cc4e: d1f7 bne.n 800cc40 + loop ++; + 800cc50: 3701 adds r7, #1 + if((HAL_GetTick()-Timeout) >= SDMMC_DATATIMEOUT) + 800cc52: f7fa fa4b bl 80070ec + 800cc56: eba0 0008 sub.w r0, r0, r8 + 800cc5a: 3001 adds r0, #1 + 800cc5c: d1c7 bne.n 800cbee + hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT; + 800cc5e: f04f 4300 mov.w r3, #2147483648 ; 0x80000000 + 800cc62: 63a3 str r3, [r4, #56] ; 0x38 + hsd->State= HAL_SD_STATE_READY; + 800cc64: 2301 movs r3, #1 + 800cc66: f884 3034 strb.w r3, [r4, #52] ; 0x34 + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + 800cc6a: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800cc6c: f043 5380 orr.w r3, r3, #268435456 ; 0x10000000 + hsd->ErrorCode |= HAL_SD_ERROR_PARAM; + 800cc70: 63a3 str r3, [r4, #56] ; 0x38 + status = HAL_ERROR; + 800cc72: 2501 movs r5, #1 + break; + 800cc74: e7c5 b.n 800cc02 + + return errorstate; + } + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL)) + 800cc76: 6b5a ldr r2, [r3, #52] ; 0x34 + 800cc78: 0791 lsls r1, r2, #30 + 800cc7a: d502 bpl.n 800cc82 + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DCRCFAIL); + 800cc7c: 2202 movs r2, #2 + + return errorstate; + } + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)) + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_RXOVERR); + 800cc7e: 639a str r2, [r3, #56] ; 0x38 + + errorstate = SDMMC_ERROR_RX_OVERRUN; + + return errorstate; + 800cc80: e7f3 b.n 800cc6a + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)) + 800cc82: 6b5a ldr r2, [r3, #52] ; 0x34 + 800cc84: 0692 lsls r2, r2, #26 + 800cc86: d501 bpl.n 800cc8c + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_RXOVERR); + 800cc88: 2220 movs r2, #32 + 800cc8a: e7f8 b.n 800cc7e + { + /* No error flag set */ + } + + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + 800cc8c: 4a20 ldr r2, [pc, #128] ; (800cd10 ) + 800cc8e: 639a str r2, [r3, #56] ; 0x38 + + /* Test if the switch mode is ok */ + if ((((uint8_t*)SD_hs)[13] & 2U) != 2U) + 800cc90: f89d 3025 ldrb.w r3, [sp, #37] ; 0x25 + 800cc94: 079b lsls r3, r3, #30 + 800cc96: d5e8 bpl.n 800cc6a + else + { +#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U) + hsd->DriveTransceiver_1_8V_Callback(SET); +#else + HAL_SDEx_DriveTransceiver_1_8V_Callback(SET); + 800cc98: 2001 movs r0, #1 + 800cc9a: f7fa fa97 bl 80071cc + 800cc9e: e7b0 b.n 800cc02 + switch (SpeedMode) + 800cca0: 2901 cmp r1, #1 + 800cca2: f43f af48 beq.w 800cb36 + 800cca6: 2902 cmp r1, #2 + 800cca8: d00c beq.n 800ccc4 + 800ccaa: b9c1 cbnz r1, 800ccde + if ((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) || + 800ccac: 6dc3 ldr r3, [r0, #92] ; 0x5c + 800ccae: f5b3 7f00 cmp.w r3, #512 ; 0x200 + 800ccb2: f43f af45 beq.w 800cb40 + 800ccb6: f5b3 7f80 cmp.w r3, #256 ; 0x100 + 800ccba: f43f af41 beq.w 800cb40 + (hsd->SdCard.CardSpeed == CARD_HIGH_SPEED) || + 800ccbe: 6bc3 ldr r3, [r0, #60] ; 0x3c + 800ccc0: 2b01 cmp r3, #1 + 800ccc2: e73c b.n 800cb3e + if ((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) || + 800ccc4: 6de3 ldr r3, [r4, #92] ; 0x5c + 800ccc6: f5b3 7f00 cmp.w r3, #512 ; 0x200 + 800ccca: f43f af39 beq.w 800cb40 + 800ccce: f5b3 7f80 cmp.w r3, #256 ; 0x100 + 800ccd2: f43f af35 beq.w 800cb40 + (hsd->SdCard.CardSpeed == CARD_HIGH_SPEED) || + 800ccd6: 6be3 ldr r3, [r4, #60] ; 0x3c + 800ccd8: 2b01 cmp r3, #1 + 800ccda: d1c6 bne.n 800cc6a + 800ccdc: e730 b.n 800cb40 + hsd->ErrorCode |= HAL_SD_ERROR_PARAM; + 800ccde: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800cce0: f043 6300 orr.w r3, r3, #134217728 ; 0x8000000 + 800cce4: e7c4 b.n 800cc70 + if ((HAL_GetTick() - tickstart) >= SDMMC_DATATIMEOUT) + 800cce6: f7fa fa01 bl 80070ec + 800ccea: 1b80 subs r0, r0, r6 + 800ccec: 3001 adds r0, #1 + 800ccee: d18b bne.n 800cc08 + hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT; + 800ccf0: f04f 4300 mov.w r3, #2147483648 ; 0x80000000 + 800ccf4: 63a3 str r3, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800ccf6: 2301 movs r3, #1 + 800ccf8: f884 3034 strb.w r3, [r4, #52] ; 0x34 + return HAL_TIMEOUT; + 800ccfc: 2503 movs r5, #3 +} + 800ccfe: 4628 mov r0, r5 + 800cd00: b016 add sp, #88 ; 0x58 + 800cd02: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + 800cd06: bf00 nop + 800cd08: 80ffff04 .word 0x80ffff04 + 800cd0c: 1fe00fff .word 0x1fe00fff + 800cd10: 18000f3a .word 0x18000f3a + +0800cd14 : + * @param SDMMCx Pointer to SDMMC register base + * @param Init SDMMC initialization structure + * @retval HAL status + */ +HAL_StatusTypeDef SDMMC_Init(SDMMC_TypeDef *SDMMCx, SDMMC_InitTypeDef Init) +{ + 800cd14: b084 sub sp, #16 + 800cd16: b510 push {r4, lr} + 800cd18: ac03 add r4, sp, #12 + 800cd1a: e884 000e stmia.w r4, {r1, r2, r3} + + /* Set SDMMC configuration parameters */ +#if !defined(STM32L4P5xx) && !defined(STM32L4Q5xx) && !defined(STM32L4R5xx) && !defined(STM32L4R7xx) && !defined(STM32L4R9xx) && !defined(STM32L4S5xx) && !defined(STM32L4S7xx) && !defined(STM32L4S9xx) + tmpreg |= Init.ClockBypass; +#endif + tmpreg |= (Init.ClockEdge |\ + 800cd1e: 9b03 ldr r3, [sp, #12] + Init.HardwareFlowControl |\ + Init.ClockDiv + ); + + /* Write to SDMMC CLKCR */ + MODIFY_REG(SDMMCx->CLKCR, CLKCR_CLEAR_MASK, tmpreg); + 800cd20: 6841 ldr r1, [r0, #4] + tmpreg |= (Init.ClockEdge |\ + 800cd22: 4313 orrs r3, r2 + Init.ClockPowerSave |\ + 800cd24: 9a05 ldr r2, [sp, #20] + 800cd26: 4313 orrs r3, r2 + Init.BusWide |\ + 800cd28: 9a06 ldr r2, [sp, #24] + 800cd2a: 4313 orrs r3, r2 + Init.HardwareFlowControl |\ + 800cd2c: 9a07 ldr r2, [sp, #28] + + return HAL_OK; +} + 800cd2e: e8bd 4010 ldmia.w sp!, {r4, lr} + Init.HardwareFlowControl |\ + 800cd32: 4313 orrs r3, r2 + MODIFY_REG(SDMMCx->CLKCR, CLKCR_CLEAR_MASK, tmpreg); + 800cd34: 4a03 ldr r2, [pc, #12] ; (800cd44 ) + 800cd36: 400a ands r2, r1 + 800cd38: 4313 orrs r3, r2 + 800cd3a: 6043 str r3, [r0, #4] +} + 800cd3c: b004 add sp, #16 + 800cd3e: 2000 movs r0, #0 + 800cd40: 4770 bx lr + 800cd42: bf00 nop + 800cd44: ffc02c00 .word 0xffc02c00 + +0800cd48 : + * @retval HAL status + */ +uint32_t SDMMC_ReadFIFO(SDMMC_TypeDef *SDMMCx) +{ + /* Read data from Rx FIFO */ + return (SDMMCx->FIFO); + 800cd48: f8d0 0080 ldr.w r0, [r0, #128] ; 0x80 +} + 800cd4c: 4770 bx lr + +0800cd4e : + * @retval HAL status + */ +HAL_StatusTypeDef SDMMC_WriteFIFO(SDMMC_TypeDef *SDMMCx, uint32_t *pWriteData) +{ + /* Write data to FIFO */ + SDMMCx->FIFO = *pWriteData; + 800cd4e: 680b ldr r3, [r1, #0] + 800cd50: f8c0 3080 str.w r3, [r0, #128] ; 0x80 + + return HAL_OK; +} + 800cd54: 2000 movs r0, #0 + 800cd56: 4770 bx lr + +0800cd58 : + * @brief Set SDMMC Power state to ON. + * @param SDMMCx Pointer to SDMMC register base + * @retval HAL status + */ +HAL_StatusTypeDef SDMMC_PowerState_ON(SDMMC_TypeDef *SDMMCx) +{ + 800cd58: b508 push {r3, lr} + /* Set power state to ON */ +#if defined(STM32L4P5xx) || defined(STM32L4Q5xx) || defined(STM32L4R5xx) || defined(STM32L4R7xx) || defined(STM32L4R9xx) || defined(STM32L4S5xx) || defined(STM32L4S7xx) || defined(STM32L4S9xx) + SDMMCx->POWER |= SDMMC_POWER_PWRCTRL; + 800cd5a: 6803 ldr r3, [r0, #0] + 800cd5c: f043 0303 orr.w r3, r3, #3 + 800cd60: 6003 str r3, [r0, #0] + SDMMCx->POWER = SDMMC_POWER_PWRCTRL; +#endif /* STM32L4P5xx || STM32L4Q5xx || STM32L4R5xx || STM32L4R7xx || STM32L4R9xx || STM32L4S5xx || STM32L4S7xx || STM32L4S9xx */ + + /* 1ms: required power up waiting time before starting the SD initialization + sequence */ + HAL_Delay(2); + 800cd62: 2002 movs r0, #2 + 800cd64: f7f6 fdd5 bl 8003912 + + return HAL_OK; +} + 800cd68: 2000 movs r0, #0 + 800cd6a: bd08 pop {r3, pc} + +0800cd6c : + * @retval HAL status + */ +HAL_StatusTypeDef SDMMC_PowerState_Cycle(SDMMC_TypeDef *SDMMCx) +{ + /* Set power state to Power Cycle*/ + SDMMCx->POWER |= SDMMC_POWER_PWRCTRL_1; + 800cd6c: 6803 ldr r3, [r0, #0] + 800cd6e: f043 0302 orr.w r3, r3, #2 + 800cd72: 6003 str r3, [r0, #0] + + return HAL_OK; +} + 800cd74: 2000 movs r0, #0 + 800cd76: 4770 bx lr + +0800cd78 : + */ +HAL_StatusTypeDef SDMMC_PowerState_OFF(SDMMC_TypeDef *SDMMCx) +{ + /* Set power state to OFF */ +#if defined(STM32L4P5xx) || defined(STM32L4Q5xx) || defined(STM32L4R5xx) || defined(STM32L4R7xx) || defined(STM32L4R9xx) || defined(STM32L4S5xx) || defined(STM32L4S7xx) || defined(STM32L4S9xx) + SDMMCx->POWER &= ~(SDMMC_POWER_PWRCTRL); + 800cd78: 6803 ldr r3, [r0, #0] + 800cd7a: f023 0303 bic.w r3, r3, #3 + 800cd7e: 6003 str r3, [r0, #0] +#else + SDMMCx->POWER = (uint32_t)0x00000000; +#endif /* STM32L4P5xx || STM32L4Q5xx || STM32L4R5xx || STM32L4R7xx || STM32L4R9xx || STM32L4S5xx || STM32L4S7xx || STM32L4S9xx */ + + return HAL_OK; +} + 800cd80: 2000 movs r0, #0 + 800cd82: 4770 bx lr + +0800cd84 : + * - 0x02: Power UP + * - 0x03: Power ON + */ +uint32_t SDMMC_GetPowerState(SDMMC_TypeDef *SDMMCx) +{ + return (SDMMCx->POWER & SDMMC_POWER_PWRCTRL); + 800cd84: 6800 ldr r0, [r0, #0] +} + 800cd86: f000 0003 and.w r0, r0, #3 + 800cd8a: 4770 bx lr + +0800cd8c : + assert_param(IS_SDMMC_RESPONSE(Command->Response)); + assert_param(IS_SDMMC_WAIT(Command->WaitForInterrupt)); + assert_param(IS_SDMMC_CPSM(Command->CPSM)); + + /* Set the SDMMC Argument value */ + SDMMCx->ARG = Command->Argument; + 800cd8c: 680b ldr r3, [r1, #0] +{ + 800cd8e: b510 push {r4, lr} + SDMMCx->ARG = Command->Argument; + 800cd90: 6083 str r3, [r0, #8] + + /* Set SDMMC command parameters */ + tmpreg |= (uint32_t)(Command->CmdIndex |\ + 800cd92: e9d1 3201 ldrd r3, r2, [r1, #4] + 800cd96: 4313 orrs r3, r2 + Command->Response |\ + 800cd98: 68ca ldr r2, [r1, #12] + Command->WaitForInterrupt |\ + Command->CPSM); + + /* Write to SDMMC CMD register */ + MODIFY_REG(SDMMCx->CMD, CMD_CLEAR_MASK, tmpreg); + 800cd9a: 68c4 ldr r4, [r0, #12] + Command->Response |\ + 800cd9c: 4313 orrs r3, r2 + Command->WaitForInterrupt |\ + 800cd9e: 690a ldr r2, [r1, #16] + 800cda0: 4313 orrs r3, r2 + MODIFY_REG(SDMMCx->CMD, CMD_CLEAR_MASK, tmpreg); + 800cda2: 4a03 ldr r2, [pc, #12] ; (800cdb0 ) + 800cda4: 4022 ands r2, r4 + 800cda6: 4313 orrs r3, r2 + 800cda8: 60c3 str r3, [r0, #12] + + return HAL_OK; +} + 800cdaa: 2000 movs r0, #0 + 800cdac: bd10 pop {r4, pc} + 800cdae: bf00 nop + 800cdb0: fffee0c0 .word 0xfffee0c0 + +0800cdb4 : + * @param SDMMCx Pointer to SDMMC register base + * @retval Command index of the last command response received + */ +uint8_t SDMMC_GetCommandResponse(SDMMC_TypeDef *SDMMCx) +{ + return (uint8_t)(SDMMCx->RESPCMD); + 800cdb4: 6900 ldr r0, [r0, #16] +} + 800cdb6: b2c0 uxtb r0, r0 + 800cdb8: 4770 bx lr + +0800cdba : + + /* Check the parameters */ + assert_param(IS_SDMMC_RESP(Response)); + + /* Get the response */ + tmp = (uint32_t)(&(SDMMCx->RESP1)) + Response; + 800cdba: 3014 adds r0, #20 + + return (*(__IO uint32_t *) tmp); + 800cdbc: 5840 ldr r0, [r0, r1] +} + 800cdbe: 4770 bx lr + +0800cdc0 : + assert_param(IS_SDMMC_TRANSFER_DIR(Data->TransferDir)); + assert_param(IS_SDMMC_TRANSFER_MODE(Data->TransferMode)); + assert_param(IS_SDMMC_DPSM(Data->DPSM)); + + /* Set the SDMMC Data TimeOut value */ + SDMMCx->DTIMER = Data->DataTimeOut; + 800cdc0: 680b ldr r3, [r1, #0] +{ + 800cdc2: b510 push {r4, lr} + SDMMCx->DTIMER = Data->DataTimeOut; + 800cdc4: 6243 str r3, [r0, #36] ; 0x24 + + /* Set the SDMMC DataLength value */ + SDMMCx->DLEN = Data->DataLength; + 800cdc6: 684b ldr r3, [r1, #4] + 800cdc8: 6283 str r3, [r0, #40] ; 0x28 + + /* Set the SDMMC data configuration parameters */ + tmpreg |= (uint32_t)(Data->DataBlockSize |\ + 800cdca: e9d1 3402 ldrd r3, r4, [r1, #8] + 800cdce: 4323 orrs r3, r4 + Data->TransferDir |\ + 800cdd0: 690c ldr r4, [r1, #16] + Data->TransferMode |\ + Data->DPSM); + + /* Write to SDMMC DCTRL */ + MODIFY_REG(SDMMCx->DCTRL, DCTRL_CLEAR_MASK, tmpreg); + 800cdd2: 6ac2 ldr r2, [r0, #44] ; 0x2c + Data->TransferMode |\ + 800cdd4: 6949 ldr r1, [r1, #20] + Data->TransferDir |\ + 800cdd6: 4323 orrs r3, r4 + Data->TransferMode |\ + 800cdd8: 430b orrs r3, r1 + MODIFY_REG(SDMMCx->DCTRL, DCTRL_CLEAR_MASK, tmpreg); + 800cdda: f022 02ff bic.w r2, r2, #255 ; 0xff + 800cdde: 4313 orrs r3, r2 + 800cde0: 62c3 str r3, [r0, #44] ; 0x2c + + return HAL_OK; + +} + 800cde2: 2000 movs r0, #0 + 800cde4: bd10 pop {r4, pc} + +0800cde6 : + * @param SDMMCx Pointer to SDMMC register base + * @retval Number of remaining data bytes to be transferred + */ +uint32_t SDMMC_GetDataCounter(SDMMC_TypeDef *SDMMCx) +{ + return (SDMMCx->DCOUNT); + 800cde6: 6b00 ldr r0, [r0, #48] ; 0x30 +} + 800cde8: 4770 bx lr + +0800cdea : + 800cdea: f8d0 0080 ldr.w r0, [r0, #128] ; 0x80 + 800cdee: 4770 bx lr + +0800cdf0 : +{ + /* Check the parameters */ + assert_param(IS_SDMMC_READWAIT_MODE(SDMMC_ReadWaitMode)); + + /* Set SDMMC read wait mode */ + MODIFY_REG(SDMMCx->DCTRL, SDMMC_DCTRL_RWMOD, SDMMC_ReadWaitMode); + 800cdf0: 6ac3 ldr r3, [r0, #44] ; 0x2c + 800cdf2: f423 6380 bic.w r3, r3, #1024 ; 0x400 + 800cdf6: 4319 orrs r1, r3 + 800cdf8: 62c1 str r1, [r0, #44] ; 0x2c + + return HAL_OK; +} + 800cdfa: 2000 movs r0, #0 + 800cdfc: 4770 bx lr + ... + +0800ce00 : + * @brief Send the Go Idle State command and check the response. + * @param SDMMCx Pointer to SDMMC register base + * @retval HAL status + */ +uint32_t SDMMC_CmdGoIdleState(SDMMC_TypeDef *SDMMCx) +{ + 800ce00: b510 push {r4, lr} + SDMMC_CmdInitTypeDef sdmmc_cmdinit; + uint32_t errorstate; + + sdmmc_cmdinit.Argument = 0U; + 800ce02: 2300 movs r3, #0 +{ + 800ce04: b086 sub sp, #24 + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_GO_IDLE_STATE; + 800ce06: e9cd 3301 strd r3, r3, [sp, #4] + sdmmc_cmdinit.Response = SDMMC_RESPONSE_NO; + sdmmc_cmdinit.WaitForInterrupt = SDMMC_WAIT_NO; + 800ce0a: e9cd 3303 strd r3, r3, [sp, #12] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800ce0e: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800ce10: f44f 5380 mov.w r3, #4096 ; 0x1000 + 800ce14: 9305 str r3, [sp, #20] +{ + 800ce16: 4604 mov r4, r0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800ce18: f7ff ffb8 bl 800cd8c + */ +static uint32_t SDMMC_GetCmdError(SDMMC_TypeDef *SDMMCx) +{ + /* 8 is the number of required instructions cycles for the below loop statement. + The SDMMC_CMDTIMEOUT is expressed in ms */ + uint32_t count = SDMMC_CMDTIMEOUT * (SystemCoreClock / 8U /1000U); + 800ce1c: 4b0a ldr r3, [pc, #40] ; (800ce48 ) + 800ce1e: f44f 52fa mov.w r2, #8000 ; 0x1f40 + 800ce22: 681b ldr r3, [r3, #0] + 800ce24: fbb3 f3f2 udiv r3, r3, r2 + 800ce28: f241 3288 movw r2, #5000 ; 0x1388 + 800ce2c: 4353 muls r3, r2 + + do + { + if (count-- == 0U) + 800ce2e: 3b01 subs r3, #1 + 800ce30: d307 bcc.n 800ce42 + { + return SDMMC_ERROR_TIMEOUT; + } + + }while(!__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CMDSENT)); + 800ce32: 6b62 ldr r2, [r4, #52] ; 0x34 + 800ce34: 0612 lsls r2, r2, #24 + 800ce36: d5fa bpl.n 800ce2e + + /* Clear all the static flags */ + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_STATIC_CMD_FLAGS); + 800ce38: 4b04 ldr r3, [pc, #16] ; (800ce4c ) + 800ce3a: 63a3 str r3, [r4, #56] ; 0x38 + + return SDMMC_ERROR_NONE; + 800ce3c: 2000 movs r0, #0 +} + 800ce3e: b006 add sp, #24 + 800ce40: bd10 pop {r4, pc} + return SDMMC_ERROR_TIMEOUT; + 800ce42: f04f 4000 mov.w r0, #2147483648 ; 0x80000000 + return errorstate; + 800ce46: e7fa b.n 800ce3e + 800ce48: 2009e2a8 .word 0x2009e2a8 + 800ce4c: 002000c5 .word 0x002000c5 + +0800ce50 : + uint32_t count = Timeout * (SystemCoreClock / 8U /1000U); + 800ce50: 4b45 ldr r3, [pc, #276] ; (800cf68 ) +{ + 800ce52: b510 push {r4, lr} + uint32_t count = Timeout * (SystemCoreClock / 8U /1000U); + 800ce54: 681b ldr r3, [r3, #0] +{ + 800ce56: 4604 mov r4, r0 + uint32_t count = Timeout * (SystemCoreClock / 8U /1000U); + 800ce58: f44f 50fa mov.w r0, #8000 ; 0x1f40 + 800ce5c: fbb3 f3f0 udiv r3, r3, r0 + }while(((sta_reg & (SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT | SDMMC_FLAG_BUSYD0END)) == 0U) || + 800ce60: 4842 ldr r0, [pc, #264] ; (800cf6c ) + uint32_t count = Timeout * (SystemCoreClock / 8U /1000U); + 800ce62: 435a muls r2, r3 + if (count-- == 0U) + 800ce64: 2a00 cmp r2, #0 + 800ce66: d048 beq.n 800cefa + sta_reg = SDMMCx->STA; + 800ce68: 6b63 ldr r3, [r4, #52] ; 0x34 + ((sta_reg & SDMMC_FLAG_CMDACT) != 0U )); + 800ce6a: 4203 tst r3, r0 + 800ce6c: d007 beq.n 800ce7e + }while(((sta_reg & (SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT | SDMMC_FLAG_BUSYD0END)) == 0U) || + 800ce6e: 049b lsls r3, r3, #18 + 800ce70: d405 bmi.n 800ce7e + if(__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT)) + 800ce72: 6b63 ldr r3, [r4, #52] ; 0x34 + 800ce74: 0758 lsls r0, r3, #29 + 800ce76: d504 bpl.n 800ce82 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT); + 800ce78: 2004 movs r0, #4 + 800ce7a: 63a0 str r0, [r4, #56] ; 0x38 +} + 800ce7c: bd10 pop {r4, pc} + 800ce7e: 3a01 subs r2, #1 + 800ce80: e7f0 b.n 800ce64 + else if(__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CCRCFAIL)) + 800ce82: 6b60 ldr r0, [r4, #52] ; 0x34 + 800ce84: f010 0001 ands.w r0, r0, #1 + 800ce88: d002 beq.n 800ce90 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CCRCFAIL); + 800ce8a: 2301 movs r3, #1 + 800ce8c: 63a3 str r3, [r4, #56] ; 0x38 + return SDMMC_ERROR_CMD_CRC_FAIL; + 800ce8e: e7f5 b.n 800ce7c + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_STATIC_CMD_FLAGS); + 800ce90: 4b37 ldr r3, [pc, #220] ; (800cf70 ) + 800ce92: 63a3 str r3, [r4, #56] ; 0x38 + return (uint8_t)(SDMMCx->RESPCMD); + 800ce94: 6923 ldr r3, [r4, #16] + if(SDMMC_GetCommandResponse(SDMMCx) != SD_CMD) + 800ce96: b2db uxtb r3, r3 + 800ce98: 4299 cmp r1, r3 + 800ce9a: d131 bne.n 800cf00 + return (*(__IO uint32_t *) tmp); + 800ce9c: 6963 ldr r3, [r4, #20] + if((response_r1 & SDMMC_OCR_ERRORBITS) == SDMMC_ALLZERO) + 800ce9e: 4835 ldr r0, [pc, #212] ; (800cf74 ) + 800cea0: 4018 ands r0, r3 + 800cea2: 2800 cmp r0, #0 + 800cea4: d0ea beq.n 800ce7c + else if((response_r1 & SDMMC_OCR_ADDR_OUT_OF_RANGE) == SDMMC_OCR_ADDR_OUT_OF_RANGE) + 800cea6: 2b00 cmp r3, #0 + 800cea8: db2c blt.n 800cf04 + else if((response_r1 & SDMMC_OCR_ADDR_MISALIGNED) == SDMMC_OCR_ADDR_MISALIGNED) + 800ceaa: 005a lsls r2, r3, #1 + 800ceac: d42d bmi.n 800cf0a + else if((response_r1 & SDMMC_OCR_BLOCK_LEN_ERR) == SDMMC_OCR_BLOCK_LEN_ERR) + 800ceae: 009c lsls r4, r3, #2 + 800ceb0: d42d bmi.n 800cf0e + else if((response_r1 & SDMMC_OCR_ERASE_SEQ_ERR) == SDMMC_OCR_ERASE_SEQ_ERR) + 800ceb2: 00d9 lsls r1, r3, #3 + 800ceb4: d42d bmi.n 800cf12 + else if((response_r1 & SDMMC_OCR_BAD_ERASE_PARAM) == SDMMC_OCR_BAD_ERASE_PARAM) + 800ceb6: 011a lsls r2, r3, #4 + 800ceb8: d42e bmi.n 800cf18 + else if((response_r1 & SDMMC_OCR_WRITE_PROT_VIOLATION) == SDMMC_OCR_WRITE_PROT_VIOLATION) + 800ceba: 015c lsls r4, r3, #5 + 800cebc: d42f bmi.n 800cf1e + else if((response_r1 & SDMMC_OCR_LOCK_UNLOCK_FAILED) == SDMMC_OCR_LOCK_UNLOCK_FAILED) + 800cebe: 01d9 lsls r1, r3, #7 + 800cec0: d430 bmi.n 800cf24 + else if((response_r1 & SDMMC_OCR_COM_CRC_FAILED) == SDMMC_OCR_COM_CRC_FAILED) + 800cec2: 021a lsls r2, r3, #8 + 800cec4: d431 bmi.n 800cf2a + else if((response_r1 & SDMMC_OCR_ILLEGAL_CMD) == SDMMC_OCR_ILLEGAL_CMD) + 800cec6: 025c lsls r4, r3, #9 + 800cec8: d432 bmi.n 800cf30 + else if((response_r1 & SDMMC_OCR_CARD_ECC_FAILED) == SDMMC_OCR_CARD_ECC_FAILED) + 800ceca: 0299 lsls r1, r3, #10 + 800cecc: d433 bmi.n 800cf36 + else if((response_r1 & SDMMC_OCR_CC_ERROR) == SDMMC_OCR_CC_ERROR) + 800cece: 02da lsls r2, r3, #11 + 800ced0: d434 bmi.n 800cf3c + else if((response_r1 & SDMMC_OCR_STREAM_READ_UNDERRUN) == SDMMC_OCR_STREAM_READ_UNDERRUN) + 800ced2: 035c lsls r4, r3, #13 + 800ced4: d435 bmi.n 800cf42 + else if((response_r1 & SDMMC_OCR_STREAM_WRITE_OVERRUN) == SDMMC_OCR_STREAM_WRITE_OVERRUN) + 800ced6: 0399 lsls r1, r3, #14 + 800ced8: d436 bmi.n 800cf48 + else if((response_r1 & SDMMC_OCR_CID_CSD_OVERWRITE) == SDMMC_OCR_CID_CSD_OVERWRITE) + 800ceda: 03da lsls r2, r3, #15 + 800cedc: d437 bmi.n 800cf4e + else if((response_r1 & SDMMC_OCR_WP_ERASE_SKIP) == SDMMC_OCR_WP_ERASE_SKIP) + 800cede: 041c lsls r4, r3, #16 + 800cee0: d438 bmi.n 800cf54 + else if((response_r1 & SDMMC_OCR_CARD_ECC_DISABLED) == SDMMC_OCR_CARD_ECC_DISABLED) + 800cee2: 0459 lsls r1, r3, #17 + 800cee4: d439 bmi.n 800cf5a + else if((response_r1 & SDMMC_OCR_ERASE_RESET) == SDMMC_OCR_ERASE_RESET) + 800cee6: 049a lsls r2, r3, #18 + 800cee8: d43a bmi.n 800cf60 + return SDMMC_ERROR_GENERAL_UNKNOWN_ERR; + 800ceea: f013 0f08 tst.w r3, #8 + 800ceee: bf14 ite ne + 800cef0: f44f 0000 movne.w r0, #8388608 ; 0x800000 + 800cef4: f44f 3080 moveq.w r0, #65536 ; 0x10000 + 800cef8: e7c0 b.n 800ce7c + return SDMMC_ERROR_TIMEOUT; + 800cefa: f04f 4000 mov.w r0, #2147483648 ; 0x80000000 + 800cefe: e7bd b.n 800ce7c + return SDMMC_ERROR_CMD_CRC_FAIL; + 800cf00: 2001 movs r0, #1 + 800cf02: e7bb b.n 800ce7c + return SDMMC_ERROR_ADDR_OUT_OF_RANGE; + 800cf04: f04f 7000 mov.w r0, #33554432 ; 0x2000000 + 800cf08: e7b8 b.n 800ce7c + return SDMMC_ERROR_ADDR_MISALIGNED; + 800cf0a: 2040 movs r0, #64 ; 0x40 + 800cf0c: e7b6 b.n 800ce7c + return SDMMC_ERROR_BLOCK_LEN_ERR; + 800cf0e: 2080 movs r0, #128 ; 0x80 + 800cf10: e7b4 b.n 800ce7c + return SDMMC_ERROR_ERASE_SEQ_ERR; + 800cf12: f44f 7080 mov.w r0, #256 ; 0x100 + 800cf16: e7b1 b.n 800ce7c + return SDMMC_ERROR_BAD_ERASE_PARAM; + 800cf18: f44f 7000 mov.w r0, #512 ; 0x200 + 800cf1c: e7ae b.n 800ce7c + return SDMMC_ERROR_WRITE_PROT_VIOLATION; + 800cf1e: f44f 6080 mov.w r0, #1024 ; 0x400 + 800cf22: e7ab b.n 800ce7c + return SDMMC_ERROR_LOCK_UNLOCK_FAILED; + 800cf24: f44f 6000 mov.w r0, #2048 ; 0x800 + 800cf28: e7a8 b.n 800ce7c + return SDMMC_ERROR_COM_CRC_FAILED; + 800cf2a: f44f 5080 mov.w r0, #4096 ; 0x1000 + 800cf2e: e7a5 b.n 800ce7c + return SDMMC_ERROR_ILLEGAL_CMD; + 800cf30: f44f 5000 mov.w r0, #8192 ; 0x2000 + 800cf34: e7a2 b.n 800ce7c + return SDMMC_ERROR_CARD_ECC_FAILED; + 800cf36: f44f 4080 mov.w r0, #16384 ; 0x4000 + 800cf3a: e79f b.n 800ce7c + return SDMMC_ERROR_CC_ERR; + 800cf3c: f44f 4000 mov.w r0, #32768 ; 0x8000 + 800cf40: e79c b.n 800ce7c + return SDMMC_ERROR_STREAM_READ_UNDERRUN; + 800cf42: f44f 3000 mov.w r0, #131072 ; 0x20000 + 800cf46: e799 b.n 800ce7c + return SDMMC_ERROR_STREAM_WRITE_OVERRUN; + 800cf48: f44f 2080 mov.w r0, #262144 ; 0x40000 + 800cf4c: e796 b.n 800ce7c + return SDMMC_ERROR_CID_CSD_OVERWRITE; + 800cf4e: f44f 2000 mov.w r0, #524288 ; 0x80000 + 800cf52: e793 b.n 800ce7c + return SDMMC_ERROR_WP_ERASE_SKIP; + 800cf54: f44f 1080 mov.w r0, #1048576 ; 0x100000 + 800cf58: e790 b.n 800ce7c + return SDMMC_ERROR_CARD_ECC_DISABLED; + 800cf5a: f44f 1000 mov.w r0, #2097152 ; 0x200000 + 800cf5e: e78d b.n 800ce7c + return SDMMC_ERROR_ERASE_RESET; + 800cf60: f44f 0080 mov.w r0, #4194304 ; 0x400000 + 800cf64: e78a b.n 800ce7c + 800cf66: bf00 nop + 800cf68: 2009e2a8 .word 0x2009e2a8 + 800cf6c: 00200045 .word 0x00200045 + 800cf70: 002000c5 .word 0x002000c5 + 800cf74: fdffe008 .word 0xfdffe008 + +0800cf78 : +{ + 800cf78: b530 push {r4, r5, lr} + 800cf7a: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800cf7c: 2510 movs r5, #16 + 800cf7e: f44f 7380 mov.w r3, #256 ; 0x100 + 800cf82: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800cf86: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800cf88: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)BlockSize; + 800cf8c: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800cf8e: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800cf90: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800cf92: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800cf96: f7ff fef9 bl 800cd8c + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_SET_BLOCKLEN, SDMMC_CMDTIMEOUT); + 800cf9a: f241 3288 movw r2, #5000 ; 0x1388 + 800cf9e: 4629 mov r1, r5 + 800cfa0: 4620 mov r0, r4 + 800cfa2: f7ff ff55 bl 800ce50 +} + 800cfa6: b007 add sp, #28 + 800cfa8: bd30 pop {r4, r5, pc} + +0800cfaa : +{ + 800cfaa: b530 push {r4, r5, lr} + 800cfac: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800cfae: 2511 movs r5, #17 + 800cfb0: f44f 7380 mov.w r3, #256 ; 0x100 + 800cfb4: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800cfb8: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800cfba: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)ReadAdd; + 800cfbe: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800cfc0: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800cfc2: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800cfc4: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800cfc8: f7ff fee0 bl 800cd8c + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_READ_SINGLE_BLOCK, SDMMC_CMDTIMEOUT); + 800cfcc: f241 3288 movw r2, #5000 ; 0x1388 + 800cfd0: 4629 mov r1, r5 + 800cfd2: 4620 mov r0, r4 + 800cfd4: f7ff ff3c bl 800ce50 +} + 800cfd8: b007 add sp, #28 + 800cfda: bd30 pop {r4, r5, pc} + +0800cfdc : +{ + 800cfdc: b530 push {r4, r5, lr} + 800cfde: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800cfe0: 2512 movs r5, #18 + 800cfe2: f44f 7380 mov.w r3, #256 ; 0x100 + 800cfe6: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800cfea: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800cfec: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)ReadAdd; + 800cff0: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800cff2: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800cff4: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800cff6: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800cffa: f7ff fec7 bl 800cd8c + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_READ_MULT_BLOCK, SDMMC_CMDTIMEOUT); + 800cffe: f241 3288 movw r2, #5000 ; 0x1388 + 800d002: 4629 mov r1, r5 + 800d004: 4620 mov r0, r4 + 800d006: f7ff ff23 bl 800ce50 +} + 800d00a: b007 add sp, #28 + 800d00c: bd30 pop {r4, r5, pc} + +0800d00e : +{ + 800d00e: b530 push {r4, r5, lr} + 800d010: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d012: 2518 movs r5, #24 + 800d014: f44f 7380 mov.w r3, #256 ; 0x100 + 800d018: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d01c: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d01e: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)WriteAdd; + 800d022: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d024: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d026: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d028: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d02c: f7ff feae bl 800cd8c + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_WRITE_SINGLE_BLOCK, SDMMC_CMDTIMEOUT); + 800d030: f241 3288 movw r2, #5000 ; 0x1388 + 800d034: 4629 mov r1, r5 + 800d036: 4620 mov r0, r4 + 800d038: f7ff ff0a bl 800ce50 +} + 800d03c: b007 add sp, #28 + 800d03e: bd30 pop {r4, r5, pc} + +0800d040 : +{ + 800d040: b530 push {r4, r5, lr} + 800d042: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d044: 2519 movs r5, #25 + 800d046: f44f 7380 mov.w r3, #256 ; 0x100 + 800d04a: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d04e: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d050: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)WriteAdd; + 800d054: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d056: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d058: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d05a: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d05e: f7ff fe95 bl 800cd8c + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_WRITE_MULT_BLOCK, SDMMC_CMDTIMEOUT); + 800d062: f241 3288 movw r2, #5000 ; 0x1388 + 800d066: 4629 mov r1, r5 + 800d068: 4620 mov r0, r4 + 800d06a: f7ff fef1 bl 800ce50 +} + 800d06e: b007 add sp, #28 + 800d070: bd30 pop {r4, r5, pc} + +0800d072 : +{ + 800d072: b530 push {r4, r5, lr} + 800d074: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d076: 2520 movs r5, #32 + 800d078: f44f 7380 mov.w r3, #256 ; 0x100 + 800d07c: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d080: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d082: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)StartAdd; + 800d086: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d088: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d08a: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d08c: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d090: f7ff fe7c bl 800cd8c + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_SD_ERASE_GRP_START, SDMMC_CMDTIMEOUT); + 800d094: f241 3288 movw r2, #5000 ; 0x1388 + 800d098: 4629 mov r1, r5 + 800d09a: 4620 mov r0, r4 + 800d09c: f7ff fed8 bl 800ce50 +} + 800d0a0: b007 add sp, #28 + 800d0a2: bd30 pop {r4, r5, pc} + +0800d0a4 : +{ + 800d0a4: b530 push {r4, r5, lr} + 800d0a6: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d0a8: 2521 movs r5, #33 ; 0x21 + 800d0aa: f44f 7380 mov.w r3, #256 ; 0x100 + 800d0ae: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d0b2: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d0b4: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)EndAdd; + 800d0b8: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d0ba: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d0bc: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d0be: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d0c2: f7ff fe63 bl 800cd8c + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_SD_ERASE_GRP_END, SDMMC_CMDTIMEOUT); + 800d0c6: f241 3288 movw r2, #5000 ; 0x1388 + 800d0ca: 4629 mov r1, r5 + 800d0cc: 4620 mov r0, r4 + 800d0ce: f7ff febf bl 800ce50 +} + 800d0d2: b007 add sp, #28 + 800d0d4: bd30 pop {r4, r5, pc} + +0800d0d6 : +{ + 800d0d6: b530 push {r4, r5, lr} + 800d0d8: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d0da: 2523 movs r5, #35 ; 0x23 + 800d0dc: f44f 7380 mov.w r3, #256 ; 0x100 + 800d0e0: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d0e4: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d0e6: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)StartAdd; + 800d0ea: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d0ec: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d0ee: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d0f0: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d0f4: f7ff fe4a bl 800cd8c + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_ERASE_GRP_START, SDMMC_CMDTIMEOUT); + 800d0f8: f241 3288 movw r2, #5000 ; 0x1388 + 800d0fc: 4629 mov r1, r5 + 800d0fe: 4620 mov r0, r4 + 800d100: f7ff fea6 bl 800ce50 +} + 800d104: b007 add sp, #28 + 800d106: bd30 pop {r4, r5, pc} + +0800d108 : +{ + 800d108: b530 push {r4, r5, lr} + 800d10a: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d10c: 2524 movs r5, #36 ; 0x24 + 800d10e: f44f 7380 mov.w r3, #256 ; 0x100 + 800d112: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d116: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d118: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)EndAdd; + 800d11c: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d11e: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d120: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d122: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d126: f7ff fe31 bl 800cd8c + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_ERASE_GRP_END, SDMMC_CMDTIMEOUT); + 800d12a: f241 3288 movw r2, #5000 ; 0x1388 + 800d12e: 4629 mov r1, r5 + 800d130: 4620 mov r0, r4 + 800d132: f7ff fe8d bl 800ce50 +} + 800d136: b007 add sp, #28 + 800d138: bd30 pop {r4, r5, pc} + +0800d13a : +{ + 800d13a: b530 push {r4, r5, lr} + 800d13c: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d13e: 2526 movs r5, #38 ; 0x26 + 800d140: f44f 7380 mov.w r3, #256 ; 0x100 + 800d144: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d148: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d14a: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = EraseType; + 800d14e: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d150: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d152: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d154: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d158: f7ff fe18 bl 800cd8c + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_ERASE, SDMMC_MAXERASETIMEOUT); + 800d15c: f24f 6218 movw r2, #63000 ; 0xf618 + 800d160: 4629 mov r1, r5 + 800d162: 4620 mov r0, r4 + 800d164: f7ff fe74 bl 800ce50 +} + 800d168: b007 add sp, #28 + 800d16a: bd30 pop {r4, r5, pc} + +0800d16c : +{ + 800d16c: b530 push {r4, r5, lr} + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_STOP_TRANSMISSION; + 800d16e: 2300 movs r3, #0 +{ + 800d170: b087 sub sp, #28 + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_STOP_TRANSMISSION; + 800d172: 250c movs r5, #12 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d174: f44f 7280 mov.w r2, #256 ; 0x100 + sdmmc_cmdinit.WaitForInterrupt = SDMMC_WAIT_NO; + 800d178: e9cd 2303 strd r2, r3, [sp, #12] + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_STOP_TRANSMISSION; + 800d17c: e9cd 3501 strd r3, r5, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d180: f44f 5380 mov.w r3, #4096 ; 0x1000 + 800d184: 9305 str r3, [sp, #20] + __SDMMC_CMDSTOP_ENABLE(SDMMCx); + 800d186: 68c3 ldr r3, [r0, #12] + 800d188: f043 0380 orr.w r3, r3, #128 ; 0x80 + 800d18c: 60c3 str r3, [r0, #12] + __SDMMC_CMDTRANS_DISABLE(SDMMCx); + 800d18e: 68c3 ldr r3, [r0, #12] + 800d190: f023 0340 bic.w r3, r3, #64 ; 0x40 +{ + 800d194: 4604 mov r4, r0 + __SDMMC_CMDTRANS_DISABLE(SDMMCx); + 800d196: 60c3 str r3, [r0, #12] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d198: a901 add r1, sp, #4 + 800d19a: f7ff fdf7 bl 800cd8c + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_STOP_TRANSMISSION, SDMMC_STOPTRANSFERTIMEOUT); + 800d19e: 4a05 ldr r2, [pc, #20] ; (800d1b4 ) + 800d1a0: 4629 mov r1, r5 + 800d1a2: 4620 mov r0, r4 + 800d1a4: f7ff fe54 bl 800ce50 + __SDMMC_CMDSTOP_DISABLE(SDMMCx); + 800d1a8: 68e3 ldr r3, [r4, #12] + 800d1aa: f023 0380 bic.w r3, r3, #128 ; 0x80 + 800d1ae: 60e3 str r3, [r4, #12] +} + 800d1b0: b007 add sp, #28 + 800d1b2: bd30 pop {r4, r5, pc} + 800d1b4: 05f5e100 .word 0x05f5e100 + +0800d1b8 : +{ + 800d1b8: b530 push {r4, r5, lr} + 800d1ba: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d1bc: 2507 movs r5, #7 + 800d1be: f44f 7380 mov.w r3, #256 ; 0x100 + 800d1c2: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d1c6: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d1c8: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)Addr; + 800d1cc: 9201 str r2, [sp, #4] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d1ce: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d1d0: 2200 movs r2, #0 + 800d1d2: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d1d6: f7ff fdd9 bl 800cd8c + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_SEL_DESEL_CARD, SDMMC_CMDTIMEOUT); + 800d1da: f241 3288 movw r2, #5000 ; 0x1388 + 800d1de: 4629 mov r1, r5 + 800d1e0: 4620 mov r0, r4 + 800d1e2: f7ff fe35 bl 800ce50 +} + 800d1e6: b007 add sp, #28 + 800d1e8: bd30 pop {r4, r5, pc} + +0800d1ea : +{ + 800d1ea: b530 push {r4, r5, lr} + 800d1ec: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d1ee: 2537 movs r5, #55 ; 0x37 + 800d1f0: f44f 7380 mov.w r3, #256 ; 0x100 + 800d1f4: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d1f8: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d1fa: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)Argument; + 800d1fe: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d200: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d202: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d204: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d208: f7ff fdc0 bl 800cd8c + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_APP_CMD, SDMMC_CMDTIMEOUT); + 800d20c: f241 3288 movw r2, #5000 ; 0x1388 + 800d210: 4629 mov r1, r5 + 800d212: 4620 mov r0, r4 + 800d214: f7ff fe1c bl 800ce50 +} + 800d218: b007 add sp, #28 + 800d21a: bd30 pop {r4, r5, pc} + +0800d21c : +{ + 800d21c: b530 push {r4, r5, lr} + 800d21e: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d220: 2506 movs r5, #6 + 800d222: f44f 7380 mov.w r3, #256 ; 0x100 + 800d226: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d22a: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d22c: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)BusWidth; + 800d230: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d232: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d234: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d236: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d23a: f7ff fda7 bl 800cd8c + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_APP_SD_SET_BUSWIDTH, SDMMC_CMDTIMEOUT); + 800d23e: f241 3288 movw r2, #5000 ; 0x1388 + 800d242: 4629 mov r1, r5 + 800d244: 4620 mov r0, r4 + 800d246: f7ff fe03 bl 800ce50 +} + 800d24a: b007 add sp, #28 + 800d24c: bd30 pop {r4, r5, pc} + +0800d24e : + 800d24e: f7ff bfe5 b.w 800d21c + +0800d252 : +{ + 800d252: b530 push {r4, r5, lr} + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SD_APP_SEND_SCR; + 800d254: 2300 movs r3, #0 +{ + 800d256: b087 sub sp, #28 + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SD_APP_SEND_SCR; + 800d258: 2533 movs r5, #51 ; 0x33 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d25a: f44f 7280 mov.w r2, #256 ; 0x100 + sdmmc_cmdinit.WaitForInterrupt = SDMMC_WAIT_NO; + 800d25e: e9cd 2303 strd r2, r3, [sp, #12] + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SD_APP_SEND_SCR; + 800d262: e9cd 3501 strd r3, r5, [sp, #4] +{ + 800d266: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d268: f44f 5380 mov.w r3, #4096 ; 0x1000 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d26c: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d26e: 9305 str r3, [sp, #20] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d270: f7ff fd8c bl 800cd8c + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_SD_APP_SEND_SCR, SDMMC_CMDTIMEOUT); + 800d274: f241 3288 movw r2, #5000 ; 0x1388 + 800d278: 4629 mov r1, r5 + 800d27a: 4620 mov r0, r4 + 800d27c: f7ff fde8 bl 800ce50 +} + 800d280: b007 add sp, #28 + 800d282: bd30 pop {r4, r5, pc} + +0800d284 : +{ + 800d284: b530 push {r4, r5, lr} + 800d286: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d288: 2503 movs r5, #3 + sdmmc_cmdinit.Argument = ((uint32_t)RCA << 16U); + 800d28a: 0409 lsls r1, r1, #16 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d28c: f44f 7380 mov.w r3, #256 ; 0x100 + 800d290: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d294: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d296: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = ((uint32_t)RCA << 16U); + 800d29a: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d29c: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d29e: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d2a0: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d2a4: f7ff fd72 bl 800cd8c + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_SET_REL_ADDR, SDMMC_CMDTIMEOUT); + 800d2a8: f241 3288 movw r2, #5000 ; 0x1388 + 800d2ac: 4629 mov r1, r5 + 800d2ae: 4620 mov r0, r4 + 800d2b0: f7ff fdce bl 800ce50 +} + 800d2b4: b007 add sp, #28 + 800d2b6: bd30 pop {r4, r5, pc} + +0800d2b8 : +{ + 800d2b8: b530 push {r4, r5, lr} + 800d2ba: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d2bc: 250d movs r5, #13 + 800d2be: f44f 7380 mov.w r3, #256 ; 0x100 + 800d2c2: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d2c6: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d2c8: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = Argument; + 800d2cc: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d2ce: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d2d0: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d2d2: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d2d6: f7ff fd59 bl 800cd8c + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_SEND_STATUS, SDMMC_CMDTIMEOUT); + 800d2da: f241 3288 movw r2, #5000 ; 0x1388 + 800d2de: 4629 mov r1, r5 + 800d2e0: 4620 mov r0, r4 + 800d2e2: f7ff fdb5 bl 800ce50 +} + 800d2e6: b007 add sp, #28 + 800d2e8: bd30 pop {r4, r5, pc} + +0800d2ea : +{ + 800d2ea: b530 push {r4, r5, lr} + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SD_APP_STATUS; + 800d2ec: 2300 movs r3, #0 +{ + 800d2ee: b087 sub sp, #28 + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SD_APP_STATUS; + 800d2f0: 250d movs r5, #13 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d2f2: f44f 7280 mov.w r2, #256 ; 0x100 + sdmmc_cmdinit.WaitForInterrupt = SDMMC_WAIT_NO; + 800d2f6: e9cd 2303 strd r2, r3, [sp, #12] + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SD_APP_STATUS; + 800d2fa: e9cd 3501 strd r3, r5, [sp, #4] +{ + 800d2fe: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d300: f44f 5380 mov.w r3, #4096 ; 0x1000 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d304: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d306: 9305 str r3, [sp, #20] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d308: f7ff fd40 bl 800cd8c + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_SD_APP_STATUS, SDMMC_CMDTIMEOUT); + 800d30c: f241 3288 movw r2, #5000 ; 0x1388 + 800d310: 4629 mov r1, r5 + 800d312: 4620 mov r0, r4 + 800d314: f7ff fd9c bl 800ce50 +} + 800d318: b007 add sp, #28 + 800d31a: bd30 pop {r4, r5, pc} + +0800d31c : +{ + 800d31c: b530 push {r4, r5, lr} + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_VOLTAGE_SWITCH; + 800d31e: 2300 movs r3, #0 +{ + 800d320: b087 sub sp, #28 + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_VOLTAGE_SWITCH; + 800d322: 250b movs r5, #11 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d324: f44f 7280 mov.w r2, #256 ; 0x100 + sdmmc_cmdinit.WaitForInterrupt = SDMMC_WAIT_NO; + 800d328: e9cd 2303 strd r2, r3, [sp, #12] + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_VOLTAGE_SWITCH; + 800d32c: e9cd 3501 strd r3, r5, [sp, #4] +{ + 800d330: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d332: f44f 5380 mov.w r3, #4096 ; 0x1000 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d336: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d338: 9305 str r3, [sp, #20] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d33a: f7ff fd27 bl 800cd8c + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_VOLTAGE_SWITCH, SDMMC_CMDTIMEOUT); + 800d33e: f241 3288 movw r2, #5000 ; 0x1388 + 800d342: 4629 mov r1, r5 + 800d344: 4620 mov r0, r4 + 800d346: f7ff fd83 bl 800ce50 +} + 800d34a: b007 add sp, #28 + 800d34c: bd30 pop {r4, r5, pc} + +0800d34e : +{ + 800d34e: b530 push {r4, r5, lr} + 800d350: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d352: 2508 movs r5, #8 + 800d354: f44f 7380 mov.w r3, #256 ; 0x100 + 800d358: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d35c: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d35e: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = Argument; + 800d362: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d364: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d366: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d368: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d36c: f7ff fd0e bl 800cd8c + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_HS_SEND_EXT_CSD,SDMMC_CMDTIMEOUT); + 800d370: f241 3288 movw r2, #5000 ; 0x1388 + 800d374: 4629 mov r1, r5 + 800d376: 4620 mov r0, r4 + 800d378: f7ff fd6a bl 800ce50 +} + 800d37c: b007 add sp, #28 + 800d37e: bd30 pop {r4, r5, pc} + +0800d380 : + uint32_t count = SDMMC_CMDTIMEOUT * (SystemCoreClock / 8U /1000U); + 800d380: 4b11 ldr r3, [pc, #68] ; (800d3c8 ) + 800d382: f44f 51fa mov.w r1, #8000 ; 0x1f40 + 800d386: 681b ldr r3, [r3, #0] + 800d388: fbb3 f3f1 udiv r3, r3, r1 + 800d38c: f241 3188 movw r1, #5000 ; 0x1388 +{ + 800d390: 4602 mov r2, r0 + uint32_t count = SDMMC_CMDTIMEOUT * (SystemCoreClock / 8U /1000U); + 800d392: 434b muls r3, r1 + if (count-- == 0U) + 800d394: 3b01 subs r3, #1 + 800d396: d313 bcc.n 800d3c0 + sta_reg = SDMMCx->STA; + 800d398: 6b51 ldr r1, [r2, #52] ; 0x34 + ((sta_reg & SDMMC_FLAG_CMDACT) != 0U )); + 800d39a: f011 0f45 tst.w r1, #69 ; 0x45 + 800d39e: d0f9 beq.n 800d394 + }while(((sta_reg & (SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT)) == 0U) || + 800d3a0: 0489 lsls r1, r1, #18 + 800d3a2: d4f7 bmi.n 800d394 + if (__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT)) + 800d3a4: 6b53 ldr r3, [r2, #52] ; 0x34 + 800d3a6: 075b lsls r3, r3, #29 + 800d3a8: d502 bpl.n 800d3b0 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT); + 800d3aa: 2004 movs r0, #4 + 800d3ac: 6390 str r0, [r2, #56] ; 0x38 + return SDMMC_ERROR_CMD_RSP_TIMEOUT; + 800d3ae: 4770 bx lr + else if (__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CCRCFAIL)) + 800d3b0: 6b50 ldr r0, [r2, #52] ; 0x34 + 800d3b2: f010 0001 ands.w r0, r0, #1 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_STATIC_CMD_FLAGS); + 800d3b6: bf0c ite eq + 800d3b8: 4b04 ldreq r3, [pc, #16] ; (800d3cc ) + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CCRCFAIL); + 800d3ba: 2301 movne r3, #1 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_STATIC_CMD_FLAGS); + 800d3bc: 6393 str r3, [r2, #56] ; 0x38 + return SDMMC_ERROR_NONE; + 800d3be: 4770 bx lr + return SDMMC_ERROR_TIMEOUT; + 800d3c0: f04f 4000 mov.w r0, #2147483648 ; 0x80000000 +} + 800d3c4: 4770 bx lr + 800d3c6: bf00 nop + 800d3c8: 2009e2a8 .word 0x2009e2a8 + 800d3cc: 002000c5 .word 0x002000c5 + +0800d3d0 : +{ + 800d3d0: b510 push {r4, lr} + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_ALL_SEND_CID; + 800d3d2: 2300 movs r3, #0 +{ + 800d3d4: b086 sub sp, #24 + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_ALL_SEND_CID; + 800d3d6: 2202 movs r2, #2 + 800d3d8: e9cd 3201 strd r3, r2, [sp, #4] + sdmmc_cmdinit.Response = SDMMC_RESPONSE_LONG; + 800d3dc: f44f 7240 mov.w r2, #768 ; 0x300 + sdmmc_cmdinit.WaitForInterrupt = SDMMC_WAIT_NO; + 800d3e0: e9cd 2303 strd r2, r3, [sp, #12] +{ + 800d3e4: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d3e6: f44f 5380 mov.w r3, #4096 ; 0x1000 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d3ea: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d3ec: 9305 str r3, [sp, #20] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d3ee: f7ff fccd bl 800cd8c + errorstate = SDMMC_GetCmdResp2(SDMMCx); + 800d3f2: 4620 mov r0, r4 + 800d3f4: f7ff ffc4 bl 800d380 +} + 800d3f8: b006 add sp, #24 + 800d3fa: bd10 pop {r4, pc} + +0800d3fc : +{ + 800d3fc: b510 push {r4, lr} + 800d3fe: b086 sub sp, #24 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_LONG; + 800d400: 2209 movs r2, #9 + 800d402: f44f 7340 mov.w r3, #768 ; 0x300 + 800d406: e9cd 2302 strd r2, r3, [sp, #8] + sdmmc_cmdinit.Argument = Argument; + 800d40a: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d40c: f44f 5380 mov.w r3, #4096 ; 0x1000 + 800d410: 2100 movs r1, #0 + 800d412: e9cd 1304 strd r1, r3, [sp, #16] +{ + 800d416: 4604 mov r4, r0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d418: a901 add r1, sp, #4 + 800d41a: f7ff fcb7 bl 800cd8c + errorstate = SDMMC_GetCmdResp2(SDMMCx); + 800d41e: 4620 mov r0, r4 + 800d420: f7ff ffae bl 800d380 +} + 800d424: b006 add sp, #24 + 800d426: bd10 pop {r4, pc} + +0800d428 : + uint32_t count = SDMMC_CMDTIMEOUT * (SystemCoreClock / 8U /1000U); + 800d428: 4b0e ldr r3, [pc, #56] ; (800d464 ) + 800d42a: f44f 51fa mov.w r1, #8000 ; 0x1f40 + 800d42e: 681b ldr r3, [r3, #0] + 800d430: fbb3 f3f1 udiv r3, r3, r1 + 800d434: f241 3188 movw r1, #5000 ; 0x1388 +{ + 800d438: 4602 mov r2, r0 + uint32_t count = SDMMC_CMDTIMEOUT * (SystemCoreClock / 8U /1000U); + 800d43a: 434b muls r3, r1 + if (count-- == 0U) + 800d43c: 3b01 subs r3, #1 + 800d43e: d30e bcc.n 800d45e + sta_reg = SDMMCx->STA; + 800d440: 6b51 ldr r1, [r2, #52] ; 0x34 + ((sta_reg & SDMMC_FLAG_CMDACT) != 0U )); + 800d442: f011 0f45 tst.w r1, #69 ; 0x45 + 800d446: d0f9 beq.n 800d43c + }while(((sta_reg & (SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT)) == 0U) || + 800d448: 0489 lsls r1, r1, #18 + 800d44a: d4f7 bmi.n 800d43c + if(__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT)) + 800d44c: 6b50 ldr r0, [r2, #52] ; 0x34 + 800d44e: f010 0004 ands.w r0, r0, #4 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT); + 800d452: bf15 itete ne + 800d454: 2004 movne r0, #4 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_STATIC_CMD_FLAGS); + 800d456: 4b04 ldreq r3, [pc, #16] ; (800d468 ) + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT); + 800d458: 6390 strne r0, [r2, #56] ; 0x38 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_STATIC_CMD_FLAGS); + 800d45a: 6393 streq r3, [r2, #56] ; 0x38 + return SDMMC_ERROR_NONE; + 800d45c: 4770 bx lr + return SDMMC_ERROR_TIMEOUT; + 800d45e: f04f 4000 mov.w r0, #2147483648 ; 0x80000000 +} + 800d462: 4770 bx lr + 800d464: 2009e2a8 .word 0x2009e2a8 + 800d468: 002000c5 .word 0x002000c5 + +0800d46c : +{ + 800d46c: b510 push {r4, lr} + 800d46e: b086 sub sp, #24 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d470: 2229 movs r2, #41 ; 0x29 + 800d472: f44f 7380 mov.w r3, #256 ; 0x100 + 800d476: e9cd 2302 strd r2, r3, [sp, #8] + sdmmc_cmdinit.Argument = Argument; + 800d47a: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d47c: f44f 5380 mov.w r3, #4096 ; 0x1000 + 800d480: 2100 movs r1, #0 + 800d482: e9cd 1304 strd r1, r3, [sp, #16] +{ + 800d486: 4604 mov r4, r0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d488: a901 add r1, sp, #4 + 800d48a: f7ff fc7f bl 800cd8c + errorstate = SDMMC_GetCmdResp3(SDMMCx); + 800d48e: 4620 mov r0, r4 + 800d490: f7ff ffca bl 800d428 +} + 800d494: b006 add sp, #24 + 800d496: bd10 pop {r4, pc} + +0800d498 : +{ + 800d498: b510 push {r4, lr} + 800d49a: b086 sub sp, #24 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d49c: 2201 movs r2, #1 + 800d49e: f44f 7380 mov.w r3, #256 ; 0x100 + 800d4a2: e9cd 2302 strd r2, r3, [sp, #8] + sdmmc_cmdinit.Argument = Argument; + 800d4a6: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d4a8: f44f 5380 mov.w r3, #4096 ; 0x1000 + 800d4ac: 2100 movs r1, #0 + 800d4ae: e9cd 1304 strd r1, r3, [sp, #16] +{ + 800d4b2: 4604 mov r4, r0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d4b4: a901 add r1, sp, #4 + 800d4b6: f7ff fc69 bl 800cd8c + errorstate = SDMMC_GetCmdResp3(SDMMCx); + 800d4ba: 4620 mov r0, r4 + 800d4bc: f7ff ffb4 bl 800d428 +} + 800d4c0: b006 add sp, #24 + 800d4c2: bd10 pop {r4, pc} + +0800d4c4 : + uint32_t count = SDMMC_CMDTIMEOUT * (SystemCoreClock / 8U /1000U); + 800d4c4: 4b1f ldr r3, [pc, #124] ; (800d544 ) +{ + 800d4c6: b510 push {r4, lr} + uint32_t count = SDMMC_CMDTIMEOUT * (SystemCoreClock / 8U /1000U); + 800d4c8: 681b ldr r3, [r3, #0] +{ + 800d4ca: 4604 mov r4, r0 + uint32_t count = SDMMC_CMDTIMEOUT * (SystemCoreClock / 8U /1000U); + 800d4cc: f44f 50fa mov.w r0, #8000 ; 0x1f40 + 800d4d0: fbb3 f3f0 udiv r3, r3, r0 + 800d4d4: f241 3088 movw r0, #5000 ; 0x1388 + 800d4d8: 4343 muls r3, r0 + if (count-- == 0U) + 800d4da: 3b01 subs r3, #1 + 800d4dc: d329 bcc.n 800d532 + sta_reg = SDMMCx->STA; + 800d4de: 6b60 ldr r0, [r4, #52] ; 0x34 + ((sta_reg & SDMMC_FLAG_CMDACT) != 0U )); + 800d4e0: f010 0f45 tst.w r0, #69 ; 0x45 + 800d4e4: d0f9 beq.n 800d4da + }while(((sta_reg & (SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT)) == 0U) || + 800d4e6: 0480 lsls r0, r0, #18 + 800d4e8: d4f7 bmi.n 800d4da + if(__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT)) + 800d4ea: 6b63 ldr r3, [r4, #52] ; 0x34 + 800d4ec: 0758 lsls r0, r3, #29 + 800d4ee: d502 bpl.n 800d4f6 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT); + 800d4f0: 2004 movs r0, #4 + 800d4f2: 63a0 str r0, [r4, #56] ; 0x38 +} + 800d4f4: bd10 pop {r4, pc} + else if(__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CCRCFAIL)) + 800d4f6: 6b60 ldr r0, [r4, #52] ; 0x34 + 800d4f8: f010 0001 ands.w r0, r0, #1 + 800d4fc: d002 beq.n 800d504 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CCRCFAIL); + 800d4fe: 2301 movs r3, #1 + 800d500: 63a3 str r3, [r4, #56] ; 0x38 + return SDMMC_ERROR_CMD_CRC_FAIL; + 800d502: e7f7 b.n 800d4f4 + return (uint8_t)(SDMMCx->RESPCMD); + 800d504: 6923 ldr r3, [r4, #16] + if(SDMMC_GetCommandResponse(SDMMCx) != SD_CMD) + 800d506: b2db uxtb r3, r3 + 800d508: 4299 cmp r1, r3 + 800d50a: d115 bne.n 800d538 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_STATIC_CMD_FLAGS); + 800d50c: 4b0e ldr r3, [pc, #56] ; (800d548 ) + 800d50e: 63a3 str r3, [r4, #56] ; 0x38 + return (*(__IO uint32_t *) tmp); + 800d510: 6963 ldr r3, [r4, #20] + if((response_r1 & (SDMMC_R6_GENERAL_UNKNOWN_ERROR | SDMMC_R6_ILLEGAL_CMD | SDMMC_R6_COM_CRC_FAILED)) == SDMMC_ALLZERO) + 800d512: f413 4060 ands.w r0, r3, #57344 ; 0xe000 + 800d516: d102 bne.n 800d51e + *pRCA = (uint16_t) (response_r1 >> 16); + 800d518: 0c1b lsrs r3, r3, #16 + 800d51a: 8013 strh r3, [r2, #0] + return SDMMC_ERROR_NONE; + 800d51c: e7ea b.n 800d4f4 + else if((response_r1 & SDMMC_R6_ILLEGAL_CMD) == SDMMC_R6_ILLEGAL_CMD) + 800d51e: 045a lsls r2, r3, #17 + 800d520: d40c bmi.n 800d53c + return SDMMC_ERROR_GENERAL_UNKNOWN_ERR; + 800d522: f413 4f00 tst.w r3, #32768 ; 0x8000 + 800d526: bf14 ite ne + 800d528: f44f 5080 movne.w r0, #4096 ; 0x1000 + 800d52c: f44f 3080 moveq.w r0, #65536 ; 0x10000 + 800d530: e7e0 b.n 800d4f4 + return SDMMC_ERROR_TIMEOUT; + 800d532: f04f 4000 mov.w r0, #2147483648 ; 0x80000000 + 800d536: e7dd b.n 800d4f4 + return SDMMC_ERROR_CMD_CRC_FAIL; + 800d538: 2001 movs r0, #1 + 800d53a: e7db b.n 800d4f4 + return SDMMC_ERROR_ILLEGAL_CMD; + 800d53c: f44f 5000 mov.w r0, #8192 ; 0x2000 + 800d540: e7d8 b.n 800d4f4 + 800d542: bf00 nop + 800d544: 2009e2a8 .word 0x2009e2a8 + 800d548: 002000c5 .word 0x002000c5 + +0800d54c : +{ + 800d54c: b530 push {r4, r5, lr} + 800d54e: b089 sub sp, #36 ; 0x24 + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SET_REL_ADDR; + 800d550: 2300 movs r3, #0 +{ + 800d552: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SET_REL_ADDR; + 800d554: 2503 movs r5, #3 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d556: f44f 7180 mov.w r1, #256 ; 0x100 + sdmmc_cmdinit.WaitForInterrupt = SDMMC_WAIT_NO; + 800d55a: e9cd 1305 strd r1, r3, [sp, #20] + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SET_REL_ADDR; + 800d55e: e9cd 3503 strd r3, r5, [sp, #12] +{ + 800d562: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d564: f44f 5380 mov.w r3, #4096 ; 0x1000 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d568: a903 add r1, sp, #12 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d56a: 9307 str r3, [sp, #28] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d56c: f7ff fc0e bl 800cd8c + errorstate = SDMMC_GetCmdResp6(SDMMCx, SDMMC_CMD_SET_REL_ADDR, pRCA); + 800d570: 9a01 ldr r2, [sp, #4] + 800d572: 4629 mov r1, r5 + 800d574: 4620 mov r0, r4 + 800d576: f7ff ffa5 bl 800d4c4 +} + 800d57a: b009 add sp, #36 ; 0x24 + 800d57c: bd30 pop {r4, r5, pc} + ... + +0800d580 : + uint32_t count = SDMMC_CMDTIMEOUT * (SystemCoreClock / 8U /1000U); + 800d580: 4b13 ldr r3, [pc, #76] ; (800d5d0 ) + 800d582: f44f 51fa mov.w r1, #8000 ; 0x1f40 + 800d586: 681b ldr r3, [r3, #0] + 800d588: fbb3 f3f1 udiv r3, r3, r1 + 800d58c: f241 3188 movw r1, #5000 ; 0x1388 +{ + 800d590: 4602 mov r2, r0 + uint32_t count = SDMMC_CMDTIMEOUT * (SystemCoreClock / 8U /1000U); + 800d592: 434b muls r3, r1 + if (count-- == 0U) + 800d594: 3b01 subs r3, #1 + 800d596: d317 bcc.n 800d5c8 + sta_reg = SDMMCx->STA; + 800d598: 6b51 ldr r1, [r2, #52] ; 0x34 + ((sta_reg & SDMMC_FLAG_CMDACT) != 0U )); + 800d59a: f011 0f45 tst.w r1, #69 ; 0x45 + 800d59e: d0f9 beq.n 800d594 + }while(((sta_reg & (SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT)) == 0U) || + 800d5a0: 0488 lsls r0, r1, #18 + 800d5a2: d4f7 bmi.n 800d594 + if(__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT)) + 800d5a4: 6b53 ldr r3, [r2, #52] ; 0x34 + 800d5a6: 0759 lsls r1, r3, #29 + 800d5a8: d502 bpl.n 800d5b0 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT); + 800d5aa: 2004 movs r0, #4 + 800d5ac: 6390 str r0, [r2, #56] ; 0x38 + return SDMMC_ERROR_CMD_RSP_TIMEOUT; + 800d5ae: 4770 bx lr + else if(__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CCRCFAIL)) + 800d5b0: 6b50 ldr r0, [r2, #52] ; 0x34 + 800d5b2: f010 0001 ands.w r0, r0, #1 + 800d5b6: d002 beq.n 800d5be + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CCRCFAIL); + 800d5b8: 2301 movs r3, #1 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CMDREND); + 800d5ba: 6393 str r3, [r2, #56] ; 0x38 + 800d5bc: 4770 bx lr + if(__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CMDREND)) + 800d5be: 6b53 ldr r3, [r2, #52] ; 0x34 + 800d5c0: 065b lsls r3, r3, #25 + 800d5c2: d503 bpl.n 800d5cc + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CMDREND); + 800d5c4: 2340 movs r3, #64 ; 0x40 + 800d5c6: e7f8 b.n 800d5ba + return SDMMC_ERROR_TIMEOUT; + 800d5c8: f04f 4000 mov.w r0, #2147483648 ; 0x80000000 +} + 800d5cc: 4770 bx lr + 800d5ce: bf00 nop + 800d5d0: 2009e2a8 .word 0x2009e2a8 + +0800d5d4 : +{ + 800d5d4: b510 push {r4, lr} + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_HS_SEND_EXT_CSD; + 800d5d6: f44f 72d5 mov.w r2, #426 ; 0x1aa +{ + 800d5da: b086 sub sp, #24 + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_HS_SEND_EXT_CSD; + 800d5dc: 2308 movs r3, #8 + 800d5de: e9cd 2301 strd r2, r3, [sp, #4] + sdmmc_cmdinit.WaitForInterrupt = SDMMC_WAIT_NO; + 800d5e2: f44f 7180 mov.w r1, #256 ; 0x100 + 800d5e6: 2300 movs r3, #0 + 800d5e8: e9cd 1303 strd r1, r3, [sp, #12] +{ + 800d5ec: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d5ee: f44f 5380 mov.w r3, #4096 ; 0x1000 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d5f2: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d5f4: 9305 str r3, [sp, #20] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d5f6: f7ff fbc9 bl 800cd8c + errorstate = SDMMC_GetCmdResp7(SDMMCx); + 800d5fa: 4620 mov r0, r4 + 800d5fc: f7ff ffc0 bl 800d580 +} + 800d600: b006 add sp, #24 + 800d602: bd10 pop {r4, pc} + +0800d604 : + 800d604: b510 push {r4, lr} + 800d606: 3901 subs r1, #1 + 800d608: 4402 add r2, r0 + 800d60a: 4290 cmp r0, r2 + 800d60c: d101 bne.n 800d612 + 800d60e: 2000 movs r0, #0 + 800d610: e005 b.n 800d61e + 800d612: 7803 ldrb r3, [r0, #0] + 800d614: f811 4f01 ldrb.w r4, [r1, #1]! + 800d618: 42a3 cmp r3, r4 + 800d61a: d001 beq.n 800d620 + 800d61c: 1b18 subs r0, r3, r4 + 800d61e: bd10 pop {r4, pc} + 800d620: 3001 adds r0, #1 + 800d622: e7f2 b.n 800d60a + +0800d624 : + 800d624: 440a add r2, r1 + 800d626: 4291 cmp r1, r2 + 800d628: f100 33ff add.w r3, r0, #4294967295 ; 0xffffffff + 800d62c: d100 bne.n 800d630 + 800d62e: 4770 bx lr + 800d630: b510 push {r4, lr} + 800d632: f811 4b01 ldrb.w r4, [r1], #1 + 800d636: f803 4f01 strb.w r4, [r3, #1]! + 800d63a: 4291 cmp r1, r2 + 800d63c: d1f9 bne.n 800d632 + 800d63e: bd10 pop {r4, pc} + +0800d640 : + 800d640: 4288 cmp r0, r1 + 800d642: b510 push {r4, lr} + 800d644: eb01 0402 add.w r4, r1, r2 + 800d648: d902 bls.n 800d650 + 800d64a: 4284 cmp r4, r0 + 800d64c: 4623 mov r3, r4 + 800d64e: d807 bhi.n 800d660 + 800d650: 1e43 subs r3, r0, #1 + 800d652: 42a1 cmp r1, r4 + 800d654: d008 beq.n 800d668 + 800d656: f811 2b01 ldrb.w r2, [r1], #1 + 800d65a: f803 2f01 strb.w r2, [r3, #1]! + 800d65e: e7f8 b.n 800d652 + 800d660: 4402 add r2, r0 + 800d662: 4601 mov r1, r0 + 800d664: 428a cmp r2, r1 + 800d666: d100 bne.n 800d66a + 800d668: bd10 pop {r4, pc} + 800d66a: f813 4d01 ldrb.w r4, [r3, #-1]! + 800d66e: f802 4d01 strb.w r4, [r2, #-1]! + 800d672: e7f7 b.n 800d664 + +0800d674 : + 800d674: 4402 add r2, r0 + 800d676: 4603 mov r3, r0 + 800d678: 4293 cmp r3, r2 + 800d67a: d100 bne.n 800d67e + 800d67c: 4770 bx lr + 800d67e: f803 1b01 strb.w r1, [r3], #1 + 800d682: e7f9 b.n 800d678 + +0800d684 : + 800d684: 46ec mov ip, sp + 800d686: e8a0 5ff0 stmia.w r0!, {r4, r5, r6, r7, r8, r9, sl, fp, ip, lr} + 800d68a: f04f 0000 mov.w r0, #0 + 800d68e: 4770 bx lr + +0800d690 : + 800d690: e8b0 5ff0 ldmia.w r0!, {r4, r5, r6, r7, r8, r9, sl, fp, ip, lr} + 800d694: 46e5 mov sp, ip + 800d696: 0008 movs r0, r1 + 800d698: bf08 it eq + 800d69a: 2001 moveq r0, #1 + 800d69c: 4770 bx lr + 800d69e: bf00 nop + +0800d6a0 : + 800d6a0: 4603 mov r3, r0 + 800d6a2: f811 2b01 ldrb.w r2, [r1], #1 + 800d6a6: f803 2b01 strb.w r2, [r3], #1 + 800d6aa: 2a00 cmp r2, #0 + 800d6ac: d1f9 bne.n 800d6a2 + 800d6ae: 4770 bx lr + +0800d6b0 : + 800d6b0: b510 push {r4, lr} + 800d6b2: 460b mov r3, r1 + 800d6b4: b162 cbz r2, 800d6d0 + 800d6b6: 3a01 subs r2, #1 + 800d6b8: d008 beq.n 800d6cc + 800d6ba: f813 4b01 ldrb.w r4, [r3], #1 + 800d6be: f800 4b01 strb.w r4, [r0], #1 + 800d6c2: 2c00 cmp r4, #0 + 800d6c4: d1f7 bne.n 800d6b6 + 800d6c6: 1a58 subs r0, r3, r1 + 800d6c8: 3801 subs r0, #1 + 800d6ca: bd10 pop {r4, pc} + 800d6cc: 2200 movs r2, #0 + 800d6ce: 7002 strb r2, [r0, #0] + 800d6d0: f813 2b01 ldrb.w r2, [r3], #1 + 800d6d4: 2a00 cmp r2, #0 + 800d6d6: d1fb bne.n 800d6d0 + 800d6d8: e7f5 b.n 800d6c6 + +0800d6da : + 800d6da: 4603 mov r3, r0 + 800d6dc: f813 2b01 ldrb.w r2, [r3], #1 + 800d6e0: 2a00 cmp r2, #0 + 800d6e2: d1fb bne.n 800d6dc + 800d6e4: 1a18 subs r0, r3, r0 + 800d6e6: 3801 subs r0, #1 + 800d6e8: 4770 bx lr + 800d6ea: 0000 movs r0, r0 + 800d6ec: 0000 movs r0, r0 + ... + +0800d6f0 <__flash_burn_veneer>: + 800d6f0: f85f f000 ldr.w pc, [pc] ; 800d6f4 <__flash_burn_veneer+0x4> + 800d6f4: 2009e001 .word 0x2009e001 + +0800d6f8 <__flash_page_erase_veneer>: + 800d6f8: f85f f000 ldr.w pc, [pc] ; 800d6fc <__flash_page_erase_veneer+0x4> + 800d6fc: 2009e08d .word 0x2009e08d + 800d700: 6f636e69 .word 0x6f636e69 + 800d704: 006e .short 0x006e + 800d706: 6944 .short 0x6944 + 800d708: 44203a65 .word 0x44203a65 + 800d70c: 44005546 .word 0x44005546 + 800d710: 203a6569 .word 0x203a6569 + 800d714: 6e776f44 .word 0x6e776f44 + 800d718: 64617267 .word 0x64617267 + 800d71c: 69440065 .word 0x69440065 + 800d720: 42203a65 .word 0x42203a65 + 800d724: 6b6e616c .word 0x6b6e616c + 800d728: 00687369 .word 0x00687369 + 800d72c: 3a656944 .word 0x3a656944 + 800d730: 69724220 .word 0x69724220 + 800d734: 42006b63 .word 0x42006b63 + 800d738: 32746f6f .word 0x32746f6f + 800d73c: 00554644 .word 0x00554644 + 800d740: 43455441 .word 0x43455441 + 800d744: 38303643 .word 0x38303643 + 800d748: 53440a42 .word 0x53440a42 + 800d74c: 33433832 .word 0x33433832 + 800d750: 4c004236 .word 0x4c004236 + 800d754: 0052 .short 0x0052 + 800d756: 6e65 .short 0x6e65 + 800d758: 5f726574 .word 0x5f726574 + 800d75c: 28756664 .word 0x28756664 + 800d760: 0029 .short 0x0029 + 800d762: 0a0d .short 0x0a0d + 800d764: 346b4d0a .word 0x346b4d0a + 800d768: 6f6f4220 .word 0x6f6f4220 + 800d76c: 616f6c74 .word 0x616f6c74 + 800d770: 3a726564 .word 0x3a726564 + 800d774: 463e0020 .word 0x463e0020 + 800d778: 57455249 .word 0x57455249 + 800d77c: 454c4c41 .word 0x454c4c41 + 800d780: 70003c44 .word 0x70003c44 + 800d784: 2d726961 .word 0x2d726961 + 800d788: 63697262 .word 0x63697262 + 800d78c: 0064656b .word 0x0064656b + 800d790: 69726556 .word 0x69726556 + 800d794: 203a7966 .word 0x203a7966 + 800d798: 00000000 .word 0x00000000 + 800d79c: 00000150 .word 0x00000150 + 800d7a0: 00000001 .word 0x00000001 + 800d7a4: 00000000 .word 0x00000000 + 800d7a8: 00000001 .word 0x00000001 + 800d7ac: 00000000 .word 0x00000000 + +0800d7b0 : + 800d7b0: 0700262e ff000707 .&....../ + +0800d7b9 : + 800d7b9: 227f0021 !..".. + +0800d7bf : + 800d7bf: 400020ae c83fa8a1 12da00d3 f1d980d5 . .@..?......... + 800d7cf: ff8130db 148da6a4 .0....... + +0800d7d8 : + 800d7d8: 227f0021 !..".. + +0800d7de : + 800d7de: 007f007f 0034007f 000d8081 000d8081 ......4......... + 800d7ee: 00628081 01030183 0183000b 000b0103 ..b............. + 800d7fe: 01030183 007f007f 0034007f ..........4.. + +0800d80b : + 800d80b: 007f007f 002b007f 8803f881 0000f085 ......+......... + 800d81b: 400380c0 00008086 03d84040 04808100 ...@....@@...... + 800d82b: 00808a40 800000f8 80000040 80834004 @.......@....@.. + 800d83b: 40038000 50f88082 041f8100 000f8310 ...@...P........ + 800d84b: 8100091f 8100031f 8a10040f 021f0008 ................ + 800d85b: 10080403 12040f00 0f001383 08821003 ................ + 800d86b: 7f007f1f 2b007f00 .......+.. + +0800d875 : + 800d875: 0037007f 40c08086 03303060 05188190 ..7....@`00..... + 800d885: 08188510 68e0f018 f8808b00 38e1071c .......h.......8 + 800d895: 0103060c 82000b01 006820ff 0e7fc182 ......... h..... + 800d8a5: 80808700 0e3860c0 85006907 04060301 .....`8..i...... + 800d8b5: 82020406 02030606 01030383 f881005e ............^... + 800d8c5: 08868804 40400000 820003d8 400380c0 ......@@.......@ + 800d8d5: c000808a 40804040 04c00080 00c08300 ....@@.@........ + 800d8e5: 84400400 80c00080 80834003 40048000 ..@......@.....@ + 800d8f5: 08008087 30488808 1f810043 1f810009 ......H0C....... + 800d905: 1f810003 1f8f0006 00070000 100f001f ................ + 800d915: 0f100f08 11030e00 001f0984 8100061f ................ + 800d925: 8412040f 1b000013 0026007f ..........&.. + +0800d932 : + 800d932: 002c007f 00888003 98f09000 1640d0a0 ..,...........@. + 800d942: 80808400 180330e0 18031081 80e03084 .....0.......0.. + 800d952: 89004380 0c18f0c0 191373e6 89010519 .C.......s...... + 800d962: 07030100 000039ef 92001501 f9ede702 .....9.......... + 800d972: 783818c8 78381838 f9c81838 0042e7ed ..8x8.8x8.....B. + 800d982: e03d0f85 000a0180 70c08085 0017023f ..=........p?... + 800d992: 07fcf883 7e870304 640464fc 03047efc .......~.d.d.~.. + 800d9a2: f0fc0783 01840043 06020301 03028306 ....C........... + 800d9b2: 82001b01 06060703 06030781 06060781 ................ + 800d9c2: 2e030782 03f88100 e0108408 40040000 ...............@ + 800d9d2: c0008084 83400380 03800080 c0808440 ......@.....@... + 800d9e2: 40048000 c0008084 81400380 81000380 ...@......@..... + 800d9f2: 81000bf8 830804f0 04c00030 00c08300 ........0....... + 800da02: 84400480 f0400080 00834003 40048000 ..@...@..@.....@ + 800da12: c0008088 40804040 81000380 81001bf8 ....@@.@........ + 800da22: 8410031f 0e000708 09841103 041f001f ................ + 800da32: 001f8300 84880347 0f007f84 13831204 ....G........... + 800da42: 00081f00 000b1b81 10040f81 0f000c83 ................ + 800da52: 08841003 0409001f 000c8412 10030f00 ................ + 800da62: 0f000883 0f881004 00001f00 031f0007 ................ + 800da72: 7f1b8100 00001000 ........ + +0800da7a : + 800da7a: 0035007f 00f0f095 6060c080 10103030 ..5.......``00.. + 800da8a: 10101818 60603030 006b80c0 0c040f04 ....00``..k..... + 800da9a: ff820003 840007ff e0fc0f03 c083006c ............l... + 800daaa: 00058080 0603018c 80800006 0f3c70c0 .............p<. + 800daba: 8e006d01 03030101 06060202 03030202 .m.............. + 800daca: 00570101 0803f881 00e01084 83400480 ..W...........@. + 800dada: 04c00080 00c08400 400380c0 80008083 ...........@.... + 800daea: 80854003 80c000c0 80834003 40040000 .@.......@.....@ + 800dafa: 80008083 80844003 048000f8 00808740 .....@......@... + 800db0a: 48880808 81003c30 8410031f 0f000708 ...H0<.......... + 800db1a: 0f8a1004 08100f00 000f100f 8300041f ................ + 800db2a: 0347001f 7f848488 00061f00 11030e81 ..G............. + 800db3a: 001f0984 8410030f 0f001f08 13841204 ................ + 800db4a: 7f1b0000 00002200 .....".. + +0800db52 : + 800db52: 007f007f 0036007f 90fc9089 0090fc90 ......6......... + 800db62: 4203fc40 f000048b 00c00000 fc4000f0 @..B..........@. + 800db72: 04814203 03840066 03030000 05078100 .B..f........... + 800db82: 04038900 03040302 7f070000 7f007f00 ................ + 800db92: 00003900 .9.. + +0800db96 : + 800db96: 0035007f c0078081 00064081 6f808082 ..5......@.....o + 800dba6: ffff8200 c0070006 c7c3c189 f0f8dcce ................ + 800dbb6: 0068c0e0 06ff7f82 068081c0 70608800 ..h...........`p + 800dbc6: 070e1c38 007f0103 f8810050 80810006 8.......P....... + 800dbd6: 80834004 40038000 00c08084 83400480 .@.....@......@. + 800dbe6: 04c00080 00c08400 4003f040 f8810009 ........@..@.... + 800dbf6: 10840803 048000e0 00808440 400380c0 ........@......@ + 800dc06: 80008083 80814004 1f810034 00821005 .....@..4....... + 800dc16: 8310040f 0347000f 7f848488 10040f00 ......G......... + 800dc26: 0f000f83 08851003 0f00001f 08811003 ................ + 800dc36: 1f810008 08841003 040f0007 000f8310 ................ + 800dc46: 8300041f 040f001f 7f138112 00001b00 ................ + +0800dc56 : + 800dc56: 007f007f 0043007f 0c30c083 01060073 ......C...0.s... + 800dc66: 0c300084 06000403 7f007f01 39007f00 ..0............9 + ... + +0800dc78 : + 800dc78: 0031007f c0e06084 85001080 f030e0e0 ..1..`........0. + 800dc88: 863008f0 6020f0f0 004f80c0 c189c00c ..0... `..O..... + 800dc98: dccec7c3 c0e0f0f8 ff8f0009 0f0f00ff ................ + 800dca8: cc8c0c0c cccc4ccc 00030f8f feff0183 .....L.......... + 800dcb8: 808a0057 3870e0c0 03070e1c 82000a01 W.....p8........ + 800dcc8: 0004ffff 301f0689 30302030 0004061f .......00 00.... + 800dcd8: 57ffff82 01018200 01820012 82031101 ...W............ + 800dce8: 00410101 f8080889 00000808 400380c0 ..A............@ + 800dcf8: 80008083 80834004 40048000 c0008084 .....@.....@.... + 800dd08: 84400380 f0400080 00094003 0804f081 ..@...@..@...... + 800dd18: 00003083 80844004 0380c000 00808340 .0...@......@... + 800dd28: 82400380 0034f880 1f101088 00001010 ..@...4......... + 800dd38: 8300041f 0409001f 000c8312 8312040f ................ + 800dd48: 071f0013 030f8100 08088110 040f8100 ................ + 800dd58: 000c8310 8411030e 1f001f09 0f810006 ................ + 800dd68: 08821003 1b007f1f .......... + +0800dd72 : + 800dd72: 002c007f 00888003 98f09000 1640d0a0 ..,...........@. + 800dd82: 80808400 180330e0 18031081 80e03084 .....0.......0.. + 800dd92: 89004380 0c18f0c0 191373e6 89010519 .C.......s...... + 800dda2: 07030100 000039ef 92001501 f9ede702 .....9.......... + 800ddb2: 783818c8 78381838 f9c81838 0042e7ed ..8x8.8x8.....B. + 800ddc2: e03d0f85 000a0180 70c08085 0017023f ..=........p?... + 800ddd2: 07fcf883 7e870304 640464fc 03047efc .......~.d.d.~.. + 800dde2: f0fc0783 01840043 06020301 03028306 ....C........... + 800ddf2: 82001b01 06060703 06030781 06060781 ................ + 800de02: 2b030782 03f88100 e0108408 40040000 ...+...........@ + 800de12: c0008084 83400380 03800080 c0808440 ......@.....@... + 800de22: 40048000 c0008084 81400380 81000380 ...@......@..... + 800de32: 81000bf8 830804f0 04000030 00808340 ........0...@... + 800de42: 840004c0 f04000c0 00034003 d8404083 ......@..@...@@. + 800de52: 80810003 80844004 0380c000 03808140 .....@......@... + 800de62: 14f88100 031f8100 07088410 11030e00 ................ + 800de72: 001f0984 8300041f 0347001f 7f848488 ..........G..... + 800de82: 12040f00 1f001383 1b810008 0f81000b ................ + 800de92: 0c831004 11030e00 001f0984 8510030f ................ + 800dea2: 00001f08 8110030f 81000408 8100031f ................ + 800deb2: 8310040f 041f000f 031f8100 7f1b8100 ................ + 800dec2: 00000c00 .... + +0800dec6 : + 800dec6: 007f007f 002f007f 0804f881 8000f083 ....../......... + 800ded6: 80844004 0380c000 00808440 0005f800 .@......@....... + 800dee6: 0004c081 8000c083 80824003 880057c0 .........@...W.. + 800def6: 0503011f 0f001009 13841204 03047f00 ................ + 800df06: 00078408 10030f00 0f000083 08841003 ................ + 800df16: 0347001f 7f848288 007f007f 002e007f ..G............. + ... + +0800df27 : + 800df27: 0035007f 04808082 60c08300 83180530 ..5........`0... + 800df37: 04c07030 6b808100 ff018600 070606fe 0p.....k........ + 800df47: e6810604 07860604 fffe0607 03006901 .............i.. + 800df57: bf078401 000580e0 0005ff81 bfe08084 ................ + 800df67: 69010307 07068300 89010303 06060203 ...i............ + 800df77: 02020607 83010303 62060703 04f88100 ...........b.... + 800df87: 00f88900 0830c000 060000f8 70008980 ......0........p + 800df97: 08088888 04f80010 00088688 f8102040 ............@ .. + 800dfa7: 0f810059 0f831004 02030300 00021f83 Y............... + 800dfb7: 00890406 11101008 1f000e11 00041005 ................ + 800dfc7: 007f1f81 ....... + +0800dfce : + 800dfce: 0035007f 04808082 60c08300 83180530 ..5........`0... + 800dfde: 04c07030 6b808100 ff018600 070606fe 0p.....k........ + 800dfee: e6810604 07860604 fffe0607 03006901 .............i.. + 800dffe: bf078401 000580e0 0005ff81 bfe08084 ................ + 800e00e: 69010307 07068300 89010303 06060203 ...i............ + 800e01e: 02020607 83010303 62060703 04f88100 ...........b.... + 800e02e: 00f88300 824804f8 80060088 88700089 ......H.......p. + 800e03e: 10080888 8804f800 30000883 88820803 ...........0.... + 800e04e: 81005770 8310040f 0408000f 000f8210 pW.............. + 800e05e: 00890406 11101008 1f000e11 00871005 ................ + 800e06e: 11121418 007f1010 ........,.. + +0800e079 : + 800e079: 0028007f 2060c085 18061030 60301085 ..(...` 0.....0` + 800e089: 000f80c0 30e0e085 3008f0f0 20f0f086 .......0...0... + 800e099: 4c80c060 fffc8300 82000e01 000eff03 `..L............ + 800e0a9: 00ffff8f 0c0c0f0f 4ccccc8c 0f8fcccc ...........L.... + 800e0b9: 01830003 004bfeff 0c060389 20303018 ......K......00 + 800e0c9: 20036020 18103089 e0713f1e 000b80c0 `. .0...?q..... + 800e0d9: 04ffff82 1f068900 30203030 04061f30 ........00 00... + 800e0e9: ffff8200 0184005e 09060703 01018200 ....^........... + 800e0f9: 01820311 88003c01 08888870 80001008 .....<..p....... + 800e109: 80834004 40040000 c0008084 83400380 .@.....@......@. + 800e119: 04800080 00808440 400380f8 00008086 ....@......@.... + 800e129: 03d84040 80c08200 80834003 40038000 @@.......@.....@ + 800e139: 42c08082 10088800 0e111110 12040f00 ...B............ + 800e149: 0e001383 09841103 061f001f 040f8100 ................ + 800e159: 00088310 8100041f 8100041f 8100031f ................ + 800e169: 8300041f 0347001f 7f848788 38100000 ......G........8 + 800e179: 83000410 04103810 38108300 19007f10 .....8.....8.... + ... + +0800e18b : + 800e18b: 0035007f 0e80c082 6a800600 ffff8200 ..5........j.... + 800e19b: 80900005 603060c0 63c080c0 30181c37 .....`0`...c7..0 + 800e1ab: 691e3f20 ffff8800 ceccc0c0 c005c1c7 ?.i............ + 800e1bb: c009c181 007f8081 f8810056 f8840004 ........V....... + 800e1cb: 0380c000 00808340 85400380 c000c080 ....@.....@..... + 800e1db: 83400380 04000080 00808340 87400380 ..@.....@.....@. + 800e1eb: 0000f880 03d84040 80c08200 80834003 ....@@.......@.. + 800e1fb: 40038000 42c08082 040f8100 000f8410 ...@...B........ + 800e20b: 0803047f 47000783 84848803 061f007f .......G........ + 800e21b: 030e8100 1f098411 10030f00 041f0882 ................ + 800e22b: 031f8100 041f8100 001f8300 82880347 ............G... + 800e23b: 007f7f84 ....".. + +0800e242 : + 800e242: 0038007f 60c08085 10033020 1018188a ..8....` 0...... + 800e252: 60303010 6b80c060 fce08400 00070107 .00``..k........ + 800e262: 07ffff82 0f038400 0068e0fc 380f0187 ..........h....8 + 800e272: 8080c060 018c0005 00060703 70c08080 `..............p + 800e282: 6d010f3c 01018e00 02020303 02020606 <..m............ + 800e292: 01010303 f881005a f8830004 40048000 ....Z..........@ + 800e2a2: c0008084 86400380 40000080 0004d840 ......@....@@... + 800e2b2: 0803f081 c0001083 c0860004 40400000 ..............@@ + 800e2c2: 820003d8 400380c0 80008083 80824003 .......@.....@.. + 800e2d2: 880042c0 18180601 0f000106 13831204 .B.............. + 800e2e2: 00091f00 00031f81 031f0182 00008301 ................ + 800e2f2: 82880347 00047f84 00031f81 00041f81 G............... + 800e302: 47001f83 84828803 22007f7f ...G.......".. + +0800e310 : + 800e310: 0038007f 60c08084 82000420 0004f8f8 ..8....` ....... + 800e320: c0606084 84006b80 0307fce0 ff820007 .``..k.......... + 800e330: 840007ff e0fc0f03 01870068 c060380f ........h....8`. + 800e340: 000a8080 c0808087 010f3c70 018e006d ........p<..m... + 800e350: 02030301 02060602 01030302 88005701 .............W.. + 800e360: 08888870 80001008 80834004 40048000 p........@.....@ + 800e370: 80008083 80824003 810008f8 860004f8 .....@.......... + 800e380: 400000f8 0003d840 0380c082 00808340 ...@@.......@... + 800e390: 83400480 03800080 f8808240 0888003b ..@.....@...;... + 800e3a0: 11111010 040f000e 00138312 8312040f ................ + 800e3b0: 030f0013 1f088210 07860008 18070718 ................ + 800e3c0: 81000407 8200031f 0803047f 0f000783 ................ + 800e3d0: 13831204 10030f00 7f1f0882 00001e00 ................ + 800e3e0: 65737361 64007472 676e776f 65646172 assert.downgrade + 800e3f0: 67697300 69616620 6f6e006c 72696620 .sig fail.no fir + 800e400: 7261776d 61460065 726f7463 6f622079 mware.Factory bo + 800e410: 5700746f 3a4e5241 64655220 67696c20 ot.WARN: Red lig + 800e420: 57007468 3a4e5241 736e5520 656e6769 ht.WARN: Unsigne + 800e430: 69662064 61776d72 47006572 20646f6f d firmware.Good + 800e440: 6d726966 65726177 726f6300 74707572 firmware.corrupt + 800e450: 72696620 7261776d firmware. + +0800e45a : + 800e45a: 2641cbb4 f36ce1f7 71b4f28f 0123fb1d ..A&..l....q..#. + 800e46a: 66d6760d 6ca38aa7 f6f9539b 0518587b .v.f...l.S..{X.. + 800e47a: e93b0b58 b89fc431 113c0444 470f0896 X.;.1...D.<....G + 800e48a: 37ed2581 4a9e237a 3818b7af da0438ba .%.7z#.J...8.8.. + 800e49a: 1dc8a2d6 df5e811c 6d290ca6 8d8f57b8 ......^...)m.W.. + 800e4aa: 9269295e c178d1ce 31d7207b b596a17b ^)i...x.{ .1{... + 800e4ba: 0c1bef3d c31a79aa c8c45845 ffeb2d8a =....y..EX...-.. + 800e4ca: 01829bfe bc5e5f87 4fe5a596 9ffe68c7 ....._^....O.h.. + 800e4da: 0166ef42 95cfc456 38f0b5f4 c5261164 B.f.V......8d.&. + 800e4ea: 66c13999 14120632 689c254c bad38c35 .9.f2...L%.h5... + 800e4fa: 8cde7824 6cdfab52 7809bfb8 3a63bb03 $x..R..l...x..c: + 800e50a: 0ed90111 8f737aa4 7f3b18bf c87b0af0 .....zs...;...{. + 800e51a: 56546067 c5ec0c82 0882bc1d ef39c116 g`TV..........9. + 800e52a: 32babff5 e35fce7c d7621e74 4cc5fce9 ...2|._.t.b....L + 800e53a: 8d11e88a 13c2adc3 2a4f2992 a4f8d2ea .........)O*.... + 800e54a: fe7cd5c4 3b450512 07598954 88d7d6da ..|...E;T.Y..... + 800e55a: 37cfb143 1f897cd2 f3acfe5b 95fc33ba C..7.|..[....3.. + 800e56a: dde7d981 14ef9525 bb97efdd a7d8f333 ....%.......3... + 800e57a: 977a2b34 73aab3ba 32419de7 17a1fcd8 4+z....s..A2.... + 800e58a: fe0bb566 89214063 8e7b92c9 590bdf72 f...c@!...{.r..Y + 800e59a: 76dc5cd0 30dd3016 56f180c2 61a85c26 .\.v.0.0...V&\.a + 800e5aa: 69694fd7 3d57b8e5 582ae235 c69acedd .Oii..W=5.*X.... + 800e5ba: 2b1ca945 8efc010c 13513fbf 137c7e80 E..+.....?Q..~|. + 800e5ca: 5e4b4fd5 d59b4c9b e0d81d9e 2246c0ad .OK^.L........F" + 800e5da: 20314553 666e6f63 66206769 006c6961 SE1 config fail. + 800e5ea: 6c706572 72206775 69757165 00646572 replug required. + 800e5fa: 72726f63 20747075 72696170 63657320 corrupt pair sec + 800e60a: 75636d00 6c756620 7562006c 66206e72 .mcu full.burn f + 800e61a: 3a6c6961 76210020 64696c61 6162003f ail: .!valid?.ba + 800e62a: 61762064 66003f6c 20747361 63697262 d val?.fast bric + 800e63a: 2e2e2e6b 64200020 00656e6f 79706f43 k... . done.Copy + 800e64a: 68676972 30322074 202d3831 43207962 right 2018- by C + 800e65a: 6b6e696f 20657469 2e636e49 206f6e00 oinkite Inc..no + 800e66a: 00726573 66206b77 0016006c 01410800 ser.wk fl.....A. + ... + 800e686: 000000ee 006100e1 218f0000 438f808f ......a....!...C + 800e696: 430080af 20834300 43c343c3 43c343c3 ...C.C. .C.C.C.C + 800e6a6: 43c343c3 0000438f ffffffff 00000000 .C.C.C.......... + 800e6b6: ffffffff 00000000 00000000 000000f0 ................ + ... + 800e6ce: 00001502 003c0000 01bc005c 01bc01fc ......<.\....... + 800e6de: 01dc01dc 03dc03d1 03dc03dc 03dc03dc ................ + 800e6ee: 01dc03dc 0001003c 00120000 00000000 ....<........... + 800e6fe: 00010000 00080000 02000000 00020000 ................ + 800e70e: 00000000 00010000 00070000 .............. + +0800e71c : + 800e71c: 0d0c0b09 .... + +0800e720 : + 800e720: 2e322e33 69742031 323d656d 30353230 3.2.1 time=20250 + 800e730: 2e353134 39303930 67203533 6d3d7469 415.090935 git=m + 800e740: 65747361 64614072 63326663 0d006538 aster@adcf2c8e.. + 800e750: .. + +0800e752 : + 800e752: 33323130 37363534 62613938 66656463 0123456789abcdef + 800e762: 41525350 6166204d 50006c69 203a5253 PSRAM fail.PSR: + 800e772: 6164616e 52535000 6321203a 6b636568 nada.PSR: !check + 800e782: 52535000 6576203a 6f697372 fc00006e .PSR: version... + 800e792: 00020000 00000000 00030000 000a0000 ................ + 800e7a2: 00080000 00100000 6f6c0000 7220676e ..........long r + 800e7b2: 20646165 6c696166 55464400 72617020 ead fail.DFU par + 800e7c2: 66206573 006c6961 646f6f67 72696620 se fail.good fir + 800e7d2: 7261776d 72770065 20676e6f 6c726f77 mware.wrong worl + 800e7e2: 64730064 64726163 6165735f 3a686372 d.sdcard_search: + 800e7f2: 64730020 64726163 6f72705f 203a6562 .sdcard_probe: + 800e802: 696e6900 61662074 73006c69 64656570 .init fail.speed + 800e812: 64697700 73620065 3f657a69 006b6f00 .wide.bsize?.ok. + 800e822: 6c696166 61657220 66440064 00655375 fail read.DfuSe. + 800e832: 6e756f66 20402064 63655200 7265766f found @ .Recover + 800e842: 6f6d2079 002e6564 1f000000 00020000 y mode.......... + 800e852: 00010000 00030000 000c0000 00040000 ................ + 800e862: 00020000 00010000 00030000 000c0000 ................ + ... + +0800e874 : + 800e874: 01002008 fffffc2f fffffffe ffffffff . ../........... + 800e884: ffffffff ffffffff ffffffff ffffffff ................ + 800e894: ffffffff d0364141 bfd25e8c af48a03b ....AA6..^..;.H. + 800e8a4: baaedce6 fffffffe ffffffff ffffffff ................ + 800e8b4: ffffffff 16f81798 59f2815b 2dce28d9 ........[..Y.(.- + 800e8c4: 029bfcdb ce870b07 55a06295 f9dcbbac .........b.U.... + 800e8d4: 79be667e fb10d4b8 9c47d08f a6855419 ~f.y......G..T.. + 800e8e4: fd17b448 0e1108a8 5da4fbfc 26a3c465 H..........]e..& + 800e8f4: 483ada77 00000007 00000000 00000000 w.:H............ + ... + 800e918: 0800663d 08005ec1 08006097 08005cad =f...^...`...\.. + +0800e928 : + 800e928: 01002008 ffffffff ffffffff ffffffff . .............. + ... + 800e944: 00000001 ffffffff fc632551 f3b9cac2 ........Q%c..... + 800e954: a7179e84 bce6faad ffffffff ffffffff ................ + 800e964: 00000000 ffffffff d898c296 f4a13945 ............E9.. + 800e974: 2deb33a0 77037d81 63a440f2 f8bce6e5 .3.-.}.w.@.c.... + 800e984: e12c4247 6b17d1f2 37bf51f5 cbb64068 GB,....k.Q.7h@.. + 800e994: 6b315ece 2bce3357 7c0f9e16 8ee7eb4a .^1kW3.+...|J... + 800e9a4: fe1a7f9b 4fe342e2 27d2604b 3bce3c3e .....B.OK`.'><.; + 800e9b4: cc53b0f6 651d06b0 769886bc b3ebbd55 ..S....e...vU... + 800e9c4: aa3a93e7 5ac635d8 08006785 08005ec1 ..:..5.Z.g...^.. + 800e9d4: 0800672b 08005d29 +g..)].. + +0800e9dc : + ... + 800e9e4: 04030201 09080706 ........ + +0800e9ec : + 800e9ec: 00000000 04030201 ........ + +0800e9f4 : + 800e9f4: 000186a0 00030d40 00061a80 000c3500 ....@........5.. + 800ea04: 000f4240 001e8480 003d0900 007a1200 @B........=...z. + 800ea14: 00f42400 016e3600 01e84800 02dc6c00 .$...6n..H...l.. + 800ea24: 20727463 3f746573 00702100 00006000 ctr set?.!p..`.. + 800ea34: 00000012 00000000 00000003 00000004 ................ + +0800ea44 : + 800ea44: 00008000 .... + +Disassembly of section .relocate: + +2009e000 : +{ +2009e000: b530 push {r4, r5, lr} + while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)) { +2009e002: 4920 ldr r1, [pc, #128] ; (2009e084 ) +2009e004: 690c ldr r4, [r1, #16] +2009e006: 03e5 lsls r5, r4, #15 +2009e008: d4fc bmi.n 2009e004 + uint32_t error = (FLASH->SR & FLASH_FLAG_SR_ERRORS); +2009e00a: 690d ldr r5, [r1, #16] + if(error) { +2009e00c: 4c1e ldr r4, [pc, #120] ; (2009e088 ) +2009e00e: 4225 tst r5, r4 +2009e010: d104 bne.n 2009e01c + if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP)) { +2009e012: 690c ldr r4, [r1, #16] +2009e014: 07e4 lsls r4, r4, #31 + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP); +2009e016: bf44 itt mi +2009e018: 2401 movmi r4, #1 +2009e01a: 610c strmi r4, [r1, #16] + FLASH->SR = FLASH->SR & FLASH_FLAG_SR_ERRORS; +2009e01c: 4919 ldr r1, [pc, #100] ; (2009e084 ) +2009e01e: 4d1a ldr r5, [pc, #104] ; (2009e088 ) +2009e020: 690c ldr r4, [r1, #16] +2009e022: 402c ands r4, r5 +2009e024: 610c str r4, [r1, #16] + __HAL_FLASH_DATA_CACHE_DISABLE(); +2009e026: 680c ldr r4, [r1, #0] +2009e028: f424 6480 bic.w r4, r4, #1024 ; 0x400 +2009e02c: 600c str r4, [r1, #0] + CLEAR_BIT(FLASH->CR, (FLASH_CR_PG | FLASH_CR_MER1 | FLASH_CR_PER | FLASH_CR_PNB)); // added +2009e02e: 694c ldr r4, [r1, #20] +2009e030: f424 64ff bic.w r4, r4, #2040 ; 0x7f8 +2009e034: f024 0407 bic.w r4, r4, #7 +2009e038: 614c str r4, [r1, #20] + SET_BIT(FLASH->CR, FLASH_CR_PG); +2009e03a: 694c ldr r4, [r1, #20] +2009e03c: f044 0401 orr.w r4, r4, #1 +2009e040: 614c str r4, [r1, #20] + *(__IO uint32_t *)(address) = (uint32_t)val; +2009e042: 6002 str r2, [r0, #0] + __ASM volatile ("isb 0xF":::"memory"); +2009e044: f3bf 8f6f isb sy + *(__IO uint32_t *)(address+4) = (uint32_t)(val >> 32); +2009e048: 6043 str r3, [r0, #4] + while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)) { +2009e04a: 690b ldr r3, [r1, #16] +2009e04c: 03da lsls r2, r3, #15 +2009e04e: d4fc bmi.n 2009e04a + uint32_t error = (FLASH->SR & FLASH_FLAG_SR_ERRORS); +2009e050: 6908 ldr r0, [r1, #16] + if(error) { +2009e052: 4028 ands r0, r5 +2009e054: d104 bne.n 2009e060 + if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP)) { +2009e056: 690b ldr r3, [r1, #16] +2009e058: 07db lsls r3, r3, #31 + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP); +2009e05a: bf44 itt mi +2009e05c: 2301 movmi r3, #1 +2009e05e: 610b strmi r3, [r1, #16] + CLEAR_BIT(FLASH->CR, FLASH_CR_PG); +2009e060: 4b08 ldr r3, [pc, #32] ; (2009e084 ) +2009e062: 695a ldr r2, [r3, #20] +2009e064: f022 0201 bic.w r2, r2, #1 +2009e068: 615a str r2, [r3, #20] + __HAL_FLASH_DATA_CACHE_RESET(); +2009e06a: 681a ldr r2, [r3, #0] +2009e06c: f442 5280 orr.w r2, r2, #4096 ; 0x1000 +2009e070: 601a str r2, [r3, #0] +2009e072: 681a ldr r2, [r3, #0] +2009e074: f422 5280 bic.w r2, r2, #4096 ; 0x1000 +2009e078: 601a str r2, [r3, #0] + __HAL_FLASH_DATA_CACHE_ENABLE(); +2009e07a: 681a ldr r2, [r3, #0] +2009e07c: f442 6280 orr.w r2, r2, #1024 ; 0x400 +2009e080: 601a str r2, [r3, #0] +} +2009e082: bd30 pop {r4, r5, pc} +2009e084: 40022000 .word 0x40022000 +2009e088: 0002c3fa .word 0x0002c3fa + +2009e08c : + if(page_num < ((BL_FLASH_SIZE + BL_NVROM_SIZE) / FLASH_ERASE_SIZE)) { +2009e08c: 4b2d ldr r3, [pc, #180] ; (2009e144 ) +2009e08e: 4003 ands r3, r0 +{ +2009e090: b510 push {r4, lr} + if(page_num < ((BL_FLASH_SIZE + BL_NVROM_SIZE) / FLASH_ERASE_SIZE)) { +2009e092: 2b00 cmp r3, #0 +2009e094: d054 beq.n 2009e140 + while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)) { +2009e096: 4b2c ldr r3, [pc, #176] ; (2009e148 ) + page_num &= 0xff; +2009e098: f3c0 3207 ubfx r2, r0, #12, #8 + while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)) { +2009e09c: 6919 ldr r1, [r3, #16] +2009e09e: 03c9 lsls r1, r1, #15 +2009e0a0: d4fc bmi.n 2009e09c + uint32_t error = (FLASH->SR & FLASH_FLAG_SR_ERRORS); +2009e0a2: 691c ldr r4, [r3, #16] + if(error) { +2009e0a4: 4929 ldr r1, [pc, #164] ; (2009e14c ) +2009e0a6: 420c tst r4, r1 +2009e0a8: d104 bne.n 2009e0b4 + if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP)) { +2009e0aa: 6919 ldr r1, [r3, #16] +2009e0ac: 07cc lsls r4, r1, #31 + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP); +2009e0ae: bf44 itt mi +2009e0b0: 2101 movmi r1, #1 +2009e0b2: 6119 strmi r1, [r3, #16] + FLASH->SR = FLASH->SR & 0xffff; +2009e0b4: 4b24 ldr r3, [pc, #144] ; (2009e148 ) +2009e0b6: 6919 ldr r1, [r3, #16] +2009e0b8: b289 uxth r1, r1 +2009e0ba: 6119 str r1, [r3, #16] + __HAL_FLASH_DATA_CACHE_DISABLE(); +2009e0bc: 6819 ldr r1, [r3, #0] +2009e0be: f421 6180 bic.w r1, r1, #1024 ; 0x400 +2009e0c2: 6019 str r1, [r3, #0] + SET_BIT(FLASH->CR, FLASH_CR_BKER); +2009e0c4: 6959 ldr r1, [r3, #20] + if(bank2) { +2009e0c6: f010 6ffe tst.w r0, #133169152 ; 0x7f00000 + SET_BIT(FLASH->CR, FLASH_CR_BKER); +2009e0ca: bf14 ite ne +2009e0cc: f441 6100 orrne.w r1, r1, #2048 ; 0x800 + CLEAR_BIT(FLASH->CR, FLASH_CR_BKER); +2009e0d0: f421 6100 biceq.w r1, r1, #2048 ; 0x800 +2009e0d4: 6159 str r1, [r3, #20] + MODIFY_REG(FLASH->CR, FLASH_CR_PNB, (page_num << POSITION_VAL(FLASH_CR_PNB))); +2009e0d6: 6959 ldr r1, [r3, #20] + uint32_t result; + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) + __ASM volatile ("rbit %0, %1" : "=r" (result) : "r" (value) ); +2009e0d8: f44f 63ff mov.w r3, #2040 ; 0x7f8 +2009e0dc: f421 61ff bic.w r1, r1, #2040 ; 0x7f8 +2009e0e0: fa93 f3a3 rbit r3, r3 + */ + if (value == 0U) + { + return 32U; + } + return __builtin_clz(value); +2009e0e4: fab3 f383 clz r3, r3 +2009e0e8: 409a lsls r2, r3 +2009e0ea: 4b17 ldr r3, [pc, #92] ; (2009e148 ) +2009e0ec: 430a orrs r2, r1 +2009e0ee: 615a str r2, [r3, #20] + SET_BIT(FLASH->CR, FLASH_CR_PER); +2009e0f0: 695a ldr r2, [r3, #20] +2009e0f2: f042 0202 orr.w r2, r2, #2 +2009e0f6: 615a str r2, [r3, #20] + SET_BIT(FLASH->CR, FLASH_CR_STRT); +2009e0f8: 695a ldr r2, [r3, #20] +2009e0fa: f442 3280 orr.w r2, r2, #65536 ; 0x10000 +2009e0fe: 615a str r2, [r3, #20] + while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)) { +2009e100: 691a ldr r2, [r3, #16] +2009e102: 03d1 lsls r1, r2, #15 +2009e104: d4fc bmi.n 2009e100 + uint32_t error = (FLASH->SR & FLASH_FLAG_SR_ERRORS); +2009e106: 6918 ldr r0, [r3, #16] +2009e108: 4a10 ldr r2, [pc, #64] ; (2009e14c ) + if(error) { +2009e10a: 4010 ands r0, r2 +2009e10c: d104 bne.n 2009e118 + if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP)) { +2009e10e: 691a ldr r2, [r3, #16] +2009e110: 07d2 lsls r2, r2, #31 + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP); +2009e112: bf44 itt mi +2009e114: 2201 movmi r2, #1 +2009e116: 611a strmi r2, [r3, #16] + CLEAR_BIT(FLASH->CR, (FLASH_CR_PER | FLASH_CR_PNB)); +2009e118: 4b0b ldr r3, [pc, #44] ; (2009e148 ) +2009e11a: 695a ldr r2, [r3, #20] +2009e11c: f422 62ff bic.w r2, r2, #2040 ; 0x7f8 +2009e120: f022 0202 bic.w r2, r2, #2 +2009e124: 615a str r2, [r3, #20] + __HAL_FLASH_DATA_CACHE_RESET(); +2009e126: 681a ldr r2, [r3, #0] +2009e128: f442 5280 orr.w r2, r2, #4096 ; 0x1000 +2009e12c: 601a str r2, [r3, #0] +2009e12e: 681a ldr r2, [r3, #0] +2009e130: f422 5280 bic.w r2, r2, #4096 ; 0x1000 +2009e134: 601a str r2, [r3, #0] + __HAL_FLASH_DATA_CACHE_ENABLE(); +2009e136: 681a ldr r2, [r3, #0] +2009e138: f442 6280 orr.w r2, r2, #1024 ; 0x400 +2009e13c: 601a str r2, [r3, #0] +} +2009e13e: bd10 pop {r4, pc} + return 1; +2009e140: 2001 movs r0, #1 +2009e142: e7fc b.n 2009e13e +2009e144: 07fe0000 .word 0x07fe0000 +2009e148: 40022000 .word 0x40022000 +2009e14c: 0002c3fa .word 0x0002c3fa diff --git a/stm32/mk4-bootloader/releases/README.md b/stm32/mk4-bootloader/releases/README.md index a32c35dc..65ea319e 100644 --- a/stm32/mk4-bootloader/releases/README.md +++ b/stm32/mk4-bootloader/releases/README.md @@ -13,3 +13,4 @@ Github is nearly free, so why not capture all the actual bits! - V3.1.4 - 12-word duress wallets - V3.1.5 - bugfix so slot 10 of trick pins is usable - V3.2.0 - share code with Q bootrom, no changes for Mk4 operation. +- V3.2.1 - enable omitted if wrong PIN options & fix "Wipe -> Wallet" trick pin option diff --git a/stm32/mk4-bootloader/se2.c b/stm32/mk4-bootloader/se2.c index 778206a6..d8ffdd53 100644 --- a/stm32/mk4-bootloader/se2.c +++ b/stm32/mk4-bootloader/se2.c @@ -729,12 +729,12 @@ se2_test_trick_pin(const char *pin, int pin_len, trick_slot_t *found_slot, bool uint16_t todo = found_slot->tc_flags; // hmm: don't need this data if safety is off.. but we have it anyway - if(found_slot->tc_flags & TC_WORD_WALLET) { + if(todo & TC_WORD_WALLET) { // it's a 12/24-word BIP-39 seed phrase, un-encrypted. if(found+1 < NUM_TRICKS) { memcpy(found_slot->xdata, &slots[found+1][0], 32); } - } else if(found_slot->tc_flags & TC_XPRV_WALLET) { + } else if(todo & TC_XPRV_WALLET) { // it's an xprv-based wallet if(found+2 < NUM_TRICKS) { memcpy(&found_slot->xdata[0], &slots[found+1][0], 32); @@ -875,14 +875,24 @@ se2_handle_bad_pin(int num_fails) if(slot.tc_flags & TC_WIPE) { // Wipe keys and stop. They can power cycle and keep trying // so only do this if a valid key currently exists. - bool valid; - const mcu_key_t *cur = mcu_key_get(&valid); + if(slot.tc_flags & TC_BRICK) { + // special case TC_WIPE|TC_BRICK + bool valid; + const mcu_key_t *cur = mcu_key_get(&valid); + if(valid) { + mcu_key_clear(cur); + oled_show(screen_wiped); + LOCKUP_FOREVER(); + } + // else fall-thru if no keys to wipe and WIPE|BRICK mode, will now brick + // used in "Last Chance" mode - if(valid) { - mcu_key_clear(cur); - oled_show(screen_wiped); - - LOCKUP_FOREVER(); + } else { + mcu_key_clear(NULL); // does valid key check + if(slot.tc_flags == TC_WIPE) { + oled_show(screen_wiped); + LOCKUP_FOREVER(); + } } } @@ -893,6 +903,13 @@ se2_handle_bad_pin(int num_fails) // brick code will happen. fast_brick(); } + + if(slot.tc_flags & TC_REBOOT) { + NVIC_SystemReset(); + } + //if(slot.tc_flags & TC_FAKE_OUT) {//nothing to do here - Silent Wipe} + // only used together with TC_WIPE. At this point we are already wiped + // EPIN_AUTH_FAIL handled by caller } } diff --git a/stm32/mk4-bootloader/version.h b/stm32/mk4-bootloader/version.h index 82a086f2..0a49027f 100644 --- a/stm32/mk4-bootloader/version.h +++ b/stm32/mk4-bootloader/version.h @@ -6,7 +6,7 @@ // Public version number for humans. Lots more version data added by Makefile. // - update ../MK4-Makefile BOOTLOADER_VERSION once this is qualified version -#define RELEASE_VERSION "3.2.0" +#define RELEASE_VERSION "3.2.1" extern const char version_string[]; diff --git a/stm32/q1-bootloader/Makefile b/stm32/q1-bootloader/Makefile index 8be24566..7b5e408f 100644 --- a/stm32/q1-bootloader/Makefile +++ b/stm32/q1-bootloader/Makefile @@ -8,8 +8,11 @@ # clobber - delete all build products # -# for any file it cant find, look in ../mk4-bootloader -VPATH = ../mk4-bootloader +# for any source file needed, look also in ../mk4-bootloader +vpath %.c ../mk4-bootloader +vpath %.S ../mk4-bootloader +vpath %.h ../mk4-bootloader +vpath %.py ../mk4-bootloader # Toolchain TOOLCHAIN = arm-none-eabi- diff --git a/stm32/q1-bootloader/releases/1.1.0.txt b/stm32/q1-bootloader/releases/1.1.0.txt new file mode 100644 index 00000000..ffb133b9 --- /dev/null +++ b/stm32/q1-bootloader/releases/1.1.0.txt @@ -0,0 +1,4 @@ +f85eb3fcc2bbaa3056ef1efb5f5de94c1527eea17c21e21f0fb4fcd6a988c8b6 bootloader.dfu +62aaa45a663e9765125f1bd9d36bd498c402a94b0fd7dfc3c9cdb771c8f2384b bootloader.bin +e16d7e6a6f7379327799e3add8948a8c903f0f8b8429084b7731fd73b60d9274 bootloader.lss +1.1.0 time=20250415.093631 git=master@28926acd diff --git a/stm32/q1-bootloader/releases/1.1.0/bootloader.bin b/stm32/q1-bootloader/releases/1.1.0/bootloader.bin new file mode 100644 index 00000000..aeb9b20c Binary files /dev/null and b/stm32/q1-bootloader/releases/1.1.0/bootloader.bin differ diff --git a/stm32/q1-bootloader/releases/1.1.0/bootloader.dfu b/stm32/q1-bootloader/releases/1.1.0/bootloader.dfu new file mode 100644 index 00000000..b458c40f Binary files /dev/null and b/stm32/q1-bootloader/releases/1.1.0/bootloader.dfu differ diff --git a/stm32/q1-bootloader/releases/1.1.0/bootloader.lss b/stm32/q1-bootloader/releases/1.1.0/bootloader.lss new file mode 100644 index 00000000..1a175a90 --- /dev/null +++ b/stm32/q1-bootloader/releases/1.1.0/bootloader.lss @@ -0,0 +1,35454 @@ + +bootloader.elf: file format elf32-littlearm + +Sections: +Idx Name Size VMA LMA File off Algn + 0 .text 00010ac4 08000000 08000000 00010000 2**8 + CONTENTS, ALLOC, LOAD, READONLY, CODE + 1 .relocate 00000150 2009e000 08010ac4 0002e000 2**2 + CONTENTS, ALLOC, LOAD, READONLY, CODE + 2 .bss 000002ec 2009e150 08010c14 0002e150 2**2 + ALLOC + 3 .stack 00000804 2009e43c 08010f00 0002e150 2**0 + ALLOC + 4 .debug_info 0002c7b2 00000000 00000000 0002e150 2**0 + CONTENTS, READONLY, DEBUGGING, OCTETS + 5 .debug_abbrev 000060d7 00000000 00000000 0005a902 2**0 + CONTENTS, READONLY, DEBUGGING, OCTETS + 6 .debug_loc 000148e6 00000000 00000000 000609d9 2**0 + CONTENTS, READONLY, DEBUGGING, OCTETS + 7 .debug_aranges 000010e8 00000000 00000000 000752bf 2**0 + CONTENTS, READONLY, DEBUGGING, OCTETS + 8 .debug_ranges 00002228 00000000 00000000 000763a7 2**0 + CONTENTS, READONLY, DEBUGGING, OCTETS + 9 .debug_macro 000325ab 00000000 00000000 000785cf 2**0 + CONTENTS, READONLY, DEBUGGING, OCTETS + 10 .debug_line 0001e38f 00000000 00000000 000aab7a 2**0 + CONTENTS, READONLY, DEBUGGING, OCTETS + 11 .debug_str 0011cf0b 00000000 00000000 000c8f09 2**0 + CONTENTS, READONLY, DEBUGGING, OCTETS + 12 .comment 00000049 00000000 00000000 001e5e14 2**0 + CONTENTS, READONLY + 13 .ARM.attributes 00000032 00000000 00000000 001e5e5d 2**0 + CONTENTS, READONLY + 14 .debug_frame 0000371c 00000000 00000000 001e5e90 2**2 + CONTENTS, READONLY, DEBUGGING, OCTETS + +Disassembly of section .text: + +08000000 <_sfixed>: + 8000000: 200a0000 .word 0x200a0000 + 8000004: 080000b5 .word 0x080000b5 + 8000008: 0800001d .word 0x0800001d + 800000c: 0800001f .word 0x0800001f + 8000010: 08000021 .word 0x08000021 + 8000014: 08000023 .word 0x08000023 + 8000018: 08000025 .word 0x08000025 + +0800001c : + 800001c: be01 bkpt 0x0001 + +0800001e : + 800001e: be02 bkpt 0x0002 + +08000020 : + 8000020: be03 bkpt 0x0003 + +08000022 : + 8000022: be04 bkpt 0x0004 + +08000024 : + 8000024: be05 bkpt 0x0005 + 8000026: e7fe b.n 8000026 + +08000028 : + ... + 8000040: 08000305 .word 0x08000305 + +08000044 : + 8000044: 00000200 .word 0x00000200 + ... + 8000060: 20296328 .word 0x20296328 + 8000064: 79706f43 .word 0x79706f43 + 8000068: 68676972 .word 0x68676972 + 800006c: 30322074 .word 0x30322074 + 8000070: 322d3831 .word 0x322d3831 + 8000074: 20323230 .word 0x20323230 + 8000078: 43207962 .word 0x43207962 + 800007c: 6b6e696f .word 0x6b6e696f + 8000080: 20657469 .word 0x20657469 + 8000084: 2e636e49 .word 0x2e636e49 + 8000088: 0a200a20 .word 0x0a200a20 + 800008c: 73696854 .word 0x73696854 + 8000090: 61707320 .word 0x61707320 + 8000094: 66206563 .word 0x66206563 + 8000098: 7220726f .word 0x7220726f + 800009c: 21746e65 .word 0x21746e65 + 80000a0: 73754a20 .word 0x73754a20 + 80000a4: 42312074 .word 0x42312074 + 80000a8: 792f4354 .word 0x792f4354 + 80000ac: 2e726165 .word 0x2e726165 + 80000b0: 0a200a20 .word 0x0a200a20 + +080000b4 : + 80000b4: f000 f816 bl 80000e4 + 80000b8: f04f 30ff mov.w r0, #4294967295 ; 0xffffffff + 80000bc: f04f 0100 mov.w r1, #0 + 80000c0: f04f 0200 mov.w r2, #0 + 80000c4: f04f 0300 mov.w r3, #0 + 80000c8: f000 f91c bl 8000304 + 80000cc: f248 0120 movw r1, #32800 ; 0x8020 + 80000d0: ea4f 3101 mov.w r1, r1, lsl #12 + 80000d4: 6808 ldr r0, [r1, #0] + 80000d6: 4685 mov sp, r0 + 80000d8: f04f 0001 mov.w r0, #1 + 80000dc: f8d1 e004 ldr.w lr, [r1, #4] + 80000e0: 4770 bx lr + ... + +080000e4 : + void +firewall_setup(void) +{ + // This is critical: without the clock enabled to "SYSCFG" we + // can't tell the FW is enabled or not! Enabling it would also not work + __HAL_RCC_SYSCFG_CLK_ENABLE(); + 80000e4: 4b1b ldr r3, [pc, #108] ; (8000154 ) +{ + 80000e6: b500 push {lr} + __HAL_RCC_SYSCFG_CLK_ENABLE(); + 80000e8: 6e1a ldr r2, [r3, #96] ; 0x60 + 80000ea: f042 0201 orr.w r2, r2, #1 + 80000ee: 661a str r2, [r3, #96] ; 0x60 + 80000f0: 6e1b ldr r3, [r3, #96] ; 0x60 +{ + 80000f2: b08b sub sp, #44 ; 0x2c + __HAL_RCC_SYSCFG_CLK_ENABLE(); + 80000f4: f003 0301 and.w r3, r3, #1 + 80000f8: 9300 str r3, [sp, #0] + 80000fa: 9b00 ldr r3, [sp, #0] + + if(__HAL_FIREWALL_IS_ENABLED()) { + 80000fc: 4b16 ldr r3, [pc, #88] ; (8000158 ) + 80000fe: 685b ldr r3, [r3, #4] + 8000100: 07db lsls r3, r3, #31 + 8000102: d524 bpl.n 800014e + // REMINDERS: + // - cannot debug anything in boot loader w/ firewall enabled (no readback, no bkpt) + // - when RDP=2, this protection still important or else python can read pairing secret + // - in factory mode (RDP!=2), it's nice to have this disabled so we can debug still + // - could look at RDP level here, but it would be harder to completely reset the bag number! + if(check_all_ones_raw(rom_secrets->bag_number, sizeof(rom_secrets->bag_number))) { + 8000104: 4815 ldr r0, [pc, #84] ; (800015c ) + 8000106: 2120 movs r1, #32 + 8000108: f002 fb74 bl 80027f4 + 800010c: b9f8 cbnz r0, 800014e + // for debug builds, never enable firewall + return; +#endif + + extern int firewall_starts; // see startup.S ... aligned@256 (0x08000300) + uint32_t start = (uint32_t)&firewall_starts; + 800010e: 4b14 ldr r3, [pc, #80] ; (8000160 ) + uint32_t len = BL_FLASH_SIZE - (start - BL_FLASH_BASE); + 8000110: 4a14 ldr r2, [pc, #80] ; (8000164 ) + // but sensitive stuff is still there (which would allow bypass) + // - so it's important to enable option bytes to set write-protect flash of entire bootloader + // - to disable debug and complete protection, must enable write-protect "level 2" (RDP=2) + // + + FIREWALL_InitTypeDef init = { + 8000112: 9302 str r3, [sp, #8] + uint32_t len = BL_FLASH_SIZE - (start - BL_FLASH_BASE); + 8000114: 1ad3 subs r3, r2, r3 + FIREWALL_InitTypeDef init = { + 8000116: e9cd 3203 strd r3, r2, [sp, #12] + 800011a: f44f 4380 mov.w r3, #16384 ; 0x4000 + 800011e: e9cd 3005 strd r3, r0, [sp, #20] + 8000122: e9cd 0007 strd r0, r0, [sp, #28] + 8000126: 9009 str r0, [sp, #36] ; 0x24 + .VDataSegmentLength = 0, + .VolatileDataExecution = 0, + .VolatileDataShared = 0, + }; + + int rv = HAL_FIREWALL_Config((FIREWALL_InitTypeDef *)&init); + 8000128: a802 add r0, sp, #8 + 800012a: f000 f821 bl 8000170 + if(rv) { + 800012e: b110 cbz r0, 8000136 + INCONSISTENT("fw"); + 8000130: 480d ldr r0, [pc, #52] ; (8000168 ) + 8000132: f000 fc81 bl 8000a38 + } + + __HAL_FIREWALL_PREARM_DISABLE(); + 8000136: 4b0d ldr r3, [pc, #52] ; (800016c ) + 8000138: 6a1a ldr r2, [r3, #32] + 800013a: f022 0201 bic.w r2, r2, #1 + 800013e: 621a str r2, [r3, #32] + 8000140: 6a1b ldr r3, [r3, #32] + 8000142: f003 0301 and.w r3, r3, #1 + 8000146: 9301 str r3, [sp, #4] + 8000148: 9b01 ldr r3, [sp, #4] + HAL_FIREWALL_EnableFirewall(); + 800014a: f000 f88b bl 8000264 +} + 800014e: b00b add sp, #44 ; 0x2c + 8000150: f85d fb04 ldr.w pc, [sp], #4 + 8000154: 40021000 .word 0x40021000 + 8000158: 40010000 .word 0x40010000 + 800015c: 0801c050 .word 0x0801c050 + 8000160: 08000300 .word 0x08000300 + 8000164: 0801c000 .word 0x0801c000 + 8000168: 0800d9a0 .word 0x0800d9a0 + 800016c: 40011c00 .word 0x40011c00 + +08000170 : + * @param fw_init: Firewall initialization structure + * @note The API returns HAL_ERROR if the Firewall is already enabled. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_FIREWALL_Config(FIREWALL_InitTypeDef * fw_init) +{ + 8000170: b573 push {r0, r1, r4, r5, r6, lr} + /* Check the Firewall initialization structure allocation */ + if(fw_init == NULL) + 8000172: b910 cbnz r0, 800017a + { + return HAL_ERROR; + 8000174: 2001 movs r0, #1 + /* Set Firewall Configuration Register VDE and VDS bits + (volatile data execution and shared configuration) */ + MODIFY_REG(FIREWALL->CR, FW_CR_VDS|FW_CR_VDE, fw_init->VolatileDataExecution|fw_init->VolatileDataShared); + + return HAL_OK; +} + 8000176: b002 add sp, #8 + 8000178: bd70 pop {r4, r5, r6, pc} + __HAL_RCC_FIREWALL_CLK_ENABLE(); + 800017a: 4b19 ldr r3, [pc, #100] ; (80001e0 ) + 800017c: 6e1a ldr r2, [r3, #96] ; 0x60 + 800017e: f042 0280 orr.w r2, r2, #128 ; 0x80 + 8000182: 661a str r2, [r3, #96] ; 0x60 + 8000184: 6e1b ldr r3, [r3, #96] ; 0x60 + 8000186: f003 0380 and.w r3, r3, #128 ; 0x80 + 800018a: 9301 str r3, [sp, #4] + 800018c: 9b01 ldr r3, [sp, #4] + if (__HAL_FIREWALL_IS_ENABLED() != RESET) + 800018e: 4b15 ldr r3, [pc, #84] ; (80001e4 ) + 8000190: 685b ldr r3, [r3, #4] + 8000192: 07db lsls r3, r3, #31 + 8000194: d5ee bpl.n 8000174 + if (fw_init->CodeSegmentLength != 0U) + 8000196: 6841 ldr r1, [r0, #4] + if (fw_init->NonVDataSegmentLength < 0x100U) + 8000198: 68c2 ldr r2, [r0, #12] + if (fw_init->CodeSegmentLength != 0U) + 800019a: b109 cbz r1, 80001a0 + if (fw_init->NonVDataSegmentLength < 0x100U) + 800019c: 2aff cmp r2, #255 ; 0xff + 800019e: d9e9 bls.n 8000174 + WRITE_REG(FIREWALL->CSSA, (FW_CSSA_ADD & fw_init->CodeSegmentStartAddress)); + 80001a0: 6803 ldr r3, [r0, #0] + 80001a2: 4e11 ldr r6, [pc, #68] ; (80001e8 ) + if (fw_init->VDataSegmentLength != 0U) + 80001a4: 6944 ldr r4, [r0, #20] + WRITE_REG(FIREWALL->CSSA, (FW_CSSA_ADD & fw_init->CodeSegmentStartAddress)); + 80001a6: ea03 0506 and.w r5, r3, r6 + 80001aa: 4b10 ldr r3, [pc, #64] ; (80001ec ) + 80001ac: 601d str r5, [r3, #0] + WRITE_REG(FIREWALL->CSL, (FW_CSL_LENG & fw_init->CodeSegmentLength)); + 80001ae: 4d10 ldr r5, [pc, #64] ; (80001f0 ) + 80001b0: 4029 ands r1, r5 + 80001b2: 6059 str r1, [r3, #4] + WRITE_REG(FIREWALL->NVDSSA, (FW_NVDSSA_ADD & fw_init->NonVDataSegmentStartAddress)); + 80001b4: 6881 ldr r1, [r0, #8] + WRITE_REG(FIREWALL->NVDSL, (FW_NVDSL_LENG & fw_init->NonVDataSegmentLength)); + 80001b6: 402a ands r2, r5 + WRITE_REG(FIREWALL->NVDSSA, (FW_NVDSSA_ADD & fw_init->NonVDataSegmentStartAddress)); + 80001b8: 4031 ands r1, r6 + 80001ba: 6099 str r1, [r3, #8] + WRITE_REG(FIREWALL->NVDSL, (FW_NVDSL_LENG & fw_init->NonVDataSegmentLength)); + 80001bc: 60da str r2, [r3, #12] + WRITE_REG(FIREWALL->VDSSA, (FW_VDSSA_ADD & fw_init->VDataSegmentStartAddress)); + 80001be: 6901 ldr r1, [r0, #16] + 80001c0: 4a0c ldr r2, [pc, #48] ; (80001f4 ) + 80001c2: 4011 ands r1, r2 + WRITE_REG(FIREWALL->VDSL, (FW_VDSL_LENG & fw_init->VDataSegmentLength)); + 80001c4: 4022 ands r2, r4 + WRITE_REG(FIREWALL->VDSSA, (FW_VDSSA_ADD & fw_init->VDataSegmentStartAddress)); + 80001c6: 6119 str r1, [r3, #16] + WRITE_REG(FIREWALL->VDSL, (FW_VDSL_LENG & fw_init->VDataSegmentLength)); + 80001c8: 615a str r2, [r3, #20] + MODIFY_REG(FIREWALL->CR, FW_CR_VDS|FW_CR_VDE, fw_init->VolatileDataExecution|fw_init->VolatileDataShared); + 80001ca: e9d0 2006 ldrd r2, r0, [r0, #24] + 80001ce: 6a19 ldr r1, [r3, #32] + 80001d0: 4302 orrs r2, r0 + 80001d2: f021 0106 bic.w r1, r1, #6 + 80001d6: 430a orrs r2, r1 + 80001d8: 621a str r2, [r3, #32] + return HAL_OK; + 80001da: 2000 movs r0, #0 + 80001dc: e7cb b.n 8000176 + 80001de: bf00 nop + 80001e0: 40021000 .word 0x40021000 + 80001e4: 40010000 .word 0x40010000 + 80001e8: 00ffff00 .word 0x00ffff00 + 80001ec: 40011c00 .word 0x40011c00 + 80001f0: 003fff00 .word 0x003fff00 + 80001f4: 0003ffc0 .word 0x0003ffc0 + +080001f8 : +void HAL_FIREWALL_GetConfig(FIREWALL_InitTypeDef * fw_config) +{ + + /* Enable Firewall clock, in case no Firewall configuration has been carried + out up to this point */ + __HAL_RCC_FIREWALL_CLK_ENABLE(); + 80001f8: 4b15 ldr r3, [pc, #84] ; (8000250 ) + 80001fa: 6e1a ldr r2, [r3, #96] ; 0x60 +{ + 80001fc: b573 push {r0, r1, r4, r5, r6, lr} + __HAL_RCC_FIREWALL_CLK_ENABLE(); + 80001fe: f042 0280 orr.w r2, r2, #128 ; 0x80 + 8000202: 661a str r2, [r3, #96] ; 0x60 + 8000204: 6e1b ldr r3, [r3, #96] ; 0x60 + + /* Retrieve code segment protection setting */ + fw_config->CodeSegmentStartAddress = (READ_REG(FIREWALL->CSSA) & FW_CSSA_ADD); + 8000206: 4e13 ldr r6, [pc, #76] ; (8000254 ) + fw_config->CodeSegmentLength = (READ_REG(FIREWALL->CSL) & FW_CSL_LENG); + 8000208: 4d13 ldr r5, [pc, #76] ; (8000258 ) + __HAL_RCC_FIREWALL_CLK_ENABLE(); + 800020a: f003 0380 and.w r3, r3, #128 ; 0x80 + 800020e: 9301 str r3, [sp, #4] + 8000210: 9b01 ldr r3, [sp, #4] + fw_config->CodeSegmentStartAddress = (READ_REG(FIREWALL->CSSA) & FW_CSSA_ADD); + 8000212: 4b12 ldr r3, [pc, #72] ; (800025c ) + 8000214: 681a ldr r2, [r3, #0] + 8000216: 4032 ands r2, r6 + 8000218: 6002 str r2, [r0, #0] + fw_config->CodeSegmentLength = (READ_REG(FIREWALL->CSL) & FW_CSL_LENG); + 800021a: 685c ldr r4, [r3, #4] + 800021c: 402c ands r4, r5 + 800021e: 6044 str r4, [r0, #4] + + /* Retrieve non volatile data segment protection setting */ + fw_config->NonVDataSegmentStartAddress = (READ_REG(FIREWALL->NVDSSA) & FW_NVDSSA_ADD); + 8000220: 6899 ldr r1, [r3, #8] + fw_config->NonVDataSegmentLength = (READ_REG(FIREWALL->NVDSL) & FW_NVDSL_LENG); + + /* Retrieve volatile data segment protection setting */ + fw_config->VDataSegmentStartAddress = (READ_REG(FIREWALL->VDSSA) & FW_VDSSA_ADD); + 8000222: 4c0f ldr r4, [pc, #60] ; (8000260 ) + fw_config->NonVDataSegmentStartAddress = (READ_REG(FIREWALL->NVDSSA) & FW_NVDSSA_ADD); + 8000224: 4031 ands r1, r6 + 8000226: 6081 str r1, [r0, #8] + fw_config->NonVDataSegmentLength = (READ_REG(FIREWALL->NVDSL) & FW_NVDSL_LENG); + 8000228: 68da ldr r2, [r3, #12] + 800022a: 402a ands r2, r5 + 800022c: 60c2 str r2, [r0, #12] + fw_config->VDataSegmentStartAddress = (READ_REG(FIREWALL->VDSSA) & FW_VDSSA_ADD); + 800022e: 6919 ldr r1, [r3, #16] + 8000230: 4021 ands r1, r4 + 8000232: 6101 str r1, [r0, #16] + fw_config->VDataSegmentLength = (READ_REG(FIREWALL->VDSL) & FW_VDSL_LENG); + 8000234: 695a ldr r2, [r3, #20] + 8000236: 4022 ands r2, r4 + 8000238: 6142 str r2, [r0, #20] + + /* Retrieve volatile data execution setting */ + fw_config->VolatileDataExecution = (READ_REG(FIREWALL->CR) & FW_CR_VDE); + 800023a: 6a1a ldr r2, [r3, #32] + 800023c: f002 0204 and.w r2, r2, #4 + 8000240: 6182 str r2, [r0, #24] + + /* Retrieve volatile data shared setting */ + fw_config->VolatileDataShared = (READ_REG(FIREWALL->CR) & FW_CR_VDS); + 8000242: 6a1b ldr r3, [r3, #32] + 8000244: f003 0302 and.w r3, r3, #2 + 8000248: 61c3 str r3, [r0, #28] + + return; +} + 800024a: b002 add sp, #8 + 800024c: bd70 pop {r4, r5, r6, pc} + 800024e: bf00 nop + 8000250: 40021000 .word 0x40021000 + 8000254: 00ffff00 .word 0x00ffff00 + 8000258: 003fff00 .word 0x003fff00 + 800025c: 40011c00 .word 0x40011c00 + 8000260: 0003ffc0 .word 0x0003ffc0 + +08000264 : + * @retval None + */ +void HAL_FIREWALL_EnableFirewall(void) +{ + /* Clears FWDIS bit of SYSCFG CFGR1 register */ + CLEAR_BIT(SYSCFG->CFGR1, SYSCFG_CFGR1_FWDIS); + 8000264: 4a02 ldr r2, [pc, #8] ; (8000270 ) + 8000266: 6853 ldr r3, [r2, #4] + 8000268: f023 0301 bic.w r3, r3, #1 + 800026c: 6053 str r3, [r2, #4] + +} + 800026e: 4770 bx lr + 8000270: 40010000 .word 0x40010000 + +08000274 : + * @retval None + */ +void HAL_FIREWALL_EnablePreArmFlag(void) +{ + /* Set FPA bit */ + SET_BIT(FIREWALL->CR, FW_CR_FPA); + 8000274: 4a02 ldr r2, [pc, #8] ; (8000280 ) + 8000276: 6a13 ldr r3, [r2, #32] + 8000278: f043 0301 orr.w r3, r3, #1 + 800027c: 6213 str r3, [r2, #32] +} + 800027e: 4770 bx lr + 8000280: 40011c00 .word 0x40011c00 + +08000284 : + * @retval None + */ +void HAL_FIREWALL_DisablePreArmFlag(void) +{ + /* Clear FPA bit */ + CLEAR_BIT(FIREWALL->CR, FW_CR_FPA); + 8000284: 4a02 ldr r2, [pc, #8] ; (8000290 ) + 8000286: 6a13 ldr r3, [r2, #32] + 8000288: f023 0301 bic.w r3, r3, #1 + 800028c: 6213 str r3, [r2, #32] +} + 800028e: 4770 bx lr + 8000290: 40011c00 .word 0x40011c00 + ... + +08000300 <_firewall_start>: + 8000300: 0f193a11 .word 0x0f193a11 + +08000304 : + 8000304: f24e 0900 movw r9, #57344 ; 0xe000 + 8000308: f2c2 0909 movt r9, #8201 ; 0x2009 + 800030c: f44f 5a00 mov.w sl, #8192 ; 0x2000 + 8000310: 44ca add sl, r9 + +08000312 : + 8000312: f849 ab04 str.w sl, [r9], #4 + 8000316: 45d1 cmp r9, sl + 8000318: d1fb bne.n 8000312 + 800031a: 46ea mov sl, sp + 800031c: 46cd mov sp, r9 + 800031e: e92d 4400 stmdb sp!, {sl, lr} + +08000322 : + 8000322: f000 f841 bl 80003a8 + 8000326: e8bd 4400 ldmia.w sp!, {sl, lr} + 800032a: 46d5 mov sp, sl + 800032c: f24e 0900 movw r9, #57344 ; 0xe000 + 8000330: f2c2 0909 movt r9, #8201 ; 0x2009 + 8000334: f44f 5a00 mov.w sl, #8192 ; 0x2000 + 8000338: 44ca add sl, r9 + +0800033a : + 800033a: f849 0b04 str.w r0, [r9], #4 + 800033e: 45d1 cmp r9, sl + 8000340: d1fb bne.n 800033a + 8000342: 4770 bx lr + +08000344 <__NVIC_SystemReset>: + \details Acts as a special kind of Data Memory Barrier. + It completes when all explicit memory accesses before this instruction complete. + */ +__STATIC_FORCEINLINE void __DSB(void) +{ + __ASM volatile ("dsb 0xF":::"memory"); + 8000344: f3bf 8f4f dsb sy +__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void) +{ + __DSB(); /* Ensure all outstanding memory accesses included + buffered write are completed before reset */ + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 8000348: 4905 ldr r1, [pc, #20] ; (8000360 <__NVIC_SystemReset+0x1c>) + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 800034a: 4b06 ldr r3, [pc, #24] ; (8000364 <__NVIC_SystemReset+0x20>) + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 800034c: 68ca ldr r2, [r1, #12] + 800034e: f402 62e0 and.w r2, r2, #1792 ; 0x700 + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 8000352: 4313 orrs r3, r2 + 8000354: 60cb str r3, [r1, #12] + 8000356: f3bf 8f4f dsb sy + SCB_AIRCR_SYSRESETREQ_Msk ); /* Keep priority group unchanged */ + __DSB(); /* Ensure completion of memory access */ + + for(;;) /* wait until reset */ + { + __NOP(); + 800035a: bf00 nop + for(;;) /* wait until reset */ + 800035c: e7fd b.n 800035a <__NVIC_SystemReset+0x16> + 800035e: bf00 nop + 8000360: e000ed00 .word 0xe000ed00 + 8000364: 05fa0004 .word 0x05fa0004 + +08000368 : +good_addr(const uint8_t *b, int minlen, int len, bool readonly) +{ + uint32_t x = (uint32_t)b; + + if(minlen) { + if(!b) return EFAULT; // gave no buffer + 8000368: b198 cbz r0, 8000392 + if(len < minlen) return ERANGE; // too small + 800036a: 4291 cmp r1, r2 + 800036c: dc13 bgt.n 8000396 + } + + if((x >= SRAM1_BASE) && ((x+len) <= BL_SRAM_BASE)) { + 800036e: f1b0 5f00 cmp.w r0, #536870912 ; 0x20000000 + 8000372: d303 bcc.n 800037c + 8000374: 490b ldr r1, [pc, #44] ; (80003a4 ) + 8000376: 4402 add r2, r0 + 8000378: 428a cmp r2, r1 + 800037a: d90e bls.n 800039a + // ok: it's inside the SRAM areas, up to where we start + return 0; + } + + if(!readonly) { + 800037c: b17b cbz r3, 800039e + return EPERM; + } + + if((x >= FIRMWARE_START) && (x - FIRMWARE_START) < FW_MAX_LENGTH_MK4) { + 800037e: f100 4077 add.w r0, r0, #4143972352 ; 0xf7000000 + 8000382: f500 007e add.w r0, r0, #16646144 ; 0xfe0000 + // inside flash of main firmware (happens for QSTR's) + return 0; + } + + return EACCES; + 8000386: f5b0 1ff0 cmp.w r0, #1966080 ; 0x1e0000 + 800038a: bf34 ite cc + 800038c: 2000 movcc r0, #0 + 800038e: 200d movcs r0, #13 + 8000390: 4770 bx lr + if(!b) return EFAULT; // gave no buffer + 8000392: 200e movs r0, #14 + 8000394: 4770 bx lr + if(len < minlen) return ERANGE; // too small + 8000396: 2022 movs r0, #34 ; 0x22 + 8000398: 4770 bx lr + return 0; + 800039a: 2000 movs r0, #0 + 800039c: 4770 bx lr + return EPERM; + 800039e: 2001 movs r0, #1 +} + 80003a0: 4770 bx lr + 80003a2: bf00 nop + 80003a4: 2009e000 .word 0x2009e000 + +080003a8 : +// + __attribute__ ((used)) + int +firewall_dispatch(int method_num, uint8_t *buf_io, int len_in, + uint32_t arg2, uint32_t incoming_sp, uint32_t incoming_lr) +{ + 80003a8: b570 push {r4, r5, r6, lr} + 80003aa: b09e sub sp, #120 ; 0x78 + 80003ac: 460d mov r5, r1 + 80003ae: 9c23 ldr r4, [sp, #140] ; 0x8c + 80003b0: 9301 str r3, [sp, #4] + __ASM volatile ("cpsid i" : : : "memory"); + 80003b2: b672 cpsid i + // in case the caller didn't already, but would just lead to a crash anyway + __disable_irq(); + + // "1=any code executed outside the protected segment will close the Firewall" + // "0=.. will reset the processor" + __HAL_FIREWALL_PREARM_DISABLE(); + 80003b4: 4ba9 ldr r3, [pc, #676] ; (800065c ) + 80003b6: 6a19 ldr r1, [r3, #32] + 80003b8: f021 0101 bic.w r1, r1, #1 + 80003bc: 6219 str r1, [r3, #32] + 80003be: 6a1b ldr r3, [r3, #32] + 80003c0: f003 0301 and.w r3, r3, #1 + 80003c4: 9302 str r3, [sp, #8] + // using read/write in place. + // - use arg2 use when a simple number is needed; never a pointer! + // - mpy may provide a pointer to flash if we give it a qstr or small value, and if + // we're reading only, that's fine. + + if(len_in > 1024) { // arbitrary max, increase as needed + 80003c6: f5b2 6f80 cmp.w r2, #1024 ; 0x400 + __HAL_FIREWALL_PREARM_DISABLE(); + 80003ca: 9b02 ldr r3, [sp, #8] + if(len_in > 1024) { // arbitrary max, increase as needed + 80003cc: f300 82ec bgt.w 80009a8 + + // Use these macros +#define REQUIRE_IN_ONLY(x) if((rv = good_addr(buf_io, (x), len_in, true))) { goto fail; } +#define REQUIRE_OUT(x) if((rv = good_addr(buf_io, (x), len_in, false))) { goto fail; } + + switch(method_num) { + 80003d0: 3001 adds r0, #1 + 80003d2: 281b cmp r0, #27 + 80003d4: f200 81c0 bhi.w 8000758 + 80003d8: e8df f010 tbh [pc, r0, lsl #1] + 80003dc: 001c02f4 .word 0x001c02f4 + 80003e0: 007f0033 .word 0x007f0033 + 80003e4: 00da00bc .word 0x00da00bc + 80003e8: 01fd00fb .word 0x01fd00fb + 80003ec: 01be01be .word 0x01be01be + 80003f0: 01be01be .word 0x01be01be + 80003f4: 010301be .word 0x010301be + 80003f8: 01be01be .word 0x01be01be + 80003fc: 012d010e .word 0x012d010e + 8000400: 0171015e .word 0x0171015e + 8000404: 020101b5 .word 0x020101b5 + 8000408: 02690210 .word 0x02690210 + 800040c: 02c002ac .word 0x02c002ac + 8000410: 02d802c8 .word 0x02d802c8 + case 0: { + REQUIRE_OUT(64); + 8000414: 2300 movs r3, #0 + 8000416: 2140 movs r1, #64 ; 0x40 + 8000418: 4628 mov r0, r5 + 800041a: 9200 str r2, [sp, #0] + 800041c: f7ff ffa4 bl 8000368 + 8000420: 4604 mov r4, r0 + 8000422: bb48 cbnz r0, 8000478 + + // Return my version string + memset(buf_io, 0, len_in); + 8000424: 4601 mov r1, r0 + 8000426: 9a00 ldr r2, [sp, #0] + 8000428: 4628 mov r0, r5 + 800042a: f00d fa7b bl 800d924 + strlcpy((char *)buf_io, version_string, len_in); + 800042e: 9a00 ldr r2, [sp, #0] + 8000430: 498b ldr r1, [pc, #556] ; (8000660 ) + 8000432: 4628 mov r0, r5 + 8000434: f00d fa8c bl 800d950 + + rv = strlen(version_string); + 8000438: 4889 ldr r0, [pc, #548] ; (8000660 ) + 800043a: f00d fa9e bl 800d97a + ae_setup(); + ae_keep_alive(); + switch(arg2) { + default: + case 0: // read state + rv = ae_get_gpio(); + 800043e: 4604 mov r4, r0 + break; + 8000440: e01a b.n 8000478 + REQUIRE_OUT(32); + 8000442: 2300 movs r3, #0 + 8000444: 2120 movs r1, #32 + 8000446: 4628 mov r0, r5 + 8000448: f7ff ff8e bl 8000368 + 800044c: 4604 mov r4, r0 + 800044e: b998 cbnz r0, 8000478 + sha256_init(&ctx); + 8000450: a80b add r0, sp, #44 ; 0x2c + 8000452: f005 f993 bl 800577c + sha256_update(&ctx, (void *)&arg2, 4); + 8000456: 2204 movs r2, #4 + 8000458: eb0d 0102 add.w r1, sp, r2 + 800045c: a80b add r0, sp, #44 ; 0x2c + 800045e: f005 f99b bl 8005798 + sha256_update(&ctx, (void *)BL_FLASH_BASE, BL_FLASH_SIZE); + 8000462: f04f 6100 mov.w r1, #134217728 ; 0x8000000 + 8000466: a80b add r0, sp, #44 ; 0x2c + 8000468: f44f 32e0 mov.w r2, #114688 ; 0x1c000 + 800046c: f005 f994 bl 8005798 + sha256_final(&ctx, buf_io); + 8000470: 4629 mov r1, r5 + 8000472: a80b add r0, sp, #44 ; 0x2c + 8000474: f005 f9d6 bl 8005824 + +fail: + + // Precaution: we don't want to leave SE1 authorized for any specific keys, + // perhaps due to an error path we didn't see. Always reset the chip. + ae_reset_chip(); + 8000478: f002 fb5c bl 8002b34 + + // Unlikely it matters, but clear flash memory cache. + __HAL_FLASH_DATA_CACHE_DISABLE(); + 800047c: 4b79 ldr r3, [pc, #484] ; (8000664 ) + 800047e: 681a ldr r2, [r3, #0] + 8000480: f422 6280 bic.w r2, r2, #1024 ; 0x400 + 8000484: 601a str r2, [r3, #0] + __HAL_FLASH_DATA_CACHE_RESET(); + 8000486: 681a ldr r2, [r3, #0] + 8000488: f442 5280 orr.w r2, r2, #4096 ; 0x1000 + 800048c: 601a str r2, [r3, #0] + 800048e: 681a ldr r2, [r3, #0] + 8000490: f422 5280 bic.w r2, r2, #4096 ; 0x1000 + 8000494: 601a str r2, [r3, #0] + __HAL_FLASH_DATA_CACHE_ENABLE(); + 8000496: 681a ldr r2, [r3, #0] + 8000498: f442 6280 orr.w r2, r2, #1024 ; 0x400 + 800049c: 601a str r2, [r3, #0] + + // .. and instruction memory (flash cache too?) + __HAL_FLASH_INSTRUCTION_CACHE_DISABLE(); + 800049e: 681a ldr r2, [r3, #0] + 80004a0: f422 7200 bic.w r2, r2, #512 ; 0x200 + 80004a4: 601a str r2, [r3, #0] + __HAL_FLASH_INSTRUCTION_CACHE_RESET(); + 80004a6: 681a ldr r2, [r3, #0] + 80004a8: f442 6200 orr.w r2, r2, #2048 ; 0x800 + 80004ac: 601a str r2, [r3, #0] + 80004ae: 681a ldr r2, [r3, #0] + 80004b0: f422 6200 bic.w r2, r2, #2048 ; 0x800 + 80004b4: 601a str r2, [r3, #0] + __HAL_FLASH_INSTRUCTION_CACHE_ENABLE(); + 80004b6: 681a ldr r2, [r3, #0] + 80004b8: f442 7200 orr.w r2, r2, #512 ; 0x200 + 80004bc: 601a str r2, [r3, #0] + + // authorize return from firewall into user's code + __HAL_FIREWALL_PREARM_ENABLE(); + 80004be: f5a3 3382 sub.w r3, r3, #66560 ; 0x10400 + + return rv; +} + 80004c2: 4620 mov r0, r4 + __HAL_FIREWALL_PREARM_ENABLE(); + 80004c4: 6a1a ldr r2, [r3, #32] + 80004c6: f042 0201 orr.w r2, r2, #1 + 80004ca: 621a str r2, [r3, #32] + 80004cc: 6a1b ldr r3, [r3, #32] + 80004ce: f003 0301 and.w r3, r3, #1 + 80004d2: 930b str r3, [sp, #44] ; 0x2c + 80004d4: 9b0b ldr r3, [sp, #44] ; 0x2c +} + 80004d6: b01e add sp, #120 ; 0x78 + 80004d8: bd70 pop {r4, r5, r6, pc} +// Write bag number (probably a string) +void flash_save_bag_number(const uint8_t new_number[32]); + +// Are we operating in level2? +static inline bool flash_is_security_level2(void) { + rng_delay(); + 80004da: f002 fa15 bl 8002908 + return ((FLASH->OPTR & FLASH_OPTR_RDP_Msk) == 0xCC); + 80004de: 4b61 ldr r3, [pc, #388] ; (8000664 ) + 80004e0: 6a1b ldr r3, [r3, #32] + 80004e2: b2db uxtb r3, r3 + 80004e4: f1a3 02cc sub.w r2, r3, #204 ; 0xcc + 80004e8: 4255 negs r5, r2 + 80004ea: 4155 adcs r5, r2 + switch(arg2) { + 80004ec: 9a01 ldr r2, [sp, #4] + 80004ee: 2a02 cmp r2, #2 + 80004f0: d01c beq.n 800052c + 80004f2: 2a03 cmp r2, #3 + 80004f4: d01f beq.n 8000536 + 80004f6: 2a01 cmp r2, #1 + 80004f8: d013 beq.n 8000522 + if(secure) { + 80004fa: 2bcc cmp r3, #204 ; 0xcc + 80004fc: f000 8221 beq.w 8000942 + puts("Die: DFU"); + 8000500: 4859 ldr r0, [pc, #356] ; (8000668 ) + scr = screen_upgrading; // was screen_dfu, but limited audience + 8000502: 4c5a ldr r4, [pc, #360] ; (800066c ) + puts("Die: DFU"); + 8000504: f004 fdb0 bl 8005068 + bool secure = flash_is_security_level2(); + 8000508: 2500 movs r5, #0 + oled_setup(); + 800050a: f000 fc33 bl 8000d74 + oled_show(scr); + 800050e: 4620 mov r0, r4 + 8000510: f000 fdb0 bl 8001074 + wipe_all_sram(); + 8000514: f000 fa70 bl 80009f8 + psram_wipe(); + 8000518: f004 fece bl 80052b8 + if(secure) { + 800051c: b18d cbz r5, 8000542 + LOCKUP_FOREVER(); + 800051e: f003 fbab bl 8003c78 + puts("Die: Downgrade"); + 8000522: 4853 ldr r0, [pc, #332] ; (8000670 ) + scr = screen_downgrade; + 8000524: 4c53 ldr r4, [pc, #332] ; (8000674 ) + puts("Die: Downgrade"); + 8000526: f004 fd9f bl 8005068 + break; + 800052a: e7ee b.n 800050a + puts("Die: Blankish"); + 800052c: 4852 ldr r0, [pc, #328] ; (8000678 ) + scr = screen_blankish; + 800052e: 4c53 ldr r4, [pc, #332] ; (800067c ) + puts("Die: Blankish"); + 8000530: f004 fd9a bl 8005068 + break; + 8000534: e7e9 b.n 800050a + puts("Die: Brick"); + 8000536: 4852 ldr r0, [pc, #328] ; (8000680 ) + scr = screen_brick; + 8000538: 4c52 ldr r4, [pc, #328] ; (8000684 ) + puts("Die: Brick"); + 800053a: f004 fd95 bl 8005068 + secure = true; // no point going into DFU, if even possible + 800053e: 2501 movs r5, #1 + break; + 8000540: e7e3 b.n 800050a + memcpy(dfu_flag->magic, REBOOT_TO_DFU, sizeof(dfu_flag->magic)); + 8000542: 4951 ldr r1, [pc, #324] ; (8000688 ) + 8000544: 4a51 ldr r2, [pc, #324] ; (800068c ) + 8000546: 6808 ldr r0, [r1, #0] + 8000548: 6849 ldr r1, [r1, #4] + 800054a: 4613 mov r3, r2 + 800054c: c303 stmia r3!, {r0, r1} + dfu_flag->screen = scr; + 800054e: 6094 str r4, [r2, #8] + NVIC_SystemReset(); + 8000550: f7ff fef8 bl 8000344 <__NVIC_SystemReset> + switch(arg2) { + 8000554: 9b01 ldr r3, [sp, #4] + 8000556: 2b02 cmp r3, #2 + 8000558: d002 beq.n 8000560 + 800055a: 2b03 cmp r3, #3 + 800055c: d016 beq.n 800058c + 800055e: b913 cbnz r3, 8000566 + oled_show(screen_logout); + 8000560: 484b ldr r0, [pc, #300] ; (8000690 ) + oled_show(screen_poweroff); + 8000562: f000 fd87 bl 8001074 + wipe_all_sram(); + 8000566: f000 fa47 bl 80009f8 + psram_wipe(); + 800056a: f004 fea5 bl 80052b8 + if(arg2 == 3) { + 800056e: 9b01 ldr r3, [sp, #4] + 8000570: 2b03 cmp r3, #3 + 8000572: d104 bne.n 800057e + delay_ms(100); + 8000574: 2064 movs r0, #100 ; 0x64 + 8000576: f003 fa85 bl 8003a84 + turn_power_off(); + 800057a: f003 fb71 bl 8003c60 + if(arg2 == 2) { + 800057e: 9b01 ldr r3, [sp, #4] + 8000580: 2b02 cmp r3, #2 + 8000582: d1cc bne.n 800051e + delay_ms(100); + 8000584: 2064 movs r0, #100 ; 0x64 + 8000586: f003 fa7d bl 8003a84 + 800058a: e7e1 b.n 8000550 + oled_show(screen_poweroff); + 800058c: 4841 ldr r0, [pc, #260] ; (8000694 ) + 800058e: e7e8 b.n 8000562 + ae_setup(); + 8000590: f002 fade bl 8002b50 + ae_keep_alive(); + 8000594: f002 fb0e bl 8002bb4 + switch(arg2) { + 8000598: 9b01 ldr r3, [sp, #4] + 800059a: 2b02 cmp r3, #2 + 800059c: d00a beq.n 80005b4 + 800059e: 2b03 cmp r3, #3 + 80005a0: d00a beq.n 80005b8 + 80005a2: 2b01 cmp r3, #1 + 80005a4: d002 beq.n 80005ac + rv = ae_get_gpio(); + 80005a6: f003 f883 bl 80036b0 + 80005aa: e748 b.n 800043e + rv = ae_set_gpio(0); + 80005ac: 2000 movs r0, #0 + rv = ae_set_gpio(1); + 80005ae: f003 f851 bl 8003654 + 80005b2: e744 b.n 800043e + 80005b4: 2001 movs r0, #1 + 80005b6: e7fa b.n 80005ae + checksum_flash(fw_digest, world_digest, 0); + 80005b8: 2200 movs r2, #0 + 80005ba: a90b add r1, sp, #44 ; 0x2c + 80005bc: a803 add r0, sp, #12 + 80005be: f001 fb2d bl 8001c1c + rv = ae_set_gpio_secure(world_digest); + 80005c2: a80b add r0, sp, #44 ; 0x2c + 80005c4: f003 f85c bl 8003680 + 80005c8: 4604 mov r4, r0 + oled_show(screen_blankish); + 80005ca: 482c ldr r0, [pc, #176] ; (800067c ) + 80005cc: f000 fd52 bl 8001074 + break; + 80005d0: e752 b.n 8000478 + ae_setup(); + 80005d2: f002 fabd bl 8002b50 + rv = (ae_pair_unlock() != 0); + 80005d6: f002 fcb1 bl 8002f3c + 80005da: 1e04 subs r4, r0, #0 + 80005dc: bf18 it ne + 80005de: 2401 movne r4, #1 + break; + 80005e0: e74a b.n 8000478 + REQUIRE_OUT(1); + 80005e2: 2300 movs r3, #0 + 80005e4: 2101 movs r1, #1 + 80005e6: 4628 mov r0, r5 + 80005e8: f7ff febe bl 8000368 + 80005ec: 4604 mov r4, r0 + 80005ee: 2800 cmp r0, #0 + 80005f0: f47f af42 bne.w 8000478 + buf_io[0] = 0; // NOT SUPPORTED on Mk4 + 80005f4: 7028 strb r0, [r5, #0] + break; + 80005f6: e73f b.n 8000478 + if(len_in != 4 && len_in != 32 && len_in != 72) { + 80005f8: 2a04 cmp r2, #4 + 80005fa: d004 beq.n 8000606 + 80005fc: 2a20 cmp r2, #32 + 80005fe: d002 beq.n 8000606 + 8000600: 2a48 cmp r2, #72 ; 0x48 + 8000602: f040 81d1 bne.w 80009a8 + REQUIRE_OUT(4); + 8000606: 2300 movs r3, #0 + 8000608: 2104 movs r1, #4 + 800060a: 4628 mov r0, r5 + 800060c: 9200 str r2, [sp, #0] + 800060e: f7ff feab bl 8000368 + 8000612: 4604 mov r4, r0 + 8000614: 2800 cmp r0, #0 + 8000616: f47f af2f bne.w 8000478 + ae_setup(); + 800061a: f002 fa99 bl 8002b50 + if(ae_read_data_slot(arg2 & 0xf, buf_io, len_in)) { + 800061e: 9801 ldr r0, [sp, #4] + 8000620: 9a00 ldr r2, [sp, #0] + 8000622: 4629 mov r1, r5 + 8000624: f000 000f and.w r0, r0, #15 + 8000628: f002 ffce bl 80035c8 + if(rv) { + 800062c: 2800 cmp r0, #0 + 800062e: f000 80d2 beq.w 80007d6 + rv = EIO; + 8000632: 2405 movs r4, #5 + 8000634: e720 b.n 8000478 + REQUIRE_OUT(MAX_PIN_LEN); + 8000636: 2300 movs r3, #0 + 8000638: 2120 movs r1, #32 + 800063a: 4628 mov r0, r5 + 800063c: f7ff fe94 bl 8000368 + 8000640: 4604 mov r4, r0 + 8000642: 2800 cmp r0, #0 + 8000644: f47f af18 bne.w 8000478 + if((arg2 < 1) || (arg2 > MAX_PIN_LEN)) { + 8000648: 9901 ldr r1, [sp, #4] + 800064a: 1e4b subs r3, r1, #1 + 800064c: 2b1f cmp r3, #31 + 800064e: f200 81ab bhi.w 80009a8 + if(pin_prefix_words((char *)buf_io, arg2, (uint32_t *)buf_io)) { + 8000652: 462a mov r2, r5 + 8000654: 4628 mov r0, r5 + 8000656: f003 fdb1 bl 80041bc + 800065a: e7e7 b.n 800062c + 800065c: 40011c00 .word 0x40011c00 + 8000660: 0801079c .word 0x0801079c + 8000664: 40022000 .word 0x40022000 + 8000668: 0800d9a6 .word 0x0800d9a6 + 800066c: 0800ff35 .word 0x0800ff35 + 8000670: 0800d9af .word 0x0800d9af + 8000674: 0800e2f2 .word 0x0800e2f2 + 8000678: 0800d9be .word 0x0800d9be + 800067c: 0800da48 .word 0x0800da48 + 8000680: 0800d9cc .word 0x0800d9cc + 8000684: 0800da61 .word 0x0800da61 + 8000688: 0800d9d7 .word 0x0800d9d7 + 800068c: 20008000 .word 0x20008000 + 8000690: 0800e5f8 .word 0x0800e5f8 + 8000694: 0800e759 .word 0x0800e759 + REQUIRE_OUT(32); + 8000698: 2300 movs r3, #0 + 800069a: 2120 movs r1, #32 + 800069c: 4628 mov r0, r5 + 800069e: f7ff fe63 bl 8000368 + 80006a2: 4604 mov r4, r0 + 80006a4: 2800 cmp r0, #0 + 80006a6: f47f aee7 bne.w 8000478 + memset(buf_io, 0x55, 32); // to help show errors + 80006aa: 2220 movs r2, #32 + 80006ac: 2155 movs r1, #85 ; 0x55 + 80006ae: 4628 mov r0, r5 + 80006b0: f00d f938 bl 800d924 + rng_buffer(buf_io, 32); + 80006b4: 2120 movs r1, #32 + 80006b6: 4628 mov r0, r5 + 80006b8: f002 f910 bl 80028dc + break; + 80006bc: e6dc b.n 8000478 + REQUIRE_OUT(PIN_ATTEMPT_SIZE_V2); + 80006be: 2300 movs r3, #0 + 80006c0: f44f 718c mov.w r1, #280 ; 0x118 + 80006c4: 4628 mov r0, r5 + 80006c6: 9200 str r2, [sp, #0] + 80006c8: f7ff fe4e bl 8000368 + 80006cc: 4604 mov r4, r0 + 80006ce: 2800 cmp r0, #0 + 80006d0: f47f aed2 bne.w 8000478 + switch(arg2) { + 80006d4: e9dd 2300 ldrd r2, r3, [sp] + 80006d8: 2b08 cmp r3, #8 + 80006da: d83d bhi.n 8000758 + 80006dc: e8df f003 tbb [pc, r3] + 80006e0: 110d0905 .word 0x110d0905 + 80006e4: 221d1915 .word 0x221d1915 + 80006e8: 26 .byte 0x26 + 80006e9: 00 .byte 0x00 + rv = pin_setup_attempt(args); + 80006ea: 4628 mov r0, r5 + 80006ec: f003 fd84 bl 80041f8 + 80006f0: e6a5 b.n 800043e + rv = pin_delay(args); + 80006f2: 4628 mov r0, r5 + 80006f4: f003 fdee bl 80042d4 + 80006f8: e6a1 b.n 800043e + rv = pin_login_attempt(args); + 80006fa: 4628 mov r0, r5 + 80006fc: f003 fdec bl 80042d8 + 8000700: e69d b.n 800043e + rv = pin_change(args); + 8000702: 4628 mov r0, r5 + 8000704: f003 fef6 bl 80044f4 + 8000708: e699 b.n 800043e + rv = pin_fetch_secret(args); + 800070a: 4628 mov r0, r5 + 800070c: f003 ffaa bl 8004664 + 8000710: e695 b.n 800043e + rv = pin_firmware_greenlight(args); + 8000712: 4628 mov r0, r5 + 8000714: f004 f966 bl 80049e4 + 8000718: e691 b.n 800043e + rv = pin_long_secret(args, NULL); + 800071a: 2100 movs r1, #0 + rv = pin_long_secret(args, &buf_io[PIN_ATTEMPT_SIZE_V2]); + 800071c: 4628 mov r0, r5 + 800071e: f004 f8a3 bl 8004868 + 8000722: e68c b.n 800043e + rv = pin_firmware_upgrade(args); + 8000724: 4628 mov r0, r5 + 8000726: f004 f99d bl 8004a64 + 800072a: e688 b.n 800043e + REQUIRE_OUT(PIN_ATTEMPT_SIZE_V2 + AE_LONG_SECRET_LEN); + 800072c: 2300 movs r3, #0 + 800072e: f44f 712e mov.w r1, #696 ; 0x2b8 + 8000732: 4628 mov r0, r5 + 8000734: f7ff fe18 bl 8000368 + 8000738: 4604 mov r4, r0 + 800073a: 2800 cmp r0, #0 + 800073c: f47f ae9c bne.w 8000478 + rv = pin_long_secret(args, &buf_io[PIN_ATTEMPT_SIZE_V2]); + 8000740: f505 718c add.w r1, r5, #280 ; 0x118 + 8000744: e7ea b.n 800071c + switch(arg2) { + 8000746: 9b01 ldr r3, [sp, #4] + 8000748: 2b64 cmp r3, #100 ; 0x64 + 800074a: d041 beq.n 80007d0 + 800074c: d806 bhi.n 800075c + 800074e: 2b01 cmp r3, #1 + 8000750: d01e beq.n 8000790 + 8000752: 2b02 cmp r3, #2 + 8000754: d028 beq.n 80007a8 + 8000756: b13b cbz r3, 8000768 + 8000758: 2402 movs r4, #2 + 800075a: e68d b.n 8000478 + 800075c: 2b65 cmp r3, #101 ; 0x65 + 800075e: d03c beq.n 80007da + 8000760: 2b66 cmp r3, #102 ; 0x66 + 8000762: d1f9 bne.n 8000758 + flash_lockdown_hard(OB_RDP_LEVEL_2); // No change possible after this. + 8000764: 20cc movs r0, #204 ; 0xcc + 8000766: e034 b.n 80007d2 + REQUIRE_OUT(32); + 8000768: 2120 movs r1, #32 + 800076a: 4628 mov r0, r5 + 800076c: f7ff fdfc bl 8000368 + 8000770: 4604 mov r4, r0 + 8000772: 2800 cmp r0, #0 + 8000774: f47f ae80 bne.w 8000478 + memcpy(buf_io, rom_secrets->bag_number, 32); + 8000778: 4a99 ldr r2, [pc, #612] ; (80009e0 ) + 800077a: 4e9a ldr r6, [pc, #616] ; (80009e4 ) + 800077c: 4613 mov r3, r2 + 800077e: cb03 ldmia r3!, {r0, r1} + 8000780: 42b3 cmp r3, r6 + 8000782: 6028 str r0, [r5, #0] + 8000784: 6069 str r1, [r5, #4] + 8000786: 461a mov r2, r3 + 8000788: f105 0508 add.w r5, r5, #8 + 800078c: d1f6 bne.n 800077c + 800078e: e673 b.n 8000478 + REQUIRE_IN_ONLY(32); + 8000790: 2120 movs r1, #32 + 8000792: 4628 mov r0, r5 + 8000794: f7ff fde8 bl 8000368 + 8000798: 4604 mov r4, r0 + 800079a: 2800 cmp r0, #0 + 800079c: f47f ae6c bne.w 8000478 + flash_save_bag_number(buf_io); + 80007a0: 4628 mov r0, r5 + 80007a2: f001 fd7f bl 80022a4 + break; + 80007a6: e667 b.n 8000478 + REQUIRE_OUT(1); + 80007a8: 2300 movs r3, #0 + 80007aa: 2101 movs r1, #1 + 80007ac: 4628 mov r0, r5 + 80007ae: f7ff fddb bl 8000368 + 80007b2: 4604 mov r4, r0 + 80007b4: 2800 cmp r0, #0 + 80007b6: f47f ae5f bne.w 8000478 + rng_delay(); + 80007ba: f002 f8a5 bl 8002908 + return ((FLASH->OPTR & FLASH_OPTR_RDP_Msk) == 0xCC); + 80007be: 4b8a ldr r3, [pc, #552] ; (80009e8 ) + 80007c0: 6a1b ldr r3, [r3, #32] + 80007c2: b2db uxtb r3, r3 + buf_io[0] = (flash_is_security_level2() ? 2 : 0xff); + 80007c4: 2bcc cmp r3, #204 ; 0xcc + 80007c6: bf0c ite eq + 80007c8: 2302 moveq r3, #2 + 80007ca: 23ff movne r3, #255 ; 0xff + buf_io[0] = 8; + 80007cc: 702b strb r3, [r5, #0] + break; + 80007ce: e653 b.n 8000478 + flash_lockdown_hard(OB_RDP_LEVEL_0); // wipes contents of flash (1->0) + 80007d0: 20aa movs r0, #170 ; 0xaa + flash_lockdown_hard(OB_RDP_LEVEL_2); // No change possible after this. + 80007d2: f001 fe9f bl 8002514 + int rv = 0; + 80007d6: 2400 movs r4, #0 + break; + 80007d8: e64e b.n 8000478 + flash_lockdown_hard(OB_RDP_LEVEL_1); // Can only do 0->1 (experiments) + 80007da: 20bb movs r0, #187 ; 0xbb + 80007dc: e7f9 b.n 80007d2 + REQUIRE_OUT(128); + 80007de: 2300 movs r3, #0 + 80007e0: 2180 movs r1, #128 ; 0x80 + 80007e2: 4628 mov r0, r5 + 80007e4: f7ff fdc0 bl 8000368 + 80007e8: 4604 mov r4, r0 + 80007ea: 2800 cmp r0, #0 + 80007ec: f47f ae44 bne.w 8000478 + ae_setup(); + 80007f0: f002 f9ae bl 8002b50 + rv = ae_config_read(buf_io); + 80007f4: 4628 mov r0, r5 + 80007f6: f002 ffac bl 8003752 + 80007fa: e717 b.n 800062c + switch(arg2) { + 80007fc: 9b01 ldr r3, [sp, #4] + 80007fe: 2b03 cmp r3, #3 + 8000800: d8aa bhi.n 8000758 + 8000802: e8df f003 tbb [pc, r3] + 8000806: 0f02 .short 0x0f02 + 8000808: 441d .short 0x441d + REQUIRE_OUT(8); + 800080a: 2300 movs r3, #0 + 800080c: 2108 movs r1, #8 + 800080e: 4628 mov r0, r5 + 8000810: f7ff fdaa bl 8000368 + 8000814: 4604 mov r4, r0 + 8000816: 2800 cmp r0, #0 + 8000818: f47f ae2e bne.w 8000478 + get_min_version(buf_io); + 800081c: 4628 mov r0, r5 + 800081e: f001 fa8d bl 8001d3c + break; + 8000822: e629 b.n 8000478 + REQUIRE_IN_ONLY(8); + 8000824: 2301 movs r3, #1 + 8000826: 2108 movs r1, #8 + 8000828: 4628 mov r0, r5 + 800082a: f7ff fd9d bl 8000368 + 800082e: 4604 mov r4, r0 + 8000830: 2800 cmp r0, #0 + 8000832: f47f ae21 bne.w 8000478 + rv = check_is_downgrade(buf_io, NULL); + 8000836: 4601 mov r1, r0 + 8000838: 4628 mov r0, r5 + 800083a: f001 fa9f bl 8001d7c + 800083e: e5fe b.n 800043e + REQUIRE_IN_ONLY(8); + 8000840: 2301 movs r3, #1 + 8000842: 2108 movs r1, #8 + 8000844: 4628 mov r0, r5 + 8000846: f7ff fd8f bl 8000368 + 800084a: 4604 mov r4, r0 + 800084c: 2800 cmp r0, #0 + 800084e: f47f ae13 bne.w 8000478 + if(buf_io[0] < 0x10 || buf_io[0] >= 0x40) { + 8000852: 782b ldrb r3, [r5, #0] + 8000854: 3b10 subs r3, #16 + rv = ERANGE; + 8000856: 2b2f cmp r3, #47 ; 0x2f + } if(check_is_downgrade(buf_io, NULL)) { + 8000858: 4601 mov r1, r0 + 800085a: 4628 mov r0, r5 + rv = ERANGE; + 800085c: bf88 it hi + 800085e: 2422 movhi r4, #34 ; 0x22 + } if(check_is_downgrade(buf_io, NULL)) { + 8000860: f001 fa8c bl 8001d7c + 8000864: 2800 cmp r0, #0 + 8000866: f040 80b9 bne.w 80009dc + get_min_version(min); + 800086a: a80b add r0, sp, #44 ; 0x2c + 800086c: f001 fa66 bl 8001d3c + if(memcmp(min, buf_io, 8) == 0) { + 8000870: 2208 movs r2, #8 + 8000872: 4629 mov r1, r5 + 8000874: a80b add r0, sp, #44 ; 0x2c + 8000876: f00d f837 bl 800d8e8 + 800087a: 2800 cmp r0, #0 + 800087c: f000 80ae beq.w 80009dc + if(record_highwater_version(buf_io)) { + 8000880: 4628 mov r0, r5 + 8000882: f001 fe61 bl 8002548 + rv = ENOMEM; + 8000886: 2800 cmp r0, #0 + 8000888: bf18 it ne + 800088a: 240c movne r4, #12 + 800088c: e5f4 b.n 8000478 + REQUIRE_OUT(4); + 800088e: 2300 movs r3, #0 + 8000890: 2104 movs r1, #4 + 8000892: 4628 mov r0, r5 + 8000894: f7ff fd68 bl 8000368 + 8000898: 4604 mov r4, r0 + 800089a: 2800 cmp r0, #0 + 800089c: f47f adec bne.w 8000478 + ae_setup(); + 80008a0: f002 f956 bl 8002b50 + rv = ae_get_counter((uint32_t *)buf_io, 0) ? EIO: 0; + 80008a4: 4621 mov r1, r4 + 80008a6: 4628 mov r0, r5 + 80008a8: f002 fd43 bl 8003332 + 80008ac: e6be b.n 800062c + REQUIRE_OUT(PIN_ATTEMPT_SIZE_V2 + sizeof(trick_slot_t)); + 80008ae: 2300 movs r3, #0 + 80008b0: f44f 71cc mov.w r1, #408 ; 0x198 + 80008b4: 4628 mov r0, r5 + 80008b6: f7ff fd57 bl 8000368 + 80008ba: 4604 mov r4, r0 + 80008bc: 2800 cmp r0, #0 + 80008be: f47f addb bne.w 8000478 + rv = pin_check_logged_in(args, &trick_mode); + 80008c2: a90b add r1, sp, #44 ; 0x2c + 80008c4: 4628 mov r0, r5 + 80008c6: f003 fde3 bl 8004490 + if(rv) goto fail; + 80008ca: 4604 mov r4, r0 + 80008cc: 2800 cmp r0, #0 + 80008ce: f47f add3 bne.w 8000478 + if(trick_mode) { + 80008d2: f89d 302c ldrb.w r3, [sp, #44] ; 0x2c + 80008d6: b10b cbz r3, 80008dc + mcu_key_clear(NULL); + 80008d8: f001 fe84 bl 80025e4 + switch(arg2) { + 80008dc: 9b01 ldr r3, [sp, #4] + 80008de: 2b01 cmp r3, #1 + trick_slot_t *slot = (trick_slot_t *)(&buf_io[PIN_ATTEMPT_SIZE_V2]); + 80008e0: f505 728c add.w r2, r5, #280 ; 0x118 + switch(arg2) { + 80008e4: d00c beq.n 8000900 + 80008e6: 2b02 cmp r3, #2 + 80008e8: d01b beq.n 8000922 + 80008ea: 2b00 cmp r3, #0 + 80008ec: f47f af34 bne.w 8000758 + if(!trick_mode) { + 80008f0: f89d 302c ldrb.w r3, [sp, #44] ; 0x2c + 80008f4: 2b00 cmp r3, #0 + 80008f6: f47f adbf bne.w 8000478 + se2_clear_tricks(); + 80008fa: f007 fb9f bl 800803c + 80008fe: e5bb b.n 8000478 + if(trick_mode) { + 8000900: f89d 102c ldrb.w r1, [sp, #44] ; 0x2c + 8000904: 2900 cmp r1, #0 + 8000906: f47f af27 bne.w 8000758 + if(slot->pin_len > 16) { + 800090a: f8d5 1170 ldr.w r1, [r5, #368] ; 0x170 + 800090e: 2910 cmp r1, #16 + 8000910: dc4a bgt.n 80009a8 + if(se2_test_trick_pin(slot->pin, slot->pin_len, slot, true)) { + 8000912: f505 70b0 add.w r0, r5, #352 ; 0x160 + 8000916: f007 fbf7 bl 8008108 + 800091a: 2800 cmp r0, #0 + 800091c: f47f adac bne.w 8000478 + 8000920: e71a b.n 8000758 + if(!trick_mode) { + 8000922: f89d 302c ldrb.w r3, [sp, #44] ; 0x2c + 8000926: 2b00 cmp r3, #0 + 8000928: f47f ada6 bne.w 8000478 + rv = se2_save_trick(slot); + 800092c: 4610 mov r0, r2 + 800092e: f007 fd05 bl 800833c + 8000932: e584 b.n 800043e + if(arg2 == 0xBeef) { + 8000934: 9b01 ldr r3, [sp, #4] + 8000936: f64b 62ef movw r2, #48879 ; 0xbeef + 800093a: 4293 cmp r3, r2 + 800093c: d103 bne.n 8000946 + fast_wipe(); + 800093e: f001 ff43 bl 80027c8 + rv = EPERM; + 8000942: 2401 movs r4, #1 + 8000944: e598 b.n 8000478 + } else if(arg2 == 0xDead) { + 8000946: f64d 62ad movw r2, #57005 ; 0xdead + 800094a: 4293 cmp r3, r2 + 800094c: d1f9 bne.n 8000942 + mcu_key_clear(NULL); + 800094e: 2000 movs r0, #0 + 8000950: f001 fe48 bl 80025e4 + oled_show(screen_wiped); + 8000954: 4825 ldr r0, [pc, #148] ; (80009ec ) + 8000956: f000 fb8d bl 8001074 + 800095a: e5e0 b.n 800051e + if(arg2 == 0xDead) fast_brick(); + 800095c: 9a01 ldr r2, [sp, #4] + 800095e: f64d 63ad movw r3, #57005 ; 0xdead + 8000962: 429a cmp r2, r3 + 8000964: d1ed bne.n 8000942 + 8000966: f001 ff01 bl 800276c + 800096a: e7ea b.n 8000942 + REQUIRE_OUT(8); + 800096c: 2300 movs r3, #0 + 800096e: 2108 movs r1, #8 + 8000970: 4628 mov r0, r5 + 8000972: f7ff fcf9 bl 8000368 + 8000976: 4604 mov r4, r0 + 8000978: 2800 cmp r0, #0 + 800097a: f47f ad7d bne.w 8000478 + mcu_key_usage(avail, consumed, total); + 800097e: f105 0208 add.w r2, r5, #8 + 8000982: 1d29 adds r1, r5, #4 + 8000984: 4628 mov r0, r5 + 8000986: f001 fe5b bl 8002640 + break; + 800098a: e575 b.n 8000478 + REQUIRE_OUT(33); + 800098c: 2300 movs r3, #0 + 800098e: 2121 movs r1, #33 ; 0x21 + 8000990: 4628 mov r0, r5 + 8000992: f7ff fce9 bl 8000368 + 8000996: 4604 mov r4, r0 + 8000998: 2800 cmp r0, #0 + 800099a: f47f ad6d bne.w 8000478 + switch(arg2) { + 800099e: 9b01 ldr r3, [sp, #4] + 80009a0: 2b01 cmp r3, #1 + 80009a2: d003 beq.n 80009ac + 80009a4: 2b02 cmp r3, #2 + 80009a6: d008 beq.n 80009ba + rv = ERANGE; + 80009a8: 2422 movs r4, #34 ; 0x22 + 80009aa: e565 b.n 8000478 + ae_setup(); + 80009ac: f002 f8d0 bl 8002b50 + ae_secure_random(&buf_io[1]); + 80009b0: 1c68 adds r0, r5, #1 + 80009b2: f002 fc35 bl 8003220 + buf_io[0] = 32; + 80009b6: 2320 movs r3, #32 + 80009b8: e708 b.n 80007cc + se2_read_rng(&buf_io[1]); + 80009ba: 1c68 adds r0, r5, #1 + 80009bc: f007 fea2 bl 8008704 + buf_io[0] = 8; + 80009c0: 2308 movs r3, #8 + 80009c2: e703 b.n 80007cc + if(incoming_lr <= BL_FLASH_BASE || incoming_lr >= (uint32_t)&firewall_starts) { + 80009c4: f1b4 6f00 cmp.w r4, #134217728 ; 0x8000000 + 80009c8: d902 bls.n 80009d0 + 80009ca: 4b09 ldr r3, [pc, #36] ; (80009f0 ) + 80009cc: 429c cmp r4, r3 + 80009ce: d302 bcc.n 80009d6 + fatal_error("LR"); + 80009d0: 4808 ldr r0, [pc, #32] ; (80009f4 ) + 80009d2: f000 f831 bl 8000a38 + system_startup(); + 80009d6: f000 f88d bl 8000af4 + break; + 80009da: e6fc b.n 80007d6 + rv = EAGAIN; + 80009dc: 240b movs r4, #11 + 80009de: e54b b.n 8000478 + 80009e0: 0801c050 .word 0x0801c050 + 80009e4: 0801c070 .word 0x0801c070 + 80009e8: 40022000 .word 0x40022000 + 80009ec: 08010174 .word 0x08010174 + 80009f0: 08000300 .word 0x08000300 + 80009f4: 0800d9e0 .word 0x0800d9e0 + +080009f8 : +// + static inline void +memset4(uint32_t *dest, uint32_t value, uint32_t byte_len) +{ + for(; byte_len; byte_len-=4, dest++) { + *dest = value; + 80009f8: 4a0a ldr r2, [pc, #40] ; (8000a24 ) + for(; byte_len; byte_len-=4, dest++) { + 80009fa: 490b ldr r1, [pc, #44] ; (8000a28 ) + +// wipe_all_sram() +// + void +wipe_all_sram(void) +{ + 80009fc: f04f 5300 mov.w r3, #536870912 ; 0x20000000 + *dest = value; + 8000a00: f843 2b04 str.w r2, [r3], #4 + for(; byte_len; byte_len-=4, dest++) { + 8000a04: 428b cmp r3, r1 + 8000a06: d1fb bne.n 8000a00 + 8000a08: 4908 ldr r1, [pc, #32] ; (8000a2c ) + 8000a0a: f04f 5380 mov.w r3, #268435456 ; 0x10000000 + *dest = value; + 8000a0e: f843 2b04 str.w r2, [r3], #4 + for(; byte_len; byte_len-=4, dest++) { + 8000a12: 428b cmp r3, r1 + 8000a14: d1fb bne.n 8000a0e + 8000a16: 4b06 ldr r3, [pc, #24] ; (8000a30 ) + 8000a18: 4906 ldr r1, [pc, #24] ; (8000a34 ) + *dest = value; + 8000a1a: f843 2b04 str.w r2, [r3], #4 + for(; byte_len; byte_len-=4, dest++) { + 8000a1e: 428b cmp r3, r1 + 8000a20: d1fb bne.n 8000a1a + STATIC_ASSERT((SRAM3_BASE + SRAM3_SIZE) - BL_SRAM_BASE == 8192); + + memset4((void *)SRAM1_BASE, noise, SRAM1_SIZE_MAX); + memset4((void *)SRAM2_BASE, noise, SRAM2_SIZE); + memset4((void *)SRAM3_BASE, noise, SRAM3_SIZE - (BL_SRAM_BASE - SRAM3_BASE)); +} + 8000a22: 4770 bx lr + 8000a24: deadbeef .word 0xdeadbeef + 8000a28: 20030000 .word 0x20030000 + 8000a2c: 10010000 .word 0x10010000 + 8000a30: 20040000 .word 0x20040000 + 8000a34: 20042000 .word 0x20042000 + +08000a38 : + +// fatal_error(const char *msg) +// + void __attribute__((noreturn)) +fatal_error(const char *msgvoid) +{ + 8000a38: b508 push {r3, lr} + oled_setup(); + 8000a3a: f000 f99b bl 8000d74 + oled_show(screen_fatal); + 8000a3e: 4802 ldr r0, [pc, #8] ; (8000a48 ) + 8000a40: f000 fb18 bl 8001074 + BREAKPOINT; +#endif + + // Maybe should do a reset after a delay, like with + // the watchdog timer or something. + LOCKUP_FOREVER(); + 8000a44: f003 f918 bl 8003c78 + 8000a48: 0800e58d .word 0x0800e58d + +08000a4c : + +// fatal_mitm() +// + void __attribute__((noreturn)) +fatal_mitm(void) +{ + 8000a4c: b508 push {r3, lr} + oled_setup(); + 8000a4e: f000 f991 bl 8000d74 + oled_show(screen_mitm); + 8000a52: 4803 ldr r0, [pc, #12] ; (8000a60 ) + 8000a54: f000 fb0e bl 8001074 + +#ifdef RELEASE + wipe_all_sram(); + 8000a58: f7ff ffce bl 80009f8 +#endif + + LOCKUP_FOREVER(); + 8000a5c: f003 f90c bl 8003c78 + 8000a60: 0800e717 .word 0x0800e717 + +08000a64 : + +// enter_dfu() +// + void __attribute__((noreturn)) +enter_dfu(void) +{ + 8000a64: b507 push {r0, r1, r2, lr} + puts("enter_dfu()"); + 8000a66: 481f ldr r0, [pc, #124] ; (8000ae4 ) + 8000a68: f004 fafe bl 8005068 + + // clear the green light, if set + ae_setup(); + 8000a6c: f002 f870 bl 8002b50 + ae_set_gpio(0); + 8000a70: 2000 movs r0, #0 + 8000a72: f002 fdef bl 8003654 + + // Reset huge parts of the chip + __HAL_RCC_APB1_FORCE_RESET(); + 8000a76: 4b1c ldr r3, [pc, #112] ; (8000ae8 ) + 8000a78: f04f 31ff mov.w r1, #4294967295 ; 0xffffffff + __HAL_RCC_APB1_RELEASE_RESET(); + 8000a7c: 2200 movs r2, #0 + __HAL_RCC_APB1_FORCE_RESET(); + 8000a7e: 6399 str r1, [r3, #56] ; 0x38 + 8000a80: 63d9 str r1, [r3, #60] ; 0x3c + __HAL_RCC_APB1_RELEASE_RESET(); + 8000a82: 639a str r2, [r3, #56] ; 0x38 + 8000a84: 63da str r2, [r3, #60] ; 0x3c + + __HAL_RCC_APB2_FORCE_RESET(); + 8000a86: 6419 str r1, [r3, #64] ; 0x40 + __HAL_RCC_APB2_RELEASE_RESET(); + 8000a88: 641a str r2, [r3, #64] ; 0x40 + + __HAL_RCC_AHB1_FORCE_RESET(); + 8000a8a: 6299 str r1, [r3, #40] ; 0x28 + __HAL_RCC_AHB1_RELEASE_RESET(); + 8000a8c: 629a str r2, [r3, #40] ; 0x28 + // But not this; it borks things. + __HAL_RCC_AHB2_FORCE_RESET(); + __HAL_RCC_AHB2_RELEASE_RESET(); +#endif + + __HAL_RCC_AHB3_FORCE_RESET(); + 8000a8e: 6319 str r1, [r3, #48] ; 0x30 + __HAL_RCC_AHB3_RELEASE_RESET(); + 8000a90: 631a str r2, [r3, #48] ; 0x30 + + __HAL_FIREWALL_PREARM_ENABLE(); + 8000a92: f5a3 4374 sub.w r3, r3, #62464 ; 0xf400 + 8000a96: 6a1a ldr r2, [r3, #32] + 8000a98: f042 0201 orr.w r2, r2, #1 + 8000a9c: 621a str r2, [r3, #32] + 8000a9e: 6a1b ldr r3, [r3, #32] + 8000aa0: f003 0301 and.w r3, r3, #1 + 8000aa4: 9301 str r3, [sp, #4] + 8000aa6: 9b01 ldr r3, [sp, #4] + + // Wipe all of memory SRAM, just in case + // there is some way to trick us into DFU + // after sensitive content in place. + wipe_all_sram(); + 8000aa8: f7ff ffa6 bl 80009f8 + rng_delay(); + 8000aac: f001 ff2c bl 8002908 + return ((FLASH->OPTR & FLASH_OPTR_RDP_Msk) == 0xCC); + 8000ab0: 4b0e ldr r3, [pc, #56] ; (8000aec ) + 8000ab2: 6a1b ldr r3, [r3, #32] + 8000ab4: b2db uxtb r3, r3 + + if(flash_is_security_level2()) { + 8000ab6: 2bcc cmp r3, #204 ; 0xcc + 8000ab8: d101 bne.n 8000abe + // cannot do DFU in RDP=2, so just die. Helps to preserve screen + LOCKUP_FOREVER(); + 8000aba: f003 f8dd bl 8003c78 + } + + // Reset clocks. + HAL_RCC_DeInit(); + 8000abe: f007 ff5f bl 8008980 + + // move system ROM into 0x0 + __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); + 8000ac2: 4a0b ldr r2, [pc, #44] ; (8000af0 ) + 8000ac4: 6813 ldr r3, [r2, #0] + 8000ac6: f023 0307 bic.w r3, r3, #7 + 8000aca: f043 0301 orr.w r3, r3, #1 + 8000ace: 6013 str r3, [r2, #0] + + // need this here?! + asm("nop; nop; nop; nop;"); + 8000ad0: bf00 nop + 8000ad2: bf00 nop + 8000ad4: bf00 nop + 8000ad6: bf00 nop + + // simulate a reset vector + __ASM volatile ("movs r0, #0\n" + 8000ad8: 2000 movs r0, #0 + 8000ada: 6803 ldr r3, [r0, #0] + 8000adc: f383 8808 msr MSP, r3 + 8000ae0: 6843 ldr r3, [r0, #4] + 8000ae2: 4798 blx r3 + "ldr r3, [r0, #4]\n" + "blx r3" + : : : "r0", "r3"); // also SP + + // NOT-REACHED. + __builtin_unreachable(); + 8000ae4: 0800d9e3 .word 0x0800d9e3 + 8000ae8: 40021000 .word 0x40021000 + 8000aec: 40022000 .word 0x40022000 + 8000af0: 40010000 .word 0x40010000 + +08000af4 : +{ + 8000af4: b510 push {r4, lr} + system_init0(); + 8000af6: f001 fa77 bl 8001fe8 + clocks_setup(); + 8000afa: f001 fa97 bl 800202c + rng_setup(); // needs to be super early + 8000afe: f001 fec1 bl 8002884 + rng_delay(); + 8000b02: f001 ff01 bl 8002908 + if(!check_all_ones(rom_secrets->bag_number, sizeof(rom_secrets->bag_number)) + 8000b06: 4838 ldr r0, [pc, #224] ; (8000be8 ) + 8000b08: 2120 movs r1, #32 + 8000b0a: f001 fe7f bl 800280c + 8000b0e: b948 cbnz r0, 8000b24 + rng_delay(); + 8000b10: f001 fefa bl 8002908 + return ((FLASH->OPTR & FLASH_OPTR_RDP_Msk) == 0xCC); + 8000b14: 4b35 ldr r3, [pc, #212] ; (8000bec ) + 8000b16: 6a1b ldr r3, [r3, #32] + 8000b18: b2db uxtb r3, r3 + && !flash_is_security_level2() + 8000b1a: 2bcc cmp r3, #204 ; 0xcc + 8000b1c: d002 beq.n 8000b24 + flash_lockdown_hard(OB_RDP_LEVEL_2); + 8000b1e: 20cc movs r0, #204 ; 0xcc + 8000b20: f001 fcf8 bl 8002514 + gpio_setup(); + 8000b24: f002 ffbe bl 8003aa4 + uint32_t reset_reason = RCC->CSR; + 8000b28: 4c31 ldr r4, [pc, #196] ; (8000bf0 ) + console_setup(); + 8000b2a: f004 f9c3 bl 8004eb4 + puts2(BOOT_BANNER); + 8000b2e: 4831 ldr r0, [pc, #196] ; (8000bf4 ) + 8000b30: f004 fa0c bl 8004f4c + puts(version_string); + 8000b34: 4830 ldr r0, [pc, #192] ; (8000bf8 ) + 8000b36: f004 fa97 bl 8005068 + uint32_t reset_reason = RCC->CSR; + 8000b3a: f8d4 3094 ldr.w r3, [r4, #148] ; 0x94 + if(reset_reason & RCC_CSR_FWRSTF) { + 8000b3e: 01db lsls r3, r3, #7 + 8000b40: d502 bpl.n 8000b48 + puts(">FIREWALLED<"); + 8000b42: 482e ldr r0, [pc, #184] ; (8000bfc ) + 8000b44: f004 fa90 bl 8005068 + SET_BIT(RCC->CSR, RCC_CSR_RMVF); + 8000b48: f8d4 3094 ldr.w r3, [r4, #148] ; 0x94 + 8000b4c: f443 0300 orr.w r3, r3, #8388608 ; 0x800000 + 8000b50: f8c4 3094 str.w r3, [r4, #148] ; 0x94 + if(memcmp(dfu_flag->magic, REBOOT_TO_DFU, sizeof(dfu_flag->magic)) == 0) { + 8000b54: 4c2a ldr r4, [pc, #168] ; (8000c00 ) + pin_setup0(); + 8000b56: f003 fa9b bl 8004090 + rng_delay(); + 8000b5a: f001 fed5 bl 8002908 + lcd_full_setup(); + 8000b5e: f000 f981 bl 8000e64 + if(memcmp(dfu_flag->magic, REBOOT_TO_DFU, sizeof(dfu_flag->magic)) == 0) { + 8000b62: 4928 ldr r1, [pc, #160] ; (8000c04 ) + 8000b64: 2208 movs r2, #8 + 8000b66: 4620 mov r0, r4 + 8000b68: f00c febe bl 800d8e8 + 8000b6c: b928 cbnz r0, 8000b7a + dfu_flag->magic[0] = 0; + 8000b6e: 7020 strb r0, [r4, #0] + oled_show(dfu_flag->screen); + 8000b70: 68a0 ldr r0, [r4, #8] + 8000b72: f000 fa7f bl 8001074 + enter_dfu(); + 8000b76: f7ff ff75 bl 8000a64 + rng_delay(); + 8000b7a: f001 fec5 bl 8002908 + oled_show_progress(screen_verify, 0); + 8000b7e: 2100 movs r1, #0 + 8000b80: 4821 ldr r0, [pc, #132] ; (8000c08 ) + 8000b82: f000 faf1 bl 8001168 + wipe_all_sram(); + 8000b86: f7ff ff37 bl 80009f8 + ae_setup(); + 8000b8a: f001 ffe1 bl 8002b50 + ae_set_gpio(0); // turn light red + 8000b8e: 2000 movs r0, #0 + 8000b90: f002 fd60 bl 8003654 + se2_setup(); + 8000b94: f007 fa0c bl 8007fb0 + se2_probe(); + 8000b98: f006 ff90 bl 8007abc + flash_setup(); + 8000b9c: f001 fbee bl 800237c + psram_setup(); + 8000ba0: f004 fa9a bl 80050d8 + if(ae_pair_unlock() != 0) { + 8000ba4: f002 f9ca bl 8002f3c + 8000ba8: b138 cbz r0, 8000bba + oled_show(screen_brick); + 8000baa: 4818 ldr r0, [pc, #96] ; (8000c0c ) + 8000bac: f000 fa62 bl 8001074 + puts("pair-bricked"); + 8000bb0: 4817 ldr r0, [pc, #92] ; (8000c10 ) + 8000bb2: f004 fa59 bl 8005068 + LOCKUP_FOREVER(); + 8000bb6: f003 f85f bl 8003c78 + puts2("Verify: "); + 8000bba: 4816 ldr r0, [pc, #88] ; (8000c14 ) + 8000bbc: f004 f9c6 bl 8004f4c + bool main_ok = verify_firmware(); + 8000bc0: f001 f996 bl 8001ef0 + if(main_ok) { + 8000bc4: b120 cbz r0, 8000bd0 +} + 8000bc6: e8bd 4010 ldmia.w sp!, {r4, lr} + oled_show(screen_blankish); + 8000bca: 4813 ldr r0, [pc, #76] ; (8000c18 ) + 8000bcc: f000 ba52 b.w 8001074 + psram_recover_firmware(); + 8000bd0: f004 fbd0 bl 8005374 + rng_delay(); + 8000bd4: f001 fe98 bl 8002908 + return ((FLASH->OPTR & FLASH_OPTR_RDP_Msk) == 0xCC); + 8000bd8: 4b04 ldr r3, [pc, #16] ; (8000bec ) + 8000bda: 6a1b ldr r3, [r3, #32] + 8000bdc: b2db uxtb r3, r3 + if(!flash_is_security_level2()) { + 8000bde: 2bcc cmp r3, #204 ; 0xcc + 8000be0: d1c9 bne.n 8000b76 + while(1) sdcard_recovery(); + 8000be2: f004 fd91 bl 8005708 + 8000be6: e7fc b.n 8000be2 + 8000be8: 0801c050 .word 0x0801c050 + 8000bec: 40022000 .word 0x40022000 + 8000bf0: 40021000 .word 0x40021000 + 8000bf4: 0800d9ef .word 0x0800d9ef + 8000bf8: 0801079c .word 0x0801079c + 8000bfc: 0800da02 .word 0x0800da02 + 8000c00: 20008000 .word 0x20008000 + 8000c04: 0800d9d7 .word 0x0800d9d7 + 8000c08: 0801004d .word 0x0801004d + 8000c0c: 0800da61 .word 0x0800da61 + 8000c10: 0800da0f .word 0x0800da0f + 8000c14: 0800da1c .word 0x0800da1c + 8000c18: 0800da48 .word 0x0800da48 + +08000c1c : + +// lcd_write_data() +// + static void +lcd_write_data(int len, const uint8_t *pixels) +{ + 8000c1c: b538 push {r3, r4, r5, lr} + HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); + 8000c1e: 2201 movs r2, #1 +{ + 8000c20: 4605 mov r5, r0 + 8000c22: 460c mov r4, r1 + HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); + 8000c24: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000c28: 2110 movs r1, #16 + 8000c2a: f000 fc5d bl 80014e8 + HAL_GPIO_WritePin(GPIOA, DC_PIN, 1); + 8000c2e: 2201 movs r2, #1 + 8000c30: f44f 7180 mov.w r1, #256 ; 0x100 + 8000c34: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000c38: f000 fc56 bl 80014e8 + HAL_GPIO_WritePin(GPIOA, CS_PIN, 0); + 8000c3c: 2200 movs r2, #0 + 8000c3e: 2110 movs r1, #16 + 8000c40: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000c44: f000 fc50 bl 80014e8 + HAL_SPI_Transmit(&spi_port, (uint8_t *)buf, len, HAL_MAX_DELAY); + 8000c48: b2aa uxth r2, r5 + 8000c4a: 4621 mov r1, r4 + 8000c4c: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 8000c50: 4805 ldr r0, [pc, #20] ; (8000c68 ) + 8000c52: f000 fce9 bl 8001628 + + write_bytes(len, pixels); + + HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); +} + 8000c56: e8bd 4038 ldmia.w sp!, {r3, r4, r5, lr} + HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); + 8000c5a: 2201 movs r2, #1 + 8000c5c: 2110 movs r1, #16 + 8000c5e: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000c62: f000 bc41 b.w 80014e8 + 8000c66: bf00 nop + 8000c68: 2009e158 .word 0x2009e158 + +08000c6c : + +// lcd_write_data1() +// + static void +lcd_write_data1(uint8_t data) +{ + 8000c6c: b507 push {r0, r1, r2, lr} + 8000c6e: f88d 0007 strb.w r0, [sp, #7] + lcd_write_data(1, &data); + 8000c72: f10d 0107 add.w r1, sp, #7 + 8000c76: 2001 movs r0, #1 + 8000c78: f7ff ffd0 bl 8000c1c +} + 8000c7c: b003 add sp, #12 + 8000c7e: f85d fb04 ldr.w pc, [sp], #4 + ... + +08000c84 : +static inline void wait_vsync(void) { + 8000c84: b538 push {r3, r4, r5, lr} + 8000c86: 4c08 ldr r4, [pc, #32] ; (8000ca8 ) + if(HAL_GPIO_ReadPin(GPIOB, TEAR_PIN) != 0) { + 8000c88: 4d08 ldr r5, [pc, #32] ; (8000cac ) + 8000c8a: f44f 6100 mov.w r1, #2048 ; 0x800 + 8000c8e: 4628 mov r0, r5 + 8000c90: f000 fc24 bl 80014dc + 8000c94: b930 cbnz r0, 8000ca4 + for(; timeout; timeout--) { + 8000c96: 3c01 subs r4, #1 + 8000c98: d1f7 bne.n 8000c8a +} + 8000c9a: e8bd 4038 ldmia.w sp!, {r3, r4, r5, lr} + puts("TEAR timeout"); + 8000c9e: 4804 ldr r0, [pc, #16] ; (8000cb0 ) + 8000ca0: f004 b9e2 b.w 8005068 +} + 8000ca4: bd38 pop {r3, r4, r5, pc} + 8000ca6: bf00 nop + 8000ca8: 000f4240 .word 0x000f4240 + 8000cac: 48000400 .word 0x48000400 + 8000cb0: 0800da25 .word 0x0800da25 + +08000cb4 : +{ + 8000cb4: b507 push {r0, r1, r2, lr} + HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); + 8000cb6: 2201 movs r2, #1 +{ + 8000cb8: f88d 0007 strb.w r0, [sp, #7] + HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); + 8000cbc: 2110 movs r1, #16 + 8000cbe: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000cc2: f000 fc11 bl 80014e8 + HAL_GPIO_WritePin(GPIOA, DC_PIN, 0); + 8000cc6: 2200 movs r2, #0 + 8000cc8: f44f 7180 mov.w r1, #256 ; 0x100 + 8000ccc: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000cd0: f000 fc0a bl 80014e8 + HAL_GPIO_WritePin(GPIOA, CS_PIN, 0); + 8000cd4: 2200 movs r2, #0 + 8000cd6: 2110 movs r1, #16 + 8000cd8: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000cdc: f000 fc04 bl 80014e8 + HAL_SPI_Transmit(&spi_port, (uint8_t *)buf, len, HAL_MAX_DELAY); + 8000ce0: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 8000ce4: f10d 0107 add.w r1, sp, #7 + 8000ce8: 2201 movs r2, #1 + 8000cea: 4806 ldr r0, [pc, #24] ; (8000d04 ) + 8000cec: f000 fc9c bl 8001628 + HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); + 8000cf0: 2201 movs r2, #1 + 8000cf2: 2110 movs r1, #16 + 8000cf4: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000cf8: f000 fbf6 bl 80014e8 +} + 8000cfc: b003 add sp, #12 + 8000cfe: f85d fb04 ldr.w pc, [sp], #4 + 8000d02: bf00 nop + 8000d04: 2009e158 .word 0x2009e158 + +08000d08 : +{ + 8000d08: b537 push {r0, r1, r2, r4, r5, lr} + 8000d0a: 460d mov r5, r1 + 8000d0c: 4614 mov r4, r2 + lcd_write_cmd(cmd); + 8000d0e: f7ff ffd1 bl 8000cb4 + uint8_t d[4] = { (a>>8), a&0xff, (b>>8), b&0xff }; + 8000d12: 0a2b lsrs r3, r5, #8 + 8000d14: f88d 3004 strb.w r3, [sp, #4] + lcd_write_data(4, d); + 8000d18: a901 add r1, sp, #4 + uint8_t d[4] = { (a>>8), a&0xff, (b>>8), b&0xff }; + 8000d1a: 0a23 lsrs r3, r4, #8 + lcd_write_data(4, d); + 8000d1c: 2004 movs r0, #4 + uint8_t d[4] = { (a>>8), a&0xff, (b>>8), b&0xff }; + 8000d1e: f88d 5005 strb.w r5, [sp, #5] + 8000d22: f88d 3006 strb.w r3, [sp, #6] + 8000d26: f88d 4007 strb.w r4, [sp, #7] + lcd_write_data(4, d); + 8000d2a: f7ff ff77 bl 8000c1c +} + 8000d2e: b003 add sp, #12 + 8000d30: bd30 pop {r4, r5, pc} + ... + +08000d34 : +// +// Just setup SPI, do not reset display, etc. +// + void +lcd_spi_setup(void) +{ + 8000d34: b538 push {r3, r4, r5, lr} +#ifndef DISABLE_LCD + // might already be setup + if(spi_port.Instance == SPI1) return; + 8000d36: 4c0d ldr r4, [pc, #52] ; (8000d6c ) + 8000d38: 4d0d ldr r5, [pc, #52] ; (8000d70 ) + 8000d3a: 6823 ldr r3, [r4, #0] + 8000d3c: 42ab cmp r3, r5 + 8000d3e: d014 beq.n 8000d6a + + memset(&spi_port, 0, sizeof(spi_port)); + 8000d40: f104 0008 add.w r0, r4, #8 + 8000d44: 225c movs r2, #92 ; 0x5c + 8000d46: 2100 movs r1, #0 + 8000d48: f00c fdec bl 800d924 + + spi_port.Instance = SPI1; + + // see SPI_InitTypeDef + spi_port.Init.Mode = SPI_MODE_MASTER; + 8000d4c: f44f 7382 mov.w r3, #260 ; 0x104 + 8000d50: 6063 str r3, [r4, #4] + spi_port.Init.Direction = SPI_DIRECTION_2LINES; + spi_port.Init.DataSize = SPI_DATASIZE_8BIT; + 8000d52: f44f 63e0 mov.w r3, #1792 ; 0x700 + 8000d56: 60e3 str r3, [r4, #12] + spi_port.Init.CLKPolarity = SPI_POLARITY_LOW; + spi_port.Init.CLKPhase = SPI_PHASE_1EDGE; + spi_port.Init.NSS = SPI_NSS_SOFT; + 8000d58: f44f 7300 mov.w r3, #512 ; 0x200 + spi_port.Instance = SPI1; + 8000d5c: 6025 str r5, [r4, #0] + spi_port.Init.NSS = SPI_NSS_SOFT; + 8000d5e: 61a3 str r3, [r4, #24] + spi_port.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; + spi_port.Init.FirstBit = SPI_FIRSTBIT_MSB; + spi_port.Init.TIMode = SPI_TIMODE_DISABLED; + spi_port.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED; + + HAL_SPI_Init(&spi_port); + 8000d60: 4620 mov r0, r4 +#endif +} + 8000d62: e8bd 4038 ldmia.w sp!, {r3, r4, r5, lr} + HAL_SPI_Init(&spi_port); + 8000d66: f000 bc01 b.w 800156c +} + 8000d6a: bd38 pop {r3, r4, r5, pc} + 8000d6c: 2009e158 .word 0x2009e158 + 8000d70: 40013000 .word 0x40013000 + +08000d74 : +// +// Ok to call this lots. +// + void +oled_setup(void) +{ + 8000d74: b530 push {r4, r5, lr} + puts("lcd disabled");return; // disable so I can use MCO +#endif + + static uint32_t inited; + + if(inited == 0x238a572F) { + 8000d76: 4b23 ldr r3, [pc, #140] ; (8000e04 ) + 8000d78: 4a23 ldr r2, [pc, #140] ; (8000e08 ) + 8000d7a: 6819 ldr r1, [r3, #0] + 8000d7c: 4291 cmp r1, r2 +{ + 8000d7e: b087 sub sp, #28 + if(inited == 0x238a572F) { + 8000d80: d03e beq.n 8000e00 + return; + } + inited = 0x238a572F; + 8000d82: 601a str r2, [r3, #0] + + // enable some internal clocks + __HAL_RCC_SPI1_CLK_ENABLE(); + 8000d84: 4b21 ldr r3, [pc, #132] ; (8000e0c ) + + // take over from GPU + // - can be issue when coming in via callgate from mpy which might have been showing menu + HAL_GPIO_WritePin(GPIOE, PIN_G_CTRL, 1); // set G_CTRL pin -- we have control + 8000d86: 4822 ldr r0, [pc, #136] ; (8000e10 ) + __HAL_RCC_SPI1_CLK_ENABLE(); + 8000d88: 6e1a ldr r2, [r3, #96] ; 0x60 + + // .. wait for GPU to finish it's work + // - might take 16+ms because waiting for next vsync, etc + for(int i=0; i<100; i++) { + if(HAL_GPIO_ReadPin(GPIOE, PIN_G_BUSY) == 0) break; + 8000d8a: 4d21 ldr r5, [pc, #132] ; (8000e10 ) + __HAL_RCC_SPI1_CLK_ENABLE(); + 8000d8c: f442 5280 orr.w r2, r2, #4096 ; 0x1000 + 8000d90: 661a str r2, [r3, #96] ; 0x60 + 8000d92: 6e1b ldr r3, [r3, #96] ; 0x60 + 8000d94: f403 5380 and.w r3, r3, #4096 ; 0x1000 + 8000d98: 9300 str r3, [sp, #0] + HAL_GPIO_WritePin(GPIOE, PIN_G_CTRL, 1); // set G_CTRL pin -- we have control + 8000d9a: 2201 movs r2, #1 + 8000d9c: 2120 movs r1, #32 + __HAL_RCC_SPI1_CLK_ENABLE(); + 8000d9e: 9b00 ldr r3, [sp, #0] + HAL_GPIO_WritePin(GPIOE, PIN_G_CTRL, 1); // set G_CTRL pin -- we have control + 8000da0: f000 fba2 bl 80014e8 + 8000da4: 2464 movs r4, #100 ; 0x64 + if(HAL_GPIO_ReadPin(GPIOE, PIN_G_BUSY) == 0) break; + 8000da6: 2104 movs r1, #4 + 8000da8: 4628 mov r0, r5 + 8000daa: f000 fb97 bl 80014dc + 8000dae: b120 cbz r0, 8000dba + delay_ms(1); + 8000db0: 2001 movs r0, #1 + 8000db2: f002 fe67 bl 8003a84 + for(int i=0; i<100; i++) { + 8000db6: 3c01 subs r4, #1 + 8000db8: d1f5 bne.n 8000da6 + } + + // Simple pins + // - must be opendrain to allow GPU to share + GPIO_InitTypeDef setup = { + 8000dba: 4d16 ldr r5, [pc, #88] ; (8000e14 ) + 8000dbc: cd0f ldmia r5!, {r0, r1, r2, r3} + 8000dbe: ac01 add r4, sp, #4 + 8000dc0: c40f stmia r4!, {r0, r1, r2, r3} + 8000dc2: 682b ldr r3, [r5, #0] + 8000dc4: 6023 str r3, [r4, #0] + .Mode = GPIO_MODE_OUTPUT_OD, + .Pull = GPIO_PULLUP, + .Speed = GPIO_SPEED_FREQ_MEDIUM, + .Alternate = 0, + }; + HAL_GPIO_Init(GPIOA, &setup); + 8000dc6: a901 add r1, sp, #4 + 8000dc8: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000dcc: f000 fa12 bl 80011f4 + + // starting values + HAL_GPIO_WritePin(GPIOA, RESET_PIN | CS_PIN | DC_PIN, 1); + 8000dd0: 2201 movs r2, #1 + 8000dd2: f44f 71a8 mov.w r1, #336 ; 0x150 + 8000dd6: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000dda: f000 fb85 bl 80014e8 + + // SPI pins (same but with AF) + setup.Pin = SPI_SCK | SPI_MOSI; + 8000dde: 23a0 movs r3, #160 ; 0xa0 + 8000de0: 9301 str r3, [sp, #4] + setup.Alternate = GPIO_AF5_SPI1; + 8000de2: 2305 movs r3, #5 + 8000de4: 9305 str r3, [sp, #20] + setup.Mode = GPIO_MODE_AF_PP; + 8000de6: 2302 movs r3, #2 + setup.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + HAL_GPIO_Init(GPIOA, &setup); + 8000de8: a901 add r1, sp, #4 + 8000dea: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + setup.Mode = GPIO_MODE_AF_PP; + 8000dee: 9302 str r3, [sp, #8] + setup.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + 8000df0: 2303 movs r3, #3 + 8000df2: 9304 str r3, [sp, #16] + HAL_GPIO_Init(GPIOA, &setup); + 8000df4: f000 f9fe bl 80011f4 + + // config SPI port + lcd_spi_setup(); + 8000df8: f7ff ff9c bl 8000d34 + rng_delay(); + 8000dfc: f001 fd84 bl 8002908 +} + 8000e00: b007 add sp, #28 + 8000e02: bd30 pop {r4, r5, pc} + 8000e04: 2009e150 .word 0x2009e150 + 8000e08: 238a572f .word 0x238a572f + 8000e0c: 40021000 .word 0x40021000 + 8000e10: 48001000 .word 0x48001000 + 8000e14: 0800da34 .word 0x0800da34 + +08000e18 : + +// lcd_fill_solid() +// + void +lcd_fill_solid(uint16_t pattern) +{ + 8000e18: b5b0 push {r4, r5, r7, lr} + // note, MADCTL MV/MX/MY setting causes row vs. col swap here + lcd_write_cmd4(0x2a, 0, LCD_WIDTH-1); // CASET - Column address set range (x) + 8000e1a: f240 123f movw r2, #319 ; 0x13f +{ + 8000e1e: af00 add r7, sp, #0 + lcd_write_cmd4(0x2a, 0, LCD_WIDTH-1); // CASET - Column address set range (x) + 8000e20: 2100 movs r1, #0 +{ + 8000e22: 4604 mov r4, r0 + lcd_write_cmd4(0x2a, 0, LCD_WIDTH-1); // CASET - Column address set range (x) + 8000e24: 202a movs r0, #42 ; 0x2a + 8000e26: f7ff ff6f bl 8000d08 + lcd_write_cmd4(0x2b, 0, LCD_HEIGHT-1); // RASET - Row address set range (y) + 8000e2a: 22ef movs r2, #239 ; 0xef + 8000e2c: 2100 movs r1, #0 + 8000e2e: 202b movs r0, #43 ; 0x2b + 8000e30: f7ff ff6a bl 8000d08 + + lcd_write_cmd(0x2c); // RAMWR - memory write + 8000e34: 202c movs r0, #44 ; 0x2c + 8000e36: f7ff ff3d bl 8000cb4 + + uint16_t row[LCD_WIDTH]; + 8000e3a: f5ad 7d20 sub.w sp, sp, #640 ; 0x280 + 8000e3e: 466d mov r5, sp + for(; byte_len; byte_len-=2, dest++) { + 8000e40: f505 7220 add.w r2, r5, #640 ; 0x280 + uint16_t row[LCD_WIDTH]; + 8000e44: 462b mov r3, r5 + *dest = value; + 8000e46: f823 4b02 strh.w r4, [r3], #2 + for(; byte_len; byte_len-=2, dest++) { + 8000e4a: 429a cmp r2, r3 + 8000e4c: d1fb bne.n 8000e46 + 8000e4e: 24f0 movs r4, #240 ; 0xf0 + memset2(row, pattern, sizeof(row)); + + for(int y=0; y + for(int y=0; y + } +} + 8000e5e: 46bd mov sp, r7 + 8000e60: bdb0 pop {r4, r5, r7, pc} + ... + +08000e64 : +{ + 8000e64: b508 push {r3, lr} + oled_setup(); + 8000e66: f7ff ff85 bl 8000d74 + lcd_write_cmd(0x28); // DISPOFF + 8000e6a: 2028 movs r0, #40 ; 0x28 + 8000e6c: f7ff ff22 bl 8000cb4 + lcd_write_cmd(0x36); // MADCTL: memory addr ctrl, page 215 + 8000e70: 2036 movs r0, #54 ; 0x36 + 8000e72: f7ff ff1f bl 8000cb4 + lcd_write_data1(0x60); // MV=1 => horz mode, first byte=top-left corner, RGB order + 8000e76: 2060 movs r0, #96 ; 0x60 + 8000e78: f7ff fef8 bl 8000c6c + lcd_fill_solid(COL_BLACK); // works only on second+ reboots/resets + 8000e7c: 2000 movs r0, #0 + 8000e7e: f7ff ffcb bl 8000e18 + delay_ms(1); + 8000e82: 2001 movs r0, #1 + 8000e84: f002 fdfe bl 8003a84 + HAL_GPIO_WritePin(GPIOA, RESET_PIN, 0); + 8000e88: 2200 movs r2, #0 + 8000e8a: 2140 movs r1, #64 ; 0x40 + 8000e8c: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000e90: f000 fb2a bl 80014e8 + delay_ms(1); + 8000e94: 2001 movs r0, #1 + 8000e96: f002 fdf5 bl 8003a84 + HAL_GPIO_WritePin(GPIOA, RESET_PIN, 1); + 8000e9a: 2201 movs r2, #1 + 8000e9c: 2140 movs r1, #64 ; 0x40 + 8000e9e: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8000ea2: f000 fb21 bl 80014e8 + delay_ms(120); // 120ms - reset recovery time + 8000ea6: 2078 movs r0, #120 ; 0x78 + 8000ea8: f002 fdec bl 8003a84 + lcd_write_cmd(0x11); // SLPOUT: Sleep Out => turn off sleep mode + 8000eac: 2011 movs r0, #17 + 8000eae: f7ff ff01 bl 8000cb4 + delay_ms(5); // 5ms - wake up time + 8000eb2: 2005 movs r0, #5 + 8000eb4: f002 fde6 bl 8003a84 + lcd_write_cmd(0x36); // MADCTL: memory addr ctrl, page 215 + 8000eb8: 2036 movs r0, #54 ; 0x36 + 8000eba: f7ff fefb bl 8000cb4 + lcd_write_data1(0x60); // MV=1 => horz mode, first byte=top-left corner, RGB order + 8000ebe: 2060 movs r0, #96 ; 0x60 + 8000ec0: f7ff fed4 bl 8000c6c + lcd_write_cmd(0x3a); // COLMOD: pixel format + 8000ec4: 203a movs r0, #58 ; 0x3a + 8000ec6: f7ff fef5 bl 8000cb4 + lcd_write_data1(0x05); // => 16bit/pixel + 8000eca: 2005 movs r0, #5 + 8000ecc: f7ff fece bl 8000c6c + lcd_write_cmd(0xb2); // PORCTRL - porch control + 8000ed0: 20b2 movs r0, #178 ; 0xb2 + 8000ed2: f7ff feef bl 8000cb4 + lcd_write_data1(0x0c); + 8000ed6: 200c movs r0, #12 + 8000ed8: f7ff fec8 bl 8000c6c + lcd_write_data1(0x0c); + 8000edc: 200c movs r0, #12 + 8000ede: f7ff fec5 bl 8000c6c + lcd_write_data1(0x00); + 8000ee2: 2000 movs r0, #0 + 8000ee4: f7ff fec2 bl 8000c6c + lcd_write_data1(0x33); + 8000ee8: 2033 movs r0, #51 ; 0x33 + 8000eea: f7ff febf bl 8000c6c + lcd_write_data1(0x33); + 8000eee: 2033 movs r0, #51 ; 0x33 + 8000ef0: f7ff febc bl 8000c6c + lcd_write_cmd(0xb7); + 8000ef4: 20b7 movs r0, #183 ; 0xb7 + 8000ef6: f7ff fedd bl 8000cb4 + lcd_write_data1(0x35); + 8000efa: 2035 movs r0, #53 ; 0x35 + 8000efc: f7ff feb6 bl 8000c6c + lcd_write_cmd(0xbb); // VCOMS + 8000f00: 20bb movs r0, #187 ; 0xbb + 8000f02: f7ff fed7 bl 8000cb4 + lcd_write_data1(0x25); //35 20 + 8000f06: 2025 movs r0, #37 ; 0x25 + 8000f08: f7ff feb0 bl 8000c6c + lcd_write_cmd(0xc0); // LCM + 8000f0c: 20c0 movs r0, #192 ; 0xc0 + 8000f0e: f7ff fed1 bl 8000cb4 + lcd_write_data1(0x2c); + 8000f12: 202c movs r0, #44 ; 0x2c + 8000f14: f7ff feaa bl 8000c6c + lcd_write_cmd(0xc2); // VDVVRHEN + 8000f18: 20c2 movs r0, #194 ; 0xc2 + 8000f1a: f7ff fecb bl 8000cb4 + lcd_write_data1(0x01); + 8000f1e: 2001 movs r0, #1 + 8000f20: f7ff fea4 bl 8000c6c + lcd_write_cmd(0xc3); // VRHS + 8000f24: 20c3 movs r0, #195 ; 0xc3 + 8000f26: f7ff fec5 bl 8000cb4 + lcd_write_data1(0x13); //0e + 8000f2a: 2013 movs r0, #19 + 8000f2c: f7ff fe9e bl 8000c6c + lcd_write_cmd(0xc4); // VDVSET + 8000f30: 20c4 movs r0, #196 ; 0xc4 + 8000f32: f7ff febf bl 8000cb4 + lcd_write_data1(0x20); + 8000f36: 2020 movs r0, #32 + 8000f38: f7ff fe98 bl 8000c6c + lcd_write_cmd(0xc6); // FRCTR2 + 8000f3c: 20c6 movs r0, #198 ; 0xc6 + 8000f3e: f7ff feb9 bl 8000cb4 + lcd_write_data1(0x0f); + 8000f42: 200f movs r0, #15 + 8000f44: f7ff fe92 bl 8000c6c + lcd_write_cmd(0xd0); // PWCTRL1 + 8000f48: 20d0 movs r0, #208 ; 0xd0 + 8000f4a: f7ff feb3 bl 8000cb4 + lcd_write_data1(0xa4); + 8000f4e: 20a4 movs r0, #164 ; 0xa4 + 8000f50: f7ff fe8c bl 8000c6c + lcd_write_data1(0xa1); + 8000f54: 20a1 movs r0, #161 ; 0xa1 + 8000f56: f7ff fe89 bl 8000c6c + lcd_write_cmd(0xe0); // PVGAMCTRL + 8000f5a: 20e0 movs r0, #224 ; 0xe0 + 8000f5c: f7ff feaa bl 8000cb4 + lcd_write_data1(0xd0); + 8000f60: 20d0 movs r0, #208 ; 0xd0 + 8000f62: f7ff fe83 bl 8000c6c + lcd_write_data1(0x00); + 8000f66: 2000 movs r0, #0 + 8000f68: f7ff fe80 bl 8000c6c + lcd_write_data1(0x03); + 8000f6c: 2003 movs r0, #3 + 8000f6e: f7ff fe7d bl 8000c6c + lcd_write_data1(0x09); + 8000f72: 2009 movs r0, #9 + 8000f74: f7ff fe7a bl 8000c6c + lcd_write_data1(0x13); + 8000f78: 2013 movs r0, #19 + 8000f7a: f7ff fe77 bl 8000c6c + lcd_write_data1(0x1c); + 8000f7e: 201c movs r0, #28 + 8000f80: f7ff fe74 bl 8000c6c + lcd_write_data1(0x3a); + 8000f84: 203a movs r0, #58 ; 0x3a + 8000f86: f7ff fe71 bl 8000c6c + lcd_write_data1(0x55); + 8000f8a: 2055 movs r0, #85 ; 0x55 + 8000f8c: f7ff fe6e bl 8000c6c + lcd_write_data1(0x48); + 8000f90: 2048 movs r0, #72 ; 0x48 + 8000f92: f7ff fe6b bl 8000c6c + lcd_write_data1(0x18); + 8000f96: 2018 movs r0, #24 + 8000f98: f7ff fe68 bl 8000c6c + lcd_write_data1(0x12); + 8000f9c: 2012 movs r0, #18 + 8000f9e: f7ff fe65 bl 8000c6c + lcd_write_data1(0x0e); + 8000fa2: 200e movs r0, #14 + 8000fa4: f7ff fe62 bl 8000c6c + lcd_write_data1(0x19); + 8000fa8: 2019 movs r0, #25 + 8000faa: f7ff fe5f bl 8000c6c + lcd_write_data1(0x1e); + 8000fae: 201e movs r0, #30 + 8000fb0: f7ff fe5c bl 8000c6c + lcd_write_cmd(0xe1); // NVGAMCTRL + 8000fb4: 20e1 movs r0, #225 ; 0xe1 + 8000fb6: f7ff fe7d bl 8000cb4 + lcd_write_data1(0xd0); + 8000fba: 20d0 movs r0, #208 ; 0xd0 + 8000fbc: f7ff fe56 bl 8000c6c + lcd_write_data1(0x00); + 8000fc0: 2000 movs r0, #0 + 8000fc2: f7ff fe53 bl 8000c6c + lcd_write_data1(0x03); + 8000fc6: 2003 movs r0, #3 + 8000fc8: f7ff fe50 bl 8000c6c + lcd_write_data1(0x09); + 8000fcc: 2009 movs r0, #9 + 8000fce: f7ff fe4d bl 8000c6c + lcd_write_data1(0x05); + 8000fd2: 2005 movs r0, #5 + 8000fd4: f7ff fe4a bl 8000c6c + lcd_write_data1(0x25); + 8000fd8: 2025 movs r0, #37 ; 0x25 + 8000fda: f7ff fe47 bl 8000c6c + lcd_write_data1(0x3a); + 8000fde: 203a movs r0, #58 ; 0x3a + 8000fe0: f7ff fe44 bl 8000c6c + lcd_write_data1(0x55); + 8000fe4: 2055 movs r0, #85 ; 0x55 + 8000fe6: f7ff fe41 bl 8000c6c + lcd_write_data1(0x50); + 8000fea: 2050 movs r0, #80 ; 0x50 + 8000fec: f7ff fe3e bl 8000c6c + lcd_write_data1(0x3d); + 8000ff0: 203d movs r0, #61 ; 0x3d + 8000ff2: f7ff fe3b bl 8000c6c + lcd_write_data1(0x1c); + 8000ff6: 201c movs r0, #28 + 8000ff8: f7ff fe38 bl 8000c6c + lcd_write_data1(0x1d); + 8000ffc: 201d movs r0, #29 + 8000ffe: f7ff fe35 bl 8000c6c + lcd_write_data1(0x1d); + 8001002: 201d movs r0, #29 + 8001004: f7ff fe32 bl 8000c6c + lcd_write_data1(0x1e); + 8001008: 201e movs r0, #30 + 800100a: f7ff fe2f bl 8000c6c + lcd_write_cmd(0x35); // TEON - Tear signal on + 800100e: 2035 movs r0, #53 ; 0x35 + 8001010: f7ff fe50 bl 8000cb4 + lcd_write_data1(0x0); + 8001014: 2000 movs r0, #0 + 8001016: f7ff fe29 bl 8000c6c + lcd_fill_solid(COL_BLACK); + 800101a: 2000 movs r0, #0 + 800101c: f7ff fefc bl 8000e18 + lcd_write_cmd(0x21); // INVON + 8001020: 2021 movs r0, #33 ; 0x21 + 8001022: f7ff fe47 bl 8000cb4 + lcd_write_cmd(0x29); // DISPON + 8001026: 2029 movs r0, #41 ; 0x29 + 8001028: f7ff fe44 bl 8000cb4 + delay_ms(50); + 800102c: 2032 movs r0, #50 ; 0x32 + 800102e: f002 fd29 bl 8003a84 + last_screen = NULL; + 8001032: 4b02 ldr r3, [pc, #8] ; (800103c ) + 8001034: 2200 movs r2, #0 + 8001036: 601a str r2, [r3, #0] +} + 8001038: bd08 pop {r3, pc} + 800103a: bf00 nop + 800103c: 2009e154 .word 0x2009e154 + +08001040 : + +// lcd_write_rows() +// + void +lcd_write_rows(int y, int num_rows, uint16_t *pixels) +{ + 8001040: b570 push {r4, r5, r6, lr} + 8001042: 4606 mov r6, r0 + 8001044: 460c mov r4, r1 + 8001046: 4615 mov r5, r2 + lcd_write_cmd4(0x2a, 0, LCD_WIDTH-1); // CASET - Column address set range (x) + 8001048: 2100 movs r1, #0 + 800104a: f240 123f movw r2, #319 ; 0x13f + 800104e: 202a movs r0, #42 ; 0x2a + 8001050: f7ff fe5a bl 8000d08 + lcd_write_cmd4(0x2b, y, LCD_HEIGHT-1); // RASET - Row address set range (y) + 8001054: b2b1 uxth r1, r6 + 8001056: 22ef movs r2, #239 ; 0xef + 8001058: 202b movs r0, #43 ; 0x2b + 800105a: f7ff fe55 bl 8000d08 + + lcd_write_cmd(0x2c); // RAMWR - memory write + 800105e: 202c movs r0, #44 ; 0x2c + 8001060: f7ff fe28 bl 8000cb4 + + lcd_write_data(num_rows * 2 * LCD_WIDTH, (uint8_t *)pixels); + 8001064: f44f 7020 mov.w r0, #640 ; 0x280 + 8001068: 4629 mov r1, r5 + 800106a: 4360 muls r0, r4 +} + 800106c: e8bd 4070 ldmia.w sp!, {r4, r5, r6, lr} + lcd_write_data(num_rows * 2 * LCD_WIDTH, (uint8_t *)pixels); + 8001070: f7ff bdd4 b.w 8000c1c + +08001074 : +// +// Perform simple RLE decompression, and pixel expansion. +// + void +oled_show(const uint8_t *pixels) +{ + 8001074: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + 8001078: f5ad 6d07 sub.w sp, sp, #2160 ; 0x870 + 800107c: af00 add r7, sp, #0 + 800107e: 4606 mov r6, r0 + oled_setup(); + 8001080: f7ff fe78 bl 8000d74 + + // we are NOT fast enough to send entire screen during the + // vblanking time, so either we show torn stuff, or we flash display off a little + wait_vsync(); + 8001084: f7ff fdfe bl 8000c84 + lcd_write_cmd(0x28); // DISPOFF + 8001088: 2028 movs r0, #40 ; 0x28 + 800108a: f7ff fe13 bl 8000cb4 + + // always full update: minus part we aren't saving "TOP_CROP" at top edge + lcd_write_cmd4(0x2a, 0, LCD_WIDTH-1); // CASET - Column address set range (x) + 800108e: f240 123f movw r2, #319 ; 0x13f + 8001092: 2100 movs r1, #0 + 8001094: 202a movs r0, #42 ; 0x2a + 8001096: f7ff fe37 bl 8000d08 + // RASET - Row address set range (y) + lcd_write_cmd4(0x2b, SCREEN_TOP_CROP, LCD_HEIGHT-1); + 800109a: 22ef movs r2, #239 ; 0xef + 800109c: 210f movs r1, #15 + 800109e: 202b movs r0, #43 ; 0x2b + 80010a0: f7ff fe32 bl 8000d08 + lcd_write_cmd(0x2c); // RAMWR - memory write + 80010a4: 202c movs r0, #44 ; 0x2c + 80010a6: f7ff fe05 bl 8000cb4 + + uint8_t buf[127]; + uint16_t expand[sizeof(buf)*8]; + const uint8_t *p = pixels; + + uint16_t blk_row[LCD_WIDTH]; + 80010aa: f5ad 7d20 sub.w sp, sp, #640 ; 0x280 + 80010ae: 46e8 mov r8, sp + *dest = value; + 80010b0: f44f 7220 mov.w r2, #640 ; 0x280 + 80010b4: 2100 movs r1, #0 + 80010b6: 4640 mov r0, r8 + 80010b8: f00c fc34 bl 800d924 + const uint8_t *p = pixels; + 80010bc: 4634 mov r4, r6 + memset2(blk_row, COL_BLACK, sizeof(blk_row)); + + while(1) { + uint8_t hdr = *(p++); + 80010be: 7823 ldrb r3, [r4, #0] + if(!hdr) break; // end marker + 80010c0: 2b00 cmp r3, #0 + 80010c2: d042 beq.n 800114a + + uint8_t len = hdr & 0x7f; + if(hdr & 0x80) { + 80010c4: 061a lsls r2, r3, #24 + uint8_t len = hdr & 0x7f; + 80010c6: f003 057f and.w r5, r3, #127 ; 0x7f + if(hdr & 0x80) { + 80010ca: d514 bpl.n 80010f6 + uint8_t hdr = *(p++); + 80010cc: 3401 adds r4, #1 + // random bytes follow + memcpy(buf, p, len); + 80010ce: 4621 mov r1, r4 + 80010d0: 462a mov r2, r5 + 80010d2: 4638 mov r0, r7 + 80010d4: f00c fc18 bl 800d908 + p += len; + 80010d8: 442c add r4, r5 + p++; + } + + // expand 'len' packed monochrome into BGR565 16-bit data: buf => expand + uint16_t *out = expand; + for(int i=0; i>= 1, out++) { + if(packed & mask) { + *out = COL_FOREGROUND; + } else { + *out = COL_BLACK; + 80010e2: f246 0cfd movw ip, #24829 ; 0x60fd + for(int i=0; i + } + } + } + lcd_write_data(len*8*2, (uint8_t *)expand); + 80010ea: f107 0180 add.w r1, r7, #128 ; 0x80 + 80010ee: 0128 lsls r0, r5, #4 + 80010f0: f7ff fd94 bl 8000c1c + 80010f4: e7e3 b.n 80010be + } else if(hdr == 0x7f) { + 80010f6: 2b7f cmp r3, #127 ; 0x7f + for(int i=0; i + for(int i=0; i + lcd_write_data(2 * LCD_WIDTH, (uint8_t *)blk_row); + 8001106: 4641 mov r1, r8 + 8001108: f44f 7020 mov.w r0, #640 ; 0x280 + 800110c: f7ff fd86 bl 8000c1c + for(int i=0; i + 8001116: e7d2 b.n 80010be + memset(buf, *p, len); + 8001118: 462a mov r2, r5 + 800111a: 4649 mov r1, r9 + 800111c: 4638 mov r0, r7 + 800111e: f00c fc01 bl 800d924 + p++; + 8001122: e7da b.n 80010da + uint8_t packed = buf[i]; + 8001124: f810 ab01 ldrb.w sl, [r0], #1 + for(uint8_t mask = 0x80; mask; mask >>= 1, out++) { + 8001128: 2180 movs r1, #128 ; 0x80 + 800112a: f103 0e10 add.w lr, r3, #16 + *out = COL_BLACK; + 800112e: ea1a 0f01 tst.w sl, r1 + 8001132: bf14 ite ne + 8001134: 46e1 movne r9, ip + 8001136: f04f 0900 moveq.w r9, #0 + 800113a: f823 9b02 strh.w r9, [r3], #2 + for(uint8_t mask = 0x80; mask; mask >>= 1, out++) { + 800113e: 4573 cmp r3, lr + 8001140: ea4f 0151 mov.w r1, r1, lsr #1 + 8001144: d1f3 bne.n 800112e + for(int i=0; i + } + + lcd_write_cmd(0x29); // DISPON + 800114a: 2029 movs r0, #41 ; 0x29 + 800114c: f7ff fdb2 bl 8000cb4 + + last_screen = pixels; + 8001150: 4b04 ldr r3, [pc, #16] ; (8001164 ) + 8001152: 601e str r6, [r3, #0] + rng_delay(); + 8001154: f001 fbd8 bl 8002908 +} + 8001158: f507 6707 add.w r7, r7, #2160 ; 0x870 + 800115c: 46bd mov sp, r7 + 800115e: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + 8001162: bf00 nop + 8001164: 2009e154 .word 0x2009e154 + +08001168 : +// +// Perform simple RLE decompression, and add a bar on final screen line. +// + void +oled_show_progress(const uint8_t *pixels, int progress) +{ + 8001168: b5b0 push {r4, r5, r7, lr} + 800116a: af00 add r7, sp, #0 + 800116c: 4605 mov r5, r0 + 800116e: 460c mov r4, r1 + oled_setup(); + 8001170: f7ff fe00 bl 8000d74 + + if(last_screen != pixels) { + 8001174: 4b1d ldr r3, [pc, #116] ; (80011ec ) + 8001176: 681b ldr r3, [r3, #0] + 8001178: 42ab cmp r3, r5 + 800117a: d002 beq.n 8001182 + oled_show(pixels); + 800117c: 4628 mov r0, r5 + 800117e: f7ff ff79 bl 8001074 + } + + uint32_t p_count = LCD_WIDTH * 10 * progress / 1000; + 8001182: f44f 6148 mov.w r1, #3200 ; 0xc80 + 8001186: 4361 muls r1, r4 + 8001188: f44f 737a mov.w r3, #1000 ; 0x3e8 + 800118c: fb91 f1f3 sdiv r1, r1, r3 + if(p_count > LCD_WIDTH) p_count = LCD_WIDTH-1; + 8001190: f240 133f movw r3, #319 ; 0x13f + 8001194: f5b1 7fa0 cmp.w r1, #320 ; 0x140 + 8001198: bf88 it hi + 800119a: 4619 movhi r1, r3 + if(p_count < 0) p_count = 0; + + // draw just the progress bar + uint16_t row[LCD_WIDTH]; + 800119c: f5ad 7d20 sub.w sp, sp, #640 ; 0x280 + 80011a0: 466c mov r4, sp + memset2(row, COL_FOREGROUND, 2*p_count); + 80011a2: 004a lsls r2, r1, #1 + 80011a4: b293 uxth r3, r2 + for(; byte_len; byte_len-=2, dest++) { + 80011a6: 4620 mov r0, r4 + *dest = value; + 80011a8: f246 05fd movw r5, #24829 ; 0x60fd + for(; byte_len; byte_len-=2, dest++) { + 80011ac: b9a3 cbnz r3, 80011d8 + memset2(&row[p_count], COL_BLACK, 2*(LCD_WIDTH-p_count)); + 80011ae: f5c1 71a0 rsb r1, r1, #320 ; 0x140 + 80011b2: 4422 add r2, r4 + 80011b4: 0049 lsls r1, r1, #1 + for(; byte_len; byte_len-=2, dest++) { + 80011b6: b289 uxth r1, r1 + 80011b8: b999 cbnz r1, 80011e2 + + wait_vsync(); + 80011ba: f7ff fd63 bl 8000c84 + 80011be: 25eb movs r5, #235 ; 0xeb + + for(int i=0; i + for(int i=0; i + } + + rng_delay(); + 80011d0: f001 fb9a bl 8002908 +} + 80011d4: 46bd mov sp, r7 + 80011d6: bdb0 pop {r4, r5, r7, pc} + for(; byte_len; byte_len-=2, dest++) { + 80011d8: 3b02 subs r3, #2 + *dest = value; + 80011da: f820 5b02 strh.w r5, [r0], #2 + for(; byte_len; byte_len-=2, dest++) { + 80011de: b29b uxth r3, r3 + 80011e0: e7e4 b.n 80011ac + *dest = value; + 80011e2: f822 3b02 strh.w r3, [r2], #2 + for(; byte_len; byte_len-=2, dest++) { + 80011e6: 3902 subs r1, #2 + 80011e8: e7e5 b.n 80011b6 + 80011ea: bf00 nop + 80011ec: 2009e154 .word 0x2009e154 + +080011f0 : +// + void +oled_factory_busy(void) +{ + // not implemented: would need to talk to GPU for this +} + 80011f0: 4770 bx lr + ... + +080011f4 : + * @param GPIO_Init: pointer to a GPIO_InitTypeDef structure that contains + * the configuration information for the specified GPIO peripheral. + * @retval None + */ +void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init) +{ + 80011f4: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + /*--------------------- EXTI Mode Configuration ------------------------*/ + /* Configure the External Interrupt or event for the current IO */ + if((GPIO_Init->Mode & EXTI_MODE) == EXTI_MODE) + { + /* Enable SYSCFG Clock */ + __HAL_RCC_SYSCFG_CLK_ENABLE(); + 80011f8: f8df 81b4 ldr.w r8, [pc, #436] ; 80013b0 + temp &= ~(((uint32_t)0x0F) << (4 * (position & 0x03))); + temp |= (GPIO_GET_INDEX(GPIOx) << (4 * (position & 0x03))); + SYSCFG->EXTICR[position >> 2] = temp; + + /* Clear EXTI line configuration */ + temp = EXTI->IMR1; + 80011fc: 4c6a ldr r4, [pc, #424] ; (80013a8 ) + temp |= (GPIO_GET_INDEX(GPIOx) << (4 * (position & 0x03))); + 80011fe: f8df 91b4 ldr.w r9, [pc, #436] ; 80013b4 +{ + 8001202: b085 sub sp, #20 + uint32_t position = 0x00; + 8001204: 2300 movs r3, #0 + while (((GPIO_Init->Pin) >> position) != RESET) + 8001206: 680a ldr r2, [r1, #0] + 8001208: fa32 f503 lsrs.w r5, r2, r3 + 800120c: d102 bne.n 8001214 + } + } + + position++; + } +} + 800120e: b005 add sp, #20 + 8001210: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + iocurrent = (GPIO_Init->Pin) & (1U << position); + 8001214: 2701 movs r7, #1 + 8001216: 409f lsls r7, r3 + if(iocurrent) + 8001218: 403a ands r2, r7 + 800121a: f000 80b4 beq.w 8001386 + if((GPIO_Init->Mode == GPIO_MODE_AF_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_OD)) + 800121e: 684d ldr r5, [r1, #4] + 8001220: f025 0a10 bic.w sl, r5, #16 + 8001224: f1ba 0f02 cmp.w sl, #2 + 8001228: d116 bne.n 8001258 + temp = GPIOx->AFR[position >> 3]; + 800122a: ea4f 0ed3 mov.w lr, r3, lsr #3 + 800122e: eb00 0e8e add.w lr, r0, lr, lsl #2 + temp &= ~((uint32_t)0xF << ((uint32_t)(position & (uint32_t)0x07) * 4)) ; + 8001232: f003 0b07 and.w fp, r3, #7 + temp = GPIOx->AFR[position >> 3]; + 8001236: f8de 6020 ldr.w r6, [lr, #32] + temp &= ~((uint32_t)0xF << ((uint32_t)(position & (uint32_t)0x07) * 4)) ; + 800123a: ea4f 0b8b mov.w fp, fp, lsl #2 + 800123e: f04f 0c0f mov.w ip, #15 + 8001242: fa0c fc0b lsl.w ip, ip, fp + 8001246: ea26 0c0c bic.w ip, r6, ip + temp |= ((uint32_t)(GPIO_Init->Alternate) << (((uint32_t)position & (uint32_t)0x07) * 4)); + 800124a: 690e ldr r6, [r1, #16] + 800124c: fa06 f60b lsl.w r6, r6, fp + 8001250: ea46 060c orr.w r6, r6, ip + GPIOx->AFR[position >> 3] = temp; + 8001254: f8ce 6020 str.w r6, [lr, #32] + temp = GPIOx->MODER; + 8001258: f8d0 b000 ldr.w fp, [r0] + temp &= ~(GPIO_MODER_MODE0 << (position * 2)); + 800125c: ea4f 0e43 mov.w lr, r3, lsl #1 + 8001260: f04f 0c03 mov.w ip, #3 + 8001264: fa0c fc0e lsl.w ip, ip, lr + 8001268: ea6f 060c mvn.w r6, ip + 800126c: ea2b 0b0c bic.w fp, fp, ip + temp |= ((GPIO_Init->Mode & GPIO_MODE) << (position * 2)); + 8001270: f005 0c03 and.w ip, r5, #3 + 8001274: fa0c fc0e lsl.w ip, ip, lr + if((GPIO_Init->Mode == GPIO_MODE_OUTPUT_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_PP) || + 8001278: f10a 3aff add.w sl, sl, #4294967295 ; 0xffffffff + temp |= ((GPIO_Init->Mode & GPIO_MODE) << (position * 2)); + 800127c: ea4c 0c0b orr.w ip, ip, fp + if((GPIO_Init->Mode == GPIO_MODE_OUTPUT_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_PP) || + 8001280: f1ba 0f01 cmp.w sl, #1 + temp &= ~(GPIO_MODER_MODE0 << (position * 2)); + 8001284: 9601 str r6, [sp, #4] + GPIOx->MODER = temp; + 8001286: f8c0 c000 str.w ip, [r0] + if((GPIO_Init->Mode == GPIO_MODE_OUTPUT_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_PP) || + 800128a: d815 bhi.n 80012b8 + temp = GPIOx->OSPEEDR; + 800128c: f8d0 c008 ldr.w ip, [r0, #8] + temp &= ~(GPIO_OSPEEDR_OSPEED0 << (position * 2)); + 8001290: ea06 0c0c and.w ip, r6, ip + temp |= (GPIO_Init->Speed << (position * 2)); + 8001294: 68ce ldr r6, [r1, #12] + 8001296: fa06 fa0e lsl.w sl, r6, lr + 800129a: ea4a 0c0c orr.w ip, sl, ip + GPIOx->OSPEEDR = temp; + 800129e: f8c0 c008 str.w ip, [r0, #8] + temp = GPIOx->OTYPER; + 80012a2: f8d0 c004 ldr.w ip, [r0, #4] + temp &= ~(GPIO_OTYPER_OT0 << position) ; + 80012a6: ea2c 0707 bic.w r7, ip, r7 + temp |= (((GPIO_Init->Mode & GPIO_OUTPUT_TYPE) >> 4) << position); + 80012aa: f3c5 1c00 ubfx ip, r5, #4, #1 + 80012ae: fa0c fc03 lsl.w ip, ip, r3 + 80012b2: ea4c 0707 orr.w r7, ip, r7 + GPIOx->OTYPER = temp; + 80012b6: 6047 str r7, [r0, #4] + temp = GPIOx->PUPDR; + 80012b8: 68c7 ldr r7, [r0, #12] + temp &= ~(GPIO_PUPDR_PUPD0 << (position * 2)); + 80012ba: 9e01 ldr r6, [sp, #4] + 80012bc: 4037 ands r7, r6 + temp |= ((GPIO_Init->Pull) << (position * 2)); + 80012be: 688e ldr r6, [r1, #8] + 80012c0: fa06 f60e lsl.w r6, r6, lr + 80012c4: 433e orrs r6, r7 + GPIOx->PUPDR = temp; + 80012c6: 60c6 str r6, [r0, #12] + if((GPIO_Init->Mode & EXTI_MODE) == EXTI_MODE) + 80012c8: 00ee lsls r6, r5, #3 + 80012ca: d55c bpl.n 8001386 + __HAL_RCC_SYSCFG_CLK_ENABLE(); + 80012cc: f8d8 6060 ldr.w r6, [r8, #96] ; 0x60 + 80012d0: f046 0601 orr.w r6, r6, #1 + 80012d4: f8c8 6060 str.w r6, [r8, #96] ; 0x60 + 80012d8: f8d8 6060 ldr.w r6, [r8, #96] ; 0x60 + 80012dc: f023 0703 bic.w r7, r3, #3 + 80012e0: f107 4780 add.w r7, r7, #1073741824 ; 0x40000000 + 80012e4: f006 0601 and.w r6, r6, #1 + 80012e8: f507 3780 add.w r7, r7, #65536 ; 0x10000 + 80012ec: 9603 str r6, [sp, #12] + temp &= ~(((uint32_t)0x0F) << (4 * (position & 0x03))); + 80012ee: f003 0c03 and.w ip, r3, #3 + __HAL_RCC_SYSCFG_CLK_ENABLE(); + 80012f2: 9e03 ldr r6, [sp, #12] + temp = SYSCFG->EXTICR[position >> 2]; + 80012f4: f8d7 a008 ldr.w sl, [r7, #8] + temp &= ~(((uint32_t)0x0F) << (4 * (position & 0x03))); + 80012f8: f04f 0e0f mov.w lr, #15 + 80012fc: ea4f 0c8c mov.w ip, ip, lsl #2 + 8001300: fa0e f60c lsl.w r6, lr, ip + temp |= (GPIO_GET_INDEX(GPIOx) << (4 * (position & 0x03))); + 8001304: f1b0 4f90 cmp.w r0, #1207959552 ; 0x48000000 + temp &= ~(((uint32_t)0x0F) << (4 * (position & 0x03))); + 8001308: ea2a 0e06 bic.w lr, sl, r6 + temp |= (GPIO_GET_INDEX(GPIOx) << (4 * (position & 0x03))); + 800130c: d03d beq.n 800138a + 800130e: 4e27 ldr r6, [pc, #156] ; (80013ac ) + 8001310: 42b0 cmp r0, r6 + 8001312: d03c beq.n 800138e + 8001314: f506 6680 add.w r6, r6, #1024 ; 0x400 + 8001318: 42b0 cmp r0, r6 + 800131a: d03a beq.n 8001392 + 800131c: f506 6680 add.w r6, r6, #1024 ; 0x400 + 8001320: 42b0 cmp r0, r6 + 8001322: d038 beq.n 8001396 + 8001324: f506 6680 add.w r6, r6, #1024 ; 0x400 + 8001328: 42b0 cmp r0, r6 + 800132a: d036 beq.n 800139a + 800132c: f506 6680 add.w r6, r6, #1024 ; 0x400 + 8001330: 42b0 cmp r0, r6 + 8001332: d034 beq.n 800139e + 8001334: 4548 cmp r0, r9 + 8001336: d034 beq.n 80013a2 + 8001338: f506 6600 add.w r6, r6, #2048 ; 0x800 + 800133c: 42b0 cmp r0, r6 + 800133e: bf0c ite eq + 8001340: 2607 moveq r6, #7 + 8001342: 2608 movne r6, #8 + 8001344: fa06 f60c lsl.w r6, r6, ip + 8001348: ea46 060e orr.w r6, r6, lr + SYSCFG->EXTICR[position >> 2] = temp; + 800134c: 60be str r6, [r7, #8] + temp = EXTI->IMR1; + 800134e: 6826 ldr r6, [r4, #0] + temp &= ~((uint32_t)iocurrent); + 8001350: 43d7 mvns r7, r2 + if((GPIO_Init->Mode & GPIO_MODE_IT) == GPIO_MODE_IT) + 8001352: f415 3f80 tst.w r5, #65536 ; 0x10000 + temp &= ~((uint32_t)iocurrent); + 8001356: bf0c ite eq + 8001358: 403e andeq r6, r7 + temp |= iocurrent; + 800135a: 4316 orrne r6, r2 + EXTI->IMR1 = temp; + 800135c: 6026 str r6, [r4, #0] + temp = EXTI->EMR1; + 800135e: 6866 ldr r6, [r4, #4] + if((GPIO_Init->Mode & GPIO_MODE_EVT) == GPIO_MODE_EVT) + 8001360: f415 3f00 tst.w r5, #131072 ; 0x20000 + temp &= ~((uint32_t)iocurrent); + 8001364: bf0c ite eq + 8001366: 403e andeq r6, r7 + temp |= iocurrent; + 8001368: 4316 orrne r6, r2 + EXTI->EMR1 = temp; + 800136a: 6066 str r6, [r4, #4] + temp = EXTI->RTSR1; + 800136c: 68a6 ldr r6, [r4, #8] + if((GPIO_Init->Mode & RISING_EDGE) == RISING_EDGE) + 800136e: f415 1f80 tst.w r5, #1048576 ; 0x100000 + temp &= ~((uint32_t)iocurrent); + 8001372: bf0c ite eq + 8001374: 403e andeq r6, r7 + temp |= iocurrent; + 8001376: 4316 orrne r6, r2 + EXTI->RTSR1 = temp; + 8001378: 60a6 str r6, [r4, #8] + temp = EXTI->FTSR1; + 800137a: 68e6 ldr r6, [r4, #12] + if((GPIO_Init->Mode & FALLING_EDGE) == FALLING_EDGE) + 800137c: 02ad lsls r5, r5, #10 + temp &= ~((uint32_t)iocurrent); + 800137e: bf54 ite pl + 8001380: 403e andpl r6, r7 + temp |= iocurrent; + 8001382: 4316 orrmi r6, r2 + EXTI->FTSR1 = temp; + 8001384: 60e6 str r6, [r4, #12] + position++; + 8001386: 3301 adds r3, #1 + 8001388: e73d b.n 8001206 + temp |= (GPIO_GET_INDEX(GPIOx) << (4 * (position & 0x03))); + 800138a: 2600 movs r6, #0 + 800138c: e7da b.n 8001344 + 800138e: 2601 movs r6, #1 + 8001390: e7d8 b.n 8001344 + 8001392: 2602 movs r6, #2 + 8001394: e7d6 b.n 8001344 + 8001396: 2603 movs r6, #3 + 8001398: e7d4 b.n 8001344 + 800139a: 2604 movs r6, #4 + 800139c: e7d2 b.n 8001344 + 800139e: 2605 movs r6, #5 + 80013a0: e7d0 b.n 8001344 + 80013a2: 2606 movs r6, #6 + 80013a4: e7ce b.n 8001344 + 80013a6: bf00 nop + 80013a8: 40010400 .word 0x40010400 + 80013ac: 48000400 .word 0x48000400 + 80013b0: 40021000 .word 0x40021000 + 80013b4: 48001800 .word 0x48001800 + +080013b8 : + * @param GPIO_Pin: specifies the port bit to be written. + * This parameter can be one of GPIO_PIN_x where x can be (0..15). + * @retval None + */ +void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin) +{ + 80013b8: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + { + tmp = ((uint32_t)0x0F) << (4 * (position & 0x03)); + SYSCFG->EXTICR[position >> 2] &= ~tmp; + + /* Clear EXTI line configuration */ + EXTI->IMR1 &= ~((uint32_t)iocurrent); + 80013bc: 4c43 ldr r4, [pc, #268] ; (80014cc ) + if(tmp == (GPIO_GET_INDEX(GPIOx) << (4 * (position & 0x03)))) + 80013be: f8df a114 ldr.w sl, [pc, #276] ; 80014d4 + 80013c2: f8df b114 ldr.w fp, [pc, #276] ; 80014d8 + uint32_t position = 0x00; + 80013c6: 2200 movs r2, #0 + iocurrent = (GPIO_Pin) & (1U << position); + 80013c8: f04f 0901 mov.w r9, #1 + while ((GPIO_Pin >> position) != RESET) + 80013cc: fa31 f302 lsrs.w r3, r1, r2 + 80013d0: d101 bne.n 80013d6 + } + } + + position++; + } +} + 80013d2: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + iocurrent = (GPIO_Pin) & (1U << position); + 80013d6: fa09 f802 lsl.w r8, r9, r2 + if (iocurrent) + 80013da: ea18 0c01 ands.w ip, r8, r1 + 80013de: d064 beq.n 80014aa + GPIOx->MODER |= (GPIO_MODER_MODE0 << (position * 2)); + 80013e0: 6805 ldr r5, [r0, #0] + 80013e2: 2303 movs r3, #3 + 80013e4: 0056 lsls r6, r2, #1 + 80013e6: fa03 f606 lsl.w r6, r3, r6 + GPIOx->AFR[position >> 3] &= ~((uint32_t)0xF << ((uint32_t)(position & (uint32_t)0x07) * 4)) ; + 80013ea: fa22 fe03 lsr.w lr, r2, r3 + GPIOx->MODER |= (GPIO_MODER_MODE0 << (position * 2)); + 80013ee: 4335 orrs r5, r6 + 80013f0: eb00 0e8e add.w lr, r0, lr, lsl #2 + 80013f4: 6005 str r5, [r0, #0] + GPIOx->AFR[position >> 3] &= ~((uint32_t)0xF << ((uint32_t)(position & (uint32_t)0x07) * 4)) ; + 80013f6: f8de 5020 ldr.w r5, [lr, #32] + 80013fa: f002 0707 and.w r7, r2, #7 + 80013fe: 462b mov r3, r5 + 8001400: 00bf lsls r7, r7, #2 + 8001402: 250f movs r5, #15 + 8001404: fa05 f707 lsl.w r7, r5, r7 + 8001408: ea23 0707 bic.w r7, r3, r7 + 800140c: f8ce 7020 str.w r7, [lr, #32] + GPIOx->OSPEEDR &= ~(GPIO_OSPEEDR_OSPEED0 << (position * 2)); + 8001410: 6887 ldr r7, [r0, #8] + 8001412: ea27 0706 bic.w r7, r7, r6 + 8001416: 6087 str r7, [r0, #8] + GPIOx->OTYPER &= ~(GPIO_OTYPER_OT0 << position) ; + 8001418: 6847 ldr r7, [r0, #4] + 800141a: ea27 0708 bic.w r7, r7, r8 + 800141e: 6047 str r7, [r0, #4] + GPIOx->PUPDR &= ~(GPIO_PUPDR_PUPD0 << (position * 2)); + 8001420: 68c7 ldr r7, [r0, #12] + 8001422: ea27 0606 bic.w r6, r7, r6 + 8001426: 60c6 str r6, [r0, #12] + tmp = SYSCFG->EXTICR[position >> 2]; + 8001428: f022 0603 bic.w r6, r2, #3 + 800142c: f106 4680 add.w r6, r6, #1073741824 ; 0x40000000 + 8001430: f506 3680 add.w r6, r6, #65536 ; 0x10000 + tmp &= (((uint32_t)0x0F) << (4 * (position & 0x03))); + 8001434: f002 0703 and.w r7, r2, #3 + tmp = SYSCFG->EXTICR[position >> 2]; + 8001438: f8d6 e008 ldr.w lr, [r6, #8] + tmp &= (((uint32_t)0x0F) << (4 * (position & 0x03))); + 800143c: 00bf lsls r7, r7, #2 + 800143e: 40bd lsls r5, r7 + if(tmp == (GPIO_GET_INDEX(GPIOx) << (4 * (position & 0x03)))) + 8001440: f1b0 4f90 cmp.w r0, #1207959552 ; 0x48000000 + tmp &= (((uint32_t)0x0F) << (4 * (position & 0x03))); + 8001444: ea05 0e0e and.w lr, r5, lr + if(tmp == (GPIO_GET_INDEX(GPIOx) << (4 * (position & 0x03)))) + 8001448: d031 beq.n 80014ae + 800144a: 4b21 ldr r3, [pc, #132] ; (80014d0 ) + 800144c: 4298 cmp r0, r3 + 800144e: d030 beq.n 80014b2 + 8001450: f503 6380 add.w r3, r3, #1024 ; 0x400 + 8001454: 4298 cmp r0, r3 + 8001456: d02e beq.n 80014b6 + 8001458: f503 6380 add.w r3, r3, #1024 ; 0x400 + 800145c: 4298 cmp r0, r3 + 800145e: d02c beq.n 80014ba + 8001460: f503 6380 add.w r3, r3, #1024 ; 0x400 + 8001464: 4298 cmp r0, r3 + 8001466: d02a beq.n 80014be + 8001468: f503 6380 add.w r3, r3, #1024 ; 0x400 + 800146c: 4298 cmp r0, r3 + 800146e: d028 beq.n 80014c2 + 8001470: 4550 cmp r0, sl + 8001472: d028 beq.n 80014c6 + 8001474: 4558 cmp r0, fp + 8001476: bf0c ite eq + 8001478: 2307 moveq r3, #7 + 800147a: 2308 movne r3, #8 + 800147c: 40bb lsls r3, r7 + 800147e: 4573 cmp r3, lr + 8001480: d113 bne.n 80014aa + SYSCFG->EXTICR[position >> 2] &= ~tmp; + 8001482: 68b3 ldr r3, [r6, #8] + 8001484: ea23 0505 bic.w r5, r3, r5 + 8001488: 60b5 str r5, [r6, #8] + EXTI->IMR1 &= ~((uint32_t)iocurrent); + 800148a: 6823 ldr r3, [r4, #0] + 800148c: ea23 030c bic.w r3, r3, ip + 8001490: 6023 str r3, [r4, #0] + EXTI->EMR1 &= ~((uint32_t)iocurrent); + 8001492: 6863 ldr r3, [r4, #4] + 8001494: ea23 030c bic.w r3, r3, ip + 8001498: 6063 str r3, [r4, #4] + EXTI->RTSR1 &= ~((uint32_t)iocurrent); + 800149a: 68a3 ldr r3, [r4, #8] + 800149c: ea23 030c bic.w r3, r3, ip + 80014a0: 60a3 str r3, [r4, #8] + EXTI->FTSR1 &= ~((uint32_t)iocurrent); + 80014a2: 68e3 ldr r3, [r4, #12] + 80014a4: ea23 030c bic.w r3, r3, ip + 80014a8: 60e3 str r3, [r4, #12] + position++; + 80014aa: 3201 adds r2, #1 + 80014ac: e78e b.n 80013cc + if(tmp == (GPIO_GET_INDEX(GPIOx) << (4 * (position & 0x03)))) + 80014ae: 2300 movs r3, #0 + 80014b0: e7e4 b.n 800147c + 80014b2: 2301 movs r3, #1 + 80014b4: e7e2 b.n 800147c + 80014b6: 2302 movs r3, #2 + 80014b8: e7e0 b.n 800147c + 80014ba: 2303 movs r3, #3 + 80014bc: e7de b.n 800147c + 80014be: 2304 movs r3, #4 + 80014c0: e7dc b.n 800147c + 80014c2: 2305 movs r3, #5 + 80014c4: e7da b.n 800147c + 80014c6: 2306 movs r3, #6 + 80014c8: e7d8 b.n 800147c + 80014ca: bf00 nop + 80014cc: 40010400 .word 0x40010400 + 80014d0: 48000400 .word 0x48000400 + 80014d4: 48001800 .word 0x48001800 + 80014d8: 48001c00 .word 0x48001c00 + +080014dc : + GPIO_PinState bitstatus; + + /* Check the parameters */ + assert_param(IS_GPIO_PIN(GPIO_Pin)); + + if((GPIOx->IDR & GPIO_Pin) != (uint32_t)GPIO_PIN_RESET) + 80014dc: 6903 ldr r3, [r0, #16] + 80014de: 4219 tst r1, r3 + else + { + bitstatus = GPIO_PIN_RESET; + } + return bitstatus; +} + 80014e0: bf14 ite ne + 80014e2: 2001 movne r0, #1 + 80014e4: 2000 moveq r0, #0 + 80014e6: 4770 bx lr + +080014e8 : +{ + /* Check the parameters */ + assert_param(IS_GPIO_PIN(GPIO_Pin)); + assert_param(IS_GPIO_PIN_ACTION(PinState)); + + if(PinState != GPIO_PIN_RESET) + 80014e8: b10a cbz r2, 80014ee + { + GPIOx->BSRR = (uint32_t)GPIO_Pin; + 80014ea: 6181 str r1, [r0, #24] + 80014ec: 4770 bx lr + } + else + { + GPIOx->BRR = (uint32_t)GPIO_Pin; + 80014ee: 6281 str r1, [r0, #40] ; 0x28 + } +} + 80014f0: 4770 bx lr + +080014f2 : +void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) +{ + /* Check the parameters */ + assert_param(IS_GPIO_PIN(GPIO_Pin)); + + GPIOx->ODR ^= GPIO_Pin; + 80014f2: 6943 ldr r3, [r0, #20] + 80014f4: 4059 eors r1, r3 + 80014f6: 6141 str r1, [r0, #20] +} + 80014f8: 4770 bx lr + +080014fa : + * @param GPIO_Pin: specifies the port bits to be locked. + * This parameter can be any combination of GPIO_Pin_x where x can be (0..15). + * @retval None + */ +HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) +{ + 80014fa: b082 sub sp, #8 + __IO uint32_t tmp = GPIO_LCKR_LCKK; + 80014fc: f44f 3380 mov.w r3, #65536 ; 0x10000 + 8001500: 9301 str r3, [sp, #4] + /* Check the parameters */ + assert_param(IS_GPIO_LOCK_INSTANCE(GPIOx)); + assert_param(IS_GPIO_PIN(GPIO_Pin)); + + /* Apply lock key write sequence */ + tmp |= GPIO_Pin; + 8001502: 9b01 ldr r3, [sp, #4] + 8001504: 430b orrs r3, r1 + 8001506: 9301 str r3, [sp, #4] + /* Set LCKx bit(s): LCKK='1' + LCK[15-0] */ + GPIOx->LCKR = tmp; + 8001508: 9b01 ldr r3, [sp, #4] + 800150a: 61c3 str r3, [r0, #28] + /* Reset LCKx bit(s): LCKK='0' + LCK[15-0] */ + GPIOx->LCKR = GPIO_Pin; + 800150c: 61c1 str r1, [r0, #28] + /* Set LCKx bit(s): LCKK='1' + LCK[15-0] */ + GPIOx->LCKR = tmp; + 800150e: 9b01 ldr r3, [sp, #4] + 8001510: 61c3 str r3, [r0, #28] + /* Read LCKK bit*/ + tmp = GPIOx->LCKR; + 8001512: 69c3 ldr r3, [r0, #28] + 8001514: 9301 str r3, [sp, #4] + + if((GPIOx->LCKR & GPIO_LCKR_LCKK) != RESET) + 8001516: 69c0 ldr r0, [r0, #28] + 8001518: f480 3080 eor.w r0, r0, #65536 ; 0x10000 + } + else + { + return HAL_ERROR; + } +} + 800151c: f3c0 4000 ubfx r0, r0, #16, #1 + 8001520: b002 add sp, #8 + 8001522: 4770 bx lr + +08001524 : + UNUSED(GPIO_Pin); + + /* NOTE: This function should not be modified, when the callback is needed, + the HAL_GPIO_EXTI_Callback could be implemented in the user file + */ +} + 8001524: 4770 bx lr + ... + +08001528 : + if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET) + 8001528: 4a04 ldr r2, [pc, #16] ; (800153c ) + 800152a: 6951 ldr r1, [r2, #20] + 800152c: 4201 tst r1, r0 +{ + 800152e: b508 push {r3, lr} + if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET) + 8001530: d002 beq.n 8001538 + __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin); + 8001532: 6150 str r0, [r2, #20] + HAL_GPIO_EXTI_Callback(GPIO_Pin); + 8001534: f7ff fff6 bl 8001524 +} + 8001538: bd08 pop {r3, pc} + 800153a: bf00 nop + 800153c: 40010400 .word 0x40010400 + +08001540 : +static HAL_StatusTypeDef SPI_WaitFifoStateUntilTimeout(SPI_HandleTypeDef *hspi, uint32_t Fifo, uint32_t State, + uint32_t Timeout, uint32_t Tickstart) +{ + __IO uint8_t tmpreg; + + while ((hspi->Instance->SR & Fifo) != State) + 8001540: 6803 ldr r3, [r0, #0] +static HAL_StatusTypeDef SPI_EndRxTxTransaction(SPI_HandleTypeDef *hspi, uint32_t Timeout, uint32_t Tickstart) + 8001542: b082 sub sp, #8 + while ((hspi->Instance->SR & Fifo) != State) + 8001544: 689a ldr r2, [r3, #8] + 8001546: f412 5fc0 tst.w r2, #6144 ; 0x1800 + 800154a: d1fb bne.n 8001544 + * @retval HAL status + */ +static HAL_StatusTypeDef SPI_WaitFlagStateUntilTimeout(SPI_HandleTypeDef *hspi, uint32_t Flag, uint32_t State, + uint32_t Timeout, uint32_t Tickstart) +{ + while ((__HAL_SPI_GET_FLAG(hspi, Flag) ? SET : RESET) != State) + 800154c: 689a ldr r2, [r3, #8] + 800154e: 0612 lsls r2, r2, #24 + 8001550: d4fc bmi.n 800154c + while ((hspi->Instance->SR & Fifo) != State) + 8001552: 6898 ldr r0, [r3, #8] + 8001554: f410 60c0 ands.w r0, r0, #1536 ; 0x600 + 8001558: d101 bne.n 800155e +} + 800155a: b002 add sp, #8 + 800155c: 4770 bx lr + tmpreg = *((__IO uint8_t *)&hspi->Instance->DR); + 800155e: 7b1a ldrb r2, [r3, #12] + 8001560: b2d2 uxtb r2, r2 + 8001562: f88d 2007 strb.w r2, [sp, #7] + UNUSED(tmpreg); + 8001566: f89d 2007 ldrb.w r2, [sp, #7] + 800156a: e7f2 b.n 8001552 + +0800156c : +{ + 800156c: b5f0 push {r4, r5, r6, r7, lr} + if (hspi == NULL) + 800156e: 2800 cmp r0, #0 + 8001570: d054 beq.n 800161c + if (hspi->State == HAL_SPI_STATE_RESET) + 8001572: f890 305d ldrb.w r3, [r0, #93] ; 0x5d + if (hspi->Init.TIMode == SPI_TIMODE_DISABLE) + 8001576: f8d0 c024 ldr.w ip, [r0, #36] ; 0x24 + if (hspi->State == HAL_SPI_STATE_RESET) + 800157a: f003 02ff and.w r2, r3, #255 ; 0xff + 800157e: b90b cbnz r3, 8001584 + hspi->Lock = HAL_UNLOCKED; + 8001580: f880 205c strb.w r2, [r0, #92] ; 0x5c + __HAL_SPI_DISABLE(hspi); + 8001584: 6801 ldr r1, [r0, #0] + if (hspi->Init.DataSize > SPI_DATASIZE_8BIT) + 8001586: 68c2 ldr r2, [r0, #12] + hspi->State = HAL_SPI_STATE_BUSY; + 8001588: 2302 movs r3, #2 + 800158a: f880 305d strb.w r3, [r0, #93] ; 0x5d + __HAL_SPI_DISABLE(hspi); + 800158e: 680b ldr r3, [r1, #0] + if (hspi->Init.DataSize > SPI_DATASIZE_8BIT) + 8001590: f5b2 6fe0 cmp.w r2, #1792 ; 0x700 + __HAL_SPI_DISABLE(hspi); + 8001594: f023 0340 bic.w r3, r3, #64 ; 0x40 + 8001598: 600b str r3, [r1, #0] + if (hspi->Init.DataSize > SPI_DATASIZE_8BIT) + 800159a: f04f 0300 mov.w r3, #0 + 800159e: d83f bhi.n 8001620 + frxth = SPI_RXFIFO_THRESHOLD_QF; + 80015a0: f44f 5580 mov.w r5, #4096 ; 0x1000 + if ((hspi->Init.DataSize != SPI_DATASIZE_16BIT) && (hspi->Init.DataSize != SPI_DATASIZE_8BIT)) + 80015a4: d000 beq.n 80015a8 + hspi->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; + 80015a6: 6283 str r3, [r0, #40] ; 0x28 + if (hspi->Init.CRCLength == SPI_CRC_LENGTH_DATASIZE) + 80015a8: 6b03 ldr r3, [r0, #48] ; 0x30 + 80015aa: b92b cbnz r3, 80015b8 + if (hspi->Init.DataSize > SPI_DATASIZE_8BIT) + 80015ac: f5b2 6fe0 cmp.w r2, #1792 ; 0x700 + hspi->Init.CRCLength = SPI_CRC_LENGTH_16BIT; + 80015b0: bf8c ite hi + 80015b2: 2302 movhi r3, #2 + hspi->Init.CRCLength = SPI_CRC_LENGTH_8BIT; + 80015b4: 2301 movls r3, #1 + 80015b6: 6303 str r3, [r0, #48] ; 0x30 + WRITE_REG(hspi->Instance->CR1, (hspi->Init.Mode | hspi->Init.Direction | + 80015b8: e9d0 3701 ldrd r3, r7, [r0, #4] + 80015bc: 433b orrs r3, r7 + 80015be: 6907 ldr r7, [r0, #16] + 80015c0: 6984 ldr r4, [r0, #24] + 80015c2: 6a86 ldr r6, [r0, #40] ; 0x28 + 80015c4: 433b orrs r3, r7 + 80015c6: 6947 ldr r7, [r0, #20] + 80015c8: 433b orrs r3, r7 + 80015ca: 69c7 ldr r7, [r0, #28] + 80015cc: 433b orrs r3, r7 + 80015ce: 6a07 ldr r7, [r0, #32] + 80015d0: 433b orrs r3, r7 + 80015d2: 4333 orrs r3, r6 + 80015d4: f404 7700 and.w r7, r4, #512 ; 0x200 + 80015d8: 433b orrs r3, r7 + 80015da: 600b str r3, [r1, #0] + if (hspi->Init.CRCLength == SPI_CRC_LENGTH_16BIT) + 80015dc: 6b03 ldr r3, [r0, #48] ; 0x30 + 80015de: 2b02 cmp r3, #2 + hspi->Instance->CR1 |= SPI_CR1_CRCL; + 80015e0: bf02 ittt eq + 80015e2: 680b ldreq r3, [r1, #0] + 80015e4: f443 6300 orreq.w r3, r3, #2048 ; 0x800 + 80015e8: 600b streq r3, [r1, #0] + WRITE_REG(hspi->Instance->CR2, (((hspi->Init.NSS >> 16U) & SPI_CR2_SSOE) | hspi->Init.TIMode | + 80015ea: 6b43 ldr r3, [r0, #52] ; 0x34 + 80015ec: ea4c 0202 orr.w r2, ip, r2 + 80015f0: 0c24 lsrs r4, r4, #16 + 80015f2: 431a orrs r2, r3 + 80015f4: f004 0404 and.w r4, r4, #4 + 80015f8: 4322 orrs r2, r4 + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 80015fa: f5b6 5f00 cmp.w r6, #8192 ; 0x2000 + WRITE_REG(hspi->Instance->CRCPR, hspi->Init.CRCPolynomial); + 80015fe: bf08 it eq + 8001600: 6ac3 ldreq r3, [r0, #44] ; 0x2c + WRITE_REG(hspi->Instance->CR2, (((hspi->Init.NSS >> 16U) & SPI_CR2_SSOE) | hspi->Init.TIMode | + 8001602: ea45 0502 orr.w r5, r5, r2 + 8001606: 604d str r5, [r1, #4] + hspi->State = HAL_SPI_STATE_READY; + 8001608: f04f 0201 mov.w r2, #1 + WRITE_REG(hspi->Instance->CRCPR, hspi->Init.CRCPolynomial); + 800160c: bf08 it eq + 800160e: 610b streq r3, [r1, #16] + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + 8001610: 2300 movs r3, #0 + 8001612: 6603 str r3, [r0, #96] ; 0x60 + hspi->State = HAL_SPI_STATE_READY; + 8001614: f880 205d strb.w r2, [r0, #93] ; 0x5d + return HAL_OK; + 8001618: 4618 mov r0, r3 +} + 800161a: bdf0 pop {r4, r5, r6, r7, pc} + return HAL_ERROR; + 800161c: 2001 movs r0, #1 + 800161e: e7fc b.n 800161a + frxth = SPI_RXFIFO_THRESHOLD_HF; + 8001620: 461d mov r5, r3 + if ((hspi->Init.DataSize != SPI_DATASIZE_16BIT) && (hspi->Init.DataSize != SPI_DATASIZE_8BIT)) + 8001622: f5b2 6f70 cmp.w r2, #3840 ; 0xf00 + 8001626: e7bd b.n 80015a4 + +08001628 : +{ + 8001628: e92d 41f3 stmdb sp!, {r0, r1, r4, r5, r6, r7, r8, lr} + 800162c: 461e mov r6, r3 + __HAL_LOCK(hspi); + 800162e: f890 305c ldrb.w r3, [r0, #92] ; 0x5c + 8001632: 2b01 cmp r3, #1 +{ + 8001634: 4604 mov r4, r0 + 8001636: 460d mov r5, r1 + 8001638: 4690 mov r8, r2 + __HAL_LOCK(hspi); + 800163a: f000 809c beq.w 8001776 + 800163e: 2301 movs r3, #1 + 8001640: f880 305c strb.w r3, [r0, #92] ; 0x5c + tickstart = HAL_GetTick(); + 8001644: f005 feca bl 80073dc + if (hspi->State != HAL_SPI_STATE_READY) + 8001648: f894 305d ldrb.w r3, [r4, #93] ; 0x5d + 800164c: 2b01 cmp r3, #1 + tickstart = HAL_GetTick(); + 800164e: 4607 mov r7, r0 + if (hspi->State != HAL_SPI_STATE_READY) + 8001650: b2d8 uxtb r0, r3 + 8001652: f040 808e bne.w 8001772 + if ((pData == NULL) || (Size == 0U)) + 8001656: 2d00 cmp r5, #0 + 8001658: d07a beq.n 8001750 + 800165a: f1b8 0f00 cmp.w r8, #0 + 800165e: d077 beq.n 8001750 + hspi->State = HAL_SPI_STATE_BUSY_TX; + 8001660: 2303 movs r3, #3 + 8001662: f884 305d strb.w r3, [r4, #93] ; 0x5d + if (hspi->Init.Direction == SPI_DIRECTION_1LINE) + 8001666: 68a3 ldr r3, [r4, #8] + SPI_1LINE_TX(hspi); + 8001668: 6822 ldr r2, [r4, #0] + hspi->pTxBuffPtr = (uint8_t *)pData; + 800166a: 63a5 str r5, [r4, #56] ; 0x38 + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + 800166c: 2100 movs r1, #0 + if (hspi->Init.Direction == SPI_DIRECTION_1LINE) + 800166e: f5b3 4f00 cmp.w r3, #32768 ; 0x8000 + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + 8001672: 6621 str r1, [r4, #96] ; 0x60 + hspi->TxXferCount = Size; + 8001674: f8a4 803e strh.w r8, [r4, #62] ; 0x3e + hspi->RxXferCount = 0U; + 8001678: f8a4 1046 strh.w r1, [r4, #70] ; 0x46 + SPI_1LINE_TX(hspi); + 800167c: bf08 it eq + 800167e: 6813 ldreq r3, [r2, #0] + hspi->TxXferSize = Size; + 8001680: f8a4 803c strh.w r8, [r4, #60] ; 0x3c + SPI_1LINE_TX(hspi); + 8001684: bf08 it eq + 8001686: f443 4380 orreq.w r3, r3, #16384 ; 0x4000 + hspi->RxISR = NULL; + 800168a: e9c4 1113 strd r1, r1, [r4, #76] ; 0x4c + hspi->pRxBuffPtr = (uint8_t *)NULL; + 800168e: 6421 str r1, [r4, #64] ; 0x40 + hspi->RxXferSize = 0U; + 8001690: f8a4 1044 strh.w r1, [r4, #68] ; 0x44 + SPI_1LINE_TX(hspi); + 8001694: bf08 it eq + 8001696: 6013 streq r3, [r2, #0] + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 8001698: 6aa3 ldr r3, [r4, #40] ; 0x28 + 800169a: f5b3 5f00 cmp.w r3, #8192 ; 0x2000 + 800169e: d107 bne.n 80016b0 + SPI_RESET_CRC(hspi); + 80016a0: 6813 ldr r3, [r2, #0] + 80016a2: f423 5300 bic.w r3, r3, #8192 ; 0x2000 + 80016a6: 6013 str r3, [r2, #0] + 80016a8: 6813 ldr r3, [r2, #0] + 80016aa: f443 5300 orr.w r3, r3, #8192 ; 0x2000 + 80016ae: 6013 str r3, [r2, #0] + if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE) + 80016b0: 6813 ldr r3, [r2, #0] + 80016b2: 0659 lsls r1, r3, #25 + __HAL_SPI_ENABLE(hspi); + 80016b4: bf5e ittt pl + 80016b6: 6813 ldrpl r3, [r2, #0] + 80016b8: f043 0340 orrpl.w r3, r3, #64 ; 0x40 + 80016bc: 6013 strpl r3, [r2, #0] + if ((hspi->Init.Mode == SPI_MODE_SLAVE) || (hspi->TxXferCount == 0x01U)) + 80016be: 6863 ldr r3, [r4, #4] + 80016c0: b11b cbz r3, 80016ca + 80016c2: 8fe3 ldrh r3, [r4, #62] ; 0x3e + 80016c4: b29b uxth r3, r3 + 80016c6: 2b01 cmp r3, #1 + 80016c8: d110 bne.n 80016ec + if (hspi->TxXferCount > 1U) + 80016ca: 8fe3 ldrh r3, [r4, #62] ; 0x3e + 80016cc: b29b uxth r3, r3 + 80016ce: 2b01 cmp r3, #1 + 80016d0: d905 bls.n 80016de + hspi->Instance->DR = *((uint16_t *)pData); + 80016d2: f835 3b02 ldrh.w r3, [r5], #2 + 80016d6: 60d3 str r3, [r2, #12] + hspi->TxXferCount -= 2U; + 80016d8: 8fe3 ldrh r3, [r4, #62] ; 0x3e + 80016da: 3b02 subs r3, #2 + 80016dc: e004 b.n 80016e8 + *((__IO uint8_t *)&hspi->Instance->DR) = (*pData++); + 80016de: f815 3b01 ldrb.w r3, [r5], #1 + 80016e2: 7313 strb r3, [r2, #12] + hspi->TxXferCount--; + 80016e4: 8fe3 ldrh r3, [r4, #62] ; 0x3e + 80016e6: 3b01 subs r3, #1 + 80016e8: b29b uxth r3, r3 + 80016ea: 87e3 strh r3, [r4, #62] ; 0x3e + while (hspi->TxXferCount > 0U) + 80016ec: 8fe3 ldrh r3, [r4, #62] ; 0x3e + 80016ee: b29b uxth r3, r3 + 80016f0: b9e3 cbnz r3, 800172c + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 80016f2: 6aa3 ldr r3, [r4, #40] ; 0x28 + 80016f4: f5b3 5f00 cmp.w r3, #8192 ; 0x2000 + SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT); + 80016f8: bf01 itttt eq + 80016fa: 6822 ldreq r2, [r4, #0] + 80016fc: 6813 ldreq r3, [r2, #0] + 80016fe: f443 5380 orreq.w r3, r3, #4096 ; 0x1000 + 8001702: 6013 streq r3, [r2, #0] + if (SPI_EndRxTxTransaction(hspi, Timeout, tickstart) != HAL_OK) + 8001704: 4620 mov r0, r4 + 8001706: f7ff ff1b bl 8001540 + 800170a: b108 cbz r0, 8001710 + hspi->ErrorCode = HAL_SPI_ERROR_FLAG; + 800170c: 2320 movs r3, #32 + 800170e: 6623 str r3, [r4, #96] ; 0x60 + if (hspi->Init.Direction == SPI_DIRECTION_2LINES) + 8001710: 68a3 ldr r3, [r4, #8] + 8001712: b933 cbnz r3, 8001722 + __HAL_SPI_CLEAR_OVRFLAG(hspi); + 8001714: 9301 str r3, [sp, #4] + 8001716: 6823 ldr r3, [r4, #0] + 8001718: 68da ldr r2, [r3, #12] + 800171a: 9201 str r2, [sp, #4] + 800171c: 689b ldr r3, [r3, #8] + 800171e: 9301 str r3, [sp, #4] + 8001720: 9b01 ldr r3, [sp, #4] + if (hspi->ErrorCode != HAL_SPI_ERROR_NONE) + 8001722: 6e20 ldr r0, [r4, #96] ; 0x60 + errorcode = HAL_BUSY; + 8001724: 3800 subs r0, #0 + 8001726: bf18 it ne + 8001728: 2001 movne r0, #1 +error: + 800172a: e011 b.n 8001750 + if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE)) + 800172c: 6823 ldr r3, [r4, #0] + 800172e: 689a ldr r2, [r3, #8] + 8001730: 0792 lsls r2, r2, #30 + 8001732: d50b bpl.n 800174c + if (hspi->TxXferCount > 1U) + 8001734: 8fe2 ldrh r2, [r4, #62] ; 0x3e + 8001736: b292 uxth r2, r2 + 8001738: 2a01 cmp r2, #1 + 800173a: d903 bls.n 8001744 + hspi->Instance->DR = *((uint16_t *)pData); + 800173c: f835 2b02 ldrh.w r2, [r5], #2 + 8001740: 60da str r2, [r3, #12] + 8001742: e7c9 b.n 80016d8 + *((__IO uint8_t *)&hspi->Instance->DR) = (*pData++); + 8001744: f815 2b01 ldrb.w r2, [r5], #1 + 8001748: 731a strb r2, [r3, #12] + hspi->TxXferCount--; + 800174a: e7cb b.n 80016e4 + if ((Timeout == 0U) || ((Timeout != HAL_MAX_DELAY) && ((HAL_GetTick() - tickstart) >= Timeout))) + 800174c: b94e cbnz r6, 8001762 + errorcode = HAL_TIMEOUT; + 800174e: 2003 movs r0, #3 + hspi->State = HAL_SPI_STATE_READY; + 8001750: 2301 movs r3, #1 + 8001752: f884 305d strb.w r3, [r4, #93] ; 0x5d + __HAL_UNLOCK(hspi); + 8001756: 2300 movs r3, #0 + 8001758: f884 305c strb.w r3, [r4, #92] ; 0x5c +} + 800175c: b002 add sp, #8 + 800175e: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + if ((Timeout == 0U) || ((Timeout != HAL_MAX_DELAY) && ((HAL_GetTick() - tickstart) >= Timeout))) + 8001762: 1c73 adds r3, r6, #1 + 8001764: d0c2 beq.n 80016ec + 8001766: f005 fe39 bl 80073dc + 800176a: 1bc0 subs r0, r0, r7 + 800176c: 42b0 cmp r0, r6 + 800176e: d3bd bcc.n 80016ec + 8001770: e7ed b.n 800174e + errorcode = HAL_BUSY; + 8001772: 2002 movs r0, #2 + 8001774: e7ec b.n 8001750 + __HAL_LOCK(hspi); + 8001776: 2002 movs r0, #2 + 8001778: e7f0 b.n 800175c + +0800177a : + * @param Timeout: Timeout duration + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, + uint32_t Timeout) +{ + 800177a: e92d 43f7 stmdb sp!, {r0, r1, r2, r4, r5, r6, r7, r8, r9, lr} + 800177e: 461e mov r6, r3 + uint32_t tmp = 0U, tmp1 = 0U; +#if (USE_SPI_CRC != 0U) + __IO uint16_t tmpreg = 0U; + 8001780: 2300 movs r3, #0 + 8001782: f8ad 3006 strh.w r3, [sp, #6] + + /* Check Direction parameter */ + assert_param(IS_SPI_DIRECTION_2LINES(hspi->Init.Direction)); + + /* Process Locked */ + __HAL_LOCK(hspi); + 8001786: f890 305c ldrb.w r3, [r0, #92] ; 0x5c +{ + 800178a: f8dd 8028 ldr.w r8, [sp, #40] ; 0x28 + __HAL_LOCK(hspi); + 800178e: 2b01 cmp r3, #1 +{ + 8001790: 4604 mov r4, r0 + 8001792: 460d mov r5, r1 + 8001794: 4617 mov r7, r2 + __HAL_LOCK(hspi); + 8001796: f000 8124 beq.w 80019e2 + 800179a: 2301 movs r3, #1 + 800179c: f880 305c strb.w r3, [r0, #92] ; 0x5c + + /* Init tickstart for timeout management*/ + tickstart = HAL_GetTick(); + 80017a0: f005 fe1c bl 80073dc + + tmp = hspi->State; + 80017a4: f894 305d ldrb.w r3, [r4, #93] ; 0x5d + tmp1 = hspi->Init.Mode; + 80017a8: 6861 ldr r1, [r4, #4] + + if (!((tmp == HAL_SPI_STATE_READY) || \ + 80017aa: 2b01 cmp r3, #1 + tickstart = HAL_GetTick(); + 80017ac: 4681 mov r9, r0 + tmp = hspi->State; + 80017ae: b2da uxtb r2, r3 + if (!((tmp == HAL_SPI_STATE_READY) || \ + 80017b0: d00a beq.n 80017c8 + 80017b2: f5b1 7f82 cmp.w r1, #260 ; 0x104 + 80017b6: f040 8112 bne.w 80019de + ((tmp1 == SPI_MODE_MASTER) && (hspi->Init.Direction == SPI_DIRECTION_2LINES) && (tmp == HAL_SPI_STATE_BUSY_RX)))) + 80017ba: 68a3 ldr r3, [r4, #8] + 80017bc: 2b00 cmp r3, #0 + 80017be: f040 810e bne.w 80019de + 80017c2: 2a04 cmp r2, #4 + 80017c4: f040 810b bne.w 80019de + { + errorcode = HAL_BUSY; + goto error; + } + + if ((pTxData == NULL) || (pRxData == NULL) || (Size == 0U)) + 80017c8: b955 cbnz r5, 80017e0 + { + errorcode = HAL_ERROR; + 80017ca: 2101 movs r1, #1 + { + errorcode = HAL_ERROR; + } + +error : + hspi->State = HAL_SPI_STATE_READY; + 80017cc: 2301 movs r3, #1 + 80017ce: f884 305d strb.w r3, [r4, #93] ; 0x5d + __HAL_UNLOCK(hspi); + 80017d2: 2300 movs r3, #0 + 80017d4: f884 305c strb.w r3, [r4, #92] ; 0x5c + return errorcode; +} + 80017d8: 4608 mov r0, r1 + 80017da: b003 add sp, #12 + 80017dc: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + if ((pTxData == NULL) || (pRxData == NULL) || (Size == 0U)) + 80017e0: 2f00 cmp r7, #0 + 80017e2: d0f2 beq.n 80017ca + 80017e4: 2e00 cmp r6, #0 + 80017e6: d0f0 beq.n 80017ca + if (hspi->State != HAL_SPI_STATE_BUSY_RX) + 80017e8: f894 305d ldrb.w r3, [r4, #93] ; 0x5d + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 80017ec: 6aa2 ldr r2, [r4, #40] ; 0x28 + hspi->pRxBuffPtr = (uint8_t *)pRxData; + 80017ee: 6427 str r7, [r4, #64] ; 0x40 + if (hspi->State != HAL_SPI_STATE_BUSY_RX) + 80017f0: 2b04 cmp r3, #4 + hspi->State = HAL_SPI_STATE_BUSY_TX_RX; + 80017f2: bf1c itt ne + 80017f4: 2305 movne r3, #5 + 80017f6: f884 305d strbne.w r3, [r4, #93] ; 0x5d + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + 80017fa: 2300 movs r3, #0 + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 80017fc: f5b2 5f00 cmp.w r2, #8192 ; 0x2000 + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + 8001800: 6623 str r3, [r4, #96] ; 0x60 + hspi->TxISR = NULL; + 8001802: e9c4 3313 strd r3, r3, [r4, #76] ; 0x4c + hspi->RxXferCount = Size; + 8001806: f8a4 6046 strh.w r6, [r4, #70] ; 0x46 + SPI_RESET_CRC(hspi); + 800180a: 6823 ldr r3, [r4, #0] + hspi->RxXferSize = Size; + 800180c: f8a4 6044 strh.w r6, [r4, #68] ; 0x44 + hspi->pTxBuffPtr = (uint8_t *)pTxData; + 8001810: 63a5 str r5, [r4, #56] ; 0x38 + hspi->TxXferCount = Size; + 8001812: 87e6 strh r6, [r4, #62] ; 0x3e + hspi->TxXferSize = Size; + 8001814: 87a6 strh r6, [r4, #60] ; 0x3c + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 8001816: d107 bne.n 8001828 + SPI_RESET_CRC(hspi); + 8001818: 681a ldr r2, [r3, #0] + 800181a: f422 5200 bic.w r2, r2, #8192 ; 0x2000 + 800181e: 601a str r2, [r3, #0] + 8001820: 681a ldr r2, [r3, #0] + 8001822: f442 5200 orr.w r2, r2, #8192 ; 0x2000 + 8001826: 601a str r2, [r3, #0] + if ((hspi->Init.DataSize > SPI_DATASIZE_8BIT) || (hspi->RxXferCount > 1U)) + 8001828: 68e2 ldr r2, [r4, #12] + 800182a: f5b2 6fe0 cmp.w r2, #1792 ; 0x700 + 800182e: d804 bhi.n 800183a + 8001830: f8b4 2046 ldrh.w r2, [r4, #70] ; 0x46 + 8001834: b292 uxth r2, r2 + 8001836: 2a01 cmp r2, #1 + 8001838: d94e bls.n 80018d8 + CLEAR_BIT(hspi->Instance->CR2, SPI_RXFIFO_THRESHOLD); + 800183a: 685a ldr r2, [r3, #4] + 800183c: f422 5280 bic.w r2, r2, #4096 ; 0x1000 + SET_BIT(hspi->Instance->CR2, SPI_RXFIFO_THRESHOLD); + 8001840: 605a str r2, [r3, #4] + if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE) + 8001842: 681a ldr r2, [r3, #0] + 8001844: 0650 lsls r0, r2, #25 + __HAL_SPI_ENABLE(hspi); + 8001846: bf5e ittt pl + 8001848: 681a ldrpl r2, [r3, #0] + 800184a: f042 0240 orrpl.w r2, r2, #64 ; 0x40 + 800184e: 601a strpl r2, [r3, #0] + if ((hspi->Init.Mode == SPI_MODE_SLAVE) || (hspi->TxXferCount == 0x01U)) + 8001850: b119 cbz r1, 800185a + 8001852: 8fe2 ldrh r2, [r4, #62] ; 0x3e + 8001854: b292 uxth r2, r2 + 8001856: 2a01 cmp r2, #1 + 8001858: d10a bne.n 8001870 + if (hspi->TxXferCount > 1U) + 800185a: 8fe2 ldrh r2, [r4, #62] ; 0x3e + 800185c: b292 uxth r2, r2 + 800185e: 2a01 cmp r2, #1 + 8001860: d93e bls.n 80018e0 + hspi->Instance->DR = *((uint16_t *)pTxData); + 8001862: f835 2b02 ldrh.w r2, [r5], #2 + 8001866: 60da str r2, [r3, #12] + hspi->TxXferCount -= 2U; + 8001868: 8fe3 ldrh r3, [r4, #62] ; 0x3e + 800186a: 3b02 subs r3, #2 + 800186c: b29b uxth r3, r3 + 800186e: 87e3 strh r3, [r4, #62] ; 0x3e + txallowed = 1U; + 8001870: 2601 movs r6, #1 + while ((hspi->TxXferCount > 0U) || (hspi->RxXferCount > 0U)) + 8001872: 8fe3 ldrh r3, [r4, #62] ; 0x3e + 8001874: b29b uxth r3, r3 + 8001876: 2b00 cmp r3, #0 + 8001878: d138 bne.n 80018ec + 800187a: f8b4 3046 ldrh.w r3, [r4, #70] ; 0x46 + 800187e: b29b uxth r3, r3 + 8001880: 2b00 cmp r3, #0 + 8001882: d133 bne.n 80018ec + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 8001884: 6aa2 ldr r2, [r4, #40] ; 0x28 + if (txallowed && (hspi->TxXferCount > 0U) && (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE))) + 8001886: 6823 ldr r3, [r4, #0] + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 8001888: f5b2 5f00 cmp.w r2, #8192 ; 0x2000 + 800188c: d10d bne.n 80018aa + while ((__HAL_SPI_GET_FLAG(hspi, Flag) ? SET : RESET) != State) + 800188e: 689a ldr r2, [r3, #8] + 8001890: 07d1 lsls r1, r2, #31 + 8001892: d5fc bpl.n 800188e + if (hspi->Init.DataSize == SPI_DATASIZE_16BIT) + 8001894: 68e2 ldr r2, [r4, #12] + 8001896: f5b2 6f70 cmp.w r2, #3840 ; 0xf00 + 800189a: f040 8092 bne.w 80019c2 + tmpreg = hspi->Instance->DR; + 800189e: 68da ldr r2, [r3, #12] + 80018a0: b292 uxth r2, r2 + tmpreg = *(__IO uint8_t *)&hspi->Instance->DR; + 80018a2: f8ad 2006 strh.w r2, [sp, #6] + UNUSED(tmpreg); + 80018a6: f8bd 2006 ldrh.w r2, [sp, #6] + if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_CRCERR)) + 80018aa: 6899 ldr r1, [r3, #8] + 80018ac: f011 0110 ands.w r1, r1, #16 + 80018b0: d007 beq.n 80018c2 + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC); + 80018b2: 6e22 ldr r2, [r4, #96] ; 0x60 + 80018b4: f042 0202 orr.w r2, r2, #2 + 80018b8: 6622 str r2, [r4, #96] ; 0x60 + __HAL_SPI_CLEAR_CRCERRFLAG(hspi); + 80018ba: f64f 72ef movw r2, #65519 ; 0xffef + 80018be: 609a str r2, [r3, #8] + errorcode = HAL_ERROR; + 80018c0: 2101 movs r1, #1 + if (SPI_EndRxTxTransaction(hspi, Timeout, tickstart) != HAL_OK) + 80018c2: 4620 mov r0, r4 + 80018c4: f7ff fe3c bl 8001540 + 80018c8: b108 cbz r0, 80018ce + hspi->ErrorCode = HAL_SPI_ERROR_FLAG; + 80018ca: 2320 movs r3, #32 + 80018cc: 6623 str r3, [r4, #96] ; 0x60 + if (hspi->ErrorCode != HAL_SPI_ERROR_NONE) + 80018ce: 6e23 ldr r3, [r4, #96] ; 0x60 + 80018d0: 2b00 cmp r3, #0 + 80018d2: f47f af7a bne.w 80017ca + 80018d6: e779 b.n 80017cc + SET_BIT(hspi->Instance->CR2, SPI_RXFIFO_THRESHOLD); + 80018d8: 685a ldr r2, [r3, #4] + 80018da: f442 5280 orr.w r2, r2, #4096 ; 0x1000 + 80018de: e7af b.n 8001840 + *(__IO uint8_t *)&hspi->Instance->DR = (*pTxData++); + 80018e0: f815 2b01 ldrb.w r2, [r5], #1 + 80018e4: 731a strb r2, [r3, #12] + hspi->TxXferCount--; + 80018e6: 8fe3 ldrh r3, [r4, #62] ; 0x3e + 80018e8: 3b01 subs r3, #1 + 80018ea: e7bf b.n 800186c + if (txallowed && (hspi->TxXferCount > 0U) && (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE))) + 80018ec: 2e00 cmp r6, #0 + 80018ee: d030 beq.n 8001952 + 80018f0: 8fe3 ldrh r3, [r4, #62] ; 0x3e + 80018f2: b29b uxth r3, r3 + 80018f4: 2b00 cmp r3, #0 + 80018f6: d02c beq.n 8001952 + 80018f8: 6823 ldr r3, [r4, #0] + 80018fa: 689a ldr r2, [r3, #8] + 80018fc: 0792 lsls r2, r2, #30 + 80018fe: d528 bpl.n 8001952 + if (hspi->TxXferCount > 1U) + 8001900: 8fe2 ldrh r2, [r4, #62] ; 0x3e + 8001902: b292 uxth r2, r2 + 8001904: 2a01 cmp r2, #1 + hspi->Instance->DR = *((uint16_t *)pTxData); + 8001906: bf8b itete hi + 8001908: f835 2b02 ldrhhi.w r2, [r5], #2 + *(__IO uint8_t *)&hspi->Instance->DR = (*pTxData++); + 800190c: f815 2b01 ldrbls.w r2, [r5], #1 + hspi->Instance->DR = *((uint16_t *)pTxData); + 8001910: 60da strhi r2, [r3, #12] + *(__IO uint8_t *)&hspi->Instance->DR = (*pTxData++); + 8001912: 731a strbls r2, [r3, #12] + hspi->TxXferCount -= 2U; + 8001914: bf8b itete hi + 8001916: 8fe3 ldrhhi r3, [r4, #62] ; 0x3e + hspi->TxXferCount--; + 8001918: 8fe3 ldrhls r3, [r4, #62] ; 0x3e + hspi->TxXferCount -= 2U; + 800191a: 3b02 subhi r3, #2 + hspi->TxXferCount--; + 800191c: f103 33ff addls.w r3, r3, #4294967295 ; 0xffffffff + 8001920: b29b uxth r3, r3 + 8001922: 87e3 strh r3, [r4, #62] ; 0x3e + if ((hspi->TxXferCount == 0U) && (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)) + 8001924: 8fe6 ldrh r6, [r4, #62] ; 0x3e + 8001926: b2b6 uxth r6, r6 + 8001928: b996 cbnz r6, 8001950 + 800192a: 6aa3 ldr r3, [r4, #40] ; 0x28 + 800192c: f5b3 5f00 cmp.w r3, #8192 ; 0x2000 + 8001930: d10f bne.n 8001952 + if (((hspi->Instance->CR1 & SPI_CR1_MSTR) == 0U) && ((hspi->Instance->CR2 & SPI_CR2_NSSP) == SPI_CR2_NSSP)) + 8001932: 6823 ldr r3, [r4, #0] + 8001934: 681a ldr r2, [r3, #0] + 8001936: 0756 lsls r6, r2, #29 + 8001938: d406 bmi.n 8001948 + 800193a: 685a ldr r2, [r3, #4] + 800193c: 0710 lsls r0, r2, #28 + SET_BIT(hspi->Instance->CR1, SPI_CR1_SSM); + 800193e: bf42 ittt mi + 8001940: 681a ldrmi r2, [r3, #0] + 8001942: f442 7200 orrmi.w r2, r2, #512 ; 0x200 + 8001946: 601a strmi r2, [r3, #0] + SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT); + 8001948: 681a ldr r2, [r3, #0] + 800194a: f442 5280 orr.w r2, r2, #4096 ; 0x1000 + 800194e: 601a str r2, [r3, #0] + txallowed = 0U; + 8001950: 2600 movs r6, #0 + if ((hspi->RxXferCount > 0U) && (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_RXNE))) + 8001952: f8b4 3046 ldrh.w r3, [r4, #70] ; 0x46 + 8001956: b29b uxth r3, r3 + 8001958: b1e3 cbz r3, 8001994 + 800195a: 6821 ldr r1, [r4, #0] + 800195c: 688b ldr r3, [r1, #8] + 800195e: f013 0301 ands.w r3, r3, #1 + 8001962: d017 beq.n 8001994 + if (hspi->RxXferCount > 1U) + 8001964: f8b4 2046 ldrh.w r2, [r4, #70] ; 0x46 + 8001968: b292 uxth r2, r2 + 800196a: 2a01 cmp r2, #1 + 800196c: d91f bls.n 80019ae + *((uint16_t *)pRxData) = hspi->Instance->DR; + 800196e: 68ca ldr r2, [r1, #12] + 8001970: f827 2b02 strh.w r2, [r7], #2 + hspi->RxXferCount -= 2U; + 8001974: f8b4 2046 ldrh.w r2, [r4, #70] ; 0x46 + 8001978: 3a02 subs r2, #2 + 800197a: b292 uxth r2, r2 + 800197c: f8a4 2046 strh.w r2, [r4, #70] ; 0x46 + if (hspi->RxXferCount <= 1U) + 8001980: f8b4 2046 ldrh.w r2, [r4, #70] ; 0x46 + 8001984: b292 uxth r2, r2 + 8001986: 2a01 cmp r2, #1 + 8001988: d803 bhi.n 8001992 + SET_BIT(hspi->Instance->CR2, SPI_RXFIFO_THRESHOLD); + 800198a: 684a ldr r2, [r1, #4] + 800198c: f442 5280 orr.w r2, r2, #4096 ; 0x1000 + 8001990: 604a str r2, [r1, #4] + txallowed = 1U; + 8001992: 461e mov r6, r3 + if ((Timeout != HAL_MAX_DELAY) && ((HAL_GetTick() - tickstart) >= Timeout)) + 8001994: f1b8 3fff cmp.w r8, #4294967295 ; 0xffffffff + 8001998: f43f af6b beq.w 8001872 + 800199c: f005 fd1e bl 80073dc + 80019a0: eba0 0009 sub.w r0, r0, r9 + 80019a4: 4540 cmp r0, r8 + 80019a6: f4ff af64 bcc.w 8001872 + errorcode = HAL_TIMEOUT; + 80019aa: 2103 movs r1, #3 + 80019ac: e70e b.n 80017cc + (*(uint8_t *)pRxData++) = *(__IO uint8_t *)&hspi->Instance->DR; + 80019ae: 7b0a ldrb r2, [r1, #12] + 80019b0: f807 2b01 strb.w r2, [r7], #1 + hspi->RxXferCount--; + 80019b4: f8b4 1046 ldrh.w r1, [r4, #70] ; 0x46 + 80019b8: 3901 subs r1, #1 + 80019ba: b289 uxth r1, r1 + 80019bc: f8a4 1046 strh.w r1, [r4, #70] ; 0x46 + 80019c0: e7e7 b.n 8001992 + tmpreg = *(__IO uint8_t *)&hspi->Instance->DR; + 80019c2: 7b1a ldrb r2, [r3, #12] + 80019c4: f8ad 2006 strh.w r2, [sp, #6] + UNUSED(tmpreg); + 80019c8: f8bd 2006 ldrh.w r2, [sp, #6] + if (hspi->Init.CRCLength == SPI_CRC_LENGTH_16BIT) + 80019cc: 6b22 ldr r2, [r4, #48] ; 0x30 + 80019ce: 2a02 cmp r2, #2 + 80019d0: f47f af6b bne.w 80018aa + while ((__HAL_SPI_GET_FLAG(hspi, Flag) ? SET : RESET) != State) + 80019d4: 689a ldr r2, [r3, #8] + 80019d6: 07d2 lsls r2, r2, #31 + 80019d8: d5fc bpl.n 80019d4 + tmpreg = *(__IO uint8_t *)&hspi->Instance->DR; + 80019da: 7b1a ldrb r2, [r3, #12] + 80019dc: e761 b.n 80018a2 + errorcode = HAL_BUSY; + 80019de: 2102 movs r1, #2 + 80019e0: e6f4 b.n 80017cc + __HAL_LOCK(hspi); + 80019e2: 2102 movs r1, #2 + 80019e4: e6f8 b.n 80017d8 + +080019e6 : +{ + 80019e6: e92d 41ff stmdb sp!, {r0, r1, r2, r3, r4, r5, r6, r7, r8, lr} + 80019ea: 461f mov r7, r3 + __IO uint16_t tmpreg = 0U; + 80019ec: 2300 movs r3, #0 + 80019ee: f8ad 300e strh.w r3, [sp, #14] + if ((hspi->Init.Mode == SPI_MODE_MASTER) && (hspi->Init.Direction == SPI_DIRECTION_2LINES)) + 80019f2: 6843 ldr r3, [r0, #4] + 80019f4: f5b3 7f82 cmp.w r3, #260 ; 0x104 +{ + 80019f8: 4604 mov r4, r0 + 80019fa: 460e mov r6, r1 + 80019fc: 4615 mov r5, r2 + if ((hspi->Init.Mode == SPI_MODE_MASTER) && (hspi->Init.Direction == SPI_DIRECTION_2LINES)) + 80019fe: d10c bne.n 8001a1a + 8001a00: 6883 ldr r3, [r0, #8] + 8001a02: b953 cbnz r3, 8001a1a + hspi->State = HAL_SPI_STATE_BUSY_RX; + 8001a04: 2304 movs r3, #4 + 8001a06: f880 305d strb.w r3, [r0, #93] ; 0x5d + return HAL_SPI_TransmitReceive(hspi, pData, pData, Size, Timeout); + 8001a0a: 4613 mov r3, r2 + 8001a0c: 9700 str r7, [sp, #0] + 8001a0e: 460a mov r2, r1 + 8001a10: f7ff feb3 bl 800177a +} + 8001a14: b004 add sp, #16 + 8001a16: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + __HAL_LOCK(hspi); + 8001a1a: f894 305c ldrb.w r3, [r4, #92] ; 0x5c + 8001a1e: 2b01 cmp r3, #1 + 8001a20: f000 80dd beq.w 8001bde + 8001a24: 2301 movs r3, #1 + 8001a26: f884 305c strb.w r3, [r4, #92] ; 0x5c + tickstart = HAL_GetTick(); + 8001a2a: f005 fcd7 bl 80073dc + if (hspi->State != HAL_SPI_STATE_READY) + 8001a2e: f894 305d ldrb.w r3, [r4, #93] ; 0x5d + 8001a32: 2b01 cmp r3, #1 + tickstart = HAL_GetTick(); + 8001a34: 4680 mov r8, r0 + if (hspi->State != HAL_SPI_STATE_READY) + 8001a36: b2d8 uxtb r0, r3 + 8001a38: f040 80cf bne.w 8001bda + if ((pData == NULL) || (Size == 0U)) + 8001a3c: 2e00 cmp r6, #0 + 8001a3e: f000 8092 beq.w 8001b66 + 8001a42: 2d00 cmp r5, #0 + 8001a44: f000 808f beq.w 8001b66 + hspi->State = HAL_SPI_STATE_BUSY_RX; + 8001a48: 2304 movs r3, #4 + 8001a4a: f884 305d strb.w r3, [r4, #93] ; 0x5d + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 8001a4e: 6aa3 ldr r3, [r4, #40] ; 0x28 + hspi->RxXferSize = Size; + 8001a50: f8a4 5044 strh.w r5, [r4, #68] ; 0x44 + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + 8001a54: 2100 movs r1, #0 + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 8001a56: f5b3 5f00 cmp.w r3, #8192 ; 0x2000 + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + 8001a5a: 6621 str r1, [r4, #96] ; 0x60 + hspi->TxISR = NULL; + 8001a5c: e9c4 1113 strd r1, r1, [r4, #76] ; 0x4c + hspi->RxXferCount = Size; + 8001a60: f8a4 5046 strh.w r5, [r4, #70] ; 0x46 + hspi->pRxBuffPtr = (uint8_t *)pData; + 8001a64: 6426 str r6, [r4, #64] ; 0x40 + SPI_RESET_CRC(hspi); + 8001a66: 6825 ldr r5, [r4, #0] + hspi->pTxBuffPtr = (uint8_t *)NULL; + 8001a68: 63a1 str r1, [r4, #56] ; 0x38 + hspi->TxXferSize = 0U; + 8001a6a: 87a1 strh r1, [r4, #60] ; 0x3c + hspi->TxXferCount = 0U; + 8001a6c: 87e1 strh r1, [r4, #62] ; 0x3e + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 8001a6e: d10d bne.n 8001a8c + SPI_RESET_CRC(hspi); + 8001a70: 682b ldr r3, [r5, #0] + 8001a72: f423 5300 bic.w r3, r3, #8192 ; 0x2000 + 8001a76: 602b str r3, [r5, #0] + 8001a78: 682b ldr r3, [r5, #0] + 8001a7a: f443 5300 orr.w r3, r3, #8192 ; 0x2000 + 8001a7e: 602b str r3, [r5, #0] + hspi->RxXferCount--; + 8001a80: f8b4 3046 ldrh.w r3, [r4, #70] ; 0x46 + 8001a84: 3b01 subs r3, #1 + 8001a86: b29b uxth r3, r3 + 8001a88: f8a4 3046 strh.w r3, [r4, #70] ; 0x46 + if (hspi->Init.DataSize > SPI_DATASIZE_8BIT) + 8001a8c: 68e3 ldr r3, [r4, #12] + 8001a8e: f5b3 6fe0 cmp.w r3, #1792 ; 0x700 + CLEAR_BIT(hspi->Instance->CR2, SPI_RXFIFO_THRESHOLD); + 8001a92: 686b ldr r3, [r5, #4] + 8001a94: bf8c ite hi + 8001a96: f423 5380 bichi.w r3, r3, #4096 ; 0x1000 + SET_BIT(hspi->Instance->CR2, SPI_RXFIFO_THRESHOLD); + 8001a9a: f443 5380 orrls.w r3, r3, #4096 ; 0x1000 + 8001a9e: 606b str r3, [r5, #4] + if (hspi->Init.Direction == SPI_DIRECTION_1LINE) + 8001aa0: 68a3 ldr r3, [r4, #8] + 8001aa2: f5b3 4f00 cmp.w r3, #32768 ; 0x8000 + SPI_1LINE_RX(hspi); + 8001aa6: bf02 ittt eq + 8001aa8: 682b ldreq r3, [r5, #0] + 8001aaa: f423 4380 biceq.w r3, r3, #16384 ; 0x4000 + 8001aae: 602b streq r3, [r5, #0] + if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE) + 8001ab0: 682b ldr r3, [r5, #0] + 8001ab2: 0658 lsls r0, r3, #25 + 8001ab4: d403 bmi.n 8001abe + __HAL_SPI_ENABLE(hspi); + 8001ab6: 682b ldr r3, [r5, #0] + 8001ab8: f043 0340 orr.w r3, r3, #64 ; 0x40 + 8001abc: 602b str r3, [r5, #0] + while (hspi->RxXferCount > 0U) + 8001abe: f8b4 3046 ldrh.w r3, [r4, #70] ; 0x46 + if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_RXNE)) + 8001ac2: 6822 ldr r2, [r4, #0] + while (hspi->RxXferCount > 0U) + 8001ac4: b29b uxth r3, r3 + 8001ac6: 2b00 cmp r3, #0 + 8001ac8: d13e bne.n 8001b48 + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + 8001aca: 6aa3 ldr r3, [r4, #40] ; 0x28 + 8001acc: f5b3 5f00 cmp.w r3, #8192 ; 0x2000 + 8001ad0: d11c bne.n 8001b0c + SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT); + 8001ad2: 6813 ldr r3, [r2, #0] + 8001ad4: f443 5380 orr.w r3, r3, #4096 ; 0x1000 + 8001ad8: 6013 str r3, [r2, #0] + while ((__HAL_SPI_GET_FLAG(hspi, Flag) ? SET : RESET) != State) + 8001ada: 6893 ldr r3, [r2, #8] + 8001adc: 07df lsls r7, r3, #31 + 8001ade: d5fc bpl.n 8001ada + if (hspi->Init.DataSize > SPI_DATASIZE_8BIT) + 8001ae0: 68e3 ldr r3, [r4, #12] + 8001ae2: f5b3 6fe0 cmp.w r3, #1792 ; 0x700 + (*(uint8_t *)pData) = *(__IO uint8_t *)&hspi->Instance->DR; + 8001ae6: bf95 itete ls + 8001ae8: 7b13 ldrbls r3, [r2, #12] + *((uint16_t *)pData) = hspi->Instance->DR; + 8001aea: 68d3 ldrhi r3, [r2, #12] + (*(uint8_t *)pData) = *(__IO uint8_t *)&hspi->Instance->DR; + 8001aec: 7033 strbls r3, [r6, #0] + *((uint16_t *)pData) = hspi->Instance->DR; + 8001aee: 8033 strhhi r3, [r6, #0] + while ((__HAL_SPI_GET_FLAG(hspi, Flag) ? SET : RESET) != State) + 8001af0: 6823 ldr r3, [r4, #0] + 8001af2: 689a ldr r2, [r3, #8] + 8001af4: 07d6 lsls r6, r2, #31 + 8001af6: d5fc bpl.n 8001af2 + if (hspi->Init.DataSize == SPI_DATASIZE_16BIT) + 8001af8: 68e1 ldr r1, [r4, #12] + 8001afa: f5b1 6f70 cmp.w r1, #3840 ; 0xf00 + 8001afe: d142 bne.n 8001b86 + tmpreg = hspi->Instance->DR; + 8001b00: 68db ldr r3, [r3, #12] + 8001b02: b29b uxth r3, r3 + tmpreg = *(__IO uint8_t *)&hspi->Instance->DR; + 8001b04: f8ad 300e strh.w r3, [sp, #14] + UNUSED(tmpreg); + 8001b08: f8bd 300e ldrh.w r3, [sp, #14] + * @param Tickstart: tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef SPI_EndRxTransaction(SPI_HandleTypeDef *hspi, uint32_t Timeout, uint32_t Tickstart) +{ + if ((hspi->Init.Mode == SPI_MODE_MASTER) && ((hspi->Init.Direction == SPI_DIRECTION_1LINE) + 8001b0c: 6861 ldr r1, [r4, #4] + 8001b0e: 6823 ldr r3, [r4, #0] + 8001b10: f5b1 7f82 cmp.w r1, #260 ; 0x104 + 8001b14: d10a bne.n 8001b2c + 8001b16: 68a2 ldr r2, [r4, #8] + 8001b18: f5b2 4f00 cmp.w r2, #32768 ; 0x8000 + 8001b1c: d002 beq.n 8001b24 + || (hspi->Init.Direction == SPI_DIRECTION_2LINES_RXONLY))) + 8001b1e: f5b2 6f80 cmp.w r2, #1024 ; 0x400 + 8001b22: d103 bne.n 8001b2c + { + /* Disable SPI peripheral */ + __HAL_SPI_DISABLE(hspi); + 8001b24: 681a ldr r2, [r3, #0] + 8001b26: f022 0240 bic.w r2, r2, #64 ; 0x40 + 8001b2a: 601a str r2, [r3, #0] + while ((__HAL_SPI_GET_FLAG(hspi, Flag) ? SET : RESET) != State) + 8001b2c: 689a ldr r2, [r3, #8] + 8001b2e: 0610 lsls r0, r2, #24 + 8001b30: d4fc bmi.n 8001b2c + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FLAG); + return HAL_TIMEOUT; + } + + if ((hspi->Init.Mode == SPI_MODE_MASTER) && ((hspi->Init.Direction == SPI_DIRECTION_1LINE) + 8001b32: f5b1 7f82 cmp.w r1, #260 ; 0x104 + 8001b36: d036 beq.n 8001ba6 + if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_CRCERR)) + 8001b38: 689a ldr r2, [r3, #8] + 8001b3a: 06d2 lsls r2, r2, #27 + 8001b3c: d445 bmi.n 8001bca + if (hspi->ErrorCode != HAL_SPI_ERROR_NONE) + 8001b3e: 6e20 ldr r0, [r4, #96] ; 0x60 + errorcode = HAL_BUSY; + 8001b40: 3800 subs r0, #0 + 8001b42: bf18 it ne + 8001b44: 2001 movne r0, #1 +error : + 8001b46: e00e b.n 8001b66 + if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_RXNE)) + 8001b48: 6893 ldr r3, [r2, #8] + 8001b4a: 07d9 lsls r1, r3, #31 + 8001b4c: d509 bpl.n 8001b62 + (* (uint8_t *)pData) = *(__IO uint8_t *)&hspi->Instance->DR; + 8001b4e: 7b13 ldrb r3, [r2, #12] + 8001b50: f806 3b01 strb.w r3, [r6], #1 + hspi->RxXferCount--; + 8001b54: f8b4 3046 ldrh.w r3, [r4, #70] ; 0x46 + 8001b58: 3b01 subs r3, #1 + 8001b5a: b29b uxth r3, r3 + 8001b5c: f8a4 3046 strh.w r3, [r4, #70] ; 0x46 + 8001b60: e7ad b.n 8001abe + if ((Timeout == 0U) || ((Timeout != HAL_MAX_DELAY) && ((HAL_GetTick() - tickstart) >= Timeout))) + 8001b62: b93f cbnz r7, 8001b74 + errorcode = HAL_TIMEOUT; + 8001b64: 2003 movs r0, #3 + hspi->State = HAL_SPI_STATE_READY; + 8001b66: 2301 movs r3, #1 + 8001b68: f884 305d strb.w r3, [r4, #93] ; 0x5d + __HAL_UNLOCK(hspi); + 8001b6c: 2300 movs r3, #0 + 8001b6e: f884 305c strb.w r3, [r4, #92] ; 0x5c + return errorcode; + 8001b72: e74f b.n 8001a14 + if ((Timeout == 0U) || ((Timeout != HAL_MAX_DELAY) && ((HAL_GetTick() - tickstart) >= Timeout))) + 8001b74: 1c7b adds r3, r7, #1 + 8001b76: d0a2 beq.n 8001abe + 8001b78: f005 fc30 bl 80073dc + 8001b7c: eba0 0008 sub.w r0, r0, r8 + 8001b80: 42b8 cmp r0, r7 + 8001b82: d39c bcc.n 8001abe + 8001b84: e7ee b.n 8001b64 + tmpreg = *(__IO uint8_t *)&hspi->Instance->DR; + 8001b86: 7b1a ldrb r2, [r3, #12] + 8001b88: f8ad 200e strh.w r2, [sp, #14] + if ((hspi->Init.DataSize == SPI_DATASIZE_8BIT) && (hspi->Init.CRCLength == SPI_CRC_LENGTH_16BIT)) + 8001b8c: f5b1 6fe0 cmp.w r1, #1792 ; 0x700 + UNUSED(tmpreg); + 8001b90: f8bd 200e ldrh.w r2, [sp, #14] + if ((hspi->Init.DataSize == SPI_DATASIZE_8BIT) && (hspi->Init.CRCLength == SPI_CRC_LENGTH_16BIT)) + 8001b94: d1ba bne.n 8001b0c + 8001b96: 6b22 ldr r2, [r4, #48] ; 0x30 + 8001b98: 2a02 cmp r2, #2 + 8001b9a: d1b7 bne.n 8001b0c + while ((__HAL_SPI_GET_FLAG(hspi, Flag) ? SET : RESET) != State) + 8001b9c: 689a ldr r2, [r3, #8] + 8001b9e: 07d5 lsls r5, r2, #31 + 8001ba0: d5fc bpl.n 8001b9c + tmpreg = *(__IO uint8_t *)&hspi->Instance->DR; + 8001ba2: 7b1b ldrb r3, [r3, #12] + 8001ba4: e7ae b.n 8001b04 + if ((hspi->Init.Mode == SPI_MODE_MASTER) && ((hspi->Init.Direction == SPI_DIRECTION_1LINE) + 8001ba6: 68a2 ldr r2, [r4, #8] + 8001ba8: f5b2 4f00 cmp.w r2, #32768 ; 0x8000 + 8001bac: d002 beq.n 8001bb4 + || (hspi->Init.Direction == SPI_DIRECTION_2LINES_RXONLY))) + 8001bae: f5b2 6f80 cmp.w r2, #1024 ; 0x400 + 8001bb2: d1c1 bne.n 8001b38 + while ((hspi->Instance->SR & Fifo) != State) + 8001bb4: 689a ldr r2, [r3, #8] + 8001bb6: f412 6fc0 tst.w r2, #1536 ; 0x600 + 8001bba: d0bd beq.n 8001b38 + tmpreg = *((__IO uint8_t *)&hspi->Instance->DR); + 8001bbc: 7b1a ldrb r2, [r3, #12] + 8001bbe: b2d2 uxtb r2, r2 + 8001bc0: f88d 200d strb.w r2, [sp, #13] + UNUSED(tmpreg); + 8001bc4: f89d 200d ldrb.w r2, [sp, #13] + 8001bc8: e7f4 b.n 8001bb4 + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC); + 8001bca: 6e22 ldr r2, [r4, #96] ; 0x60 + 8001bcc: f042 0202 orr.w r2, r2, #2 + 8001bd0: 6622 str r2, [r4, #96] ; 0x60 + __HAL_SPI_CLEAR_CRCERRFLAG(hspi); + 8001bd2: f64f 72ef movw r2, #65519 ; 0xffef + 8001bd6: 609a str r2, [r3, #8] + 8001bd8: e7b1 b.n 8001b3e + errorcode = HAL_BUSY; + 8001bda: 2002 movs r0, #2 + 8001bdc: e7c3 b.n 8001b66 + __HAL_LOCK(hspi); + 8001bde: 2002 movs r0, #2 + 8001be0: e718 b.n 8001a14 + ... + +08001be4 : + +// checksum_more() +// + static void +checksum_more(SHA256_CTX *ctx, uint32_t *total, const uint8_t *addr, int len) +{ + 8001be4: b5f8 push {r3, r4, r5, r6, r7, lr} + 8001be6: 460c mov r4, r1 + // mk4 has hardware hash engine, and no DFU button + int percent = ((*total) * 100) / TOTAL_CHECKSUM_LEN; + 8001be8: 6809 ldr r1, [r1, #0] +{ + 8001bea: 461d mov r5, r3 + int percent = ((*total) * 100) / TOTAL_CHECKSUM_LEN; + 8001bec: 2364 movs r3, #100 ; 0x64 +{ + 8001bee: 4617 mov r7, r2 + 8001bf0: 4606 mov r6, r0 + int percent = ((*total) * 100) / TOTAL_CHECKSUM_LEN; + 8001bf2: 4359 muls r1, r3 + puts2("Verify %0x"); + puthex2(percent); + putchar('\n'); +#endif + + oled_show_progress(screen_verify, percent); + 8001bf4: 4807 ldr r0, [pc, #28] ; (8001c14 ) + 8001bf6: 4b08 ldr r3, [pc, #32] ; (8001c18 ) + 8001bf8: fbb1 f1f3 udiv r1, r1, r3 + 8001bfc: f7ff fab4 bl 8001168 + + sha256_update(ctx, addr, len); + 8001c00: 462a mov r2, r5 + 8001c02: 4639 mov r1, r7 + 8001c04: 4630 mov r0, r6 + 8001c06: f003 fdc7 bl 8005798 + *total += len; + 8001c0a: 6823 ldr r3, [r4, #0] + 8001c0c: 442b add r3, r5 + 8001c0e: 6023 str r3, [r4, #0] +} + 8001c10: bdf8 pop {r3, r4, r5, r6, r7, pc} + 8001c12: bf00 nop + 8001c14: 0801004d .word 0x0801004d + 8001c18: 0018541c .word 0x0018541c + +08001c1c : + +// checksum_flash() +// + void +checksum_flash(uint8_t fw_digest[32], uint8_t world_digest[32], uint32_t fw_length) +{ + 8001c1c: b570 push {r4, r5, r6, lr} + 8001c1e: b09c sub sp, #112 ; 0x70 + 8001c20: 4606 mov r6, r0 + 8001c22: 460d mov r5, r1 + 8001c24: 4614 mov r4, r2 + const uint8_t *start = (const uint8_t *)FIRMWARE_START; + + rng_delay(); + 8001c26: f000 fe6f bl 8002908 + + SHA256_CTX ctx; + uint32_t total_len = 0; + 8001c2a: 2300 movs r3, #0 + 8001c2c: 9300 str r3, [sp, #0] + + if(fw_length == 0) { + 8001c2e: 2c00 cmp r4, #0 + 8001c30: d15f bne.n 8001cf2 + uint8_t first[32]; + sha256_init(&ctx); + 8001c32: a809 add r0, sp, #36 ; 0x24 + 8001c34: f003 fda2 bl 800577c + + // use length from header in flash + fw_length = FW_HDR->firmware_length; + 8001c38: 4b36 ldr r3, [pc, #216] ; (8001d14 ) + + // start of firmware (just after we end) to header + checksum_more(&ctx, &total_len, start, FW_HEADER_OFFSET + FW_HEADER_SIZE - 64); + 8001c3a: 4a37 ldr r2, [pc, #220] ; (8001d18 ) + fw_length = FW_HDR->firmware_length; + 8001c3c: f8d3 4098 ldr.w r4, [r3, #152] ; 0x98 + checksum_more(&ctx, &total_len, start, FW_HEADER_OFFSET + FW_HEADER_SIZE - 64); + 8001c40: 4669 mov r1, sp + 8001c42: f44f 537f mov.w r3, #16320 ; 0x3fc0 + 8001c46: a809 add r0, sp, #36 ; 0x24 + 8001c48: f7ff ffcc bl 8001be4 + + // from after header to end + checksum_more(&ctx, &total_len, start + FW_HEADER_OFFSET + FW_HEADER_SIZE, + 8001c4c: 4a33 ldr r2, [pc, #204] ; (8001d1c ) + 8001c4e: f5a4 4380 sub.w r3, r4, #16384 ; 0x4000 + 8001c52: 4669 mov r1, sp + 8001c54: a809 add r0, sp, #36 ; 0x24 + 8001c56: f7ff ffc5 bl 8001be4 + fw_length - (FW_HEADER_OFFSET + FW_HEADER_SIZE)); + + sha256_final(&ctx, first); + 8001c5a: a901 add r1, sp, #4 + 8001c5c: a809 add r0, sp, #36 ; 0x24 + 8001c5e: f003 fde1 bl 8005824 + + // double SHA256 + sha256_single(first, sizeof(first), fw_digest); + 8001c62: 4632 mov r2, r6 + 8001c64: 2120 movs r1, #32 + 8001c66: a801 add r0, sp, #4 + 8001c68: f003 fdf0 bl 800584c + // fw_digest should already be populated by caller + total_len = fw_length - 64; + } + + // start over, and get the rest of flash. All of it. + sha256_init(&ctx); + 8001c6c: a809 add r0, sp, #36 ; 0x24 + 8001c6e: f003 fd85 bl 800577c + + // .. and chain in what we have so far + sha256_update(&ctx, fw_digest, 32); + 8001c72: 2220 movs r2, #32 + 8001c74: 4631 mov r1, r6 + 8001c76: a809 add r0, sp, #36 ; 0x24 + 8001c78: f003 fd8e bl 8005798 + + // Bootloader, including pairing secret area, but excluding MCU keys. + const uint8_t *base = (const uint8_t *)BL_FLASH_BASE; + checksum_more(&ctx, &total_len, base, ((uint8_t *)MCU_KEYS)-base); + 8001c7c: f44f 33f0 mov.w r3, #122880 ; 0x1e000 + 8001c80: f04f 6200 mov.w r2, #134217728 ; 0x8000000 + 8001c84: 4669 mov r1, sp + 8001c86: a809 add r0, sp, #36 ; 0x24 + 8001c88: f7ff ffac bl 8001be4 + + // Probably-blank area after firmware, and filesystem area. + // Important: firmware images (fw_length) must be aligned with flash erase unit size (4k). + const uint8_t *fs = start + fw_length; + const uint8_t *last = base + MAIN_FLASH_SIZE; + checksum_more(&ctx, &total_len, fs, last-fs); + 8001c8c: f104 6200 add.w r2, r4, #134217728 ; 0x8000000 + 8001c90: f5c4 13b0 rsb r3, r4, #1441792 ; 0x160000 + 8001c94: f502 3200 add.w r2, r2, #131072 ; 0x20000 + 8001c98: 4669 mov r1, sp + 8001c9a: a809 add r0, sp, #36 ; 0x24 + 8001c9c: f7ff ffa2 bl 8001be4 + + rng_delay(); + 8001ca0: f000 fe32 bl 8002908 + + // OTP area + checksum_more(&ctx, &total_len, (void *)0x1fff7000, 0x400); + 8001ca4: 4a1e ldr r2, [pc, #120] ; (8001d20 ) + 8001ca6: f44f 6380 mov.w r3, #1024 ; 0x400 + 8001caa: 4669 mov r1, sp + 8001cac: a809 add r0, sp, #36 ; 0x24 + 8001cae: f7ff ff99 bl 8001be4 + + // "just in case" ... the option bytes (2 banks) + checksum_more(&ctx, &total_len, (void *)0x1fff7800, 0x28); + 8001cb2: 4a1c ldr r2, [pc, #112] ; (8001d24 ) + 8001cb4: 2328 movs r3, #40 ; 0x28 + 8001cb6: 4669 mov r1, sp + 8001cb8: a809 add r0, sp, #36 ; 0x24 + 8001cba: f7ff ff93 bl 8001be4 + checksum_more(&ctx, &total_len, (void *)0x1ffff800, 0x28); + 8001cbe: 4a1a ldr r2, [pc, #104] ; (8001d28 ) + 8001cc0: 2328 movs r3, #40 ; 0x28 + 8001cc2: 4669 mov r1, sp + 8001cc4: a809 add r0, sp, #36 ; 0x24 + 8001cc6: f7ff ff8d bl 8001be4 + + // System ROM (they say it can't change, but clearly + // implemented as flash cells) + checksum_more(&ctx, &total_len, (void *)0x1fff0000, 0x7000); + 8001cca: 4a18 ldr r2, [pc, #96] ; (8001d2c ) + 8001ccc: f44f 43e0 mov.w r3, #28672 ; 0x7000 + 8001cd0: 4669 mov r1, sp + 8001cd2: a809 add r0, sp, #36 ; 0x24 + 8001cd4: f7ff ff86 bl 8001be4 + + // device serial number, just for kicks + checksum_more(&ctx, &total_len, (void *)0x1fff7590, 12); + 8001cd8: 4a15 ldr r2, [pc, #84] ; (8001d30 ) + 8001cda: 230c movs r3, #12 + 8001cdc: 4669 mov r1, sp + 8001cde: a809 add r0, sp, #36 ; 0x24 + 8001ce0: f7ff ff80 bl 8001be4 + + ASSERT(total_len == TOTAL_CHECKSUM_LEN); + 8001ce4: 4b13 ldr r3, [pc, #76] ; (8001d34 ) + 8001ce6: 9a00 ldr r2, [sp, #0] + 8001ce8: 429a cmp r2, r3 + 8001cea: d006 beq.n 8001cfa + 8001cec: 4812 ldr r0, [pc, #72] ; (8001d38 ) + 8001cee: f7fe fea3 bl 8000a38 + total_len = fw_length - 64; + 8001cf2: f1a4 0340 sub.w r3, r4, #64 ; 0x40 + 8001cf6: 9300 str r3, [sp, #0] + 8001cf8: e7b8 b.n 8001c6c + + sha256_final(&ctx, world_digest); + 8001cfa: 4629 mov r1, r5 + 8001cfc: a809 add r0, sp, #36 ; 0x24 + 8001cfe: f003 fd91 bl 8005824 + + // double SHA256 (a bitcoin fetish) + sha256_single(world_digest, 32, world_digest); + 8001d02: 462a mov r2, r5 + 8001d04: 2120 movs r1, #32 + 8001d06: 4628 mov r0, r5 + 8001d08: f003 fda0 bl 800584c + + rng_delay(); + 8001d0c: f000 fdfc bl 8002908 +} + 8001d10: b01c add sp, #112 ; 0x70 + 8001d12: bd70 pop {r4, r5, r6, pc} + 8001d14: 08023f00 .word 0x08023f00 + 8001d18: 08020000 .word 0x08020000 + 8001d1c: 08024000 .word 0x08024000 + 8001d20: 1fff7000 .word 0x1fff7000 + 8001d24: 1fff7800 .word 0x1fff7800 + 8001d28: 1ffff800 .word 0x1ffff800 + 8001d2c: 1fff0000 .word 0x1fff0000 + 8001d30: 1fff7590 .word 0x1fff7590 + 8001d34: 0018541c .word 0x0018541c + 8001d38: 0801046c .word 0x0801046c + +08001d3c : +// Scan the OTP area and determine what the current min-version (timestamp) +// we can allow. All zeros if any if okay. +// + void +get_min_version(uint8_t min_version[8]) +{ + 8001d3c: b570 push {r4, r5, r6, lr} + 8001d3e: 4604 mov r4, r0 + const uint8_t *otp = (const uint8_t *)OPT_FLASH_BASE; + 8001d40: 4d0c ldr r5, [pc, #48] ; (8001d74 ) + + rng_delay(); + memset(min_version, 0, 8); + + for(int i=0; i) + rng_delay(); + 8001d44: f000 fde0 bl 8002908 + memset(min_version, 0, 8); + 8001d48: 2300 movs r3, #0 + 8001d4a: 6023 str r3, [r4, #0] + 8001d4c: 6063 str r3, [r4, #4] + // is it programmed? + if(otp[0] == 0xff) continue; + + // is it a timestamp value? + if(otp[0] >= 0x40) continue; + if(otp[0] < 0x10) continue; + 8001d4e: 782b ldrb r3, [r5, #0] + 8001d50: 3b10 subs r3, #16 + 8001d52: 2b2f cmp r3, #47 ; 0x2f + 8001d54: d80a bhi.n 8001d6c + + if(memcmp(otp, min_version, 8) > 0) { + 8001d56: 4621 mov r1, r4 + 8001d58: 2208 movs r2, #8 + 8001d5a: 4628 mov r0, r5 + 8001d5c: f00b fdc4 bl 800d8e8 + 8001d60: 2800 cmp r0, #0 + memcpy(min_version, otp, 8); + 8001d62: bfc1 itttt gt + 8001d64: 462b movgt r3, r5 + 8001d66: cb03 ldmiagt r3!, {r0, r1} + 8001d68: 6020 strgt r0, [r4, #0] + 8001d6a: 6061 strgt r1, [r4, #4] + for(int i=0; i + } + } +} + 8001d72: bd70 pop {r4, r5, r6, pc} + 8001d74: 1fff7000 .word 0x1fff7000 + 8001d78: 1fff7400 .word 0x1fff7400 + +08001d7c : + +// check_is_downgrade() +// + bool +check_is_downgrade(const uint8_t timestamp[8], const char *version) +{ + 8001d7c: b513 push {r0, r1, r4, lr} + 8001d7e: 4604 mov r4, r0 + } +#endif + + // look at FW_HDR->timestamp and compare to a growing list in main flash OTP + uint8_t min[8]; + get_min_version(min); + 8001d80: 4668 mov r0, sp + 8001d82: f7ff ffdb bl 8001d3c + + return (memcmp(timestamp, min, 8) < 0); + 8001d86: 2208 movs r2, #8 + 8001d88: 4669 mov r1, sp + 8001d8a: 4620 mov r0, r4 + 8001d8c: f00b fdac bl 800d8e8 +} + 8001d90: 0fc0 lsrs r0, r0, #31 + 8001d92: b002 add sp, #8 + 8001d94: bd10 pop {r4, pc} + +08001d96 : + +// warn_fishy_firmware() +// + void +warn_fishy_firmware(const uint8_t *pixels) +{ + 8001d96: b538 push {r3, r4, r5, lr} + 8001d98: 4605 mov r5, r0 + const int wait = 100; +#else + const int wait = 10; +#endif + + for(int i=0; i < wait; i++) { + 8001d9a: 2400 movs r4, #0 + oled_show_progress(pixels, (i*100)/wait); + 8001d9c: 4621 mov r1, r4 + 8001d9e: 4628 mov r0, r5 + 8001da0: f7ff f9e2 bl 8001168 + for(int i=0; i < wait; i++) { + 8001da4: 3401 adds r4, #1 + + delay_ms(250); + 8001da6: 20fa movs r0, #250 ; 0xfa + 8001da8: f001 fe6c bl 8003a84 + for(int i=0; i < wait; i++) { + 8001dac: 2c64 cmp r4, #100 ; 0x64 + 8001dae: d1f5 bne.n 8001d9c + } +} + 8001db0: bd38 pop {r3, r4, r5, pc} + ... + +08001db4 : + +// verify_header() +// + bool +verify_header(const coldcardFirmwareHeader_t *hdr) +{ + 8001db4: b510 push {r4, lr} + 8001db6: 4604 mov r4, r0 + rng_delay(); + 8001db8: f000 fda6 bl 8002908 + + if(hdr->magic_value != FW_HEADER_MAGIC) goto fail; + 8001dbc: 6822 ldr r2, [r4, #0] + 8001dbe: 4b0b ldr r3, [pc, #44] ; (8001dec ) + 8001dc0: 429a cmp r2, r3 + 8001dc2: d110 bne.n 8001de6 + if(hdr->version_string[0] == 0x0) goto fail; + 8001dc4: 7b20 ldrb r0, [r4, #12] + 8001dc6: b168 cbz r0, 8001de4 + if(hdr->timestamp[0] >= 0x40) goto fail; // 22 yr product lifetime + 8001dc8: 7923 ldrb r3, [r4, #4] + 8001dca: 2b3f cmp r3, #63 ; 0x3f + 8001dcc: d80b bhi.n 8001de6 + if(hdr->firmware_length < FW_MIN_LENGTH) goto fail; + 8001dce: 69a3 ldr r3, [r4, #24] + 8001dd0: f5a3 2380 sub.w r3, r3, #262144 ; 0x40000 + 8001dd4: f5b3 1fd0 cmp.w r3, #1703936 ; 0x1a0000 + 8001dd8: d205 bcs.n 8001de6 + if(hdr->firmware_length >= FW_MAX_LENGTH_MK4) goto fail; + if(hdr->pubkey_num >= NUM_KNOWN_PUBKEYS) goto fail; + 8001dda: 6960 ldr r0, [r4, #20] + 8001ddc: 2805 cmp r0, #5 + 8001dde: bf8c ite hi + 8001de0: 2000 movhi r0, #0 + 8001de2: 2001 movls r0, #1 + + return true; +fail: + return false; +} + 8001de4: bd10 pop {r4, pc} + return false; + 8001de6: 2000 movs r0, #0 + 8001de8: e7fc b.n 8001de4 + 8001dea: bf00 nop + 8001dec: cc001234 .word 0xcc001234 + +08001df0 : +// +// Given double-sha256 over the firmware bytes, check the signature. +// + bool +verify_signature(const coldcardFirmwareHeader_t *hdr, const uint8_t fw_check[32]) +{ + 8001df0: b530 push {r4, r5, lr} + // this takes a few ms at least, not fast. + int ok = uECC_verify(approved_pubkeys[hdr->pubkey_num], fw_check, 32, + 8001df2: 6943 ldr r3, [r0, #20] + 8001df4: 4d0b ldr r5, [pc, #44] ; (8001e24 ) +{ + 8001df6: b085 sub sp, #20 + int ok = uECC_verify(approved_pubkeys[hdr->pubkey_num], fw_check, 32, + 8001df8: eb05 1583 add.w r5, r5, r3, lsl #6 +{ + 8001dfc: 4604 mov r4, r0 + 8001dfe: 9103 str r1, [sp, #12] + int ok = uECC_verify(approved_pubkeys[hdr->pubkey_num], fw_check, 32, + 8001e00: f004 fee8 bl 8006bd4 + 8001e04: f104 0340 add.w r3, r4, #64 ; 0x40 + 8001e08: 9903 ldr r1, [sp, #12] + 8001e0a: 9000 str r0, [sp, #0] + 8001e0c: 2220 movs r2, #32 + 8001e0e: 4628 mov r0, r5 + 8001e10: f005 f967 bl 80070e2 + 8001e14: 4604 mov r4, r0 + hdr->signature, uECC_secp256k1()); + + //puts(ok ? "Sig ok" : "Sig fail"); + rng_delay(); + 8001e16: f000 fd77 bl 8002908 + + return ok; +} + 8001e1a: 1e20 subs r0, r4, #0 + 8001e1c: bf18 it ne + 8001e1e: 2001 movne r0, #1 + 8001e20: b005 add sp, #20 + 8001e22: bd30 pop {r4, r5, pc} + 8001e24: 080104e6 .word 0x080104e6 + +08001e28 : +// Check hdr, and even signature of protential new firmware in PSRAM. +// Returns checksum needed for 608 +// + bool +verify_firmware_in_ram(const uint8_t *start, uint32_t len, uint8_t world_check[32]) +{ + 8001e28: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + const coldcardFirmwareHeader_t *hdr = (const coldcardFirmwareHeader_t *) + 8001e2c: f500 567e add.w r6, r0, #16256 ; 0x3f80 +{ + 8001e30: b09c sub sp, #112 ; 0x70 + 8001e32: 4605 mov r5, r0 + (start + FW_HEADER_OFFSET); + uint8_t fw_digest[32]; + + // check basics like verison, hw compat, etc + if(!verify_header(hdr)) goto fail; + 8001e34: 4630 mov r0, r6 +{ + 8001e36: 4617 mov r7, r2 + if(!verify_header(hdr)) goto fail; + 8001e38: f7ff ffbc bl 8001db4 + 8001e3c: 4604 mov r4, r0 + 8001e3e: b150 cbz r0, 8001e56 + + if(check_is_downgrade(hdr->timestamp, (const char *)hdr->version_string)) { + 8001e40: f106 010c add.w r1, r6, #12 + 8001e44: 1d30 adds r0, r6, #4 + 8001e46: f7ff ff99 bl 8001d7c + 8001e4a: 4604 mov r4, r0 + 8001e4c: b138 cbz r0, 8001e5e + puts("downgrade"); + 8001e4e: 481e ldr r0, [pc, #120] ; (8001ec8 ) + 8001e50: f003 f90a bl 8005068 + + checksum_flash(fw_digest, world_check, hdr->firmware_length); + + return true; +fail: + return false; + 8001e54: 2400 movs r4, #0 +} + 8001e56: 4620 mov r0, r4 + 8001e58: b01c add sp, #112 ; 0x70 + 8001e5a: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + rng_delay(); + 8001e5e: f000 fd53 bl 8002908 + hdr->firmware_length - (FW_HEADER_OFFSET + FW_HEADER_SIZE)); + 8001e62: f505 5840 add.w r8, r5, #12288 ; 0x3000 + sha256_init(&ctx); + 8001e66: a809 add r0, sp, #36 ; 0x24 + uint32_t total_len = 0; + 8001e68: 9400 str r4, [sp, #0] + sha256_init(&ctx); + 8001e6a: f003 fc87 bl 800577c + checksum_more(&ctx, &total_len, start, FW_HEADER_OFFSET + FW_HEADER_SIZE - 64); + 8001e6e: f44f 537f mov.w r3, #16320 ; 0x3fc0 + 8001e72: 462a mov r2, r5 + 8001e74: 4669 mov r1, sp + 8001e76: a809 add r0, sp, #36 ; 0x24 + 8001e78: f7ff feb4 bl 8001be4 + hdr->firmware_length - (FW_HEADER_OFFSET + FW_HEADER_SIZE)); + 8001e7c: f8d8 3f98 ldr.w r3, [r8, #3992] ; 0xf98 + checksum_more(&ctx, &total_len, start + FW_HEADER_OFFSET + FW_HEADER_SIZE, + 8001e80: f505 4280 add.w r2, r5, #16384 ; 0x4000 + 8001e84: f5a3 4380 sub.w r3, r3, #16384 ; 0x4000 + 8001e88: 4669 mov r1, sp + 8001e8a: a809 add r0, sp, #36 ; 0x24 + 8001e8c: f7ff feaa bl 8001be4 + sha256_final(&ctx, fw_digest); + 8001e90: a901 add r1, sp, #4 + 8001e92: a809 add r0, sp, #36 ; 0x24 + 8001e94: f003 fcc6 bl 8005824 + sha256_single(fw_digest, 32, fw_digest); + 8001e98: aa01 add r2, sp, #4 + 8001e9a: 4610 mov r0, r2 + 8001e9c: 2120 movs r1, #32 + 8001e9e: f003 fcd5 bl 800584c + rng_delay(); + 8001ea2: f000 fd31 bl 8002908 + if(!verify_signature(hdr, fw_digest)) { + 8001ea6: a901 add r1, sp, #4 + 8001ea8: 4630 mov r0, r6 + 8001eaa: f7ff ffa1 bl 8001df0 + 8001eae: 4604 mov r4, r0 + 8001eb0: b918 cbnz r0, 8001eba + puts("sig fail"); + 8001eb2: 4806 ldr r0, [pc, #24] ; (8001ecc ) + 8001eb4: f003 f8d8 bl 8005068 + goto fail; + 8001eb8: e7cd b.n 8001e56 + checksum_flash(fw_digest, world_check, hdr->firmware_length); + 8001eba: f8d8 2f98 ldr.w r2, [r8, #3992] ; 0xf98 + 8001ebe: 4639 mov r1, r7 + 8001ec0: a801 add r0, sp, #4 + 8001ec2: f7ff feab bl 8001c1c + return true; + 8001ec6: e7c6 b.n 8001e56 + 8001ec8: 08010473 .word 0x08010473 + 8001ecc: 0801047d .word 0x0801047d + +08001ed0 : +// - don't set the light at this point. +// - requires bootloader to have been unchanged since world_check recorded (debug issue) +// + bool +verify_world_checksum(const uint8_t world_check[32]) +{ + 8001ed0: b507 push {r0, r1, r2, lr} + 8001ed2: 9001 str r0, [sp, #4] + ae_setup(); + 8001ed4: f000 fe3c bl 8002b50 + ae_pair_unlock(); + 8001ed8: f001 f830 bl 8002f3c + + return (ae_checkmac_hard(KEYNUM_firmware, world_check) == 0); + 8001edc: 9901 ldr r1, [sp, #4] + 8001ede: 200e movs r0, #14 + 8001ee0: f001 f9ba bl 8003258 +} + 8001ee4: fab0 f080 clz r0, r0 + 8001ee8: 0940 lsrs r0, r0, #5 + 8001eea: b003 add sp, #12 + 8001eec: f85d fb04 ldr.w pc, [sp], #4 + +08001ef0 : + +// verify_firmware() +// + bool +verify_firmware(void) +{ + 8001ef0: b570 push {r4, r5, r6, lr} + STATIC_ASSERT(sizeof(coldcardFirmwareHeader_t) == FW_HEADER_SIZE); + + rng_delay(); + + // watch for unprogrammed header. and some + if(FW_HDR->version_string[0] == 0xff) goto blank; + 8001ef2: 4e2a ldr r6, [pc, #168] ; (8001f9c ) +{ + 8001ef4: b090 sub sp, #64 ; 0x40 + rng_delay(); + 8001ef6: f000 fd07 bl 8002908 + if(FW_HDR->version_string[0] == 0xff) goto blank; + 8001efa: f896 308c ldrb.w r3, [r6, #140] ; 0x8c + 8001efe: 2bff cmp r3, #255 ; 0xff + 8001f00: d107 bne.n 8001f12 + puts("corrupt firmware"); + oled_show(screen_corrupt); + return false; + +blank: + puts("no firmware"); + 8001f02: 4827 ldr r0, [pc, #156] ; (8001fa0 ) + puts("corrupt firmware"); + 8001f04: f003 f8b0 bl 8005068 + oled_show(screen_corrupt); + 8001f08: 4826 ldr r0, [pc, #152] ; (8001fa4 ) + 8001f0a: f7ff f8b3 bl 8001074 + return false; + 8001f0e: 2400 movs r4, #0 + 8001f10: e030 b.n 8001f74 + if(!verify_header(FW_HDR)) goto fail; + 8001f12: 4825 ldr r0, [pc, #148] ; (8001fa8 ) + 8001f14: f7ff ff4e bl 8001db4 + 8001f18: 2800 cmp r0, #0 + 8001f1a: d03c beq.n 8001f96 + rng_delay(); + 8001f1c: f000 fcf4 bl 8002908 + checksum_flash(fw_check, world_check, 0); + 8001f20: 2200 movs r2, #0 + 8001f22: a908 add r1, sp, #32 + 8001f24: 4668 mov r0, sp + 8001f26: f7ff fe79 bl 8001c1c + rng_delay(); + 8001f2a: f000 fced bl 8002908 + if(!verify_signature(FW_HDR, fw_check)) goto fail; + 8001f2e: 481e ldr r0, [pc, #120] ; (8001fa8 ) + 8001f30: 4669 mov r1, sp + 8001f32: f7ff ff5d bl 8001df0 + 8001f36: 4604 mov r4, r0 + 8001f38: b368 cbz r0, 8001f96 + int not_green = ae_set_gpio_secure(world_check); + 8001f3a: a808 add r0, sp, #32 + 8001f3c: f001 fba0 bl 8003680 + 8001f40: 4605 mov r5, r0 + rng_delay(); + 8001f42: f000 fce1 bl 8002908 + rng_delay(); + 8001f46: f000 fcdf bl 8002908 + return ((FLASH->OPTR & FLASH_OPTR_RDP_Msk) == 0xCC); + 8001f4a: 4b18 ldr r3, [pc, #96] ; (8001fac ) + 8001f4c: 6a1b ldr r3, [r3, #32] + 8001f4e: b2db uxtb r3, r3 + if(!flash_is_security_level2() && not_green) { + 8001f50: 2bcc cmp r3, #204 ; 0xcc + 8001f52: d008 beq.n 8001f66 + 8001f54: b18d cbz r5, 8001f7a + oled_show_progress(screen_verify, 100); + 8001f56: 4816 ldr r0, [pc, #88] ; (8001fb0 ) + 8001f58: 2164 movs r1, #100 ; 0x64 + 8001f5a: f7ff f905 bl 8001168 + puts("Factory boot"); + 8001f5e: 4815 ldr r0, [pc, #84] ; (8001fb4 ) + puts("Good firmware"); + 8001f60: f003 f882 bl 8005068 + 8001f64: e006 b.n 8001f74 + } else if(not_green) { + 8001f66: b145 cbz r5, 8001f7a + puts("WARN: Red light"); + 8001f68: 4813 ldr r0, [pc, #76] ; (8001fb8 ) + 8001f6a: f003 f87d bl 8005068 + warn_fishy_firmware(screen_red_light); + 8001f6e: 4813 ldr r0, [pc, #76] ; (8001fbc ) + warn_fishy_firmware(screen_devmode); + 8001f70: f7ff ff11 bl 8001d96 + oled_show(screen_corrupt); + + return false; +} + 8001f74: 4620 mov r0, r4 + 8001f76: b010 add sp, #64 ; 0x40 + 8001f78: bd70 pop {r4, r5, r6, pc} + } else if(FW_HDR->pubkey_num == 0) { + 8001f7a: f8d6 3094 ldr.w r3, [r6, #148] ; 0x94 + 8001f7e: b923 cbnz r3, 8001f8a + puts("WARN: Unsigned firmware"); + 8001f80: 480f ldr r0, [pc, #60] ; (8001fc0 ) + 8001f82: f003 f871 bl 8005068 + warn_fishy_firmware(screen_devmode); + 8001f86: 480f ldr r0, [pc, #60] ; (8001fc4 ) + 8001f88: e7f2 b.n 8001f70 + oled_show_progress(screen_verify, 100); + 8001f8a: 4809 ldr r0, [pc, #36] ; (8001fb0 ) + 8001f8c: 2164 movs r1, #100 ; 0x64 + 8001f8e: f7ff f8eb bl 8001168 + puts("Good firmware"); + 8001f92: 480d ldr r0, [pc, #52] ; (8001fc8 ) + 8001f94: e7e4 b.n 8001f60 + puts("corrupt firmware"); + 8001f96: 480d ldr r0, [pc, #52] ; (8001fcc ) + 8001f98: e7b4 b.n 8001f04 + 8001f9a: bf00 nop + 8001f9c: 08023f00 .word 0x08023f00 + 8001fa0: 08010486 .word 0x08010486 + 8001fa4: 0800db0d .word 0x0800db0d + 8001fa8: 08023f80 .word 0x08023f80 + 8001fac: 40022000 .word 0x40022000 + 8001fb0: 0801004d .word 0x0801004d + 8001fb4: 08010492 .word 0x08010492 + 8001fb8: 0801049f .word 0x0801049f + 8001fbc: 0800ec15 .word 0x0800ec15 + 8001fc0: 080104af .word 0x080104af + 8001fc4: 0800ddcf .word 0x0800ddcf + 8001fc8: 080104c7 .word 0x080104c7 + 8001fcc: 080104d5 .word 0x080104d5 + +08001fd0 : + void +systick_setup(void) +{ + const uint32_t ticks = HCLK_FREQUENCY/1000; + + SysTick->LOAD = (ticks - 1); + 8001fd0: f04f 23e0 mov.w r3, #3758153728 ; 0xe000e000 + 8001fd4: 4a03 ldr r2, [pc, #12] ; (8001fe4 ) + 8001fd6: 615a str r2, [r3, #20] + SysTick->VAL = 0; + 8001fd8: 2200 movs r2, #0 + 8001fda: 619a str r2, [r3, #24] + SysTick->CTRL = SYSTICK_CLKSOURCE_HCLK | SysTick_CTRL_ENABLE_Msk; + 8001fdc: 2205 movs r2, #5 + 8001fde: 611a str r2, [r3, #16] +} + 8001fe0: 4770 bx lr + 8001fe2: bf00 nop + 8001fe4: 0001d4bf .word 0x0001d4bf + +08001fe8 : + SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; +#endif + + /* FPU settings ------------------------------------------------------------*/ +#if (__FPU_PRESENT == 1) && (__FPU_USED == 1) + SCB->CPACR |= ((3UL << 20U)|(3UL << 22U)); /* set CP10 and CP11 Full Access */ + 8001fe8: 4a0e ldr r2, [pc, #56] ; (8002024 ) + 8001fea: f8d2 3088 ldr.w r3, [r2, #136] ; 0x88 + 8001fee: f443 0370 orr.w r3, r3, #15728640 ; 0xf00000 + 8001ff2: f8c2 3088 str.w r3, [r2, #136] ; 0x88 +#endif + + /* Reset the RCC clock configuration to the default reset state ------------*/ + /* Set MSION bit */ + RCC->CR |= RCC_CR_MSION; + 8001ff6: 4b0c ldr r3, [pc, #48] ; (8002028 ) + 8001ff8: 681a ldr r2, [r3, #0] + + /* Reset CFGR register */ + RCC->CFGR = 0x00000000U; + 8001ffa: 2100 movs r1, #0 + RCC->CR |= RCC_CR_MSION; + 8001ffc: f042 0201 orr.w r2, r2, #1 + 8002000: 601a str r2, [r3, #0] + RCC->CFGR = 0x00000000U; + 8002002: 6099 str r1, [r3, #8] + + /* Reset HSEON, CSSON , HSION, and PLLON bits */ + RCC->CR &= 0xEAF6FFFFU; + 8002004: 681a ldr r2, [r3, #0] + 8002006: f022 52a8 bic.w r2, r2, #352321536 ; 0x15000000 + 800200a: f422 2210 bic.w r2, r2, #589824 ; 0x90000 + 800200e: 601a str r2, [r3, #0] + + /* Reset PLLCFGR register */ + RCC->PLLCFGR = 0x00001000U; + 8002010: f44f 5280 mov.w r2, #4096 ; 0x1000 + 8002014: 60da str r2, [r3, #12] + + /* Reset HSEBYP bit */ + RCC->CR &= 0xFFFBFFFFU; + 8002016: 681a ldr r2, [r3, #0] + 8002018: f422 2280 bic.w r2, r2, #262144 ; 0x40000 + 800201c: 601a str r2, [r3, #0] + + /* Disable all interrupts */ + RCC->CIER = 0x00000000U; + 800201e: 6199 str r1, [r3, #24] +} + 8002020: 4770 bx lr + 8002022: bf00 nop + 8002024: e000ed00 .word 0xe000ed00 + 8002028: 40021000 .word 0x40021000 + +0800202c : + +// clocks_setup() +// + void +clocks_setup(void) +{ + 800202c: e92d 43f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, lr} + + // setup power supplies + HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST); + + // Configure LSE Drive Capability + __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW); + 8002030: 4c41 ldr r4, [pc, #260] ; (8002138 ) +{ + 8002032: b0c1 sub sp, #260 ; 0x104 + HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST); + 8002034: 2000 movs r0, #0 + 8002036: f005 f9e7 bl 8007408 + __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW); + 800203a: f8d4 3090 ldr.w r3, [r4, #144] ; 0x90 + 800203e: f023 0318 bic.w r3, r3, #24 + 8002042: f8c4 3090 str.w r3, [r4, #144] ; 0x90 + + // Enable HSE Oscillator and activate PLL with HSE as source + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; + + RCC_OscInitStruct.HSEState = RCC_HSE_ON; + 8002046: 2201 movs r2, #1 + 8002048: f44f 3380 mov.w r3, #65536 ; 0x10000 + 800204c: e9cd 230a strd r2, r3, [sp, #40] ; 0x28 + RCC_OscInitStruct.LSEState = RCC_LSE_OFF; + RCC_OscInitStruct.MSIState = RCC_MSI_OFF; + + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + 8002050: 2703 movs r7, #3 + + // Select PLL as system clock source and configure + // the HCLK, PCLK1 and PCLK2 clocks dividers + RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK + 8002052: 230f movs r3, #15 + RCC_OscInitStruct.LSEState = RCC_LSE_OFF; + 8002054: 2500 movs r5, #0 + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + 8002056: 2602 movs r6, #2 + | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + 8002058: e9cd 3705 strd r3, r7, [sp, #20] + + RCC_OscInitStruct.PLL.PLLM = CKCC_CLK_PLLM; + RCC_OscInitStruct.PLL.PLLN = CKCC_CLK_PLLN; + RCC_OscInitStruct.PLL.PLLP = CKCC_CLK_PLLP; + 800205c: f04f 0807 mov.w r8, #7 + 8002060: 233c movs r3, #60 ; 0x3c + RCC_OscInitStruct.PLL.PLLQ = CKCC_CLK_PLLQ; + 8002062: f04f 0905 mov.w r9, #5 + + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; + + HAL_RCC_OscConfig(&RCC_OscInitStruct); + 8002066: a80a add r0, sp, #40 ; 0x28 + RCC_OscInitStruct.PLL.PLLP = CKCC_CLK_PLLP; + 8002068: e9cd 3817 strd r3, r8, [sp, #92] ; 0x5c + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + 800206c: e9cd 6714 strd r6, r7, [sp, #80] ; 0x50 + RCC_OscInitStruct.PLL.PLLR = CKCC_CLK_PLLR; + 8002070: e9cd 9619 strd r9, r6, [sp, #100] ; 0x64 + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; + 8002074: e9cd 5507 strd r5, r5, [sp, #28] + RCC_OscInitStruct.LSEState = RCC_LSE_OFF; + 8002078: 950c str r5, [sp, #48] ; 0x30 + RCC_OscInitStruct.MSIState = RCC_MSI_OFF; + 800207a: 9510 str r5, [sp, #64] ; 0x40 + RCC_OscInitStruct.PLL.PLLM = CKCC_CLK_PLLM; + 800207c: 9616 str r6, [sp, #88] ; 0x58 + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; + 800207e: 9509 str r5, [sp, #36] ; 0x24 + HAL_RCC_OscConfig(&RCC_OscInitStruct); + 8002080: f006 fd64 bl 8008b4c + + HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5); + 8002084: 4649 mov r1, r9 + 8002086: a805 add r0, sp, #20 + 8002088: f007 f80e bl 80090a8 + + // DIS-able MSI-Hardware auto calibration mode with LSE + CLEAR_BIT(RCC->CR, RCC_CR_MSIPLLEN); + 800208c: 6823 ldr r3, [r4, #0] + 800208e: f023 0304 bic.w r3, r3, #4 + 8002092: 6023 str r3, [r4, #0] + + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct; + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SAI1|RCC_PERIPHCLK_I2C2 + 8002094: 4b29 ldr r3, [pc, #164] ; (800213c ) + 8002096: 931b str r3, [sp, #108] ; 0x6c + + // PLLSAI is used to clock USB, ADC, I2C1 and RNG. The frequency is + // HSE(8MHz)/PLLM(2)*PLLSAI1N(24)/PLLSAIQ(2) = 48MHz. + // + PeriphClkInitStruct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI1; + PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLLSAI1; + 8002098: f04f 5380 mov.w r3, #268435456 ; 0x10000000 + 800209c: 933b str r3, [sp, #236] ; 0xec + PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLLSAI1; + 800209e: f04f 6380 mov.w r3, #67108864 ; 0x4000000 + 80020a2: 9338 str r3, [sp, #224] ; 0xe0 + PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_HSE_DIV32; // but unused + PeriphClkInitStruct.RngClockSelection = RCC_RNGCLKSOURCE_PLLSAI1; + 80020a4: 933a str r3, [sp, #232] ; 0xe8 + + PeriphClkInitStruct.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_HSE; + PeriphClkInitStruct.PLLSAI1.PLLSAI1M = 2; + PeriphClkInitStruct.PLLSAI1.PLLSAI1N = 24; + 80020a6: 2318 movs r3, #24 + PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_HSE_DIV32; // but unused + 80020a8: f44f 7240 mov.w r2, #768 ; 0x300 + PeriphClkInitStruct.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV7; + 80020ac: e9cd 381e strd r3, r8, [sp, #120] ; 0x78 + PeriphClkInitStruct.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2; + PeriphClkInitStruct.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_SAI1CLK + |RCC_PLLSAI1_48M2CLK + |RCC_PLLSAI1_ADC1CLK; + + HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct); + 80020b0: a81b add r0, sp, #108 ; 0x6c + PeriphClkInitStruct.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_SAI1CLK + 80020b2: 4b23 ldr r3, [pc, #140] ; (8002140 ) + PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_HSE_DIV32; // but unused + 80020b4: 923f str r2, [sp, #252] ; 0xfc + PeriphClkInitStruct.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_SAI1CLK + 80020b6: 9322 str r3, [sp, #136] ; 0x88 + PeriphClkInitStruct.PLLSAI1.PLLSAI1M = 2; + 80020b8: e9cd 761c strd r7, r6, [sp, #112] ; 0x70 + PeriphClkInitStruct.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2; + 80020bc: e9cd 6620 strd r6, r6, [sp, #128] ; 0x80 + PeriphClkInitStruct.I2c2ClockSelection = RCC_I2C2CLKSOURCE_PCLK1; + 80020c0: 9531 str r5, [sp, #196] ; 0xc4 + PeriphClkInitStruct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI1; + 80020c2: 9536 str r5, [sp, #216] ; 0xd8 + HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct); + 80020c4: f007 fb14 bl 80096f0 + + __HAL_RCC_RTC_ENABLE(); + 80020c8: f8d4 3090 ldr.w r3, [r4, #144] ; 0x90 + 80020cc: f443 4300 orr.w r3, r3, #32768 ; 0x8000 + 80020d0: f8c4 3090 str.w r3, [r4, #144] ; 0x90 + __HAL_RCC_HASH_CLK_ENABLE(); // for SHA256 + 80020d4: 6ce3 ldr r3, [r4, #76] ; 0x4c + 80020d6: f443 3300 orr.w r3, r3, #131072 ; 0x20000 + 80020da: 64e3 str r3, [r4, #76] ; 0x4c + 80020dc: 6ce3 ldr r3, [r4, #76] ; 0x4c + 80020de: f403 3300 and.w r3, r3, #131072 ; 0x20000 + 80020e2: 9301 str r3, [sp, #4] + 80020e4: 9b01 ldr r3, [sp, #4] + __HAL_RCC_SPI1_CLK_ENABLE(); // for OLED + 80020e6: 6e23 ldr r3, [r4, #96] ; 0x60 + 80020e8: f443 5380 orr.w r3, r3, #4096 ; 0x1000 + 80020ec: 6623 str r3, [r4, #96] ; 0x60 + 80020ee: 6e23 ldr r3, [r4, #96] ; 0x60 + 80020f0: f403 5380 and.w r3, r3, #4096 ; 0x1000 + 80020f4: 9302 str r3, [sp, #8] + 80020f6: 9b02 ldr r3, [sp, #8] + //__HAL_RCC_SPI2_CLK_ENABLE(); // for SPI flash + __HAL_RCC_DMAMUX1_CLK_ENABLE(); // (need this) because code missing in mpy? + 80020f8: 6ca3 ldr r3, [r4, #72] ; 0x48 + 80020fa: f043 0304 orr.w r3, r3, #4 + 80020fe: 64a3 str r3, [r4, #72] ; 0x48 + 8002100: 6ca3 ldr r3, [r4, #72] ; 0x48 + 8002102: f003 0304 and.w r3, r3, #4 + 8002106: 9303 str r3, [sp, #12] + 8002108: 9b03 ldr r3, [sp, #12] + + // for SE2 + __HAL_RCC_I2C2_CLK_ENABLE(); + 800210a: 6da3 ldr r3, [r4, #88] ; 0x58 + 800210c: f443 0380 orr.w r3, r3, #4194304 ; 0x400000 + 8002110: 65a3 str r3, [r4, #88] ; 0x58 + 8002112: 6da3 ldr r3, [r4, #88] ; 0x58 + 8002114: f403 0380 and.w r3, r3, #4194304 ; 0x400000 + 8002118: 9304 str r3, [sp, #16] + 800211a: 9b04 ldr r3, [sp, #16] + __HAL_RCC_I2C2_FORCE_RESET(); + 800211c: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800211e: f443 0380 orr.w r3, r3, #4194304 ; 0x400000 + 8002122: 63a3 str r3, [r4, #56] ; 0x38 + __HAL_RCC_I2C2_RELEASE_RESET(); + 8002124: 6ba3 ldr r3, [r4, #56] ; 0x38 + 8002126: f423 0380 bic.w r3, r3, #4194304 ; 0x400000 + 800212a: 63a3 str r3, [r4, #56] ; 0x38 + + // setup SYSTICK, but we don't have the irq hooked up and not using HAL + // but we use it in polling mode for delay_ms() + systick_setup(); + 800212c: f7ff ff50 bl 8001fd0 + +} + 8002130: b041 add sp, #260 ; 0x104 + 8002132: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + 8002136: bf00 nop + 8002138: 40021000 .word 0x40021000 + 800213c: 00066880 .word 0x00066880 + 8002140: 01110000 .word 0x01110000 + +08002144 : + } else { + + // write changes to OB flash bytes + + // Set OPTSTRT bit + SET_BIT(FLASH->CR, FLASH_CR_OPTSTRT); + 8002144: 4b13 ldr r3, [pc, #76] ; (8002194 ) + 8002146: 695a ldr r2, [r3, #20] + 8002148: f442 3200 orr.w r2, r2, #131072 ; 0x20000 + 800214c: 615a str r2, [r3, #20] + while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)) { + 800214e: 691a ldr r2, [r3, #16] + 8002150: 03d2 lsls r2, r2, #15 + 8002152: d4fc bmi.n 800214e + uint32_t error = (FLASH->SR & FLASH_FLAG_SR_ERRORS); + 8002154: 6919 ldr r1, [r3, #16] + if(error) { + 8002156: 4a10 ldr r2, [pc, #64] ; (8002198 ) + 8002158: 4211 tst r1, r2 + 800215a: d104 bne.n 8002166 + if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP)) { + 800215c: 691a ldr r2, [r3, #16] + 800215e: 07d0 lsls r0, r2, #31 + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP); + 8002160: bf44 itt mi + 8002162: 2201 movmi r2, #1 + 8002164: 611a strmi r2, [r3, #16] + + /// Wait for update to complete + _flash_wait_done(); + + // lock OB again. + SET_BIT(FLASH->CR, FLASH_CR_OPTLOCK); + 8002166: 4b0b ldr r3, [pc, #44] ; (8002194 ) + 8002168: 695a ldr r2, [r3, #20] + 800216a: f042 4280 orr.w r2, r2, #1073741824 ; 0x40000000 + 800216e: 615a str r2, [r3, #20] + + // include "launch" to make them take effect NOW + SET_BIT(FLASH->CR, FLASH_CR_OBL_LAUNCH); + 8002170: 695a ldr r2, [r3, #20] + 8002172: f042 6200 orr.w r2, r2, #134217728 ; 0x8000000 + 8002176: 615a str r2, [r3, #20] + while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)) { + 8002178: 691a ldr r2, [r3, #16] + 800217a: 03d1 lsls r1, r2, #15 + 800217c: d4fc bmi.n 8002178 + uint32_t error = (FLASH->SR & FLASH_FLAG_SR_ERRORS); + 800217e: 6919 ldr r1, [r3, #16] + if(error) { + 8002180: 4a05 ldr r2, [pc, #20] ; (8002198 ) + 8002182: 4211 tst r1, r2 + 8002184: d104 bne.n 8002190 + if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP)) { + 8002186: 691a ldr r2, [r3, #16] + 8002188: 07d2 lsls r2, r2, #31 + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP); + 800218a: bf44 itt mi + 800218c: 2201 movmi r2, #1 + 800218e: 611a strmi r2, [r3, #16] + + _flash_wait_done(); + } +} + 8002190: 4770 bx lr + 8002192: bf00 nop + 8002194: 40022000 .word 0x40022000 + 8002198: 0002c3fa .word 0x0002c3fa + +0800219c : +{ + 800219c: b507 push {r0, r1, r2, lr} + memcpy(&_srelocate, &_etext, ((uint32_t)&_erelocate)-(uint32_t)&_srelocate); + 800219e: 4809 ldr r0, [pc, #36] ; (80021c4 ) + 80021a0: 4a09 ldr r2, [pc, #36] ; (80021c8 ) + 80021a2: 490a ldr r1, [pc, #40] ; (80021cc ) + 80021a4: 1a12 subs r2, r2, r0 + 80021a6: f00b fbaf bl 800d908 + __HAL_RCC_FLASH_CLK_ENABLE(); + 80021aa: 4b09 ldr r3, [pc, #36] ; (80021d0 ) + 80021ac: 6c9a ldr r2, [r3, #72] ; 0x48 + 80021ae: f442 7280 orr.w r2, r2, #256 ; 0x100 + 80021b2: 649a str r2, [r3, #72] ; 0x48 + 80021b4: 6c9b ldr r3, [r3, #72] ; 0x48 + 80021b6: f403 7380 and.w r3, r3, #256 ; 0x100 + 80021ba: 9301 str r3, [sp, #4] + 80021bc: 9b01 ldr r3, [sp, #4] +} + 80021be: b003 add sp, #12 + 80021c0: f85d fb04 ldr.w pc, [sp], #4 + 80021c4: 2009e000 .word 0x2009e000 + 80021c8: 2009e150 .word 0x2009e150 + 80021cc: 08010ac4 .word 0x08010ac4 + 80021d0: 40021000 .word 0x40021000 + +080021d4 : + SET_BIT(FLASH->CR, FLASH_CR_LOCK); + 80021d4: 4a02 ldr r2, [pc, #8] ; (80021e0 ) + 80021d6: 6953 ldr r3, [r2, #20] + 80021d8: f043 4300 orr.w r3, r3, #2147483648 ; 0x80000000 + 80021dc: 6153 str r3, [r2, #20] +} + 80021de: 4770 bx lr + 80021e0: 40022000 .word 0x40022000 + +080021e4 : +{ + 80021e4: b508 push {r3, lr} + if(READ_BIT(FLASH->CR, FLASH_CR_LOCK)) { + 80021e6: 4b08 ldr r3, [pc, #32] ; (8002208 ) + 80021e8: 695a ldr r2, [r3, #20] + 80021ea: 2a00 cmp r2, #0 + 80021ec: da0a bge.n 8002204 + WRITE_REG(FLASH->KEYR, FLASH_KEY1); + 80021ee: 4a07 ldr r2, [pc, #28] ; (800220c ) + 80021f0: 609a str r2, [r3, #8] + WRITE_REG(FLASH->KEYR, FLASH_KEY2); + 80021f2: f102 3288 add.w r2, r2, #2290649224 ; 0x88888888 + 80021f6: 609a str r2, [r3, #8] + if(READ_BIT(FLASH->CR, FLASH_CR_LOCK)) { + 80021f8: 695b ldr r3, [r3, #20] + 80021fa: 2b00 cmp r3, #0 + 80021fc: da02 bge.n 8002204 + INCONSISTENT("failed to unlock"); + 80021fe: 4804 ldr r0, [pc, #16] ; (8002210 ) + 8002200: f7fe fc1a bl 8000a38 +} + 8002204: bd08 pop {r3, pc} + 8002206: bf00 nop + 8002208: 40022000 .word 0x40022000 + 800220c: 45670123 .word 0x45670123 + 8002210: 0800d9a0 .word 0x0800d9a0 + +08002214 : +{ + 8002214: b510 push {r4, lr} + if(!lock) { + 8002216: b980 cbnz r0, 800223a + if(READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK)) { + 8002218: 4c0a ldr r4, [pc, #40] ; (8002244 ) + 800221a: 6963 ldr r3, [r4, #20] + 800221c: 005a lsls r2, r3, #1 + 800221e: d510 bpl.n 8002242 + flash_unlock(); + 8002220: f7ff ffe0 bl 80021e4 + WRITE_REG(FLASH->OPTKEYR, FLASH_OPTKEY1); + 8002224: 4b08 ldr r3, [pc, #32] ; (8002248 ) + 8002226: 60e3 str r3, [r4, #12] + WRITE_REG(FLASH->OPTKEYR, FLASH_OPTKEY2); + 8002228: f103 3344 add.w r3, r3, #1145324612 ; 0x44444444 + 800222c: 60e3 str r3, [r4, #12] + if(READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK)) { + 800222e: 6963 ldr r3, [r4, #20] + 8002230: 005b lsls r3, r3, #1 + 8002232: d506 bpl.n 8002242 + INCONSISTENT("failed to OB unlock"); + 8002234: 4805 ldr r0, [pc, #20] ; (800224c ) + 8002236: f7fe fbff bl 8000a38 +} + 800223a: e8bd 4010 ldmia.w sp!, {r4, lr} + 800223e: f7ff bf81 b.w 8002144 + 8002242: bd10 pop {r4, pc} + 8002244: 40022000 .word 0x40022000 + 8002248: 08192a3b .word 0x08192a3b + 800224c: 0800d9a0 .word 0x0800d9a0 + +08002250 : +// +// Write the serial number of ATECC608 into flash forever. +// + void +flash_save_ae_serial(const uint8_t serial[9]) +{ + 8002250: b51f push {r0, r1, r2, r3, r4, lr} + 8002252: 4602 mov r2, r0 + uint64_t tmp[2]; + memset(&tmp, 0x0, sizeof(tmp)); + 8002254: 2300 movs r3, #0 + memcpy(&tmp, serial, 9); + 8002256: 6800 ldr r0, [r0, #0] + 8002258: 6851 ldr r1, [r2, #4] + 800225a: 7a12 ldrb r2, [r2, #8] + memset(&tmp, 0x0, sizeof(tmp)); + 800225c: e9cd 3302 strd r3, r3, [sp, #8] + memcpy(&tmp, serial, 9); + 8002260: 466b mov r3, sp + 8002262: c303 stmia r3!, {r0, r1} + 8002264: 701a strb r2, [r3, #0] + + flash_setup0(); + 8002266: f7ff ff99 bl 800219c + flash_unlock(); + 800226a: f7ff ffbb bl 80021e4 + + if(flash_burn((uint32_t)&rom_secrets->ae_serial_number[0], tmp[0])) { + 800226e: e9dd 2300 ldrd r2, r3, [sp] + 8002272: 4809 ldr r0, [pc, #36] ; (8002298 ) + 8002274: f00b fb8c bl 800d990 <__flash_burn_veneer> + 8002278: b110 cbz r0, 8002280 + INCONSISTENT("fail1"); + 800227a: 4808 ldr r0, [pc, #32] ; (800229c ) + 800227c: f7fe fbdc bl 8000a38 + } + if(flash_burn((uint32_t)&rom_secrets->ae_serial_number[1], tmp[1])) { + 8002280: e9dd 2302 ldrd r2, r3, [sp, #8] + 8002284: 4806 ldr r0, [pc, #24] ; (80022a0 ) + 8002286: f00b fb83 bl 800d990 <__flash_burn_veneer> + 800228a: 2800 cmp r0, #0 + 800228c: d1f5 bne.n 800227a + INCONSISTENT("fail2"); + } + + flash_lock(); +} + 800228e: b005 add sp, #20 + 8002290: f85d eb04 ldr.w lr, [sp], #4 + flash_lock(); + 8002294: f7ff bf9e b.w 80021d4 + 8002298: 0801c040 .word 0x0801c040 + 800229c: 0800d9a0 .word 0x0800d9a0 + 80022a0: 0801c048 .word 0x0801c048 + +080022a4 : +// +// Write bag number (probably a string) +// + void +flash_save_bag_number(const uint8_t new_number[32]) +{ + 80022a4: b570 push {r4, r5, r6, lr} + 80022a6: b088 sub sp, #32 + uint32_t dest = (uint32_t)&rom_secrets->bag_number[0]; + uint64_t tmp[4] = { 0 }; + uint64_t *src = tmp; + + STATIC_ASSERT(sizeof(tmp) == 32); + memcpy(tmp, new_number, 32); + 80022a8: 4603 mov r3, r0 + 80022aa: 466c mov r4, sp + 80022ac: f100 0520 add.w r5, r0, #32 + 80022b0: 6818 ldr r0, [r3, #0] + 80022b2: 6859 ldr r1, [r3, #4] + 80022b4: 4622 mov r2, r4 + 80022b6: c203 stmia r2!, {r0, r1} + 80022b8: 3308 adds r3, #8 + 80022ba: 42ab cmp r3, r5 + 80022bc: 4614 mov r4, r2 + 80022be: d1f7 bne.n 80022b0 + + flash_setup0(); + 80022c0: f7ff ff6c bl 800219c + flash_unlock(); + 80022c4: f7ff ff8e bl 80021e4 + uint32_t dest = (uint32_t)&rom_secrets->bag_number[0]; + 80022c8: 4d09 ldr r5, [pc, #36] ; (80022f0 ) + + // NOTE: can only write once! No provision for read/check/update. + for(int i=0; i<(32/8); i++, dest+=8, src++) { + 80022ca: 4e0a ldr r6, [pc, #40] ; (80022f4 ) + 80022cc: 466c mov r4, sp + if(flash_burn(dest, *src)) { + 80022ce: e8f4 2302 ldrd r2, r3, [r4], #8 + 80022d2: 4628 mov r0, r5 + 80022d4: f00b fb5c bl 800d990 <__flash_burn_veneer> + 80022d8: b110 cbz r0, 80022e0 + INCONSISTENT("fail write"); + 80022da: 4807 ldr r0, [pc, #28] ; (80022f8 ) + 80022dc: f7fe fbac bl 8000a38 + for(int i=0; i<(32/8); i++, dest+=8, src++) { + 80022e0: 3508 adds r5, #8 + 80022e2: 42b5 cmp r5, r6 + 80022e4: d1f3 bne.n 80022ce + } + } + + flash_lock(); +} + 80022e6: b008 add sp, #32 + 80022e8: e8bd 4070 ldmia.w sp!, {r4, r5, r6, lr} + flash_lock(); + 80022ec: f7ff bf72 b.w 80021d4 + 80022f0: 0801c050 .word 0x0801c050 + 80022f4: 0801c070 .word 0x0801c070 + 80022f8: 0800d9a0 .word 0x0800d9a0 + +080022fc : +// Save bunch of stuff related to SE2. Allow updates to sections that are +// given as ones at this point. +// + void +flash_save_se2_data(const se2_secrets_t *se2) +{ + 80022fc: e92d 41f3 stmdb sp!, {r0, r1, r4, r5, r6, r7, r8, lr} + 8002300: 4605 mov r5, r0 + uint8_t *dest = (uint8_t *)&rom_secrets->se2; + 8002302: 4c1a ldr r4, [pc, #104] ; (800236c ) + STATIC_ASSERT(offsetof(rom_secrets_t, se2) % 8 == 0); + + flash_setup0(); + flash_unlock(); + + for(int i=0; i<(sizeof(se2_secrets_t)/8); i++, dest+=8, src+=8) { + 8002304: f8df 8070 ldr.w r8, [pc, #112] ; 8002378 + flash_setup0(); + 8002308: f7ff ff48 bl 800219c + flash_unlock(); + 800230c: f7ff ff6a bl 80021e4 + for(int i=0; i<(sizeof(se2_secrets_t)/8); i++, dest+=8, src+=8) { + 8002310: 1b2d subs r5, r5, r4 + 8002312: eb05 0c04 add.w ip, r5, r4 + uint64_t val; + memcpy(&val, src, sizeof(val)); + 8002316: 5928 ldr r0, [r5, r4] + 8002318: f8dc 1004 ldr.w r1, [ip, #4] + 800231c: 466b mov r3, sp + + // don't write if all ones or already written correctly + if(val == ~0) continue; + 800231e: f1b1 3fff cmp.w r1, #4294967295 ; 0xffffffff + 8002322: bf08 it eq + 8002324: f1b0 3fff cmpeq.w r0, #4294967295 ; 0xffffffff + memcpy(&val, src, sizeof(val)); + 8002328: c303 stmia r3!, {r0, r1} + if(val == ~0) continue; + 800232a: 4607 mov r7, r0 + 800232c: 460e mov r6, r1 + 800232e: d015 beq.n 800235c + if(check_equal(dest, src, 8)) continue; + 8002330: 2208 movs r2, #8 + 8002332: 4661 mov r1, ip + 8002334: 4620 mov r0, r4 + 8002336: f000 fa82 bl 800283e + 800233a: b978 cbnz r0, 800235c + + // can't write if not ones already + ASSERT(check_all_ones(dest, 8)); + 800233c: 2108 movs r1, #8 + 800233e: 4620 mov r0, r4 + 8002340: f000 fa64 bl 800280c + 8002344: b910 cbnz r0, 800234c + 8002346: 480a ldr r0, [pc, #40] ; (8002370 ) + + if(flash_burn((uint32_t)dest, val)) { + INCONSISTENT("fail write"); + 8002348: f7fe fb76 bl 8000a38 + if(flash_burn((uint32_t)dest, val)) { + 800234c: 463a mov r2, r7 + 800234e: 4633 mov r3, r6 + 8002350: 4620 mov r0, r4 + 8002352: f00b fb1d bl 800d990 <__flash_burn_veneer> + 8002356: b108 cbz r0, 800235c + INCONSISTENT("fail write"); + 8002358: 4806 ldr r0, [pc, #24] ; (8002374 ) + 800235a: e7f5 b.n 8002348 + for(int i=0; i<(sizeof(se2_secrets_t)/8); i++, dest+=8, src+=8) { + 800235c: 3408 adds r4, #8 + 800235e: 4544 cmp r4, r8 + 8002360: d1d7 bne.n 8002312 + } + } + + flash_lock(); +} + 8002362: b002 add sp, #8 + 8002364: e8bd 41f0 ldmia.w sp!, {r4, r5, r6, r7, r8, lr} + flash_lock(); + 8002368: f7ff bf34 b.w 80021d4 + 800236c: 0801c0b0 .word 0x0801c0b0 + 8002370: 0801046c .word 0x0801046c + 8002374: 0800d9a0 .word 0x0800d9a0 + 8002378: 0801c190 .word 0x0801c190 + +0800237c : +// +// This is really a state-machine, to recover boards that are booted w/ missing AE chip. +// + void +flash_setup(void) +{ + 800237c: e92d 43f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, lr} + + // see if we have picked a pairing secret yet. + // NOTE: critical section for glitching (at least in past versions) + // - check_all.. functions have a rng_delay in them already + rng_delay(); + bool blank_ps = check_all_ones(rom_secrets->pairing_secret, 32); + 8002380: 4e58 ldr r6, [pc, #352] ; (80024e4 ) +{ + 8002382: b08b sub sp, #44 ; 0x2c + flash_setup0(); + 8002384: f7ff ff0a bl 800219c + rng_delay(); + 8002388: f000 fabe bl 8002908 + bool blank_ps = check_all_ones(rom_secrets->pairing_secret, 32); + 800238c: 2120 movs r1, #32 + 800238e: 4630 mov r0, r6 + 8002390: f000 fa3c bl 800280c + bool zeroed_ps = check_all_zeros(rom_secrets->pairing_secret, 32); + 8002394: 2120 movs r1, #32 + bool blank_ps = check_all_ones(rom_secrets->pairing_secret, 32); + 8002396: 4681 mov r9, r0 + bool zeroed_ps = check_all_zeros(rom_secrets->pairing_secret, 32); + 8002398: 4630 mov r0, r6 + 800239a: f000 fa41 bl 8002820 + bool blank_xor = check_all_ones(rom_secrets->pairing_secret_xor, 32); + 800239e: 2120 movs r1, #32 + bool zeroed_ps = check_all_zeros(rom_secrets->pairing_secret, 32); + 80023a0: 4604 mov r4, r0 + bool blank_xor = check_all_ones(rom_secrets->pairing_secret_xor, 32); + 80023a2: 4851 ldr r0, [pc, #324] ; (80024e8 ) + 80023a4: f000 fa32 bl 800280c + bool blank_ae = (~rom_secrets->ae_serial_number[0] == 0); + 80023a8: e9d6 7810 ldrd r7, r8, [r6, #64] ; 0x40 + bool blank_xor = check_all_ones(rom_secrets->pairing_secret_xor, 32); + 80023ac: 4605 mov r5, r0 + rng_delay(); + 80023ae: f000 faab bl 8002908 + + if(zeroed_ps) { + 80023b2: b124 cbz r4, 80023be + // fast brick process leaves us w/ zero pairing secret + oled_show(screen_brick); + 80023b4: 484d ldr r0, [pc, #308] ; (80024ec ) + 80023b6: f7fe fe5d bl 8001074 + // Hardware fail speaking to AE chip ... be careful not to brick here. + // Do not continue!! We might fix the board, or add missing pullup, etc. + oled_show(screen_se1_issue); + puts("SE1 config fail"); + + LOCKUP_FOREVER(); + 80023ba: f001 fc5d bl 8003c78 + if(blank_ps) { + 80023be: f1b9 0f00 cmp.w r9, #0 + 80023c2: d03e beq.n 8002442 + rng_setup(); + 80023c4: f000 fa5e bl 8002884 + oled_show(screen_se_setup); + 80023c8: 4849 ldr r0, [pc, #292] ; (80024f0 ) + 80023ca: f7fe fe53 bl 8001074 + for(int i=0; i<8; i++) { + 80023ce: ae02 add r6, sp, #8 + oled_show(screen_se_setup); + 80023d0: 46b1 mov r9, r6 + secret[i] = rng_sample(); + 80023d2: f000 fa45 bl 8002860 + for(int i=0; i<8; i++) { + 80023d6: 3401 adds r4, #1 + 80023d8: 2c08 cmp r4, #8 + secret[i] = rng_sample(); + 80023da: f849 0b04 str.w r0, [r9], #4 + for(int i=0; i<8; i++) { + 80023de: d1f8 bne.n 80023d2 + while(secret[0] == ~0) { + 80023e0: 9b02 ldr r3, [sp, #8] + 80023e2: 3301 adds r3, #1 + 80023e4: d00d beq.n 8002402 + flash_unlock(); + 80023e6: f7ff fefd bl 80021e4 + uint32_t dest = (uint32_t)&rom_secrets->pairing_secret; + 80023ea: 4c3e ldr r4, [pc, #248] ; (80024e4 ) + for(int i=0; i<8; i+=2, dest += 8) { + 80023ec: f8df 90f8 ldr.w r9, [pc, #248] ; 80024e8 + if(flash_burn(dest, val)) { + 80023f0: e9d6 3200 ldrd r3, r2, [r6] + 80023f4: 4620 mov r0, r4 + 80023f6: f00b facb bl 800d990 <__flash_burn_veneer> + 80023fa: b130 cbz r0, 800240a + INCONSISTENT("flash fail"); + 80023fc: 483d ldr r0, [pc, #244] ; (80024f4 ) + 80023fe: f7fe fb1b bl 8000a38 + secret[0] = rng_sample(); + 8002402: f000 fa2d bl 8002860 + 8002406: 9002 str r0, [sp, #8] + 8002408: e7ea b.n 80023e0 + for(int i=0; i<8; i+=2, dest += 8) { + 800240a: 3408 adds r4, #8 + 800240c: 454c cmp r4, r9 + 800240e: f106 0608 add.w r6, r6, #8 + 8002412: d1ed bne.n 80023f0 + flash_lock(); + 8002414: f7ff fede bl 80021d4 + flash_unlock(); + 8002418: f7ff fee4 bl 80021e4 + uint32_t dest = (uint32_t)&rom_secrets->hash_cache_secret; + 800241c: 4c36 ldr r4, [pc, #216] ; (80024f8 ) + for(int i=0; i) + uint64_t val = ((uint64_t)rng_sample() << 32) | rng_sample(); + 8002420: f000 fa1e bl 8002860 + 8002424: 9001 str r0, [sp, #4] + 8002426: f000 fa1b bl 8002860 + if(flash_burn(dest, val)) { + 800242a: 9b01 ldr r3, [sp, #4] + uint64_t val = ((uint64_t)rng_sample() << 32) | rng_sample(); + 800242c: 4602 mov r2, r0 + if(flash_burn(dest, val)) { + 800242e: 4620 mov r0, r4 + 8002430: f00b faae bl 800d990 <__flash_burn_veneer> + 8002434: 2800 cmp r0, #0 + 8002436: d1e1 bne.n 80023fc + for(int i=0; i + flash_lock(); + 800243e: f7ff fec9 bl 80021d4 + if(blank_xor || blank_ae) { + 8002442: b92d cbnz r5, 8002450 + 8002444: f1b8 3fff cmp.w r8, #4294967295 ; 0xffffffff + 8002448: bf08 it eq + 800244a: f1b7 3fff cmpeq.w r7, #4294967295 ; 0xffffffff + 800244e: d126 bne.n 800249e + se2_setup_config(); + 8002450: f005 fb94 bl 8007b7c + int rv = ae_setup_config(); + 8002454: f001 f992 bl 800377c + 8002458: 4604 mov r4, r0 + rng_delay(); + 800245a: f000 fa55 bl 8002908 + if(rv) { + 800245e: b134 cbz r4, 800246e + oled_show(screen_se1_issue); + 8002460: 4827 ldr r0, [pc, #156] ; (8002500 ) + 8002462: f7fe fe07 bl 8001074 + puts("SE1 config fail"); + 8002466: 4827 ldr r0, [pc, #156] ; (8002504 ) + 8002468: f002 fdfe bl 8005068 + 800246c: e7a5 b.n 80023ba + } + + rng_delay(); + 800246e: f000 fa4b bl 8002908 + if(blank_xor) { + 8002472: b195 cbz r5, 800249a + flash_unlock(); + 8002474: f7ff feb6 bl 80021e4 + uint64_t *src = (uint64_t *)&rom_secrets->pairing_secret; + 8002478: 4c1a ldr r4, [pc, #104] ; (80024e4 ) + for(int i=0; i<(32/8); i++, dest+=8, src++) { + 800247a: 4e1b ldr r6, [pc, #108] ; (80024e8 ) + uint64_t val = ~(*src); + 800247c: e9d4 2300 ldrd r2, r3, [r4] + if(flash_burn(dest, val)) { + 8002480: f104 0020 add.w r0, r4, #32 + 8002484: 43d2 mvns r2, r2 + 8002486: 43db mvns r3, r3 + 8002488: f00b fa82 bl 800d990 <__flash_burn_veneer> + 800248c: 2800 cmp r0, #0 + 800248e: d1b5 bne.n 80023fc + for(int i=0; i<(32/8); i++, dest+=8, src++) { + 8002490: 3408 adds r4, #8 + 8002492: 42b4 cmp r4, r6 + 8002494: d1f2 bne.n 800247c + flash_lock(); + 8002496: f7ff fe9d bl 80021d4 + + // real power cycle required now. +#ifdef FOR_Q1_ONLY + // Q: just do it (we warned them) + extern void turn_power_off(void); + turn_power_off(); + 800249a: f001 fbe1 bl 8003c60 + puts("replug required"); + LOCKUP_FOREVER(); +#endif + } + + rng_delay(); + 800249e: f000 fa33 bl 8002908 + if(!blank_ps && !blank_xor) { + 80024a2: b9e5 cbnz r5, 80024de + // check the XOR value also written: 2 phase commit + uint8_t tmp[32]; + memcpy(tmp, rom_secrets->pairing_secret, 32); + 80024a4: 4d0f ldr r5, [pc, #60] ; (80024e4 ) + 80024a6: cd0f ldmia r5!, {r0, r1, r2, r3} + 80024a8: ac02 add r4, sp, #8 + 80024aa: c40f stmia r4!, {r0, r1, r2, r3} + 80024ac: e895 000f ldmia.w r5, {r0, r1, r2, r3} + 80024b0: e884 000f stmia.w r4, {r0, r1, r2, r3} + 80024b4: ab02 add r3, sp, #8 + 80024b6: 4a0c ldr r2, [pc, #48] ; (80024e8 ) +bool check_equal(const void *aV, const void *bV, int len); + +// XOR-mixin more bytes; acc = acc XOR more for each byte +void static inline xor_mixin(uint8_t *acc, const uint8_t *more, int len) +{ + for(; len; len--, more++, acc++) { + 80024b8: 4c13 ldr r4, [pc, #76] ; (8002508 ) + 80024ba: 4618 mov r0, r3 + *(acc) ^= *(more); + 80024bc: 7819 ldrb r1, [r3, #0] + 80024be: f812 5b01 ldrb.w r5, [r2], #1 + 80024c2: 4069 eors r1, r5 + for(; len; len--, more++, acc++) { + 80024c4: 42a2 cmp r2, r4 + *(acc) ^= *(more); + 80024c6: f803 1b01 strb.w r1, [r3], #1 + for(; len; len--, more++, acc++) { + 80024ca: d1f7 bne.n 80024bc + xor_mixin(tmp, rom_secrets->pairing_secret_xor, 32); + + if(!check_all_ones(tmp, 32)) { + 80024cc: 2120 movs r1, #32 + 80024ce: f000 f99d bl 800280c + 80024d2: b920 cbnz r0, 80024de + oled_show(screen_corrupt); + 80024d4: 480d ldr r0, [pc, #52] ; (800250c ) + 80024d6: f7fe fdcd bl 8001074 + puts("corrupt pair sec"); + 80024da: 480d ldr r0, [pc, #52] ; (8002510 ) + 80024dc: e7c4 b.n 8002468 + // That's fine if we intend to ship units locked already. + + // Do NOT do write every boot, as it might wear-out + // the flash bits in OB. + +} + 80024de: b00b add sp, #44 ; 0x2c + 80024e0: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + 80024e4: 0801c000 .word 0x0801c000 + 80024e8: 0801c020 .word 0x0801c020 + 80024ec: 0800da61 .word 0x0800da61 + 80024f0: 0800f671 .word 0x0800f671 + 80024f4: 0800d9a0 .word 0x0800d9a0 + 80024f8: 0801c070 .word 0x0801c070 + 80024fc: 0801c0b0 .word 0x0801c0b0 + 8002500: 0800f13a .word 0x0800f13a + 8002504: 08010666 .word 0x08010666 + 8002508: 0801c040 .word 0x0801c040 + 800250c: 0800db0d .word 0x0800db0d + 8002510: 08010676 .word 0x08010676 + +08002514 : +// +// This is a one-way trip. Might need power cycle to (fully?) take effect. +// + void +flash_lockdown_hard(uint8_t rdp_level_code) +{ + 8002514: b510 push {r4, lr} + 8002516: 4604 mov r4, r0 +#if RELEASE + flash_setup0(); + 8002518: f7ff fe40 bl 800219c + + // see FLASH_OB_WRPConfig() + + flash_ob_lock(false); + 800251c: 2000 movs r0, #0 + 800251e: f7ff fe79 bl 8002214 + // lock first 128k-8k against any writes + FLASH->WRP1AR = (num_pages_locked << 16); + 8002522: 4b08 ldr r3, [pc, #32] ; (8002544 ) + 8002524: f44f 2260 mov.w r2, #917504 ; 0xe0000 + 8002528: 62da str r2, [r3, #44] ; 0x2c + FLASH->WRP1BR = 0xff; // unused. + 800252a: 22ff movs r2, #255 ; 0xff + 800252c: 631a str r2, [r3, #48] ; 0x30 + FLASH->WRP2AR = 0xff; // unused. + 800252e: 64da str r2, [r3, #76] ; 0x4c + FLASH->WRP2BR = 0xff; // unused. + 8002530: 651a str r2, [r3, #80] ; 0x50 + // the RDP level is decreased from Level 1 to Level 0)." + // - D-bus access blocked, even for code running inside the PCROP area! (AN4758) + // So literal values and constant tables and such would need special linking. + + // set protection level + uint32_t was = FLASH->OPTR & ~0xff; + 8002532: 6a1a ldr r2, [r3, #32] + 8002534: f022 02ff bic.w r2, r2, #255 ; 0xff + FLASH->OPTR = was | rdp_level_code; // select level X, other values as observed + 8002538: 4322 orrs r2, r4 + 800253a: 621a str r2, [r3, #32] +#else + puts2("flash_lockdown_hard("); + puthex2(rdp_level_code); + puts(") skipped"); +#endif +} + 800253c: e8bd 4010 ldmia.w sp!, {r4, lr} + 8002540: f7ff be00 b.w 8002144 + 8002544: 40022000 .word 0x40022000 + +08002548 : + +// record_highwater_version() +// + int +record_highwater_version(const uint8_t timestamp[8]) +{ + 8002548: b537 push {r0, r1, r2, r4, r5, lr} + const uint8_t *otp = (const uint8_t *)OPT_FLASH_BASE; + + ASSERT(timestamp[0] < 0x40); + ASSERT(timestamp[0] >= 0x10); + 800254a: 7802 ldrb r2, [r0, #0] + 800254c: 3a10 subs r2, #16 + 800254e: 2a2f cmp r2, #47 ; 0x2f +{ + 8002550: 4603 mov r3, r0 + ASSERT(timestamp[0] >= 0x10); + 8002552: d902 bls.n 800255a + ASSERT(timestamp[0] < 0x40); + 8002554: 4810 ldr r0, [pc, #64] ; (8002598 ) + 8002556: f7fe fa6f bl 8000a38 + + uint64_t val = 0; + memcpy(&val, timestamp, 8); + 800255a: 6800 ldr r0, [r0, #0] + 800255c: 6859 ldr r1, [r3, #4] + const uint8_t *otp = (const uint8_t *)OPT_FLASH_BASE; + 800255e: 4c0f ldr r4, [pc, #60] ; (800259c ) + + // just write to first blank slot we can find. + for(int i=0; i) + memcpy(&val, timestamp, 8); + 8002562: 466a mov r2, sp + 8002564: c203 stmia r2!, {r0, r1} + if(check_all_ones(otp, 8)) { + 8002566: 2108 movs r1, #8 + 8002568: 4620 mov r0, r4 + 800256a: f000 f94f bl 800280c + 800256e: b168 cbz r0, 800258c + // write here. + flash_setup0(); + 8002570: f7ff fe14 bl 800219c + flash_unlock(); + 8002574: f7ff fe36 bl 80021e4 + flash_burn((uint32_t)otp, val); + 8002578: e9dd 2300 ldrd r2, r3, [sp] + 800257c: 4620 mov r0, r4 + 800257e: f00b fa07 bl 800d990 <__flash_burn_veneer> + flash_lock(); + 8002582: f7ff fe27 bl 80021d4 + + return 0; + 8002586: 2000 movs r0, #0 + } + } + + // no space. + return 1; +} + 8002588: b003 add sp, #12 + 800258a: bd30 pop {r4, r5, pc} + for(int i=0; i + return 1; + 8002592: 2001 movs r0, #1 + 8002594: e7f8 b.n 8002588 + 8002596: bf00 nop + 8002598: 0801046c .word 0x0801046c + 800259c: 1fff7000 .word 0x1fff7000 + 80025a0: 1fff7400 .word 0x1fff7400 + +080025a4 : + +// mcu_key_get() +// + const mcu_key_t * +mcu_key_get(bool *valid) +{ + 80025a4: b570 push {r4, r5, r6, lr} + // get current "mcu_key" value; first byte will never be 0x0 or 0xff + // - except if no key set yet/recently wiped + // - if none set, returns ptr to first available slot which will be all ones + const mcu_key_t *ptr = MCU_KEYS, *avail=NULL; + + for(int i=0; i) + const mcu_key_t *ptr = MCU_KEYS, *avail=NULL; + 80025a8: 4c0d ldr r4, [pc, #52] ; (80025e0 ) +{ + 80025aa: 4606 mov r6, r0 + const mcu_key_t *ptr = MCU_KEYS, *avail=NULL; + 80025ac: 2500 movs r5, #0 + if(ptr->value[0] == 0xff) { + 80025ae: 7823 ldrb r3, [r4, #0] + 80025b0: 2bff cmp r3, #255 ; 0xff + 80025b2: d10b bne.n 80025cc + if(!avail) { + 80025b4: 2d00 cmp r5, #0 + 80025b6: bf08 it eq + 80025b8: 4625 moveq r5, r4 + for(int i=0; i + *valid = true; + return ptr; + } + } + + rng_delay(); + 80025c0: f000 f9a2 bl 8002908 + *valid = false; + 80025c4: 2300 movs r3, #0 + 80025c6: 7033 strb r3, [r6, #0] + return avail; + 80025c8: 462c mov r4, r5 + 80025ca: e005 b.n 80025d8 + } else if(ptr->value[0] != 0x00) { + 80025cc: 2b00 cmp r3, #0 + 80025ce: d0f4 beq.n 80025ba + rng_delay(); + 80025d0: f000 f99a bl 8002908 + *valid = true; + 80025d4: 2301 movs r3, #1 + 80025d6: 7033 strb r3, [r6, #0] +} + 80025d8: 4620 mov r0, r4 + 80025da: bd70 pop {r4, r5, r6, pc} + 80025dc: 08020000 .word 0x08020000 + 80025e0: 0801e000 .word 0x0801e000 + +080025e4 : + +// mcu_key_clear() +// + void +mcu_key_clear(const mcu_key_t *cur) +{ + 80025e4: b513 push {r0, r1, r4, lr} + if(!cur) { + 80025e6: 4604 mov r4, r0 + 80025e8: b938 cbnz r0, 80025fa + bool valid; + cur = mcu_key_get(&valid); + 80025ea: f10d 0007 add.w r0, sp, #7 + 80025ee: f7ff ffd9 bl 80025a4 + + if(!valid) return; + 80025f2: f89d 3007 ldrb.w r3, [sp, #7] + cur = mcu_key_get(&valid); + 80025f6: 4604 mov r4, r0 + if(!valid) return; + 80025f8: b1fb cbz r3, 800263a + } + + // no delays here since decision has been made, and don't + // want to give them more time to interrupt us + flash_setup0(); + 80025fa: f7ff fdcf bl 800219c + flash_unlock(); + 80025fe: f7ff fdf1 bl 80021e4 + uint32_t pos = (uint32_t)cur; + flash_burn(pos, 0); pos += 8; + 8002602: 2200 movs r2, #0 + 8002604: 2300 movs r3, #0 + 8002606: 4620 mov r0, r4 + 8002608: f00b f9c2 bl 800d990 <__flash_burn_veneer> + flash_burn(pos, 0); pos += 8; + 800260c: 2200 movs r2, #0 + 800260e: 2300 movs r3, #0 + 8002610: f104 0008 add.w r0, r4, #8 + 8002614: f00b f9bc bl 800d990 <__flash_burn_veneer> + flash_burn(pos, 0); pos += 8; + 8002618: 2200 movs r2, #0 + 800261a: 2300 movs r3, #0 + 800261c: f104 0010 add.w r0, r4, #16 + 8002620: f00b f9b6 bl 800d990 <__flash_burn_veneer> + flash_burn(pos, 0); + 8002624: 2200 movs r2, #0 + 8002626: 2300 movs r3, #0 + 8002628: f104 0018 add.w r0, r4, #24 + 800262c: f00b f9b0 bl 800d990 <__flash_burn_veneer> + flash_lock(); +} + 8002630: b002 add sp, #8 + 8002632: e8bd 4010 ldmia.w sp!, {r4, lr} + flash_lock(); + 8002636: f7ff bdcd b.w 80021d4 +} + 800263a: b002 add sp, #8 + 800263c: bd10 pop {r4, pc} + ... + +08002640 : + +// mcu_key_usage() +// + void +mcu_key_usage(int *avail_out, int *consumed_out, int *total_out) +{ + 8002640: b5f0 push {r4, r5, r6, r7, lr} + const mcu_key_t *ptr = MCU_KEYS; + int avail = 0, used = 0; + 8002642: 2300 movs r3, #0 + const mcu_key_t *ptr = MCU_KEYS; + 8002644: 4c09 ldr r4, [pc, #36] ; (800266c ) + + for(int i=0; i) + int avail = 0, used = 0; + 8002648: 461d mov r5, r3 + if(ptr->value[0] == 0xff) { + 800264a: 7826 ldrb r6, [r4, #0] + 800264c: 2eff cmp r6, #255 ; 0xff + 800264e: d109 bne.n 8002664 + avail ++; + 8002650: 3501 adds r5, #1 + for(int i=0; i + } else if(ptr->value[0] == 0x00) { + used ++; + } + } + + *avail_out = avail; + 8002658: 6005 str r5, [r0, #0] + *consumed_out = used; + 800265a: 600b str r3, [r1, #0] + *total_out = NUM_MCU_KEYS; + 800265c: f44f 7380 mov.w r3, #256 ; 0x100 + 8002660: 6013 str r3, [r2, #0] +} + 8002662: bdf0 pop {r4, r5, r6, r7, pc} + } else if(ptr->value[0] == 0x00) { + 8002664: 2e00 cmp r6, #0 + 8002666: d1f4 bne.n 8002652 + used ++; + 8002668: 3301 adds r3, #1 + 800266a: e7f2 b.n 8002652 + 800266c: 0801e000 .word 0x0801e000 + 8002670: 08020000 .word 0x08020000 + +08002674 : + +// mcu_key_pick() +// + const mcu_key_t * +mcu_key_pick(void) +{ + 8002674: b5f0 push {r4, r5, r6, r7, lr} + 8002676: b08b sub sp, #44 ; 0x2c + mcu_key_t n; + + // get some good entropy, and whiten it just in case. + do { + rng_buffer(n.value, 32); + 8002678: ad02 add r5, sp, #8 + 800267a: 2120 movs r1, #32 + 800267c: 4628 mov r0, r5 + 800267e: f000 f92d bl 80028dc + sha256_single(n.value, 32, n.value); + 8002682: 462a mov r2, r5 + 8002684: 2120 movs r1, #32 + 8002686: 4628 mov r0, r5 + 8002688: f003 f8e0 bl 800584c + sha256_single(n.value, 32, n.value); + 800268c: 462a mov r2, r5 + 800268e: 2120 movs r1, #32 + 8002690: 4628 mov r0, r5 + 8002692: f003 f8db bl 800584c + } while(n.value[0] == 0x0 || n.value[0] == 0xff); + 8002696: f89d 3008 ldrb.w r3, [sp, #8] + 800269a: 3b01 subs r3, #1 + 800269c: b2db uxtb r3, r3 + 800269e: 2bfd cmp r3, #253 ; 0xfd + 80026a0: d8eb bhi.n 800267a + + int err = 0; + const mcu_key_t *cur; + + do { + bool valid = false; + 80026a2: 2300 movs r3, #0 + cur = mcu_key_get(&valid); + 80026a4: 4668 mov r0, sp + bool valid = false; + 80026a6: f88d 3000 strb.w r3, [sp] + cur = mcu_key_get(&valid); + 80026aa: f7ff ff7b bl 80025a4 + + if(!cur) { + 80026ae: 4604 mov r4, r0 + 80026b0: b938 cbnz r0, 80026c2 + // no free slots. we are brick. + puts("mcu full"); + 80026b2: 4828 ldr r0, [pc, #160] ; (8002754 ) + 80026b4: f002 fcd8 bl 8005068 + oled_show(screen_brick); + 80026b8: 4827 ldr r0, [pc, #156] ; (8002758 ) + 80026ba: f7fe fcdb bl 8001074 + + LOCKUP_FOREVER(); + 80026be: f001 fadb bl 8003c78 + } + + if(valid) { + 80026c2: f89d 3000 ldrb.w r3, [sp] + 80026c6: b14b cbz r3, 80026dc + // clear existing key, if it's defined. + ASSERT(cur->value[0] != 0x00); + 80026c8: 7803 ldrb r3, [r0, #0] + 80026ca: 3b01 subs r3, #1 + 80026cc: b2db uxtb r3, r3 + 80026ce: 2bfd cmp r3, #253 ; 0xfd + 80026d0: d902 bls.n 80026d8 + 80026d2: 4822 ldr r0, [pc, #136] ; (800275c ) + 80026d4: f7fe f9b0 bl 8000a38 + ASSERT(cur->value[0] != 0xff); + + mcu_key_clear(cur); + 80026d8: f7ff ff84 bl 80025e4 + continue; + } + } while(0); + + // burn it + flash_setup0(); + 80026dc: f7ff fd5e bl 800219c + flash_unlock(); + 80026e0: f7ff fd80 bl 80021e4 + uint32_t pos = (uint32_t)cur; + const uint8_t *fr = n.value; + + for(int i=0; i<32; i+= 8, pos += 8, fr += 8) { + 80026e4: 2700 movs r7, #0 + uint64_t v; + memcpy(&v, fr, sizeof(v)); + 80026e6: 19ea adds r2, r5, r7 + 80026e8: 59e8 ldr r0, [r5, r7] + 80026ea: 6851 ldr r1, [r2, #4] + 80026ec: 466b mov r3, sp + 80026ee: c303 stmia r3!, {r0, r1} + + err = flash_burn(pos, v); + 80026f0: 19e0 adds r0, r4, r7 + 80026f2: e9dd 2300 ldrd r2, r3, [sp] + 80026f6: f00b f94b bl 800d990 <__flash_burn_veneer> + if(err) break; + 80026fa: 4606 mov r6, r0 + 80026fc: b910 cbnz r0, 8002704 + for(int i=0; i<32; i+= 8, pos += 8, fr += 8) { + 80026fe: 3708 adds r7, #8 + 8002700: 2f20 cmp r7, #32 + 8002702: d1f0 bne.n 80026e6 + } + flash_lock(); + 8002704: f7ff fd66 bl 80021d4 + + // NOTE: Errors not expected, but lets be graceful about them. + + if(err) { + 8002708: b166 cbz r6, 8002724 + // what to do? + puts("burn fail: "); + 800270a: 4815 ldr r0, [pc, #84] ; (8002760 ) + 800270c: f002 fcac bl 8005068 + puthex2(err); + 8002710: b2f0 uxtb r0, r6 + 8002712: f002 fc4d bl 8004fb0 + putchar('\n'); + 8002716: 200a movs r0, #10 + 8002718: f002 fc2c bl 8004f74 + return NULL; + } + + if(after != cur || !check_equal(after->value, n.value, 32)) { + puts("bad val?"); + return NULL; + 800271c: 2400 movs r4, #0 + } + + return cur; +} + 800271e: 4620 mov r0, r4 + 8002720: b00b add sp, #44 ; 0x2c + 8002722: bdf0 pop {r4, r5, r6, r7, pc} + const mcu_key_t *after = mcu_key_get(&valid); + 8002724: 4668 mov r0, sp + bool valid = false; + 8002726: f88d 6000 strb.w r6, [sp] + const mcu_key_t *after = mcu_key_get(&valid); + 800272a: f7ff ff3b bl 80025a4 + if(!valid) { + 800272e: f89d 2000 ldrb.w r2, [sp] + 8002732: b91a cbnz r2, 800273c + puts("!valid?"); + 8002734: 480b ldr r0, [pc, #44] ; (8002764 ) + puts("bad val?"); + 8002736: f002 fc97 bl 8005068 + 800273a: e7ef b.n 800271c + if(after != cur || !check_equal(after->value, n.value, 32)) { + 800273c: 4284 cmp r4, r0 + 800273e: d001 beq.n 8002744 + puts("bad val?"); + 8002740: 4809 ldr r0, [pc, #36] ; (8002768 ) + 8002742: e7f8 b.n 8002736 + if(after != cur || !check_equal(after->value, n.value, 32)) { + 8002744: 2220 movs r2, #32 + 8002746: 4629 mov r1, r5 + 8002748: f000 f879 bl 800283e + 800274c: 2800 cmp r0, #0 + 800274e: d1e6 bne.n 800271e + 8002750: e7f6 b.n 8002740 + 8002752: bf00 nop + 8002754: 08010687 .word 0x08010687 + 8002758: 0800da61 .word 0x0800da61 + 800275c: 0801046c .word 0x0801046c + 8002760: 08010690 .word 0x08010690 + 8002764: 0801069c .word 0x0801069c + 8002768: 080106a4 .word 0x080106a4 + +0800276c : + +// fast_brick() +// + void +fast_brick(void) +{ + 800276c: b538 push {r3, r4, r5, lr} +#ifndef RELEASE + puts2("DISABLED fast brick... "); + oled_show(screen_brick); +#else + // do a fast wipe of our key + mcu_key_clear(NULL); + 800276e: 2000 movs r0, #0 + 8002770: f7ff ff38 bl 80025e4 + + // brick SE1 for future + ae_brick_myself(); + 8002774: f001 f970 bl 8003a58 + + // NOTE: could brick SE1 (somewhat) by dec'ing the counter, which will + // invalidate all PIN hashes + + // no going back from that -- but for privacy, wipe more stuff + oled_show(screen_brick); + 8002778: 480e ldr r0, [pc, #56] ; (80027b4 ) + uint32_t bot = (uint32_t)MCU_KEYS; + flash_page_erase(bot); + + // 2: LFS area first, since holds settings (AES'ed w/ lost key, but yeah) + // 3: the firmware, not a secret anyway + for(uint32_t pos=(FLASH_BASE + 0x200000 - FLASH_ERASE_SIZE); + 800277a: 4c0f ldr r4, [pc, #60] ; (80027b8 ) + 800277c: 4d0f ldr r5, [pc, #60] ; (80027bc ) + oled_show(screen_brick); + 800277e: f7fe fc79 bl 8001074 + puts2("fast brick... "); + 8002782: 480f ldr r0, [pc, #60] ; (80027c0 ) + 8002784: f002 fbe2 bl 8004f4c + flash_setup0(); + 8002788: f7ff fd08 bl 800219c + flash_unlock(); + 800278c: f7ff fd2a bl 80021e4 + flash_page_erase(bot); + 8002790: 480a ldr r0, [pc, #40] ; (80027bc ) + 8002792: f00b f901 bl 800d998 <__flash_page_erase_veneer> + pos > bot; pos -= FLASH_ERASE_SIZE) { + flash_page_erase(pos); + 8002796: 4620 mov r0, r4 + pos > bot; pos -= FLASH_ERASE_SIZE) { + 8002798: f5a4 5480 sub.w r4, r4, #4096 ; 0x1000 + flash_page_erase(pos); + 800279c: f00b f8fc bl 800d998 <__flash_page_erase_veneer> + for(uint32_t pos=(FLASH_BASE + 0x200000 - FLASH_ERASE_SIZE); + 80027a0: 42ac cmp r4, r5 + 80027a2: d1f8 bne.n 8002796 + } + flash_lock(); + puts(" done"); + 80027a4: 4807 ldr r0, [pc, #28] ; (80027c4 ) + flash_lock(); + 80027a6: f7ff fd15 bl 80021d4 + puts(" done"); + 80027aa: f002 fc5d bl 8005068 +#endif + + LOCKUP_FOREVER(); + 80027ae: f001 fa63 bl 8003c78 + 80027b2: bf00 nop + 80027b4: 0800da61 .word 0x0800da61 + 80027b8: 081ff000 .word 0x081ff000 + 80027bc: 0801e000 .word 0x0801e000 + 80027c0: 080106ad .word 0x080106ad + 80027c4: 080106bc .word 0x080106bc + +080027c8 : + +// fast_wipe() +// + void +fast_wipe(void) +{ + 80027c8: b508 push {r3, lr} + // dump (part of) the main seed key and become a new Coldcard + // - lots of other code can and will detect a missing MCU key as "blank" + // - and the check value on main seed will be garbage now + mcu_key_clear(NULL); + 80027ca: 2000 movs r0, #0 + 80027cc: f7ff ff0a bl 80025e4 + __ASM volatile ("dsb 0xF":::"memory"); + 80027d0: f3bf 8f4f dsb sy + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 80027d4: 4905 ldr r1, [pc, #20] ; (80027ec ) + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 80027d6: 4b06 ldr r3, [pc, #24] ; (80027f0 ) + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 80027d8: 68ca ldr r2, [r1, #12] + 80027da: f402 62e0 and.w r2, r2, #1792 ; 0x700 + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 80027de: 4313 orrs r3, r2 + 80027e0: 60cb str r3, [r1, #12] + 80027e2: f3bf 8f4f dsb sy + __NOP(); + 80027e6: bf00 nop + for(;;) /* wait until reset */ + 80027e8: e7fd b.n 80027e6 + 80027ea: bf00 nop + 80027ec: e000ed00 .word 0xe000ed00 + 80027f0: 05fa0004 .word 0x05fa0004 + +080027f4 : +check_all_ones_raw(const void *ptrV, int len) +{ + uint8_t rv = 0xff; + const uint8_t *ptr = (const uint8_t *)ptrV; + + for(; len; len--, ptr++) { + 80027f4: 4401 add r1, r0 + uint8_t rv = 0xff; + 80027f6: 23ff movs r3, #255 ; 0xff + for(; len; len--, ptr++) { + 80027f8: 4288 cmp r0, r1 + 80027fa: d103 bne.n 8002804 + rv &= *ptr; + } + + return (rv == 0xff); +} + 80027fc: 3bff subs r3, #255 ; 0xff + 80027fe: 4258 negs r0, r3 + 8002800: 4158 adcs r0, r3 + 8002802: 4770 bx lr + rv &= *ptr; + 8002804: f810 2b01 ldrb.w r2, [r0], #1 + 8002808: 4013 ands r3, r2 + for(; len; len--, ptr++) { + 800280a: e7f5 b.n 80027f8 + +0800280c : +// +// Return T if all bytes are 0xFF +// + bool +check_all_ones(const void *ptrV, int len) +{ + 800280c: b507 push {r0, r1, r2, lr} + bool rv = check_all_ones_raw(ptrV, len); + 800280e: f7ff fff1 bl 80027f4 + 8002812: 9001 str r0, [sp, #4] + + rng_delay(); + 8002814: f000 f878 bl 8002908 + + return rv; +} + 8002818: 9801 ldr r0, [sp, #4] + 800281a: b003 add sp, #12 + 800281c: f85d fb04 ldr.w pc, [sp], #4 + +08002820 : +// +// Return T if all bytes are 0x00 +// + bool +check_all_zeros(const void *ptrV, int len) +{ + 8002820: b510 push {r4, lr} + 8002822: 4401 add r1, r0 + uint8_t rv = 0x0; + 8002824: 2400 movs r4, #0 + const uint8_t *ptr = (const uint8_t *)ptrV; + + for(; len; len--, ptr++) { + 8002826: 4288 cmp r0, r1 + 8002828: d105 bne.n 8002836 + rv |= *ptr; + } + + rng_delay(); + 800282a: f000 f86d bl 8002908 + return (rv == 0x00); +} + 800282e: fab4 f084 clz r0, r4 + 8002832: 0940 lsrs r0, r0, #5 + 8002834: bd10 pop {r4, pc} + rv |= *ptr; + 8002836: f810 3b01 ldrb.w r3, [r0], #1 + 800283a: 431c orrs r4, r3 + for(; len; len--, ptr++) { + 800283c: e7f3 b.n 8002826 + +0800283e : + const uint8_t *left = (const uint8_t *)aV; + const uint8_t *right = (const uint8_t *)bV; + uint8_t diff = 0; + int i; + + for (i = 0; i < len; i++) { + 800283e: 2300 movs r3, #0 +{ + 8002840: b570 push {r4, r5, r6, lr} + uint8_t diff = 0; + 8002842: 461c mov r4, r3 + for (i = 0; i < len; i++) { + 8002844: 4293 cmp r3, r2 + 8002846: db05 blt.n 8002854 + diff |= (left[i] ^ right[i]); + } + + rng_delay(); + 8002848: f000 f85e bl 8002908 + return (diff == 0); +} + 800284c: fab4 f084 clz r0, r4 + 8002850: 0940 lsrs r0, r0, #5 + 8002852: bd70 pop {r4, r5, r6, pc} + diff |= (left[i] ^ right[i]); + 8002854: 5cc5 ldrb r5, [r0, r3] + 8002856: 5cce ldrb r6, [r1, r3] + 8002858: 4075 eors r5, r6 + 800285a: 432c orrs r4, r5 + for (i = 0; i < len; i++) { + 800285c: 3301 adds r3, #1 + 800285e: e7f1 b.n 8002844 + +08002860 : + } + + // Get the new number + uint32_t rv = RNG->DR; + + if(rv != last_rng_result && rv) { + 8002860: 4b06 ldr r3, [pc, #24] ; (800287c ) + while(!(RNG->SR & RNG_FLAG_DRDY)) { + 8002862: 4a07 ldr r2, [pc, #28] ; (8002880 ) + if(rv != last_rng_result && rv) { + 8002864: 6819 ldr r1, [r3, #0] + while(!(RNG->SR & RNG_FLAG_DRDY)) { + 8002866: 6850 ldr r0, [r2, #4] + 8002868: 07c0 lsls r0, r0, #31 + 800286a: d5fc bpl.n 8002866 + uint32_t rv = RNG->DR; + 800286c: 6890 ldr r0, [r2, #8] + if(rv != last_rng_result && rv) { + 800286e: 4281 cmp r1, r0 + 8002870: d0f9 beq.n 8002866 + 8002872: 2800 cmp r0, #0 + 8002874: d0f7 beq.n 8002866 + last_rng_result = rv; + 8002876: 6018 str r0, [r3, #0] + + // keep trying if not a new number + } + + // NOT-REACHED +} + 8002878: 4770 bx lr + 800287a: bf00 nop + 800287c: 2009e1bc .word 0x2009e1bc + 8002880: 50060800 .word 0x50060800 + +08002884 : + if(RNG->CR & RNG_CR_RNGEN) { + 8002884: 4b12 ldr r3, [pc, #72] ; (80028d0 ) + 8002886: 681a ldr r2, [r3, #0] + 8002888: 0752 lsls r2, r2, #29 +{ + 800288a: b513 push {r0, r1, r4, lr} + if(RNG->CR & RNG_CR_RNGEN) { + 800288c: d41d bmi.n 80028ca + __HAL_RCC_RNG_CLK_ENABLE(); + 800288e: 4a11 ldr r2, [pc, #68] ; (80028d4 ) + 8002890: 6cd1 ldr r1, [r2, #76] ; 0x4c + 8002892: f441 2180 orr.w r1, r1, #262144 ; 0x40000 + 8002896: 64d1 str r1, [r2, #76] ; 0x4c + 8002898: 6cd2 ldr r2, [r2, #76] ; 0x4c + 800289a: f402 2280 and.w r2, r2, #262144 ; 0x40000 + 800289e: 9201 str r2, [sp, #4] + 80028a0: 9a01 ldr r2, [sp, #4] + RNG->CR |= RNG_CR_RNGEN; + 80028a2: 681a ldr r2, [r3, #0] + 80028a4: f042 0204 orr.w r2, r2, #4 + 80028a8: 601a str r2, [r3, #0] + uint32_t chk = rng_sample(); + 80028aa: f7ff ffd9 bl 8002860 + 80028ae: 4604 mov r4, r0 + uint32_t chk2 = rng_sample(); + 80028b0: f7ff ffd6 bl 8002860 + if(chk == 0 || chk == ~0 + 80028b4: 1e63 subs r3, r4, #1 + 80028b6: 3303 adds r3, #3 + 80028b8: d804 bhi.n 80028c4 + || chk2 == 0 || chk2 == ~0 + 80028ba: 1e43 subs r3, r0, #1 + 80028bc: 3303 adds r3, #3 + 80028be: d801 bhi.n 80028c4 + || chk == chk2 + 80028c0: 4284 cmp r4, r0 + 80028c2: d102 bne.n 80028ca + INCONSISTENT("bad rng"); + 80028c4: 4804 ldr r0, [pc, #16] ; (80028d8 ) + 80028c6: f7fe f8b7 bl 8000a38 +} + 80028ca: b002 add sp, #8 + 80028cc: bd10 pop {r4, pc} + 80028ce: bf00 nop + 80028d0: 50060800 .word 0x50060800 + 80028d4: 40021000 .word 0x40021000 + 80028d8: 0800d9a0 .word 0x0800d9a0 + +080028dc : + +// rng_buffer() +// + void +rng_buffer(uint8_t *result, int len) +{ + 80028dc: b573 push {r0, r1, r4, r5, r6, lr} + 80028de: 460c mov r4, r1 + 80028e0: 1845 adds r5, r0, r1 + while(len > 0) { + 80028e2: 2c00 cmp r4, #0 + 80028e4: eba5 0604 sub.w r6, r5, r4 + 80028e8: dc01 bgt.n 80028ee + memcpy(result, &t, MIN(4, len)); + + len -= 4; + result += 4; + } +} + 80028ea: b002 add sp, #8 + 80028ec: bd70 pop {r4, r5, r6, pc} + uint32_t t = rng_sample(); + 80028ee: f7ff ffb7 bl 8002860 + memcpy(result, &t, MIN(4, len)); + 80028f2: 2c04 cmp r4, #4 + 80028f4: 4622 mov r2, r4 + uint32_t t = rng_sample(); + 80028f6: 9001 str r0, [sp, #4] + memcpy(result, &t, MIN(4, len)); + 80028f8: bfa8 it ge + 80028fa: 2204 movge r2, #4 + 80028fc: a901 add r1, sp, #4 + 80028fe: 4630 mov r0, r6 + 8002900: f00b f802 bl 800d908 + len -= 4; + 8002904: 3c04 subs r4, #4 + result += 4; + 8002906: e7ec b.n 80028e2 + +08002908 : +// +// Call anytime. Delays for a random time period to fustrate glitchers. +// + void +rng_delay(void) +{ + 8002908: b508 push {r3, lr} + uint32_t r = rng_sample() % 8; + 800290a: f7ff ffa9 bl 8002860 + uint32_t cnt = (1< + cnt--; + } +} + 800291e: bd08 pop {r3, pc} + +08002920 <_send_byte>: + static inline void +_send_byte(uint8_t ch) +{ + // reset timeout timer (Systick) + uint32_t ticks = 0; + SysTick->VAL = 0; + 8002920: f04f 22e0 mov.w r2, #3758153728 ; 0xe000e000 +{ + 8002924: b510 push {r4, lr} + SysTick->VAL = 0; + 8002926: 2300 movs r3, #0 + + while(!(MY_UART->ISR & UART_FLAG_TXE)) { + 8002928: 4c07 ldr r4, [pc, #28] ; (8002948 <_send_byte+0x28>) + SysTick->VAL = 0; + 800292a: 6193 str r3, [r2, #24] + while(!(MY_UART->ISR & UART_FLAG_TXE)) { + 800292c: 230b movs r3, #11 + 800292e: 69e1 ldr r1, [r4, #28] + 8002930: 0609 lsls r1, r1, #24 + 8002932: d404 bmi.n 800293e <_send_byte+0x1e> + // busy-wait until able to send (no fifo?) + if(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) { + 8002934: 6911 ldr r1, [r2, #16] + 8002936: 03c9 lsls r1, r1, #15 + 8002938: d5f9 bpl.n 800292e <_send_byte+0xe> + // failsafe timeout + ticks += 1; + if(ticks > 10) break; + 800293a: 3b01 subs r3, #1 + 800293c: d1f7 bne.n 800292e <_send_byte+0xe> + } + } + MY_UART->TDR = ch; + 800293e: 4b02 ldr r3, [pc, #8] ; (8002948 <_send_byte+0x28>) + 8002940: b280 uxth r0, r0 + 8002942: 8518 strh r0, [r3, #40] ; 0x28 +} + 8002944: bd10 pop {r4, pc} + 8002946: bf00 nop + 8002948: 40004c00 .word 0x40004c00 + +0800294c <_send_bits>: + +// _send_bits() +// + static void +_send_bits(uint8_t tx) +{ + 800294c: b570 push {r4, r5, r6, lr} + 800294e: 4606 mov r6, r0 + 8002950: 2508 movs r5, #8 + // serialize and send one byte + uint8_t mask = 0x1; + 8002952: 2401 movs r4, #1 + + for(int i=0; i<8; i++, mask <<= 1) { + uint8_t h = (tx & mask) ? BIT1 : BIT0; + 8002954: 4226 tst r6, r4 + + _send_byte(h); + 8002956: bf14 ite ne + 8002958: 207f movne r0, #127 ; 0x7f + 800295a: 207d moveq r0, #125 ; 0x7d + 800295c: f7ff ffe0 bl 8002920 <_send_byte> + for(int i=0; i<8; i++, mask <<= 1) { + 8002960: 0064 lsls r4, r4, #1 + 8002962: 3d01 subs r5, #1 + 8002964: b2e4 uxtb r4, r4 + 8002966: d1f5 bne.n 8002954 <_send_bits+0x8> + } +} + 8002968: bd70 pop {r4, r5, r6, pc} + +0800296a <_send_serialized>: + +// _send_serialized() +// + static void +_send_serialized(const uint8_t *buf, int len) +{ + 800296a: b538 push {r3, r4, r5, lr} + 800296c: 4604 mov r4, r0 + 800296e: 1845 adds r5, r0, r1 + for(int i=0; i + for(int i=0; i + } +} + 800297c: bd38 pop {r3, r4, r5, pc} + ... + +08002980 <_flush_rx>: +// + static inline void +_flush_rx(void) +{ + // reset timeout timer (Systick) + SysTick->VAL = 0; + 8002980: f04f 23e0 mov.w r3, #3758153728 ; 0xe000e000 + 8002984: 2200 movs r2, #0 + + while(!(MY_UART->ISR & UART_FLAG_TC)) { + 8002986: 490b ldr r1, [pc, #44] ; (80029b4 <_flush_rx+0x34>) + SysTick->VAL = 0; + 8002988: 619a str r2, [r3, #24] + while(!(MY_UART->ISR & UART_FLAG_TC)) { + 800298a: 69ca ldr r2, [r1, #28] + 800298c: 0652 lsls r2, r2, #25 + 800298e: d402 bmi.n 8002996 <_flush_rx+0x16> + // wait for last bit(byte) to be serialized and sent + + if(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) { + 8002990: 691a ldr r2, [r3, #16] + 8002992: 03d0 lsls r0, r2, #15 + 8002994: d5f9 bpl.n 800298a <_flush_rx+0xa> + break; + } + } + + // We actually need this delay here! + __NOP(); + 8002996: bf00 nop + __NOP(); + 8002998: bf00 nop + __NOP(); + 800299a: bf00 nop + __NOP(); + 800299c: bf00 nop + __NOP(); + 800299e: bf00 nop + __NOP(); + 80029a0: bf00 nop + __NOP(); + 80029a2: bf00 nop + __NOP(); + 80029a4: bf00 nop + + // clear junk in rx buffer + MY_UART->RQR = USART_RQR_RXFRQ; + 80029a6: 4b03 ldr r3, [pc, #12] ; (80029b4 <_flush_rx+0x34>) + 80029a8: 2208 movs r2, #8 + 80029aa: 831a strh r2, [r3, #24] + + // clear overrun error + // clear rx timeout flag + // clear framing error + MY_UART->ICR = USART_ICR_ORECF | USART_ICR_RTOCF | USART_ICR_FECF; + 80029ac: f640 020a movw r2, #2058 ; 0x80a + 80029b0: 621a str r2, [r3, #32] +} + 80029b2: 4770 bx lr + 80029b4: 40004c00 .word 0x40004c00 + +080029b8 : + uint16_t crc_register = 0; + uint16_t polynom = 0x8005; + uint8_t shift_register; + uint8_t data_bit, crc_bit; + + crc_register = (((uint16_t) crc[0]) & 0x00FF) | (((uint16_t) crc[1]) << 8); + 80029b8: 8813 ldrh r3, [r2, #0] +{ + 80029ba: b5f0 push {r4, r5, r6, r7, lr} + 80029bc: 4408 add r0, r1 + + // Shift CRC to the left by 1. + crc_register <<= 1; + + if ((data_bit ^ crc_bit) != 0) + crc_register ^= polynom; + 80029be: f248 0605 movw r6, #32773 ; 0x8005 + for (counter = 0; counter < length; counter++) { + 80029c2: 4281 cmp r1, r0 + 80029c4: d103 bne.n 80029ce + } + } + + crc[0] = (uint8_t) (crc_register & 0x00FF); + 80029c6: 7013 strb r3, [r2, #0] + crc[1] = (uint8_t) (crc_register >> 8); + 80029c8: 0a1b lsrs r3, r3, #8 + 80029ca: 7053 strb r3, [r2, #1] +} + 80029cc: bdf0 pop {r4, r5, r6, r7, pc} + data_bit = (data[counter] & shift_register) ? 1 : 0; + 80029ce: f811 7b01 ldrb.w r7, [r1], #1 + 80029d2: 2508 movs r5, #8 + for (shift_register = 0x01; shift_register > 0x00; shift_register <<= 1) { + 80029d4: 2401 movs r4, #1 + data_bit = (data[counter] & shift_register) ? 1 : 0; + 80029d6: 4227 tst r7, r4 + crc_bit = crc_register >> 15; + 80029d8: ea4f 3cd3 mov.w ip, r3, lsr #15 + if ((data_bit ^ crc_bit) != 0) + 80029dc: bf18 it ne + 80029de: f04f 0e01 movne.w lr, #1 + crc_register <<= 1; + 80029e2: ea4f 0343 mov.w r3, r3, lsl #1 + if ((data_bit ^ crc_bit) != 0) + 80029e6: bf08 it eq + 80029e8: f04f 0e00 moveq.w lr, #0 + 80029ec: 45e6 cmp lr, ip + crc_register <<= 1; + 80029ee: b29b uxth r3, r3 + crc_register ^= polynom; + 80029f0: bf18 it ne + 80029f2: 4073 eorne r3, r6 + for (shift_register = 0x01; shift_register > 0x00; shift_register <<= 1) { + 80029f4: 0064 lsls r4, r4, #1 + 80029f6: 3d01 subs r5, #1 + 80029f8: b2e4 uxtb r4, r4 + 80029fa: d1ec bne.n 80029d6 + 80029fc: e7e1 b.n 80029c2 + +080029fe : + +// ae_check_crc() +// + static bool +ae_check_crc(const uint8_t *data, uint8_t length) +{ + 80029fe: b573 push {r0, r1, r4, r5, r6, lr} + uint8_t obs[2] = { 0, 0 }; + + if(data[0] != length) { + 8002a00: 7806 ldrb r6, [r0, #0] + uint8_t obs[2] = { 0, 0 }; + 8002a02: 2400 movs r4, #0 + if(data[0] != length) { + 8002a04: 428e cmp r6, r1 +{ + 8002a06: 4605 mov r5, r0 + uint8_t obs[2] = { 0, 0 }; + 8002a08: f8ad 4004 strh.w r4, [sp, #4] + if(data[0] != length) { + 8002a0c: d113 bne.n 8002a36 + // length is wrong + STATS(crc_len_error++); + return false; + } + + crc16_chain(length-2, data, obs); + 8002a0e: 4629 mov r1, r5 + 8002a10: 1eb0 subs r0, r6, #2 + + return (obs[0] == data[length-2] && obs[1] == data[length-1]); + 8002a12: 4435 add r5, r6 + crc16_chain(length-2, data, obs); + 8002a14: aa01 add r2, sp, #4 + 8002a16: b2c0 uxtb r0, r0 + 8002a18: f7ff ffce bl 80029b8 + return (obs[0] == data[length-2] && obs[1] == data[length-1]); + 8002a1c: f89d 2004 ldrb.w r2, [sp, #4] + 8002a20: f815 3c02 ldrb.w r3, [r5, #-2] + 8002a24: 429a cmp r2, r3 + 8002a26: d106 bne.n 8002a36 + 8002a28: f815 4c01 ldrb.w r4, [r5, #-1] + 8002a2c: f89d 0005 ldrb.w r0, [sp, #5] + 8002a30: 1a23 subs r3, r4, r0 + 8002a32: 425c negs r4, r3 + 8002a34: 415c adcs r4, r3 + return false; + 8002a36: 4620 mov r0, r4 +} + 8002a38: b002 add sp, #8 + 8002a3a: bd70 pop {r4, r5, r6, pc} + +08002a3c : +{ + 8002a3c: b508 push {r3, lr} + _send_byte(0x00); + 8002a3e: 2000 movs r0, #0 + 8002a40: f7ff ff6e bl 8002920 <_send_byte> + delay_ms(3); // measured: ~2.9ms + 8002a44: 2003 movs r0, #3 + 8002a46: f001 f81d bl 8003a84 +} + 8002a4a: e8bd 4008 ldmia.w sp!, {r3, lr} + _flush_rx(); + 8002a4e: f7ff bf97 b.w 8002980 <_flush_rx> + +08002a52 : +{ + 8002a52: b508 push {r3, lr} + ae_wake(); + 8002a54: f7ff fff2 bl 8002a3c +} + 8002a58: e8bd 4008 ldmia.w sp!, {r3, lr} + _send_bits(IOFLAG_IDLE); + 8002a5c: 20bb movs r0, #187 ; 0xbb + 8002a5e: f7ff bf75 b.w 800294c <_send_bits> + ... + +08002a64 : +{ + 8002a64: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + int max_expect = (max_len+1) * 8; + 8002a68: 3101 adds r1, #1 + uint8_t raw[max_expect]; + 8002a6a: 466b mov r3, sp + 8002a6c: eba3 03c1 sub.w r3, r3, r1, lsl #3 +{ + 8002a70: af00 add r7, sp, #0 + 8002a72: 4606 mov r6, r0 + uint8_t raw[max_expect]; + 8002a74: 469d mov sp, r3 + _send_bits(IOFLAG_TX); + 8002a76: 2088 movs r0, #136 ; 0x88 + int max_expect = (max_len+1) * 8; + 8002a78: 00cd lsls r5, r1, #3 + _send_bits(IOFLAG_TX); + 8002a7a: f7ff ff67 bl 800294c <_send_bits> + _flush_rx(); + 8002a7e: f7ff ff7f bl 8002980 <_flush_rx> + int actual = 0; + 8002a82: 2200 movs r2, #0 + while(!(MY_UART->ISR & UART_FLAG_RXNE) && !(MY_UART->ISR & UART_FLAG_RTOF)) { + 8002a84: 4829 ldr r0, [pc, #164] ; (8002b2c ) + uint8_t raw[max_expect]; + 8002a86: 466c mov r4, sp + for(uint8_t *p = raw; ; actual++) { + 8002a88: 4669 mov r1, sp + SysTick->VAL = 0; + 8002a8a: f04f 2ce0 mov.w ip, #3758153728 ; 0xe000e000 + 8002a8e: 4696 mov lr, r2 + 8002a90: f8cc e018 str.w lr, [ip, #24] + while(!(MY_UART->ISR & UART_FLAG_RXNE) && !(MY_UART->ISR & UART_FLAG_RTOF)) { + 8002a94: 2305 movs r3, #5 + 8002a96: f8d0 801c ldr.w r8, [r0, #28] + 8002a9a: f018 0f20 tst.w r8, #32 + 8002a9e: d104 bne.n 8002aaa + 8002aa0: f8d0 801c ldr.w r8, [r0, #28] + 8002aa4: f418 6f00 tst.w r8, #2048 ; 0x800 + 8002aa8: d008 beq.n 8002abc + if(MY_UART->ISR & UART_FLAG_RXNE) { + 8002aaa: 69c3 ldr r3, [r0, #28] + 8002aac: 069b lsls r3, r3, #26 + 8002aae: d52e bpl.n 8002b0e + return MY_UART->RDR & 0x7f; + 8002ab0: 8c83 ldrh r3, [r0, #36] ; 0x24 + if(actual < max_expect) { + 8002ab2: 42aa cmp r2, r5 + return MY_UART->RDR & 0x7f; + 8002ab4: b29b uxth r3, r3 + if(actual < max_expect) { + 8002ab6: db34 blt.n 8002b22 + for(uint8_t *p = raw; ; actual++) { + 8002ab8: 3201 adds r2, #1 + 8002aba: e7e9 b.n 8002a90 + if(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) { + 8002abc: f8dc 8010 ldr.w r8, [ip, #16] + 8002ac0: f418 3f80 tst.w r8, #65536 ; 0x10000 + 8002ac4: d0e7 beq.n 8002a96 + if(ticks >= 5) { + 8002ac6: 3b01 subs r3, #1 + 8002ac8: d1e5 bne.n 8002a96 + actual &= ~7; + 8002aca: f022 0107 bic.w r1, r2, #7 + while(from_len > 0) { + 8002ace: 3d08 subs r5, #8 + 8002ad0: 4425 add r5, r4 + 8002ad2: 4623 mov r3, r4 + 8002ad4: 4421 add r1, r4 + 8002ad6: 1ac8 subs r0, r1, r3 + 8002ad8: 2800 cmp r0, #0 + 8002ada: dd14 ble.n 8002b06 + 8002adc: f103 3cff add.w ip, r3, #4294967295 ; 0xffffffff + uint8_t rv = 0, mask = 0x1; + 8002ae0: 2001 movs r0, #1 + 8002ae2: 2400 movs r4, #0 + for(int i=0; i<8; i++, mask <<= 1) { + 8002ae4: f103 0e07 add.w lr, r3, #7 + if(from[i] == BIT1) { + 8002ae8: f81c 8f01 ldrb.w r8, [ip, #1]! + 8002aec: f1b8 0f7f cmp.w r8, #127 ; 0x7f + rv |= mask; + 8002af0: bf08 it eq + 8002af2: 4304 orreq r4, r0 + for(int i=0; i<8; i++, mask <<= 1) { + 8002af4: 0040 lsls r0, r0, #1 + 8002af6: 45f4 cmp ip, lr + 8002af8: b2c0 uxtb r0, r0 + 8002afa: d1f5 bne.n 8002ae8 + from += 8; + 8002afc: 3308 adds r3, #8 + if(max_into <= 0) break; + 8002afe: 42ab cmp r3, r5 + *(into++) = rv; + 8002b00: f806 4b01 strb.w r4, [r6], #1 + if(max_into <= 0) break; + 8002b04: d1e7 bne.n 8002ad6 + return actual / 8; + 8002b06: 10d0 asrs r0, r2, #3 +} + 8002b08: 46bd mov sp, r7 + 8002b0a: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + if(MY_UART->ISR & UART_FLAG_RTOF) { + 8002b0e: 69c3 ldr r3, [r0, #28] + 8002b10: 051b lsls r3, r3, #20 + 8002b12: d503 bpl.n 8002b1c + MY_UART->ICR = USART_ICR_RTOCF; + 8002b14: f44f 6300 mov.w r3, #2048 ; 0x800 + 8002b18: 6203 str r3, [r0, #32] + if(ch < 0) { + 8002b1a: e7d6 b.n 8002aca + INCONSISTENT("rxf"); + 8002b1c: 4804 ldr r0, [pc, #16] ; (8002b30 ) + 8002b1e: f7fd ff8b bl 8000a38 + *(p++) = ch; + 8002b22: f003 037f and.w r3, r3, #127 ; 0x7f + 8002b26: f801 3b01 strb.w r3, [r1], #1 + 8002b2a: e7c5 b.n 8002ab8 + 8002b2c: 40004c00 .word 0x40004c00 + 8002b30: 0800d9a0 .word 0x0800d9a0 + +08002b34 : + if(ae_chip_is_setup == AE_CHIP_IS_SETUP) { + 8002b34: 4b04 ldr r3, [pc, #16] ; (8002b48 ) + 8002b36: 681a ldr r2, [r3, #0] + 8002b38: 4b04 ldr r3, [pc, #16] ; (8002b4c ) + 8002b3a: 429a cmp r2, r3 + 8002b3c: d102 bne.n 8002b44 + _send_bits(IOFLAG_SLEEP); + 8002b3e: 20cc movs r0, #204 ; 0xcc + 8002b40: f7ff bf04 b.w 800294c <_send_bits> +} + 8002b44: 4770 bx lr + 8002b46: bf00 nop + 8002b48: 2009e1c0 .word 0x2009e1c0 + 8002b4c: 35d25d63 .word 0x35d25d63 + +08002b50 : + __HAL_RCC_UART4_CLK_ENABLE(); + 8002b50: 4b13 ldr r3, [pc, #76] ; (8002ba0 ) + 8002b52: 6d9a ldr r2, [r3, #88] ; 0x58 + 8002b54: f442 2200 orr.w r2, r2, #524288 ; 0x80000 + 8002b58: 659a str r2, [r3, #88] ; 0x58 + 8002b5a: 6d9b ldr r3, [r3, #88] ; 0x58 +{ + 8002b5c: b082 sub sp, #8 + __HAL_RCC_UART4_CLK_ENABLE(); + 8002b5e: f403 2300 and.w r3, r3, #524288 ; 0x80000 + 8002b62: 9301 str r3, [sp, #4] + 8002b64: 9b01 ldr r3, [sp, #4] + MY_UART->CR1 = 0; + 8002b66: 4b0f ldr r3, [pc, #60] ; (8002ba4 ) + 8002b68: 2200 movs r2, #0 + 8002b6a: 601a str r2, [r3, #0] + MY_UART->CR1 = 0x1000002d & ~(0 + 8002b6c: 4a0e ldr r2, [pc, #56] ; (8002ba8 ) + 8002b6e: 601a str r2, [r3, #0] + MY_UART->RTOR = 24; // timeout in bit periods: 3 chars or so + 8002b70: 2218 movs r2, #24 + 8002b72: 615a str r2, [r3, #20] + MY_UART->CR2 = USART_CR2_RTOEN; // rx timeout enable + 8002b74: f44f 0200 mov.w r2, #8388608 ; 0x800000 + 8002b78: 605a str r2, [r3, #4] + MY_UART->CR3 = USART_CR3_HDSEL | USART_CR3_ONEBIT; + 8002b7a: f640 0208 movw r2, #2056 ; 0x808 + 8002b7e: 609a str r2, [r3, #8] + MY_UART->BRR = 521; // 230400 bps @ 120 Mhz SYSCLK + 8002b80: f240 2209 movw r2, #521 ; 0x209 + 8002b84: 60da str r2, [r3, #12] + MY_UART->ICR = USART_ICR_RTOCF; + 8002b86: f44f 6200 mov.w r2, #2048 ; 0x800 + 8002b8a: 621a str r2, [r3, #32] + MY_UART->CR1 |= USART_CR1_UE; + 8002b8c: 681a ldr r2, [r3, #0] + 8002b8e: f042 0201 orr.w r2, r2, #1 + 8002b92: 601a str r2, [r3, #0] + ae_chip_is_setup = AE_CHIP_IS_SETUP; + 8002b94: 4b05 ldr r3, [pc, #20] ; (8002bac ) + 8002b96: 4a06 ldr r2, [pc, #24] ; (8002bb0 ) + 8002b98: 601a str r2, [r3, #0] +} + 8002b9a: b002 add sp, #8 + 8002b9c: 4770 bx lr + 8002b9e: bf00 nop + 8002ba0: 40021000 .word 0x40021000 + 8002ba4: 40004c00 .word 0x40004c00 + 8002ba8: 1000002c .word 0x1000002c + 8002bac: 2009e1c0 .word 0x2009e1c0 + 8002bb0: 35d25d63 .word 0x35d25d63 + +08002bb4 : + ae_send_idle(); + 8002bb4: f7ff bf4d b.w 8002a52 + +08002bb8 : +// Read a one-byte status/error code response from chip. It's wrapped as 4 bytes: +// (len=4) (value) (crc16) (crc16) +// + int +ae_read1(void) +{ + 8002bb8: b513 push {r0, r1, r4, lr} + 8002bba: 2408 movs r4, #8 + uint8_t msg[4]; + + for(int retry=7; retry >= 0; retry--) { + // tell it we want to read a response, read it, and deserialize + int rv = ae_read_response(msg, 4); + 8002bbc: 2104 movs r1, #4 + 8002bbe: eb0d 0001 add.w r0, sp, r1 + 8002bc2: f7ff ff4f bl 8002a64 + + if(rv == 0) { + 8002bc6: 4601 mov r1, r0 + 8002bc8: b938 cbnz r0, 8002bda + // nothing heard, it's probably still processing + ERR("not rdy"); + STATS(not_ready++); + + delay_ms(5); + 8002bca: 2005 movs r0, #5 + 8002bcc: f000 ff5a bl 8003a84 + for(int retry=7; retry >= 0; retry--) { + 8002bd0: 3c01 subs r4, #1 + 8002bd2: d1f3 bne.n 8002bbc + try_again: + STATS(l1_retry++); + } + + // fail. + return -1; + 8002bd4: f04f 30ff mov.w r0, #4294967295 ; 0xffffffff + 8002bd8: e008 b.n 8002bec + if(rv != 4) { + 8002bda: 2804 cmp r0, #4 + 8002bdc: d1f8 bne.n 8002bd0 + if(!ae_check_crc(msg, 4)) { + 8002bde: a801 add r0, sp, #4 + 8002be0: f7ff ff0d bl 80029fe + 8002be4: 2800 cmp r0, #0 + 8002be6: d0f3 beq.n 8002bd0 + return msg[1]; + 8002be8: f89d 0005 ldrb.w r0, [sp, #5] +} + 8002bec: b002 add sp, #8 + 8002bee: bd10 pop {r4, pc} + +08002bf0 : +// Read and check CRC over N bytes, wrapped in 3-bytes of framing overhead. +// Return -1 for timeout, zero for normal, and one-byte error code otherwise. +// + int +ae_read_n(uint8_t len, uint8_t *body) +{ + 8002bf0: e92d 43f8 stmdb sp!, {r3, r4, r5, r6, r7, r8, r9, lr} + uint8_t tmp[1+len+2]; + 8002bf4: f100 030a add.w r3, r0, #10 + 8002bf8: f403 73fc and.w r3, r3, #504 ; 0x1f8 +{ + 8002bfc: af00 add r7, sp, #0 + uint8_t tmp[1+len+2]; + 8002bfe: ebad 0d03 sub.w sp, sp, r3 +{ + 8002c02: 460d mov r5, r1 + uint8_t tmp[1+len+2]; + 8002c04: 1cc6 adds r6, r0, #3 + 8002c06: 46e8 mov r8, sp + 8002c08: f04f 0908 mov.w r9, #8 + + for(int retry=7; retry >= 0; retry--) { + + int actual = ae_read_response(tmp, len+3); + 8002c0c: 4631 mov r1, r6 + 8002c0e: 4640 mov r0, r8 + 8002c10: f7ff ff28 bl 8002a64 + if(actual < 4) { + 8002c14: 2803 cmp r0, #3 + int actual = ae_read_response(tmp, len+3); + 8002c16: 4604 mov r4, r0 + if(actual < 4) { + 8002c18: dc0b bgt.n 8002c32 + + if(actual == 0) { + 8002c1a: b910 cbnz r0, 8002c22 + // nothing heard, it's probably still processing + delay_ms(5); + 8002c1c: 2005 movs r0, #5 + 8002c1e: f000 ff31 bl 8003a84 + + return 0; + + try_again: + STATS(ln_retry++); + ae_wake(); + 8002c22: f7ff ff0b bl 8002a3c + for(int retry=7; retry >= 0; retry--) { + 8002c26: f1b9 0901 subs.w r9, r9, #1 + 8002c2a: d1ef bne.n 8002c0c + } + + return -1; + 8002c2c: f04f 30ff mov.w r0, #4294967295 ; 0xffffffff + 8002c30: e007 b.n 8002c42 + uint8_t resp_len = tmp[0]; + 8002c32: f898 3000 ldrb.w r3, [r8] + if(resp_len != (len + 3)) { + 8002c36: 42b3 cmp r3, r6 + 8002c38: d006 beq.n 8002c48 + if(resp_len == 4) { + 8002c3a: 2b04 cmp r3, #4 + 8002c3c: d1f1 bne.n 8002c22 + return tmp[1]; + 8002c3e: f898 0001 ldrb.w r0, [r8, #1] +} + 8002c42: 46bd mov sp, r7 + 8002c44: e8bd 83f8 ldmia.w sp!, {r3, r4, r5, r6, r7, r8, r9, pc} + if(!ae_check_crc(tmp, actual)) { + 8002c48: b2c1 uxtb r1, r0 + 8002c4a: 4640 mov r0, r8 + 8002c4c: f7ff fed7 bl 80029fe + 8002c50: 2800 cmp r0, #0 + 8002c52: d0e6 beq.n 8002c22 + memcpy(body, tmp+1, actual-3); + 8002c54: 1ee2 subs r2, r4, #3 + 8002c56: f108 0101 add.w r1, r8, #1 + 8002c5a: 4628 mov r0, r5 + 8002c5c: f00a fe54 bl 800d908 + return 0; + 8002c60: 2000 movs r0, #0 + 8002c62: e7ee b.n 8002c42 + +08002c64 : + +// ae_send_n() +// + void +ae_send_n(aeopcode_t opcode, uint8_t p1, uint16_t p2, const uint8_t *data, uint8_t data_len) +{ + 8002c64: b530 push {r4, r5, lr} + 8002c66: b085 sub sp, #20 + 8002c68: 461d mov r5, r3 + 8002c6a: f89d 4020 ldrb.w r4, [sp, #32] + uint8_t framed_len; + uint8_t op; + uint8_t p1; + uint8_t p2_lsb; + uint8_t p2_msb; + } known = { + 8002c6e: f88d 200c strb.w r2, [sp, #12] + 8002c72: 2377 movs r3, #119 ; 0x77 + 8002c74: 0a12 lsrs r2, r2, #8 + 8002c76: f88d 3008 strb.w r3, [sp, #8] + .ioflag = IOFLAG_CMD, + .framed_len = (data_len + 7), // 7 = (1 len) + (4 bytes of msg) + (2 crc) + 8002c7a: 1de3 adds r3, r4, #7 + } known = { + 8002c7c: f88d 3009 strb.w r3, [sp, #9] + 8002c80: f88d 200d strb.w r2, [sp, #13] + 8002c84: f88d 000a strb.w r0, [sp, #10] + 8002c88: f88d 100b strb.w r1, [sp, #11] + STATS(last_op = opcode); + STATS(last_p1 = p1); + STATS(last_p2 = p2); + + // important to wake chip at this point. + ae_wake(); + 8002c8c: f7ff fed6 bl 8002a3c + + _send_serialized((const uint8_t *)&known, sizeof(known)); + 8002c90: 2106 movs r1, #6 + 8002c92: a802 add r0, sp, #8 + 8002c94: f7ff fe69 bl 800296a <_send_serialized> + + // CRC will start from frame_len onwards + uint8_t crc[2] = {0, 0}; + 8002c98: 2300 movs r3, #0 + crc16_chain(sizeof(known)-1, &known.framed_len, crc); + 8002c9a: aa01 add r2, sp, #4 + 8002c9c: f10d 0109 add.w r1, sp, #9 + 8002ca0: 2005 movs r0, #5 + uint8_t crc[2] = {0, 0}; + 8002ca2: f8ad 3004 strh.w r3, [sp, #4] + crc16_chain(sizeof(known)-1, &known.framed_len, crc); + 8002ca6: f7ff fe87 bl 80029b8 + + // insert a variable-length body area (sometimes) + if(data_len) { + 8002caa: b144 cbz r4, 8002cbe + _send_serialized(data, data_len); + 8002cac: 4621 mov r1, r4 + 8002cae: 4628 mov r0, r5 + 8002cb0: f7ff fe5b bl 800296a <_send_serialized> + + crc16_chain(data_len, data, crc); + 8002cb4: aa01 add r2, sp, #4 + 8002cb6: 4629 mov r1, r5 + 8002cb8: 4620 mov r0, r4 + 8002cba: f7ff fe7d bl 80029b8 + } + + // send final CRC bytes + _send_serialized(crc, 2); + 8002cbe: 2102 movs r1, #2 + 8002cc0: a801 add r0, sp, #4 + 8002cc2: f7ff fe52 bl 800296a <_send_serialized> +} + 8002cc6: b005 add sp, #20 + 8002cc8: bd30 pop {r4, r5, pc} + +08002cca : +{ + 8002cca: b507 push {r0, r1, r2, lr} + ae_send_n(opcode, p1, p2, NULL, 0); + 8002ccc: 2300 movs r3, #0 + 8002cce: 9300 str r3, [sp, #0] + 8002cd0: f7ff ffc8 bl 8002c64 +} + 8002cd4: b003 add sp, #12 + 8002cd6: f85d fb04 ldr.w pc, [sp], #4 + +08002cda : +// +// Do Info(p1=2) command, and return result. +// + uint16_t +ae_get_info(void) +{ + 8002cda: b507 push {r0, r1, r2, lr} + // not doing error checking here + ae_send(OP_Info, 0x2, 0); + 8002cdc: 2200 movs r2, #0 + 8002cde: 2102 movs r1, #2 + 8002ce0: 2030 movs r0, #48 ; 0x30 + 8002ce2: f7ff fff2 bl 8002cca + + // note: always returns 4 bytes, but most are garbage and unused. + uint8_t tmp[4]; + ae_read_n(4, tmp); + 8002ce6: a901 add r1, sp, #4 + 8002ce8: 2004 movs r0, #4 + 8002cea: f7ff ff81 bl 8002bf0 + + return (tmp[0] << 8) | tmp[1]; + 8002cee: f8bd 0004 ldrh.w r0, [sp, #4] + 8002cf2: ba40 rev16 r0, r0 +} + 8002cf4: b280 uxth r0, r0 + 8002cf6: b003 add sp, #12 + 8002cf8: f85d fb04 ldr.w pc, [sp], #4 + +08002cfc : +// Load Tempkey with a specific value. Resulting Tempkey cannot be +// used with many commands/keys, but is needed for signing. +// + int +ae_load_nonce(const uint8_t nonce[32]) +{ + 8002cfc: b507 push {r0, r1, r2, lr} + // p1=3 + ae_send_n(OP_Nonce, 3, 0, nonce, 32); // 608a ok + 8002cfe: 2220 movs r2, #32 +{ + 8002d00: 4603 mov r3, r0 + ae_send_n(OP_Nonce, 3, 0, nonce, 32); // 608a ok + 8002d02: 9200 str r2, [sp, #0] + 8002d04: 2103 movs r1, #3 + 8002d06: 2200 movs r2, #0 + 8002d08: 2016 movs r0, #22 + 8002d0a: f7ff ffab bl 8002c64 + + return ae_read1(); +} + 8002d0e: b003 add sp, #12 + 8002d10: f85d eb04 ldr.w lr, [sp], #4 + return ae_read1(); + 8002d14: f7ff bf50 b.w 8002bb8 + +08002d18 : +// Load 32bytes of message digest with a specific value. +// Needed for signing. +// + int +ae_load_msgdigest(const uint8_t md[32]) +{ + 8002d18: b507 push {r0, r1, r2, lr} + ae_send_n(OP_Nonce, (1<<6) | 3, 0, md, 32); + 8002d1a: 2220 movs r2, #32 +{ + 8002d1c: 4603 mov r3, r0 + ae_send_n(OP_Nonce, (1<<6) | 3, 0, md, 32); + 8002d1e: 9200 str r2, [sp, #0] + 8002d20: 2143 movs r1, #67 ; 0x43 + 8002d22: 2200 movs r2, #0 + 8002d24: 2016 movs r0, #22 + 8002d26: f7ff ff9d bl 8002c64 + + return ae_read1(); +} + 8002d2a: b003 add sp, #12 + 8002d2c: f85d eb04 ldr.w lr, [sp], #4 + return ae_read1(); + 8002d30: f7ff bf42 b.w 8002bb8 + +08002d34 : +// Load Tempkey with a nonce value that we both know, but +// is random and we both know is random! Tricky! +// + int +ae_pick_nonce(const uint8_t num_in[20], uint8_t tempkey[32]) +{ + 8002d34: b5f0 push {r4, r5, r6, r7, lr} + 8002d36: b09f sub sp, #124 ; 0x7c + // We provide some 20 bytes of randomness to chip + // The chip must provide 32-bytes of random-ness, + // so no choice in args to OP.Nonce here (due to ReqRandom). + ae_send_n(OP_Nonce, 0, 0, num_in, 20); + 8002d38: 2200 movs r2, #0 + 8002d3a: 2714 movs r7, #20 + 8002d3c: 4603 mov r3, r0 +{ + 8002d3e: 4605 mov r5, r0 + 8002d40: 460e mov r6, r1 + ae_send_n(OP_Nonce, 0, 0, num_in, 20); + 8002d42: 2016 movs r0, #22 + 8002d44: 4611 mov r1, r2 + 8002d46: 9700 str r7, [sp, #0] + 8002d48: f7ff ff8c bl 8002c64 + + // Nonce command returns the RNG result, but not contents of TempKey + uint8_t randout[32]; + int rv = ae_read_n(32, randout); + 8002d4c: a903 add r1, sp, #12 + 8002d4e: 2020 movs r0, #32 + 8002d50: f7ff ff4e bl 8002bf0 + RET_IF_BAD(rv); + 8002d54: 4604 mov r4, r0 + 8002d56: b9e0 cbnz r0, 8002d92 + // + // return sha256(rndout + num_in + b'\x16\0\0').digest() + // + SHA256_CTX ctx; + + sha256_init(&ctx); + 8002d58: a80b add r0, sp, #44 ; 0x2c + 8002d5a: f002 fd0f bl 800577c + sha256_update(&ctx, randout, 32); + 8002d5e: 2220 movs r2, #32 + 8002d60: a903 add r1, sp, #12 + 8002d62: a80b add r0, sp, #44 ; 0x2c + 8002d64: f002 fd18 bl 8005798 + sha256_update(&ctx, num_in, 20); + 8002d68: 463a mov r2, r7 + 8002d6a: 4629 mov r1, r5 + 8002d6c: a80b add r0, sp, #44 ; 0x2c + 8002d6e: f002 fd13 bl 8005798 + const uint8_t fixed[3] = { 0x16, 0, 0 }; + 8002d72: 4b09 ldr r3, [pc, #36] ; (8002d98 ) + 8002d74: 881a ldrh r2, [r3, #0] + 8002d76: f8ad 2008 strh.w r2, [sp, #8] + 8002d7a: 789b ldrb r3, [r3, #2] + 8002d7c: f88d 300a strb.w r3, [sp, #10] + sha256_update(&ctx, fixed, 3); + 8002d80: a902 add r1, sp, #8 + 8002d82: a80b add r0, sp, #44 ; 0x2c + 8002d84: 2203 movs r2, #3 + 8002d86: f002 fd07 bl 8005798 + + sha256_final(&ctx, tempkey); + 8002d8a: 4631 mov r1, r6 + 8002d8c: a80b add r0, sp, #44 ; 0x2c + 8002d8e: f002 fd49 bl 8005824 + + return 0; +} + 8002d92: 4620 mov r0, r4 + 8002d94: b01f add sp, #124 ; 0x7c + 8002d96: bdf0 pop {r4, r5, r6, r7, pc} + 8002d98: 080106f0 .word 0x080106f0 + +08002d9c : +// Check that TempKey is holding what we think it does. Uses the MAC +// command over contents of Tempkey and our shared secret. +// + bool +ae_is_correct_tempkey(const uint8_t expected_tempkey[32]) +{ + 8002d9c: b570 push {r4, r5, r6, lr} + const uint8_t mode = (1<<6) // include full serial number + | (0<<2) // TempKey.SourceFlag == 0 == 'rand' + | (0<<1) // first 32 bytes are the shared secret + | (1<<0); // second 32 bytes are tempkey + + ae_send(OP_MAC, mode, KEYNUM_pairing); + 8002d9e: 2141 movs r1, #65 ; 0x41 +{ + 8002da0: b0a8 sub sp, #160 ; 0xa0 + 8002da2: 4604 mov r4, r0 + ae_send(OP_MAC, mode, KEYNUM_pairing); + 8002da4: 2201 movs r2, #1 + 8002da6: 2008 movs r0, #8 + 8002da8: f7ff ff8f bl 8002cca + + // read chip's answer + uint8_t resp[32]; + int rv = ae_read_n(32, resp); + 8002dac: a905 add r1, sp, #20 + 8002dae: 2020 movs r0, #32 + 8002db0: f7ff ff1e bl 8002bf0 + if(rv) return false; + 8002db4: 2800 cmp r0, #0 + 8002db6: d135 bne.n 8002e24 + ae_send_idle(); + 8002db8: f7ff fe4b bl 8002a52 + ae_keep_alive(); + + // Duplicate the hash process, and then compare. + SHA256_CTX ctx; + + sha256_init(&ctx); + 8002dbc: a815 add r0, sp, #84 ; 0x54 + 8002dbe: f002 fcdd bl 800577c + sha256_update(&ctx, rom_secrets->pairing_secret, 32); + 8002dc2: 4919 ldr r1, [pc, #100] ; (8002e28 ) + 8002dc4: 2220 movs r2, #32 + 8002dc6: a815 add r0, sp, #84 ; 0x54 + 8002dc8: f002 fce6 bl 8005798 + sha256_update(&ctx, expected_tempkey, 32); + 8002dcc: 2220 movs r2, #32 + 8002dce: 4621 mov r1, r4 + 8002dd0: a815 add r0, sp, #84 ; 0x54 + 8002dd2: f002 fce1 bl 8005798 + + const uint8_t fixed[16] = { OP_MAC, mode, KEYNUM_pairing, 0x0, + 8002dd6: 4b15 ldr r3, [pc, #84] ; (8002e2c ) + 8002dd8: aa01 add r2, sp, #4 + 8002dda: f103 0610 add.w r6, r3, #16 + 8002dde: 4615 mov r5, r2 + 8002de0: 6818 ldr r0, [r3, #0] + 8002de2: 6859 ldr r1, [r3, #4] + 8002de4: 4614 mov r4, r2 + 8002de6: c403 stmia r4!, {r0, r1} + 8002de8: 3308 adds r3, #8 + 8002dea: 42b3 cmp r3, r6 + 8002dec: 4622 mov r2, r4 + 8002dee: d1f7 bne.n 8002de0 + 0,0,0,0, 0,0,0,0, // eight zeros + 0,0,0, // three zeros + 0xEE }; + sha256_update(&ctx, fixed, sizeof(fixed)); + 8002df0: 2210 movs r2, #16 + 8002df2: 4629 mov r1, r5 + 8002df4: a815 add r0, sp, #84 ; 0x54 + 8002df6: f002 fccf bl 8005798 + + sha256_update(&ctx, ((const uint8_t *)rom_secrets->ae_serial_number)+4, 4); + 8002dfa: 490d ldr r1, [pc, #52] ; (8002e30 ) + 8002dfc: 2204 movs r2, #4 + 8002dfe: a815 add r0, sp, #84 ; 0x54 + 8002e00: f002 fcca bl 8005798 + sha256_update(&ctx, ((const uint8_t *)rom_secrets->ae_serial_number)+0, 4); + 8002e04: 2204 movs r2, #4 + 8002e06: 490b ldr r1, [pc, #44] ; (8002e34 ) + 8002e08: a815 add r0, sp, #84 ; 0x54 + 8002e0a: f002 fcc5 bl 8005798 + // this verifies no problem. + ASSERT(ctx.datalen + (ctx.bitlen/8) == 32+32+1+1+2+8+3+1+4+2+2); // == 88 +#endif + + uint8_t actual[32]; + sha256_final(&ctx, actual); + 8002e0e: a90d add r1, sp, #52 ; 0x34 + 8002e10: a815 add r0, sp, #84 ; 0x54 + 8002e12: f002 fd07 bl 8005824 + + return check_equal(actual, resp, 32); + 8002e16: 2220 movs r2, #32 + 8002e18: a905 add r1, sp, #20 + 8002e1a: a80d add r0, sp, #52 ; 0x34 + 8002e1c: f7ff fd0f bl 800283e +} + 8002e20: b028 add sp, #160 ; 0xa0 + 8002e22: bd70 pop {r4, r5, r6, pc} + if(rv) return false; + 8002e24: 2000 movs r0, #0 + 8002e26: e7fb b.n 8002e20 + 8002e28: 0801c000 .word 0x0801c000 + 8002e2c: 080106f3 .word 0x080106f3 + 8002e30: 0801c044 .word 0x0801c044 + 8002e34: 0801c040 .word 0x0801c040 + +08002e38 : +// inside the 508a/608a, like use of a specific key, but not for us to +// authenticate the 508a/608a or its contents/state. +// + int +ae_checkmac(uint8_t keynum, const uint8_t secret[32]) +{ + 8002e38: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + 8002e3c: b0c2 sub sp, #264 ; 0x108 + + // Since this is part of the hash, we want random bytes + // for our "other data". Also a number for "numin" of nonce + uint8_t od[32], numin[20]; + + rng_buffer(od, sizeof(od)); + 8002e3e: ad0b add r5, sp, #44 ; 0x2c +{ + 8002e40: 4607 mov r7, r0 + 8002e42: 460e mov r6, r1 + rng_buffer(od, sizeof(od)); + 8002e44: 4628 mov r0, r5 + 8002e46: 2120 movs r1, #32 + 8002e48: f7ff fd48 bl 80028dc + rng_buffer(numin, sizeof(numin)); + 8002e4c: 2114 movs r1, #20 + 8002e4e: a806 add r0, sp, #24 + 8002e50: f7ff fd44 bl 80028dc + ae_send_idle(); + 8002e54: f7ff fdfd bl 8002a52 + + // need this one, want to reset watchdog to this point. + ae_keep_alive(); + + // - load tempkey with a known nonce value + uint8_t zeros[8] = {0}; + 8002e58: 2300 movs r3, #0 + uint8_t tempkey[32]; + rv = ae_pick_nonce(numin, tempkey); + 8002e5a: a913 add r1, sp, #76 ; 0x4c + 8002e5c: a806 add r0, sp, #24 + uint8_t zeros[8] = {0}; + 8002e5e: e9cd 3304 strd r3, r3, [sp, #16] + rv = ae_pick_nonce(numin, tempkey); + 8002e62: f7ff ff67 bl 8002d34 + RET_IF_BAD(rv); + 8002e66: 4604 mov r4, r0 + 8002e68: 2800 cmp r0, #0 + 8002e6a: d15d bne.n 8002f28 + + // - hash nonce and lots of other bits together + SHA256_CTX ctx; + sha256_init(&ctx); + 8002e6c: a81b add r0, sp, #108 ; 0x6c + 8002e6e: f002 fc85 bl 800577c + + // shared secret is 32 bytes from flash + sha256_update(&ctx, secret, 32); + 8002e72: 2220 movs r2, #32 + 8002e74: 4631 mov r1, r6 + 8002e76: a81b add r0, sp, #108 ; 0x6c + 8002e78: f002 fc8e bl 8005798 + + sha256_update(&ctx, tempkey, 32); + 8002e7c: 2220 movs r2, #32 + 8002e7e: a913 add r1, sp, #76 ; 0x4c + 8002e80: a81b add r0, sp, #108 ; 0x6c + 8002e82: f002 fc89 bl 8005798 + sha256_update(&ctx, &od[0], 4); + 8002e86: 2204 movs r2, #4 + 8002e88: 4629 mov r1, r5 + 8002e8a: a81b add r0, sp, #108 ; 0x6c + 8002e8c: f002 fc84 bl 8005798 + + sha256_update(&ctx, zeros, 8); + 8002e90: 2208 movs r2, #8 + 8002e92: a904 add r1, sp, #16 + 8002e94: a81b add r0, sp, #108 ; 0x6c + 8002e96: f002 fc7f bl 8005798 + + sha256_update(&ctx, &od[4], 3); + 8002e9a: 2203 movs r2, #3 + 8002e9c: a90c add r1, sp, #48 ; 0x30 + 8002e9e: a81b add r0, sp, #108 ; 0x6c + 8002ea0: f002 fc7a bl 8005798 + + uint8_t ee = 0xEE; + 8002ea4: 23ee movs r3, #238 ; 0xee + sha256_update(&ctx, &ee, 1); + 8002ea6: 2201 movs r2, #1 + 8002ea8: f10d 010b add.w r1, sp, #11 + 8002eac: a81b add r0, sp, #108 ; 0x6c + uint8_t ee = 0xEE; + 8002eae: f88d 300b strb.w r3, [sp, #11] + sha256_update(&ctx, &ee, 1); + 8002eb2: f002 fc71 bl 8005798 + sha256_update(&ctx, &od[7], 4); + 8002eb6: 2204 movs r2, #4 + 8002eb8: f10d 0133 add.w r1, sp, #51 ; 0x33 + 8002ebc: a81b add r0, sp, #108 ; 0x6c + 8002ebe: f002 fc6b bl 8005798 + + uint8_t snp[2] = { 0x01, 0x23 }; + 8002ec2: f242 3301 movw r3, #8961 ; 0x2301 + sha256_update(&ctx, snp, 2); + 8002ec6: 2202 movs r2, #2 + 8002ec8: a903 add r1, sp, #12 + 8002eca: a81b add r0, sp, #108 ; 0x6c + uint8_t snp[2] = { 0x01, 0x23 }; + 8002ecc: f8ad 300c strh.w r3, [sp, #12] + sha256_update(&ctx, snp, 2); + 8002ed0: f002 fc62 bl 8005798 + sha256_update(&ctx, &od[11], 2); + 8002ed4: 2202 movs r2, #2 + 8002ed6: f10d 0137 add.w r1, sp, #55 ; 0x37 + 8002eda: a81b add r0, sp, #108 ; 0x6c + 8002edc: f002 fc5c bl 8005798 + uint8_t resp[32]; + uint8_t od[13]; + } req; + + // content doesn't matter, but nice and visible: + memcpy(req.ch3, copyright_msg, 32); + 8002ee0: 4b15 ldr r3, [pc, #84] ; (8002f38 ) + 8002ee2: ac2e add r4, sp, #184 ; 0xb8 + 8002ee4: f103 0220 add.w r2, r3, #32 + 8002ee8: 46a0 mov r8, r4 + 8002eea: 6818 ldr r0, [r3, #0] + 8002eec: 6859 ldr r1, [r3, #4] + 8002eee: 4626 mov r6, r4 + 8002ef0: c603 stmia r6!, {r0, r1} + 8002ef2: 3308 adds r3, #8 + 8002ef4: 4293 cmp r3, r2 + 8002ef6: 4634 mov r4, r6 + 8002ef8: d1f7 bne.n 8002eea + // this verifies no problem. + int l = (ctx.blocks * 64) + ctx.npartial; + ASSERT(l == 32+32+4+8+3+1+4+2+2); // == 88 +#endif + + sha256_final(&ctx, req.resp); + 8002efa: a936 add r1, sp, #216 ; 0xd8 + 8002efc: a81b add r0, sp, #108 ; 0x6c + 8002efe: f002 fc91 bl 8005824 + memcpy(req.od, od, 13); + 8002f02: e895 000f ldmia.w r5, {r0, r1, r2, r3} + 8002f06: ac3e add r4, sp, #248 ; 0xf8 + 8002f08: c407 stmia r4!, {r0, r1, r2} + 8002f0a: 7023 strb r3, [r4, #0] + + STATIC_ASSERT(sizeof(req) == 32 + 32 + 13); + + // Give our answer to the chip. + ae_send_n(OP_CheckMac, 0x01, keynum, (uint8_t *)&req, sizeof(req)); + 8002f0c: 234d movs r3, #77 ; 0x4d + 8002f0e: 9300 str r3, [sp, #0] + 8002f10: 463a mov r2, r7 + 8002f12: 4643 mov r3, r8 + 8002f14: 2101 movs r1, #1 + 8002f16: 2028 movs r0, #40 ; 0x28 + 8002f18: f7ff fea4 bl 8002c64 + + rv = ae_read1(); + 8002f1c: f7ff fe4c bl 8002bb8 + if(rv != 0) { + 8002f20: 4604 mov r4, r0 + 8002f22: b928 cbnz r0, 8002f30 + ae_send_idle(); + 8002f24: f7ff fd95 bl 8002a52 + + // just in case ... always restart watchdog timer. + ae_keep_alive(); + + return 0; +} + 8002f28: 4620 mov r0, r4 + 8002f2a: b042 add sp, #264 ; 0x108 + 8002f2c: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + return -1; + 8002f30: f04f 34ff mov.w r4, #4294967295 ; 0xffffffff + 8002f34: e7f8 b.n 8002f28 + 8002f36: bf00 nop + 8002f38: 080106c2 .word 0x080106c2 + +08002f3c : + return ae_checkmac(KEYNUM_pairing, rom_secrets->pairing_secret); + 8002f3c: 4901 ldr r1, [pc, #4] ; (8002f44 ) + 8002f3e: 2001 movs r0, #1 + 8002f40: f7ff bf7a b.w 8002e38 + 8002f44: 0801c000 .word 0x0801c000 + +08002f48 : +// Sign a message (already digested) +// + int +ae_sign_authed(uint8_t keynum, const uint8_t msg_hash[32], + uint8_t signature[64], int auth_kn, const uint8_t auth_digest[32]) +{ + 8002f48: b570 push {r4, r5, r6, lr} + 8002f4a: 460e mov r6, r1 + 8002f4c: 4604 mov r4, r0 + 8002f4e: 4615 mov r5, r2 + // indicate we know the PIN + ae_pair_unlock(); + 8002f50: f7ff fff4 bl 8002f3c + int rv = ae_checkmac(KEYNUM_main_pin, auth_digest); + 8002f54: 9904 ldr r1, [sp, #16] + 8002f56: 2003 movs r0, #3 + 8002f58: f7ff ff6e bl 8002e38 + RET_IF_BAD(rv); + 8002f5c: b990 cbnz r0, 8002f84 + + // send what we need signed + rv = ae_load_msgdigest(msg_hash); + 8002f5e: 4630 mov r0, r6 + 8002f60: f7ff feda bl 8002d18 + RET_IF_BAD(rv); + 8002f64: b970 cbnz r0, 8002f84 + + do { + ae_send(OP_Sign, (7<<5), keynum); + 8002f66: b2a4 uxth r4, r4 + 8002f68: 4622 mov r2, r4 + 8002f6a: 21e0 movs r1, #224 ; 0xe0 + 8002f6c: 2041 movs r0, #65 ; 0x41 + 8002f6e: f7ff feac bl 8002cca + + delay_ms(60); // min time for processing + 8002f72: 203c movs r0, #60 ; 0x3c + 8002f74: f000 fd86 bl 8003a84 + + rv = ae_read_n(64, signature); + 8002f78: 4629 mov r1, r5 + 8002f7a: 2040 movs r0, #64 ; 0x40 + 8002f7c: f7ff fe38 bl 8002bf0 + } while(rv == AE_ECC_FAULT); + 8002f80: 2805 cmp r0, #5 + 8002f82: d0f1 beq.n 8002f68 + + return rv; +} + 8002f84: bd70 pop {r4, r5, r6, pc} + ... + +08002f88 : + +// ae_gen_ecc_key() +// + int +ae_gen_ecc_key(uint8_t keynum, uint8_t pubkey_out[64]) +{ + 8002f88: b530 push {r4, r5, lr} + int rv; + uint8_t junk[3] = { 0 }; + 8002f8a: 4b0f ldr r3, [pc, #60] ; (8002fc8 ) +{ + 8002f8c: b085 sub sp, #20 + uint8_t junk[3] = { 0 }; + 8002f8e: f8b3 3013 ldrh.w r3, [r3, #19] + 8002f92: f8ad 300c strh.w r3, [sp, #12] + 8002f96: 2300 movs r3, #0 +{ + 8002f98: 460c mov r4, r1 + uint8_t junk[3] = { 0 }; + 8002f9a: f88d 300e strb.w r3, [sp, #14] + + do { + ae_send_n(OP_GenKey, (1<<2), keynum, junk, 3); + 8002f9e: 4605 mov r5, r0 + 8002fa0: 2303 movs r3, #3 + 8002fa2: 462a mov r2, r5 + 8002fa4: 2104 movs r1, #4 + 8002fa6: 9300 str r3, [sp, #0] + 8002fa8: 2040 movs r0, #64 ; 0x40 + 8002faa: ab03 add r3, sp, #12 + 8002fac: f7ff fe5a bl 8002c64 + + delay_ms(100); // to avoid timeouts + 8002fb0: 2064 movs r0, #100 ; 0x64 + 8002fb2: f000 fd67 bl 8003a84 + + rv = ae_read_n(64, pubkey_out); + 8002fb6: 4621 mov r1, r4 + 8002fb8: 2040 movs r0, #64 ; 0x40 + 8002fba: f7ff fe19 bl 8002bf0 + } while(rv == AE_ECC_FAULT); + 8002fbe: 2805 cmp r0, #5 + 8002fc0: d0ee beq.n 8002fa0 + + return rv; +} + 8002fc2: b005 add sp, #20 + 8002fc4: bd30 pop {r4, r5, pc} + 8002fc6: bf00 nop + 8002fc8: 080106f0 .word 0x080106f0 + +08002fcc : +// 508a: Different opcode, OP_HMAC does exactly 32 bytes w/ less steps. +// 608a: Use old SHA256 command, but with new flags. +// + int +ae_hmac32(uint8_t keynum, const uint8_t msg[32], uint8_t digest[32]) +{ + 8002fcc: b530 push {r4, r5, lr} + 8002fce: b085 sub sp, #20 + 8002fd0: 4615 mov r5, r2 + 8002fd2: 9103 str r1, [sp, #12] + // Start SHA w/ HMAC setup + ae_send(OP_SHA, 4, keynum); // 4 = HMAC_Init + 8002fd4: 4602 mov r2, r0 + 8002fd6: 2104 movs r1, #4 + 8002fd8: 2047 movs r0, #71 ; 0x47 + 8002fda: f7ff fe76 bl 8002cca + + // expect zero, meaning "ready" + int rv = ae_read1(); + 8002fde: f7ff fdeb bl 8002bb8 + RET_IF_BAD(rv); + 8002fe2: b970 cbnz r0, 8003002 + + // send the contents to be hashed + ae_send_n(OP_SHA, (3<<6) | 2, 32, msg, 32); // 2 = Finalize, 3=Place output + 8002fe4: 2420 movs r4, #32 + 8002fe6: 9b03 ldr r3, [sp, #12] + 8002fe8: 9400 str r4, [sp, #0] + 8002fea: 4622 mov r2, r4 + 8002fec: 21c2 movs r1, #194 ; 0xc2 + 8002fee: 2047 movs r0, #71 ; 0x47 + 8002ff0: f7ff fe38 bl 8002c64 + + // read result + return ae_read_n(32, digest); + 8002ff4: 4629 mov r1, r5 + 8002ff6: 4620 mov r0, r4 +} + 8002ff8: b005 add sp, #20 + 8002ffa: e8bd 4030 ldmia.w sp!, {r4, r5, lr} + return ae_read_n(32, digest); + 8002ffe: f7ff bdf7 b.w 8002bf0 +} + 8003002: b005 add sp, #20 + 8003004: bd30 pop {r4, r5, pc} + +08003006 : +// +// Return the serial number: it's 9 bytes, altho 3 are fixed. +// + int +ae_get_serial(uint8_t serial[6]) +{ + 8003006: b510 push {r4, lr} + ae_send(OP_Read, 0x80, 0x0); + 8003008: 2200 movs r2, #0 +{ + 800300a: b08c sub sp, #48 ; 0x30 + ae_send(OP_Read, 0x80, 0x0); + 800300c: 2180 movs r1, #128 ; 0x80 +{ + 800300e: 4604 mov r4, r0 + ae_send(OP_Read, 0x80, 0x0); + 8003010: 2002 movs r0, #2 + 8003012: f7ff fe5a bl 8002cca + + uint8_t temp[32]; + int rv = ae_read_n(32, temp); + 8003016: a904 add r1, sp, #16 + 8003018: 2020 movs r0, #32 + 800301a: f7ff fde9 bl 8002bf0 + RET_IF_BAD(rv); + 800301e: 4603 mov r3, r0 + 8003020: b9b8 cbnz r0, 8003052 + + // reformat to 9 bytes. + uint8_t ts[9]; + memcpy(ts, &temp[0], 4); + memcpy(&ts[4], &temp[8], 5); + 8003022: e9dd 0106 ldrd r0, r1, [sp, #24] + 8003026: 9a04 ldr r2, [sp, #16] + 8003028: f88d 100c strb.w r1, [sp, #12] + + // check the hard-coded values + if((ts[0] != 0x01) || (ts[1] != 0x23) || (ts[8] != 0xEE)) return 1; + 800302c: b2d1 uxtb r1, r2 + 800302e: 2901 cmp r1, #1 + memcpy(ts, &temp[0], 4); + 8003030: 9201 str r2, [sp, #4] + memcpy(&ts[4], &temp[8], 5); + 8003032: 9002 str r0, [sp, #8] + if((ts[0] != 0x01) || (ts[1] != 0x23) || (ts[8] != 0xEE)) return 1; + 8003034: d110 bne.n 8003058 + 8003036: f3c2 2207 ubfx r2, r2, #8, #8 + 800303a: 2a23 cmp r2, #35 ; 0x23 + 800303c: d10c bne.n 8003058 + 800303e: f89d 200c ldrb.w r2, [sp, #12] + 8003042: 2aee cmp r2, #238 ; 0xee + 8003044: d10a bne.n 800305c + + // save only the unique bits. + memcpy(serial, ts+2, 6); + 8003046: f8dd 2006 ldr.w r2, [sp, #6] + 800304a: 6022 str r2, [r4, #0] + 800304c: f8bd 200a ldrh.w r2, [sp, #10] + 8003050: 80a2 strh r2, [r4, #4] + + return 0; +} + 8003052: 4618 mov r0, r3 + 8003054: b00c add sp, #48 ; 0x30 + 8003056: bd10 pop {r4, pc} + if((ts[0] != 0x01) || (ts[1] != 0x23) || (ts[8] != 0xEE)) return 1; + 8003058: 2301 movs r3, #1 + 800305a: e7fa b.n 8003052 + 800305c: 460b mov r3, r1 + 800305e: e7f8 b.n 8003052 + +08003060 : +{ + 8003060: b513 push {r0, r1, r4, lr} + ae_wake(); + 8003062: f7ff fceb bl 8002a3c + _send_bits(IOFLAG_SLEEP); + 8003066: 20cc movs r0, #204 ; 0xcc + 8003068: f7ff fc70 bl 800294c <_send_bits> + ae_wake(); + 800306c: f7ff fce6 bl 8002a3c + ae_read1(); + 8003070: f7ff fda2 bl 8002bb8 + uint8_t chk = ae_read1(); + 8003074: f7ff fda0 bl 8002bb8 + if(chk != AE_AFTER_WAKE) return "wk fl"; + 8003078: b2c0 uxtb r0, r0 + 800307a: 2811 cmp r0, #17 + 800307c: d10e bne.n 800309c + if(ae_get_serial(serial)) return "no ser"; + 800307e: 4668 mov r0, sp + 8003080: f7ff ffc1 bl 8003006 + 8003084: 4604 mov r4, r0 + 8003086: b938 cbnz r0, 8003098 + ae_wake(); + 8003088: f7ff fcd8 bl 8002a3c + _send_bits(IOFLAG_SLEEP); + 800308c: 20cc movs r0, #204 ; 0xcc + 800308e: f7ff fc5d bl 800294c <_send_bits> + return NULL; + 8003092: 4620 mov r0, r4 +} + 8003094: b002 add sp, #8 + 8003096: bd10 pop {r4, pc} + if(ae_get_serial(serial)) return "no ser"; + 8003098: 4801 ldr r0, [pc, #4] ; (80030a0 ) + 800309a: e7fb b.n 8003094 + if(chk != AE_AFTER_WAKE) return "wk fl"; + 800309c: 4801 ldr r0, [pc, #4] ; (80030a4 ) + 800309e: e7f9 b.n 8003094 + 80030a0: 080106e3 .word 0x080106e3 + 80030a4: 080106ea .word 0x080106ea + +080030a8 : +// +// -- can also lock it. +// + int +ae_write_data_slot(int slot_num, const uint8_t *data, int len, bool lock_it) +{ + 80030a8: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + 80030ac: 4699 mov r9, r3 + ASSERT(len >= 32); + 80030ae: f1a2 0320 sub.w r3, r2, #32 +{ + 80030b2: b085 sub sp, #20 + ASSERT(len >= 32); + 80030b4: f5b3 7fc0 cmp.w r3, #384 ; 0x180 +{ + 80030b8: 4604 mov r4, r0 + 80030ba: af02 add r7, sp, #8 + 80030bc: 460d mov r5, r1 + 80030be: 4690 mov r8, r2 + ASSERT(len >= 32); + 80030c0: d902 bls.n 80030c8 + 80030c2: 482d ldr r0, [pc, #180] ; (8003178 ) + 80030c4: f7fd fcb8 bl 8000a38 + ASSERT(len <= 416); + + for(int blk=0, xlen=len; xlen>0; blk++, xlen-=32) { + // have to write each "block" of 32-bytes, separately + // zone => data + ae_send_n(OP_Write, 0x80|2, (blk<<8) | (slot_num<<3), data+(blk*32), 32); + 80030c8: ea4f 0ac0 mov.w sl, r0, lsl #3 + 80030cc: fa0f fa8a sxth.w sl, sl + 80030d0: 2600 movs r6, #0 + 80030d2: f04f 0b20 mov.w fp, #32 + 80030d6: ebc6 3246 rsb r2, r6, r6, lsl #13 + 80030da: ea4a 02c2 orr.w r2, sl, r2, lsl #3 + 80030de: b292 uxth r2, r2 + 80030e0: 1bab subs r3, r5, r6 + 80030e2: 2182 movs r1, #130 ; 0x82 + 80030e4: 2012 movs r0, #18 + 80030e6: f8cd b000 str.w fp, [sp] + 80030ea: f7ff fdbb bl 8002c64 + + int rv = ae_read1(); + 80030ee: f7ff fd63 bl 8002bb8 + RET_IF_BAD(rv); + 80030f2: 2800 cmp r0, #0 + 80030f4: d13c bne.n 8003170 + for(int blk=0, xlen=len; xlen>0; blk++, xlen-=32) { + 80030f6: 3e20 subs r6, #32 + 80030f8: eb06 0308 add.w r3, r6, r8 + 80030fc: 2b00 cmp r3, #0 + 80030fe: dcea bgt.n 80030d6 + } + + if(lock_it) { + 8003100: f1b9 0f00 cmp.w r9, #0 + 8003104: d034 beq.n 8003170 + ASSERT(slot_num != 8); // no support for mega slot 8 + 8003106: 2c08 cmp r4, #8 + if(lock_it) { + 8003108: 466e mov r6, sp + ASSERT(slot_num != 8); // no support for mega slot 8 + 800310a: d0da beq.n 80030c2 + ASSERT(len == 32); // probably not a limitation here + 800310c: f1b8 0f20 cmp.w r8, #32 + 8003110: d1d7 bne.n 80030c2 + + // Assume 36/72-byte long slot, which will be partially written, and rest + // should be ones. + const int slot_len = (slot_num <= 7) ? 36 : 72; + 8003112: 2c08 cmp r4, #8 + 8003114: bfb4 ite lt + 8003116: f04f 0824 movlt.w r8, #36 ; 0x24 + 800311a: f04f 0848 movge.w r8, #72 ; 0x48 + uint8_t copy[slot_len]; + 800311e: f108 0307 add.w r3, r8, #7 + 8003122: f003 03f8 and.w r3, r3, #248 ; 0xf8 + 8003126: ebad 0d03 sub.w sp, sp, r3 + 800312a: ab02 add r3, sp, #8 + + memset(copy, 0xff, slot_len); + 800312c: 4642 mov r2, r8 + 800312e: 21ff movs r1, #255 ; 0xff + 8003130: 4618 mov r0, r3 + 8003132: f00a fbf7 bl 800d924 + memcpy(copy, data, len); + 8003136: f105 0120 add.w r1, r5, #32 + memset(copy, 0xff, slot_len); + 800313a: 4603 mov r3, r0 + memcpy(copy, data, len); + 800313c: 4602 mov r2, r0 + 800313e: f855 0b04 ldr.w r0, [r5], #4 + 8003142: f842 0b04 str.w r0, [r2], #4 + 8003146: 428d cmp r5, r1 + 8003148: d1f9 bne.n 800313e + + // calc expected CRC + uint8_t crc[2] = {0, 0}; + 800314a: 2200 movs r2, #0 + crc16_chain(slot_len, copy, crc); + 800314c: 4619 mov r1, r3 + uint8_t crc[2] = {0, 0}; + 800314e: 80ba strh r2, [r7, #4] + crc16_chain(slot_len, copy, crc); + 8003150: 4640 mov r0, r8 + 8003152: 1d3a adds r2, r7, #4 + 8003154: f7ff fc30 bl 80029b8 + + // do the lock + ae_send(OP_Lock, 2 | (slot_num << 2), (crc[1]<<8) | crc[0]); + 8003158: 00a1 lsls r1, r4, #2 + 800315a: f041 0102 orr.w r1, r1, #2 + 800315e: 88ba ldrh r2, [r7, #4] + 8003160: f001 01fe and.w r1, r1, #254 ; 0xfe + 8003164: 2017 movs r0, #23 + 8003166: f7ff fdb0 bl 8002cca + + int rv = ae_read1(); + 800316a: f7ff fd25 bl 8002bb8 + RET_IF_BAD(rv); + 800316e: 46b5 mov sp, r6 + } + + return 0; +} + 8003170: 370c adds r7, #12 + 8003172: 46bd mov sp, r7 + 8003174: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + 8003178: 0801046c .word 0x0801046c + +0800317c : + +// ae_gendig_slot() +// + int +ae_gendig_slot(int slot_num, const uint8_t slot_contents[32], uint8_t digest[32]) +{ + 800317c: b5f0 push {r4, r5, r6, r7, lr} + 800317e: b0ab sub sp, #172 ; 0xac + 8003180: 4605 mov r5, r0 + 8003182: 460f mov r7, r1 + // Construct a digest on the device (and here) that depends on the secret + // contents of a specific slot. + uint8_t num_in[20], tempkey[32]; + + rng_buffer(num_in, sizeof(num_in)); + 8003184: a803 add r0, sp, #12 + 8003186: 2114 movs r1, #20 +{ + 8003188: 4616 mov r6, r2 + rng_buffer(num_in, sizeof(num_in)); + 800318a: f7ff fba7 bl 80028dc + int rv = ae_pick_nonce(num_in, tempkey); + 800318e: a90f add r1, sp, #60 ; 0x3c + 8003190: a803 add r0, sp, #12 + 8003192: f7ff fdcf bl 8002d34 + RET_IF_BAD(rv); + 8003196: 4604 mov r4, r0 + 8003198: 2800 cmp r0, #0 + 800319a: d13d bne.n 8003218 + + //using Zone=2="Data" => "KeyID specifies a slot in the Data zone" + ae_send(OP_GenDig, 0x2, slot_num); + 800319c: b2aa uxth r2, r5 + 800319e: 2102 movs r1, #2 + 80031a0: 2015 movs r0, #21 + 80031a2: f7ff fd92 bl 8002cca + + rv = ae_read1(); + 80031a6: f7ff fd07 bl 8002bb8 + RET_IF_BAD(rv); + 80031aa: 4604 mov r4, r0 + 80031ac: bba0 cbnz r0, 8003218 + ae_send_idle(); + 80031ae: f7ff fc50 bl 8002a52 + // msg = hkey + b'\x15\x02' + ustruct.pack(" + + uint8_t args[7] = { OP_GenDig, 2, slot_num, 0, 0xEE, 0x01, 0x23 }; + 80031b8: 2302 movs r3, #2 + 80031ba: f88d 3005 strb.w r3, [sp, #5] + 80031be: 23ee movs r3, #238 ; 0xee + 80031c0: f88d 3008 strb.w r3, [sp, #8] + 80031c4: 2301 movs r3, #1 + 80031c6: 2215 movs r2, #21 + 80031c8: f88d 3009 strb.w r3, [sp, #9] + uint8_t zeros[25] = { 0 }; + 80031cc: 4621 mov r1, r4 + uint8_t args[7] = { OP_GenDig, 2, slot_num, 0, 0xEE, 0x01, 0x23 }; + 80031ce: 2323 movs r3, #35 ; 0x23 + uint8_t zeros[25] = { 0 }; + 80031d0: a809 add r0, sp, #36 ; 0x24 + uint8_t args[7] = { OP_GenDig, 2, slot_num, 0, 0xEE, 0x01, 0x23 }; + 80031d2: f88d 300a strb.w r3, [sp, #10] + 80031d6: f88d 2004 strb.w r2, [sp, #4] + 80031da: f88d 5006 strb.w r5, [sp, #6] + 80031de: f88d 4007 strb.w r4, [sp, #7] + uint8_t zeros[25] = { 0 }; + 80031e2: 9408 str r4, [sp, #32] + 80031e4: f00a fb9e bl 800d924 + + sha256_update(&ctx, slot_contents, 32); + 80031e8: 2220 movs r2, #32 + 80031ea: 4639 mov r1, r7 + 80031ec: a817 add r0, sp, #92 ; 0x5c + 80031ee: f002 fad3 bl 8005798 + sha256_update(&ctx, args, sizeof(args)); + 80031f2: 2207 movs r2, #7 + 80031f4: a901 add r1, sp, #4 + 80031f6: a817 add r0, sp, #92 ; 0x5c + 80031f8: f002 face bl 8005798 + sha256_update(&ctx, zeros, sizeof(zeros)); + 80031fc: 2219 movs r2, #25 + 80031fe: a908 add r1, sp, #32 + 8003200: a817 add r0, sp, #92 ; 0x5c + 8003202: f002 fac9 bl 8005798 + sha256_update(&ctx, tempkey, 32); + 8003206: a90f add r1, sp, #60 ; 0x3c + 8003208: a817 add r0, sp, #92 ; 0x5c + 800320a: 2220 movs r2, #32 + 800320c: f002 fac4 bl 8005798 + + sha256_final(&ctx, digest); + 8003210: 4631 mov r1, r6 + 8003212: a817 add r0, sp, #92 ; 0x5c + 8003214: f002 fb06 bl 8005824 + + return 0; +} + 8003218: 4620 mov r0, r4 + 800321a: b02b add sp, #172 ; 0xac + 800321c: bdf0 pop {r4, r5, r6, r7, pc} + ... + +08003220 : +{ + 8003220: b507 push {r0, r1, r2, lr} + 8003222: 4602 mov r2, r0 + int rv = ae_gendig_slot(KEYNUM_pairing, rom_secrets->pairing_secret, randout); + 8003224: 9001 str r0, [sp, #4] + 8003226: 490b ldr r1, [pc, #44] ; (8003254 ) + 8003228: 2001 movs r0, #1 + 800322a: f7ff ffa7 bl 800317c + if(rv || !ae_is_correct_tempkey(randout)) { + 800322e: 9a01 ldr r2, [sp, #4] + 8003230: b108 cbz r0, 8003236 + fatal_mitm(); + 8003232: f7fd fc0b bl 8000a4c + if(rv || !ae_is_correct_tempkey(randout)) { + 8003236: 4610 mov r0, r2 + 8003238: 9201 str r2, [sp, #4] + 800323a: f7ff fdaf bl 8002d9c + 800323e: 2800 cmp r0, #0 + 8003240: d0f7 beq.n 8003232 + sha256_single(randout, 32, randout); + 8003242: 9a01 ldr r2, [sp, #4] + 8003244: 2120 movs r1, #32 + 8003246: 4610 mov r0, r2 +} + 8003248: b003 add sp, #12 + 800324a: f85d eb04 ldr.w lr, [sp], #4 + sha256_single(randout, 32, randout); + 800324e: f002 bafd b.w 800584c + 8003252: bf00 nop + 8003254: 0801c000 .word 0x0801c000 + +08003258 : +{ + 8003258: b510 push {r4, lr} + 800325a: b088 sub sp, #32 + int rv = ae_gendig_slot(keynum, secret, digest); + 800325c: 466a mov r2, sp + 800325e: f7ff ff8d bl 800317c + RET_IF_BAD(rv); + 8003262: 4604 mov r4, r0 + 8003264: b930 cbnz r0, 8003274 + if(!ae_is_correct_tempkey(digest)) return -2; + 8003266: 4668 mov r0, sp + 8003268: f7ff fd98 bl 8002d9c + 800326c: 2800 cmp r0, #0 + 800326e: bf08 it eq + 8003270: f06f 0401 mvneq.w r4, #1 +} + 8003274: 4620 mov r0, r4 + 8003276: b008 add sp, #32 + 8003278: bd10 pop {r4, pc} + +0800327a : +// the digest should be, and ask the chip to do the same. Verify we match +// using MAC command (done elsewhere). +// + int +ae_gendig_counter(int counter_num, const uint32_t expected_value, uint8_t digest[32]) +{ + 800327a: b5f0 push {r4, r5, r6, r7, lr} + 800327c: b0ad sub sp, #180 ; 0xb4 + 800327e: 4605 mov r5, r0 + 8003280: 9101 str r1, [sp, #4] + uint8_t num_in[20], tempkey[32]; + + rng_buffer(num_in, sizeof(num_in)); + 8003282: a804 add r0, sp, #16 + 8003284: 2114 movs r1, #20 +{ + 8003286: 4616 mov r6, r2 + rng_buffer(num_in, sizeof(num_in)); + 8003288: f7ff fb28 bl 80028dc + int rv = ae_pick_nonce(num_in, tempkey); + 800328c: a909 add r1, sp, #36 ; 0x24 + 800328e: a804 add r0, sp, #16 + 8003290: f7ff fd50 bl 8002d34 + RET_IF_BAD(rv); + 8003294: 4604 mov r4, r0 + 8003296: 2800 cmp r0, #0 + 8003298: d148 bne.n 800332c + + //using Zone=4="Counter" => "KeyID specifies the monotonic counter ID" + ae_send(OP_GenDig, 0x4, counter_num); + 800329a: b2aa uxth r2, r5 + 800329c: 2104 movs r1, #4 + 800329e: 2015 movs r0, #21 + 80032a0: f7ff fd13 bl 8002cca + + rv = ae_read1(); + 80032a4: f7ff fc88 bl 8002bb8 + RET_IF_BAD(rv); + 80032a8: 4604 mov r4, r0 + 80032aa: 2800 cmp r0, #0 + 80032ac: d13e bne.n 800332c + ae_send_idle(); + 80032ae: f7ff fbd0 bl 8002a52 + // msg = hkey + b'\x15\x02' + ustruct.pack(" + + uint8_t zeros[32] = { 0 }; + 80032b8: 221c movs r2, #28 + 80032ba: 4621 mov r1, r4 + 80032bc: a812 add r0, sp, #72 ; 0x48 + 80032be: 9411 str r4, [sp, #68] ; 0x44 + 80032c0: f00a fb30 bl 800d924 + uint8_t args[8] = { OP_GenDig, 0x4, counter_num, 0, 0xEE, 0x01, 0x23, 0x0 }; + 80032c4: 2315 movs r3, #21 + 80032c6: f88d 3008 strb.w r3, [sp, #8] + 80032ca: 23ee movs r3, #238 ; 0xee + 80032cc: f88d 300c strb.w r3, [sp, #12] + 80032d0: 2301 movs r3, #1 + 80032d2: 2704 movs r7, #4 + 80032d4: f88d 300d strb.w r3, [sp, #13] + + sha256_update(&ctx, zeros, 32); + 80032d8: 2220 movs r2, #32 + uint8_t args[8] = { OP_GenDig, 0x4, counter_num, 0, 0xEE, 0x01, 0x23, 0x0 }; + 80032da: 2323 movs r3, #35 ; 0x23 + sha256_update(&ctx, zeros, 32); + 80032dc: a911 add r1, sp, #68 ; 0x44 + 80032de: a819 add r0, sp, #100 ; 0x64 + uint8_t args[8] = { OP_GenDig, 0x4, counter_num, 0, 0xEE, 0x01, 0x23, 0x0 }; + 80032e0: f88d 300e strb.w r3, [sp, #14] + 80032e4: f88d 7009 strb.w r7, [sp, #9] + 80032e8: f88d 500a strb.w r5, [sp, #10] + 80032ec: f88d 400b strb.w r4, [sp, #11] + 80032f0: f88d 400f strb.w r4, [sp, #15] + sha256_update(&ctx, zeros, 32); + 80032f4: f002 fa50 bl 8005798 + sha256_update(&ctx, args, sizeof(args)); + 80032f8: 2208 movs r2, #8 + 80032fa: eb0d 0102 add.w r1, sp, r2 + 80032fe: a819 add r0, sp, #100 ; 0x64 + 8003300: f002 fa4a bl 8005798 + sha256_update(&ctx, (const uint8_t *)&expected_value, 4); + 8003304: 463a mov r2, r7 + 8003306: eb0d 0107 add.w r1, sp, r7 + 800330a: a819 add r0, sp, #100 ; 0x64 + 800330c: f002 fa44 bl 8005798 + sha256_update(&ctx, zeros, 20); + 8003310: 2214 movs r2, #20 + 8003312: a911 add r1, sp, #68 ; 0x44 + 8003314: a819 add r0, sp, #100 ; 0x64 + 8003316: f002 fa3f bl 8005798 + sha256_update(&ctx, tempkey, 32); + 800331a: a909 add r1, sp, #36 ; 0x24 + 800331c: a819 add r0, sp, #100 ; 0x64 + 800331e: 2220 movs r2, #32 + 8003320: f002 fa3a bl 8005798 + + sha256_final(&ctx, digest); + 8003324: 4631 mov r1, r6 + 8003326: a819 add r0, sp, #100 ; 0x64 + 8003328: f002 fa7c bl 8005824 + + return 0; +} + 800332c: 4620 mov r0, r4 + 800332e: b02d add sp, #180 ; 0xb4 + 8003330: bdf0 pop {r4, r5, r6, r7, pc} + +08003332 : +{ + 8003332: b570 push {r4, r5, r6, lr} + ae_send(OP_Counter, 0x0, counter_number); + 8003334: 460a mov r2, r1 +{ + 8003336: b088 sub sp, #32 + 8003338: 4606 mov r6, r0 + 800333a: 460d mov r5, r1 + ae_send(OP_Counter, 0x0, counter_number); + 800333c: 2024 movs r0, #36 ; 0x24 + 800333e: 2100 movs r1, #0 + 8003340: f7ff fcc3 bl 8002cca + int rv = ae_read_n(4, (uint8_t *)result); + 8003344: 4631 mov r1, r6 + 8003346: 2004 movs r0, #4 + 8003348: f7ff fc52 bl 8002bf0 + RET_IF_BAD(rv); + 800334c: 4604 mov r4, r0 + 800334e: b960 cbnz r0, 800336a + rv = ae_gendig_counter(counter_number, *result, digest); + 8003350: 6831 ldr r1, [r6, #0] + 8003352: 466a mov r2, sp + 8003354: 4628 mov r0, r5 + 8003356: f7ff ff90 bl 800327a + RET_IF_BAD(rv); + 800335a: 4604 mov r4, r0 + 800335c: b928 cbnz r0, 800336a + if(!ae_is_correct_tempkey(digest)) { + 800335e: 4668 mov r0, sp + 8003360: f7ff fd1c bl 8002d9c + 8003364: b908 cbnz r0, 800336a + fatal_mitm(); + 8003366: f7fd fb71 bl 8000a4c +} + 800336a: 4620 mov r0, r4 + 800336c: b008 add sp, #32 + 800336e: bd70 pop {r4, r5, r6, pc} + +08003370 : +{ + 8003370: e92d 43f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, lr} + 8003374: 4606 mov r6, r0 + 8003376: b089 sub sp, #36 ; 0x24 + 8003378: 460d mov r5, r1 + 800337a: 4617 mov r7, r2 + for(int i=0; i + int rv = ae_gendig_counter(counter_number, *result, digest); + 8003388: 6831 ldr r1, [r6, #0] + 800338a: 466a mov r2, sp + 800338c: 4628 mov r0, r5 + 800338e: f7ff ff74 bl 800327a + RET_IF_BAD(rv); + 8003392: 4604 mov r4, r0 + 8003394: b998 cbnz r0, 80033be + if(!ae_is_correct_tempkey(digest)) { + 8003396: 4668 mov r0, sp + 8003398: f7ff fd00 bl 8002d9c + 800339c: b978 cbnz r0, 80033be + fatal_mitm(); + 800339e: f7fd fb55 bl 8000a4c + ae_send(OP_Counter, 0x1, counter_number); + 80033a2: 464a mov r2, r9 + 80033a4: 2101 movs r1, #1 + 80033a6: 2024 movs r0, #36 ; 0x24 + 80033a8: f7ff fc8f bl 8002cca + int rv = ae_read_n(4, (uint8_t *)result); + 80033ac: 4631 mov r1, r6 + 80033ae: 2004 movs r0, #4 + 80033b0: f7ff fc1e bl 8002bf0 + RET_IF_BAD(rv); + 80033b4: 4604 mov r4, r0 + 80033b6: b910 cbnz r0, 80033be + for(int i=0; i +} + 80033be: 4620 mov r0, r4 + 80033c0: b009 add sp, #36 ; 0x24 + 80033c2: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + +080033c6 : +// ae_encrypted_read32() +// + int +ae_encrypted_read32(int data_slot, int blk, + int read_kn, const uint8_t read_key[32], uint8_t data[32]) +{ + 80033c6: b5f0 push {r4, r5, r6, r7, lr} + 80033c8: b08b sub sp, #44 ; 0x2c + 80033ca: 4617 mov r7, r2 + 80033cc: 460e mov r6, r1 + 80033ce: 9d10 ldr r5, [sp, #64] ; 0x40 + 80033d0: 9301 str r3, [sp, #4] + 80033d2: 4604 mov r4, r0 + uint8_t digest[32]; + + ae_pair_unlock(); + 80033d4: f7ff fdb2 bl 8002f3c + + int rv = ae_gendig_slot(read_kn, read_key, digest); + 80033d8: 9901 ldr r1, [sp, #4] + 80033da: aa02 add r2, sp, #8 + 80033dc: 4638 mov r0, r7 + 80033de: f7ff fecd bl 800317c + RET_IF_BAD(rv); + 80033e2: b9c0 cbnz r0, 8003416 + + // read nth 32-byte "block" + ae_send(OP_Read, 0x82, (blk << 8) | (data_slot<<3)); + 80033e4: 00e4 lsls r4, r4, #3 + 80033e6: ea44 2206 orr.w r2, r4, r6, lsl #8 + 80033ea: 2182 movs r1, #130 ; 0x82 + 80033ec: 2002 movs r0, #2 + 80033ee: b292 uxth r2, r2 + 80033f0: f7ff fc6b bl 8002cca + + rv = ae_read_n(32, data); + 80033f4: 4629 mov r1, r5 + 80033f6: 2020 movs r0, #32 + 80033f8: f7ff fbfa bl 8002bf0 + RET_IF_BAD(rv); + 80033fc: b958 cbnz r0, 8003416 + 80033fe: 1e6a subs r2, r5, #1 + 8003400: ab02 add r3, sp, #8 + 8003402: 351f adds r5, #31 + *(acc) ^= *(more); + 8003404: f812 1f01 ldrb.w r1, [r2, #1]! + 8003408: f813 4b01 ldrb.w r4, [r3], #1 + for(; len; len--, more++, acc++) { + 800340c: 4295 cmp r5, r2 + *(acc) ^= *(more); + 800340e: ea81 0104 eor.w r1, r1, r4 + 8003412: 7011 strb r1, [r2, #0] + for(; len; len--, more++, acc++) { + 8003414: d1f6 bne.n 8003404 + + xor_mixin(data, digest, 32); + + return 0; +} + 8003416: b00b add sp, #44 ; 0x2c + 8003418: bdf0 pop {r4, r5, r6, r7, pc} + ... + +0800341c : + +// ae_encrypted_read() +// + int +ae_encrypted_read(int data_slot, int read_kn, const uint8_t read_key[32], uint8_t *data, int len) +{ + 800341c: e92d 43f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, lr} + 8003420: b08b sub sp, #44 ; 0x2c + 8003422: 4607 mov r7, r0 + 8003424: 9d12 ldr r5, [sp, #72] ; 0x48 + // not clear if chip supports 4-byte encrypted reads + ASSERT((len == 32) || (len == 72)); + 8003426: 2d20 cmp r5, #32 +{ + 8003428: 4688 mov r8, r1 + 800342a: 4691 mov r9, r2 + 800342c: 461e mov r6, r3 + ASSERT((len == 32) || (len == 72)); + 800342e: d004 beq.n 800343a + 8003430: 2d48 cmp r5, #72 ; 0x48 + 8003432: d002 beq.n 800343a + 8003434: 4815 ldr r0, [pc, #84] ; (800348c ) + 8003436: f7fd faff bl 8000a38 + + int rv = ae_encrypted_read32(data_slot, 0, read_kn, read_key, data); + 800343a: 9600 str r6, [sp, #0] + 800343c: 464b mov r3, r9 + 800343e: 4642 mov r2, r8 + 8003440: 2100 movs r1, #0 + 8003442: 4638 mov r0, r7 + 8003444: f7ff ffbf bl 80033c6 + RET_IF_BAD(rv); + 8003448: 4604 mov r4, r0 + 800344a: b9d0 cbnz r0, 8003482 + + if(len == 32) return 0; + 800344c: 2d20 cmp r5, #32 + 800344e: d018 beq.n 8003482 + + rv = ae_encrypted_read32(data_slot, 1, read_kn, read_key, data+32); + 8003450: f106 0320 add.w r3, r6, #32 + 8003454: 9300 str r3, [sp, #0] + 8003456: 4642 mov r2, r8 + 8003458: 464b mov r3, r9 + 800345a: 2101 movs r1, #1 + 800345c: 4638 mov r0, r7 + 800345e: f7ff ffb2 bl 80033c6 + RET_IF_BAD(rv); + 8003462: 4604 mov r4, r0 + 8003464: b968 cbnz r0, 8003482 + + uint8_t tmp[32]; + rv = ae_encrypted_read32(data_slot, 2, read_kn, read_key, tmp); + 8003466: ad02 add r5, sp, #8 + 8003468: 9500 str r5, [sp, #0] + 800346a: 464b mov r3, r9 + 800346c: 4642 mov r2, r8 + 800346e: 2102 movs r1, #2 + 8003470: 4638 mov r0, r7 + 8003472: f7ff ffa8 bl 80033c6 + RET_IF_BAD(rv); + 8003476: 4604 mov r4, r0 + 8003478: b918 cbnz r0, 8003482 + + memcpy(data+64, tmp, 72-64); + 800347a: 462a mov r2, r5 + 800347c: ca03 ldmia r2!, {r0, r1} + 800347e: 6430 str r0, [r6, #64] ; 0x40 + 8003480: 6471 str r1, [r6, #68] ; 0x44 + + return 0; +} + 8003482: 4620 mov r0, r4 + 8003484: b00b add sp, #44 ; 0x2c + 8003486: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + 800348a: bf00 nop + 800348c: 0801046c .word 0x0801046c + +08003490 : +// ae_encrypted_write() +// + int +ae_encrypted_write32(int data_slot, int blk, int write_kn, + const uint8_t write_key[32], const uint8_t data[32]) +{ + 8003490: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + 8003494: b0b8 sub sp, #224 ; 0xe0 + 8003496: 4617 mov r7, r2 + 8003498: 460d mov r5, r1 + 800349a: 9e3e ldr r6, [sp, #248] ; 0xf8 + 800349c: 9303 str r3, [sp, #12] + 800349e: 4604 mov r4, r0 + uint8_t digest[32]; + + ae_pair_unlock(); + 80034a0: f7ff fd4c bl 8002f3c + + // generate a hash over shared secret and rng + int rv = ae_gendig_slot(write_kn, write_key, digest); + 80034a4: 9903 ldr r1, [sp, #12] + 80034a6: aa0d add r2, sp, #52 ; 0x34 + 80034a8: 4638 mov r0, r7 + 80034aa: f7ff fe67 bl 800317c + RET_IF_BAD(rv); + 80034ae: 2800 cmp r0, #0 + 80034b0: d151 bne.n 8003556 + 80034b2: 1e72 subs r2, r6, #1 + 80034b4: af0d add r7, sp, #52 ; 0x34 + 80034b6: a915 add r1, sp, #84 ; 0x54 + 80034b8: f106 0c1f add.w ip, r6, #31 + + // encrypt the data to be written, and append an authenticating MAC + uint8_t body[32 + 32]; + + for(int i=0; i<32; i++) { + body[i] = data[i] ^ digest[i]; + 80034bc: f812 ef01 ldrb.w lr, [r2, #1]! + 80034c0: f817 0b01 ldrb.w r0, [r7], #1 + for(int i=0; i<32; i++) { + 80034c4: 4562 cmp r2, ip + body[i] = data[i] ^ digest[i]; + 80034c6: ea80 000e eor.w r0, r0, lr + 80034ca: f801 0b01 strb.w r0, [r1], #1 + for(int i=0; i<32; i++) { + 80034ce: d1f5 bne.n 80034bc + // + (b'\0'*25) + // + new_value) + // assert len(msg) == 32+1+1+2+1+2+25+32 + // + SHA256_CTX ctx; + sha256_init(&ctx); + 80034d0: a825 add r0, sp, #148 ; 0x94 + 80034d2: f002 f953 bl 800577c + + uint8_t p1 = 0x80|2; // 32 bytes into a data slot + uint8_t p2_lsb = (data_slot << 3); + uint8_t p2_msb = blk; + + uint8_t args[7] = { OP_Write, p1, p2_lsb, p2_msb, 0xEE, 0x01, 0x23 }; + 80034d6: 22ee movs r2, #238 ; 0xee + 80034d8: f88d 2014 strb.w r2, [sp, #20] + 80034dc: 2201 movs r2, #1 + 80034de: f88d 2015 strb.w r2, [sp, #21] + uint8_t p2_lsb = (data_slot << 3); + 80034e2: 00e4 lsls r4, r4, #3 + uint8_t args[7] = { OP_Write, p1, p2_lsb, p2_msb, 0xEE, 0x01, 0x23 }; + 80034e4: 2223 movs r2, #35 ; 0x23 + uint8_t zeros[25] = { 0 }; + 80034e6: 2100 movs r1, #0 + uint8_t p2_lsb = (data_slot << 3); + 80034e8: b2e4 uxtb r4, r4 + uint8_t args[7] = { OP_Write, p1, p2_lsb, p2_msb, 0xEE, 0x01, 0x23 }; + 80034ea: 2712 movs r7, #18 + 80034ec: f04f 0882 mov.w r8, #130 ; 0x82 + 80034f0: f88d 2016 strb.w r2, [sp, #22] + uint8_t zeros[25] = { 0 }; + 80034f4: a807 add r0, sp, #28 + 80034f6: 2215 movs r2, #21 + 80034f8: 9106 str r1, [sp, #24] + uint8_t args[7] = { OP_Write, p1, p2_lsb, p2_msb, 0xEE, 0x01, 0x23 }; + 80034fa: f88d 7010 strb.w r7, [sp, #16] + 80034fe: f88d 8011 strb.w r8, [sp, #17] + 8003502: f88d 4012 strb.w r4, [sp, #18] + uint8_t p2_msb = blk; + 8003506: f88d 5013 strb.w r5, [sp, #19] + uint8_t zeros[25] = { 0 }; + 800350a: f00a fa0b bl 800d924 + + sha256_update(&ctx, digest, 32); + 800350e: 2220 movs r2, #32 + 8003510: a90d add r1, sp, #52 ; 0x34 + 8003512: a825 add r0, sp, #148 ; 0x94 + 8003514: f002 f940 bl 8005798 + sha256_update(&ctx, args, sizeof(args)); + 8003518: 2207 movs r2, #7 + 800351a: a904 add r1, sp, #16 + 800351c: a825 add r0, sp, #148 ; 0x94 + 800351e: f002 f93b bl 8005798 + sha256_update(&ctx, zeros, sizeof(zeros)); + 8003522: 2219 movs r2, #25 + 8003524: a906 add r1, sp, #24 + 8003526: a825 add r0, sp, #148 ; 0x94 + 8003528: f002 f936 bl 8005798 + sha256_update(&ctx, data, 32); + 800352c: 2220 movs r2, #32 + 800352e: 4631 mov r1, r6 + 8003530: a825 add r0, sp, #148 ; 0x94 + 8003532: f002 f931 bl 8005798 + + sha256_final(&ctx, &body[32]); + 8003536: a91d add r1, sp, #116 ; 0x74 + 8003538: a825 add r0, sp, #148 ; 0x94 + 800353a: f002 f973 bl 8005824 + + ae_send_n(OP_Write, p1, (p2_msb << 8) | p2_lsb, body, sizeof(body)); + 800353e: 2140 movs r1, #64 ; 0x40 + 8003540: ea44 2205 orr.w r2, r4, r5, lsl #8 + 8003544: b292 uxth r2, r2 + 8003546: 9100 str r1, [sp, #0] + 8003548: ab15 add r3, sp, #84 ; 0x54 + 800354a: 4641 mov r1, r8 + 800354c: 4638 mov r0, r7 + 800354e: f7ff fb89 bl 8002c64 + + return ae_read1(); + 8003552: f7ff fb31 bl 8002bb8 +} + 8003556: b038 add sp, #224 ; 0xe0 + 8003558: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + +0800355c : +// ae_encrypted_write() +// + int +ae_encrypted_write(int data_slot, int write_kn, const uint8_t write_key[32], + const uint8_t *data, int len) +{ + 800355c: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + 8003560: b08a sub sp, #40 ; 0x28 + ASSERT(data_slot >= 0); + ASSERT(data_slot <= 15); + 8003562: 280f cmp r0, #15 +{ + 8003564: 9d12 ldr r5, [sp, #72] ; 0x48 + 8003566: 4606 mov r6, r0 + 8003568: 460f mov r7, r1 + 800356a: 4690 mov r8, r2 + 800356c: 4699 mov r9, r3 + ASSERT(data_slot <= 15); + 800356e: d902 bls.n 8003576 + ASSERT(data_slot >= 0); + 8003570: 4814 ldr r0, [pc, #80] ; (80035c4 ) + 8003572: f7fd fa61 bl 8000a38 + + for(int blk=0; blk<3 && len>0; blk++, len-=32) { + 8003576: 2400 movs r4, #0 + int here = MIN(32, len); + + // be nice and don't read past end of input buffer + uint8_t tmp[32] = { 0 }; + 8003578: 46a2 mov sl, r4 + for(int blk=0; blk<3 && len>0; blk++, len-=32) { + 800357a: 2d00 cmp r5, #0 + 800357c: dd1d ble.n 80035ba + uint8_t tmp[32] = { 0 }; + 800357e: 221c movs r2, #28 + 8003580: 2100 movs r1, #0 + 8003582: a803 add r0, sp, #12 + 8003584: f8cd a008 str.w sl, [sp, #8] + 8003588: f00a f9cc bl 800d924 + memcpy(tmp, data+(32*blk), here); + 800358c: ab02 add r3, sp, #8 + 800358e: 2d20 cmp r5, #32 + 8003590: 462a mov r2, r5 + 8003592: eb09 1144 add.w r1, r9, r4, lsl #5 + 8003596: bfa8 it ge + 8003598: 2220 movge r2, #32 + 800359a: 4618 mov r0, r3 + 800359c: f00a f9b4 bl 800d908 + + int rv = ae_encrypted_write32(data_slot, blk, write_kn, write_key, tmp); + 80035a0: 4643 mov r3, r8 + 80035a2: 9000 str r0, [sp, #0] + 80035a4: 463a mov r2, r7 + 80035a6: 4621 mov r1, r4 + 80035a8: 4630 mov r0, r6 + 80035aa: f7ff ff71 bl 8003490 + RET_IF_BAD(rv); + 80035ae: b928 cbnz r0, 80035bc + for(int blk=0; blk<3 && len>0; blk++, len-=32) { + 80035b0: 3401 adds r4, #1 + 80035b2: 2c03 cmp r4, #3 + 80035b4: f1a5 0520 sub.w r5, r5, #32 + 80035b8: d1df bne.n 800357a + } + + return 0; + 80035ba: 2000 movs r0, #0 +} + 80035bc: b00a add sp, #40 ; 0x28 + 80035be: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + 80035c2: bf00 nop + 80035c4: 0801046c .word 0x0801046c + +080035c8 : + +// ae_read_data_slot() +// + int +ae_read_data_slot(int slot_num, uint8_t *data, int len) +{ + 80035c8: b570 push {r4, r5, r6, lr} + ASSERT((len == 4) || (len == 32) || (len == 72)); + 80035ca: 2a04 cmp r2, #4 +{ + 80035cc: b088 sub sp, #32 + 80035ce: 460d mov r5, r1 + 80035d0: 4616 mov r6, r2 + ASSERT((len == 4) || (len == 32) || (len == 72)); + 80035d2: d006 beq.n 80035e2 + 80035d4: 2a20 cmp r2, #32 + 80035d6: d038 beq.n 800364a + 80035d8: 2a48 cmp r2, #72 ; 0x48 + 80035da: d036 beq.n 800364a + 80035dc: 481c ldr r0, [pc, #112] ; (8003650 ) + 80035de: f7fd fa2b bl 8000a38 + + // zone => data + // only reading first block of 32 bytes. ignore the rest + ae_send(OP_Read, (len == 4 ? 0x00 : 0x80) | 2, (slot_num<<3)); + 80035e2: 2102 movs r1, #2 + 80035e4: 00c4 lsls r4, r0, #3 + 80035e6: b2a2 uxth r2, r4 + 80035e8: 2002 movs r0, #2 + 80035ea: f7ff fb6e bl 8002cca + + int rv = ae_read_n((len == 4) ? 4 : 32, data); + 80035ee: 2e04 cmp r6, #4 + 80035f0: 4629 mov r1, r5 + 80035f2: bf0c ite eq + 80035f4: 2004 moveq r0, #4 + 80035f6: 2020 movne r0, #32 + 80035f8: f7ff fafa bl 8002bf0 + RET_IF_BAD(rv); + 80035fc: 4603 mov r3, r0 + 80035fe: bb08 cbnz r0, 8003644 + + if(len == 72) { + 8003600: 2e48 cmp r6, #72 ; 0x48 + 8003602: d11f bne.n 8003644 + // read second block + ae_send(OP_Read, 0x82, (1<<8) | (slot_num<<3)); + 8003604: b224 sxth r4, r4 + 8003606: f444 7280 orr.w r2, r4, #256 ; 0x100 + 800360a: b292 uxth r2, r2 + 800360c: 2182 movs r1, #130 ; 0x82 + 800360e: 2002 movs r0, #2 + 8003610: f7ff fb5b bl 8002cca + + int rv = ae_read_n(32, data+32); + 8003614: f105 0120 add.w r1, r5, #32 + 8003618: 2020 movs r0, #32 + 800361a: f7ff fae9 bl 8002bf0 + RET_IF_BAD(rv); + 800361e: 4603 mov r3, r0 + 8003620: b980 cbnz r0, 8003644 + + // read third block, but only using part of it + uint8_t tmp[32]; + ae_send(OP_Read, 0x82, (2<<8) | (slot_num<<3)); + 8003622: f444 7400 orr.w r4, r4, #512 ; 0x200 + 8003626: b2a2 uxth r2, r4 + 8003628: 2182 movs r1, #130 ; 0x82 + 800362a: 2002 movs r0, #2 + 800362c: f7ff fb4d bl 8002cca + + rv = ae_read_n(32, tmp); + 8003630: 4669 mov r1, sp + 8003632: 2020 movs r0, #32 + 8003634: f7ff fadc bl 8002bf0 + RET_IF_BAD(rv); + 8003638: 4603 mov r3, r0 + 800363a: b918 cbnz r0, 8003644 + + memcpy(data+64, tmp, 72-64); + 800363c: 466a mov r2, sp + 800363e: ca03 ldmia r2!, {r0, r1} + 8003640: 6428 str r0, [r5, #64] ; 0x40 + 8003642: 6469 str r1, [r5, #68] ; 0x44 + } + + return 0; +} + 8003644: 4618 mov r0, r3 + 8003646: b008 add sp, #32 + 8003648: bd70 pop {r4, r5, r6, pc} + ae_send(OP_Read, (len == 4 ? 0x00 : 0x80) | 2, (slot_num<<3)); + 800364a: 2182 movs r1, #130 ; 0x82 + 800364c: e7ca b.n 80035e4 + 800364e: bf00 nop + 8003650: 0801046c .word 0x0801046c + +08003654 : + +// ae_set_gpio() +// + int +ae_set_gpio(int state) +{ + 8003654: b513 push {r0, r1, r4, lr} + // 1=turn on green, 0=red light (if not yet configured to be secure) + ae_send(OP_Info, 3, 2 | (!!state)); + 8003656: 1e04 subs r4, r0, #0 + 8003658: bf14 ite ne + 800365a: 2203 movne r2, #3 + 800365c: 2202 moveq r2, #2 + 800365e: 2103 movs r1, #3 + 8003660: 2030 movs r0, #48 ; 0x30 + 8003662: f7ff fb32 bl 8002cca + + // "Always return the current state in the first byte followed by three bytes of 0x00" + // - simple 1/0, in LSB. + uint8_t resp[4]; + + int rv = ae_read_n(4, resp); + 8003666: a901 add r1, sp, #4 + 8003668: 2004 movs r0, #4 + 800366a: f7ff fac1 bl 8002bf0 + RET_IF_BAD(rv); + 800366e: b928 cbnz r0, 800367c + + return (resp[0] != state) ? -1 : 0; + 8003670: f89d 0004 ldrb.w r0, [sp, #4] + 8003674: 1b00 subs r0, r0, r4 + 8003676: bf18 it ne + 8003678: f04f 30ff movne.w r0, #4294967295 ; 0xffffffff +} + 800367c: b002 add sp, #8 + 800367e: bd10 pop {r4, pc} + +08003680 : +// +// Set the GPIO using secure hash generated somehow already. +// + int +ae_set_gpio_secure(uint8_t digest[32]) +{ + 8003680: b538 push {r3, r4, r5, lr} + 8003682: 4605 mov r5, r0 + ae_pair_unlock(); + 8003684: f7ff fc5a bl 8002f3c + ae_checkmac(KEYNUM_firmware, digest); + 8003688: 4629 mov r1, r5 + 800368a: 200e movs r0, #14 + 800368c: f7ff fbd4 bl 8002e38 + + int rv = ae_set_gpio(1); + 8003690: 2001 movs r0, #1 + 8003692: f7ff ffdf bl 8003654 + + if(rv == 0) { + 8003696: 4604 mov r4, r0 + 8003698: b940 cbnz r0, 80036ac + // trust that readback, and so do a verify that the chip has + // the digest we think it does. If MitM wanted to turn off the output, + // they can do that anytime regardless. We just don't want them to be + // able to fake it being set, and therefore bypass the + // "unsigned firmware" delay and warning. + ae_pair_unlock(); + 800369a: f7ff fc4f bl 8002f3c + + if(ae_checkmac_hard(KEYNUM_firmware, digest) != 0) { + 800369e: 4629 mov r1, r5 + 80036a0: 200e movs r0, #14 + 80036a2: f7ff fdd9 bl 8003258 + 80036a6: b108 cbz r0, 80036ac + fatal_mitm(); + 80036a8: f7fd f9d0 bl 8000a4c + } + } + + return rv; +} + 80036ac: 4620 mov r0, r4 + 80036ae: bd38 pop {r3, r4, r5, pc} + +080036b0 : +// +// IMPORTANT: do not trust this result, could be MitM'ed. +// + uint8_t +ae_get_gpio(void) +{ + 80036b0: b507 push {r0, r1, r2, lr} + // not doing error checking here + ae_send(OP_Info, 0x3, 0); + 80036b2: 2200 movs r2, #0 + 80036b4: 2103 movs r1, #3 + 80036b6: 2030 movs r0, #48 ; 0x30 + 80036b8: f7ff fb07 bl 8002cca + + // note: always returns 4 bytes, but most are garbage and unused. + uint8_t tmp[4]; + ae_read_n(4, tmp); + 80036bc: a901 add r1, sp, #4 + 80036be: 2004 movs r0, #4 + 80036c0: f7ff fa96 bl 8002bf0 + + return tmp[0]; +} + 80036c4: f89d 0004 ldrb.w r0, [sp, #4] + 80036c8: b003 add sp, #12 + 80036ca: f85d fb04 ldr.w pc, [sp], #4 + +080036ce : +// +// Read a 4-byte area from config area, or -1 if fail. +// + int +ae_read_config_word(int offset, uint8_t *dest) +{ + 80036ce: b510 push {r4, lr} + offset &= 0x7f; + + // read 32 bits (aligned) + ae_send(OP_Read, 0x00, offset/4); + 80036d0: f3c0 0284 ubfx r2, r0, #2, #5 +{ + 80036d4: 460c mov r4, r1 + ae_send(OP_Read, 0x00, offset/4); + 80036d6: 2002 movs r0, #2 + 80036d8: 2100 movs r1, #0 + 80036da: f7ff faf6 bl 8002cca + + int rv = ae_read_n(4, dest); + 80036de: 4621 mov r1, r4 + 80036e0: 2004 movs r0, #4 + 80036e2: f7ff fa85 bl 8002bf0 + if(rv) return -1; + 80036e6: 3800 subs r0, #0 + 80036e8: bf18 it ne + 80036ea: 2001 movne r0, #1 + + return 0; +} + 80036ec: 4240 negs r0, r0 + 80036ee: bd10 pop {r4, pc} + +080036f0 : +{ + 80036f0: b513 push {r0, r1, r4, lr} + 80036f2: 4604 mov r4, r0 + ae_read_config_word(offset, tmp); + 80036f4: a901 add r1, sp, #4 + 80036f6: f7ff ffea bl 80036ce + return tmp[offset % 4]; + 80036fa: 4263 negs r3, r4 + 80036fc: f003 0303 and.w r3, r3, #3 + 8003700: f004 0403 and.w r4, r4, #3 + 8003704: bf58 it pl + 8003706: 425c negpl r4, r3 + 8003708: f104 0308 add.w r3, r4, #8 + 800370c: eb0d 0403 add.w r4, sp, r3 +} + 8003710: f814 0c04 ldrb.w r0, [r4, #-4] + 8003714: b002 add sp, #8 + 8003716: bd10 pop {r4, pc} + +08003718 : + +// ae_destroy_key() +// + int +ae_destroy_key(int keynum) +{ + 8003718: b510 push {r4, lr} + 800371a: b090 sub sp, #64 ; 0x40 + uint8_t numin[20]; + + // Load tempkey with a known (random) nonce value + rng_buffer(numin, sizeof(numin)); + 800371c: 2114 movs r1, #20 +{ + 800371e: 4604 mov r4, r0 + rng_buffer(numin, sizeof(numin)); + 8003720: a803 add r0, sp, #12 + 8003722: f7ff f8db bl 80028dc + ae_send_n(OP_Nonce, 0, 0, numin, 20); + 8003726: 2314 movs r3, #20 + 8003728: 2200 movs r2, #0 + 800372a: 9300 str r3, [sp, #0] + 800372c: 4611 mov r1, r2 + 800372e: 2016 movs r0, #22 + 8003730: ab03 add r3, sp, #12 + 8003732: f7ff fa97 bl 8002c64 + + // Nonce command returns the RNG result, not contents of TempKey, + // but since we are destroying, no need to calculate what it is. + uint8_t randout[32]; + int rv = ae_read_n(32, randout); + 8003736: a908 add r1, sp, #32 + 8003738: 2020 movs r0, #32 + 800373a: f7ff fa59 bl 8002bf0 + RET_IF_BAD(rv); + 800373e: b930 cbnz r0, 800374e + + // do a "DeriveKey" operation, based on that! + ae_send(OP_DeriveKey, 0x00, keynum); + 8003740: 4601 mov r1, r0 + 8003742: b2a2 uxth r2, r4 + 8003744: 201c movs r0, #28 + 8003746: f7ff fac0 bl 8002cca + + return ae_read1(); + 800374a: f7ff fa35 bl 8002bb8 +} + 800374e: b010 add sp, #64 ; 0x40 + 8003750: bd10 pop {r4, pc} + +08003752 : + +// ae_config_read() +// + int +ae_config_read(uint8_t config[128]) +{ + 8003752: b538 push {r3, r4, r5, lr} + 8003754: 4605 mov r5, r0 + for(int blk=0; blk<4; blk++) { + 8003756: 2400 movs r4, #0 + // read 32 bytes (aligned) from config "zone" + ae_send(OP_Read, 0x80, blk<<3); + 8003758: 00e2 lsls r2, r4, #3 + 800375a: 2180 movs r1, #128 ; 0x80 + 800375c: 2002 movs r0, #2 + 800375e: b292 uxth r2, r2 + 8003760: f7ff fab3 bl 8002cca + + int rv = ae_read_n(32, &config[32*blk]); + 8003764: eb05 1144 add.w r1, r5, r4, lsl #5 + 8003768: 2020 movs r0, #32 + 800376a: f7ff fa41 bl 8002bf0 + if(rv) return EIO; + 800376e: b918 cbnz r0, 8003778 + for(int blk=0; blk<4; blk++) { + 8003770: 3401 adds r4, #1 + 8003772: 2c04 cmp r4, #4 + 8003774: d1f0 bne.n 8003758 + } + + return 0; +} + 8003776: bd38 pop {r3, r4, r5, pc} + if(rv) return EIO; + 8003778: 2005 movs r0, #5 + 800377a: e7fc b.n 8003776 + +0800377c : +// us to write the (existing) pairing secret into, they would see the pairing +// secret in cleartext. They could then restore original chip and access freely. +// + int +ae_setup_config(void) +{ + 800377c: b5f0 push {r4, r5, r6, r7, lr} + 800377e: 2405 movs r4, #5 + 8003780: f5ad 7d41 sub.w sp, sp, #772 ; 0x304 + // Need to wake up AE, since many things happen before this point. + for(int retry=0; retry<5; retry++) { + if(!ae_probe()) break; + 8003784: f7ff fc6c bl 8003060 + 8003788: b108 cbz r0, 800378e + for(int retry=0; retry<5; retry++) { + 800378a: 3c01 subs r4, #1 + 800378c: d1fa bne.n 8003784 + // Is data zone is locked? + // Allow rest of function to happen if it's not. + +#if 1 + // 0x55 = unlocked; 0x00 = locked + bool data_locked = (ae_read_config_byte(86) != 0x55); + 800378e: 2056 movs r0, #86 ; 0x56 + 8003790: f7ff ffae bl 80036f0 + if(data_locked) return 0; // basically success + 8003794: 2855 cmp r0, #85 ; 0x55 + 8003796: f040 80df bne.w 8003958 + + // To lock, we need a CRC over whole thing, but we + // only set a few values... plus the serial number is + // in there, so start with some readout. + uint8_t config[128]; + int rv = ae_config_read(config); + 800379a: a838 add r0, sp, #224 ; 0xe0 + 800379c: f7ff ffd9 bl 8003752 + if(rv) return rv; + 80037a0: 4604 mov r4, r0 + 80037a2: 2800 cmp r0, #0 + 80037a4: f040 80d9 bne.w 800395a + uint8_t config[128]; + while(ae_config_read(config)) ; +#endif + + // verify some fixed values + ASSERT(config[0] == 0x01); + 80037a8: f89d 30e0 ldrb.w r3, [sp, #224] ; 0xe0 + 80037ac: 2b01 cmp r3, #1 + 80037ae: d002 beq.n 80037b6 + 80037b0: 486f ldr r0, [pc, #444] ; (8003970 ) + + ae_keep_alive(); + + // lock config zone + if(ae_lock_config_zone(config)) { + INCONSISTENT("conf lock"); + 80037b2: f7fd f941 bl 8000a38 + ASSERT(config[1] == 0x23); + 80037b6: f89d 30e1 ldrb.w r3, [sp, #225] ; 0xe1 + 80037ba: 2b23 cmp r3, #35 ; 0x23 + 80037bc: d1f8 bne.n 80037b0 + ASSERT(config[12] == 0xee); + 80037be: f89d 30ec ldrb.w r3, [sp, #236] ; 0xec + 80037c2: 2bee cmp r3, #238 ; 0xee + 80037c4: d1f4 bne.n 80037b0 + int8_t partno = ((config[6]>>4)&0xf); + 80037c6: f89d 30e6 ldrb.w r3, [sp, #230] ; 0xe6 + ASSERT(partno == 6); + 80037ca: 091b lsrs r3, r3, #4 + 80037cc: 2b06 cmp r3, #6 + 80037ce: d1ef bne.n 80037b0 + memcpy(serial, &config[0], 4); + 80037d0: 9b38 ldr r3, [sp, #224] ; 0xe0 + 80037d2: 9303 str r3, [sp, #12] + memcpy(&serial[4], &config[8], 5); + 80037d4: ab3a add r3, sp, #232 ; 0xe8 + 80037d6: e893 0003 ldmia.w r3, {r0, r1} + 80037da: 9004 str r0, [sp, #16] + 80037dc: f88d 1014 strb.w r1, [sp, #20] + if(check_all_ones(rom_secrets->ae_serial_number, 9)) { + 80037e0: 4864 ldr r0, [pc, #400] ; (8003974 ) + 80037e2: 2109 movs r1, #9 + 80037e4: f7ff f812 bl 800280c + 80037e8: b110 cbz r0, 80037f0 + flash_save_ae_serial(serial); + 80037ea: a803 add r0, sp, #12 + 80037ec: f7fe fd30 bl 8002250 + if(!check_equal(rom_secrets->ae_serial_number, serial, 9)) { + 80037f0: 4860 ldr r0, [pc, #384] ; (8003974 ) + 80037f2: 2209 movs r2, #9 + 80037f4: a903 add r1, sp, #12 + 80037f6: f7ff f822 bl 800283e + 80037fa: 2800 cmp r0, #0 + 80037fc: f000 80b6 beq.w 800396c + if(config[87] == 0x55) { + 8003800: f89d 3137 ldrb.w r3, [sp, #311] ; 0x137 + 8003804: 2b55 cmp r3, #85 ; 0x55 + 8003806: d12b bne.n 8003860 + memcpy(&config[16], config_1, sizeof(config_1)); + 8003808: 495b ldr r1, [pc, #364] ; (8003978 ) + 800380a: 2244 movs r2, #68 ; 0x44 + 800380c: a83c add r0, sp, #240 ; 0xf0 + 800380e: f00a f87b bl 800d908 + memcpy(&config[90], config_2, sizeof(config_2)); + 8003812: 4b5a ldr r3, [pc, #360] ; (800397c ) + 8003814: f50d 729d add.w r2, sp, #314 ; 0x13a + 8003818: f103 0124 add.w r1, r3, #36 ; 0x24 + 800381c: f853 0b04 ldr.w r0, [r3], #4 + 8003820: f842 0b04 str.w r0, [r2], #4 + 8003824: 428b cmp r3, r1 + 8003826: d1f9 bne.n 800381c + 8003828: 881b ldrh r3, [r3, #0] + 800382a: 8013 strh r3, [r2, #0] + for(int n=16; n<128; n+= 4) { + 800382c: 2510 movs r5, #16 + ae_send_n(OP_Write, 0, n/4, &config[n], 4); + 800382e: 2604 movs r6, #4 + if(n == 84) continue; // that word not writable + 8003830: 2d54 cmp r5, #84 ; 0x54 + 8003832: d130 bne.n 8003896 + for(int n=16; n<128; n+= 4) { + 8003834: 3504 adds r5, #4 + 8003836: 2d80 cmp r5, #128 ; 0x80 + 8003838: d1fa bne.n 8003830 + ae_send_idle(); + 800383a: f7ff f90a bl 8002a52 + uint8_t crc[2] = {0, 0}; + 800383e: 2600 movs r6, #0 + crc16_chain(128, config, crc); + 8003840: aa58 add r2, sp, #352 ; 0x160 + 8003842: a938 add r1, sp, #224 ; 0xe0 + 8003844: 4628 mov r0, r5 + uint8_t crc[2] = {0, 0}; + 8003846: f8ad 6160 strh.w r6, [sp, #352] ; 0x160 + crc16_chain(128, config, crc); + 800384a: f7ff f8b5 bl 80029b8 + ae_send(OP_Lock, 0x0, (crc[1]<<8) | crc[0]); + 800384e: f8bd 2160 ldrh.w r2, [sp, #352] ; 0x160 + 8003852: 4631 mov r1, r6 + 8003854: 2017 movs r0, #23 + 8003856: f7ff fa38 bl 8002cca + return ae_read1(); + 800385a: f7ff f9ad bl 8002bb8 + if(ae_lock_config_zone(config)) { + 800385e: bb38 cbnz r0, 80038b0 + // Load data zone with some known values. + // The datazone still unlocked, so no encryption needed (nor possible). + + // will use zeros for all PIN codes, and customer-defined-secret starting values + uint8_t zeros[72]; + memset(zeros, 0, sizeof(zeros)); + 8003860: 2248 movs r2, #72 ; 0x48 + 8003862: 2100 movs r1, #0 + 8003864: a826 add r0, sp, #152 ; 0x98 + 8003866: f00a f85d bl 800d924 + se2_save_auth_pubkey(pubkey); + break; + } + + case 0: + if(ae_write_data_slot(kn, (const uint8_t *)copyright_msg, 32, true)) { + 800386a: 4e45 ldr r6, [pc, #276] ; (8003980 ) + 800386c: f8bd 5138 ldrh.w r5, [sp, #312] ; 0x138 + if(ae_write_data_slot(kn, rom_secrets->pairing_secret, 32, false)) { + 8003870: 4f44 ldr r7, [pc, #272] ; (8003984 ) + ae_send_idle(); + 8003872: f7ff f8ee bl 8002a52 + if(!(unlocked & (1< + switch(kn) { + 800387e: 2c0e cmp r4, #14 + 8003880: d85c bhi.n 800393c + 8003882: e8df f004 tbb [pc, r4] + 8003886: 176e .short 0x176e + 8003888: 29202920 .word 0x29202920 + 800388c: 2d304c3e .word 0x2d304c3e + 8003890: 2d2d2d2d .word 0x2d2d2d2d + 8003894: 29 .byte 0x29 + 8003895: 00 .byte 0x00 + ae_send_n(OP_Write, 0, n/4, &config[n], 4); + 8003896: ab38 add r3, sp, #224 ; 0xe0 + 8003898: 442b add r3, r5 + 800389a: f3c5 028f ubfx r2, r5, #2, #16 + 800389e: 2100 movs r1, #0 + 80038a0: 2012 movs r0, #18 + 80038a2: 9600 str r6, [sp, #0] + 80038a4: f7ff f9de bl 8002c64 + int rv = ae_read1(); + 80038a8: f7ff f986 bl 8002bb8 + if(rv) return rv; + 80038ac: 2800 cmp r0, #0 + 80038ae: d0c1 beq.n 8003834 + INCONSISTENT("conf lock"); + 80038b0: 4835 ldr r0, [pc, #212] ; (8003988 ) + 80038b2: e77e b.n 80037b2 + if(ae_write_data_slot(kn, rom_secrets->pairing_secret, 32, false)) { + 80038b4: 2300 movs r3, #0 + 80038b6: 2220 movs r2, #32 + 80038b8: 4639 mov r1, r7 + 80038ba: 2001 movs r0, #1 + if(ae_write_data_slot(kn, (const uint8_t *)copyright_msg, 32, true)) { + 80038bc: f7ff fbf4 bl 80030a8 + 80038c0: 2800 cmp r0, #0 + 80038c2: d03b beq.n 800393c + 80038c4: e7f4 b.n 80038b0 + rng_buffer(tmp, sizeof(tmp)); + 80038c6: 2120 movs r1, #32 + 80038c8: a806 add r0, sp, #24 + 80038ca: f7ff f807 bl 80028dc + if(ae_write_data_slot(kn, tmp, 32, true)) { + 80038ce: 2301 movs r3, #1 + 80038d0: 2220 movs r2, #32 + 80038d2: a906 add r1, sp, #24 + if(ae_write_data_slot(kn, zeros, 32, false)) { + 80038d4: 4620 mov r0, r4 + 80038d6: e7f1 b.n 80038bc + 80038d8: 2300 movs r3, #0 + 80038da: 2220 movs r2, #32 + 80038dc: a926 add r1, sp, #152 ; 0x98 + 80038de: e7f9 b.n 80038d4 + if(ae_write_data_slot(kn, zeros, 72, false)) { + 80038e0: 2300 movs r3, #0 + 80038e2: 2248 movs r2, #72 ; 0x48 + 80038e4: e7fa b.n 80038dc + uint8_t long_zeros[416] = {0}; + 80038e6: 2300 movs r3, #0 + 80038e8: 4619 mov r1, r3 + 80038ea: f44f 72ce mov.w r2, #412 ; 0x19c + 80038ee: a859 add r0, sp, #356 ; 0x164 + 80038f0: 9358 str r3, [sp, #352] ; 0x160 + 80038f2: f00a f817 bl 800d924 + if(ae_write_data_slot(kn, long_zeros, 416, false)) { + 80038f6: 2300 movs r3, #0 + 80038f8: f44f 72d0 mov.w r2, #416 ; 0x1a0 + 80038fc: a958 add r1, sp, #352 ; 0x160 + 80038fe: 2008 movs r0, #8 + 8003900: e7dc b.n 80038bc + uint32_t buf[32/4] = { 1024, 1024 }; + 8003902: 2218 movs r2, #24 + 8003904: 2100 movs r1, #0 + 8003906: a810 add r0, sp, #64 ; 0x40 + 8003908: f00a f80c bl 800d924 + 800390c: f44f 6380 mov.w r3, #1024 ; 0x400 + 8003910: e9cd 330e strd r3, r3, [sp, #56] ; 0x38 + if(ae_write_data_slot(KEYNUM_match_count, (const uint8_t *)buf,sizeof(buf),false)) { + 8003914: 2220 movs r2, #32 + 8003916: 2300 movs r3, #0 + 8003918: a90e add r1, sp, #56 ; 0x38 + 800391a: 2006 movs r0, #6 + 800391c: e7ce b.n 80038bc + if(ae_checkmac_hard(KEYNUM_main_pin, zeros) != 0) { + 800391e: a926 add r1, sp, #152 ; 0x98 + 8003920: 2003 movs r0, #3 + 8003922: f7ff fc99 bl 8003258 + 8003926: 2800 cmp r0, #0 + 8003928: d1c2 bne.n 80038b0 + if(ae_gen_ecc_key(KEYNUM_joiner_key, pubkey)) { + 800392a: a916 add r1, sp, #88 ; 0x58 + 800392c: 2007 movs r0, #7 + 800392e: f7ff fb2b bl 8002f88 + 8003932: 2800 cmp r0, #0 + 8003934: d1bc bne.n 80038b0 + se2_save_auth_pubkey(pubkey); + 8003936: a816 add r0, sp, #88 ; 0x58 + 8003938: f004 f9e4 bl 8007d04 + for(int kn=0; kn<16; kn++) { + 800393c: 3401 adds r4, #1 + 800393e: 2c10 cmp r4, #16 + 8003940: d197 bne.n 8003872 + ae_send_idle(); + 8003942: f7ff f886 bl 8002a52 + ae_send(OP_Lock, 0x81, 0x0000); + 8003946: 2200 movs r2, #0 + 8003948: 2181 movs r1, #129 ; 0x81 + 800394a: 2017 movs r0, #23 + 800394c: f7ff f9bd bl 8002cca + return ae_read1(); + 8003950: f7ff f932 bl 8002bb8 + } + } + + // lock the data zone and effectively enter normal operation. + ae_keep_alive(); + if(ae_lock_data_zone()) { + 8003954: 2800 cmp r0, #0 + 8003956: d1ab bne.n 80038b0 + if(data_locked) return 0; // basically success + 8003958: 2400 movs r4, #0 + INCONSISTENT("data lock"); + } + + return 0; +} + 800395a: 4620 mov r0, r4 + 800395c: f50d 7d41 add.w sp, sp, #772 ; 0x304 + 8003960: bdf0 pop {r4, r5, r6, r7, pc} + if(ae_write_data_slot(kn, (const uint8_t *)copyright_msg, 32, true)) { + 8003962: 2301 movs r3, #1 + 8003964: 2220 movs r2, #32 + 8003966: 4631 mov r1, r6 + 8003968: 2000 movs r0, #0 + 800396a: e7a7 b.n 80038bc + return EPERM; + 800396c: 2401 movs r4, #1 + 800396e: e7f4 b.n 800395a + 8003970: 0801046c .word 0x0801046c + 8003974: 0801c040 .word 0x0801c040 + 8003978: 08010706 .word 0x08010706 + 800397c: 0801074a .word 0x0801074a + 8003980: 080106c2 .word 0x080106c2 + 8003984: 0801c000 .word 0x0801c000 + 8003988: 0800d9a0 .word 0x0800d9a0 + +0800398c : +// - but our time to do each iteration is limited by software SHA256 in ae_pair_unlock +// + int +ae_stretch_iter(const uint8_t start[32], uint8_t end[32], int iterations) +{ + ASSERT(start != end); // we can't work inplace + 800398c: 4288 cmp r0, r1 +{ + 800398e: b570 push {r4, r5, r6, lr} + 8003990: 460c mov r4, r1 + 8003992: 4615 mov r5, r2 + ASSERT(start != end); // we can't work inplace + 8003994: d102 bne.n 800399c + 8003996: 4810 ldr r0, [pc, #64] ; (80039d8 ) + 8003998: f7fd f84e bl 8000a38 + memcpy(end, start, 32); + 800399c: 460b mov r3, r1 + 800399e: f100 0220 add.w r2, r0, #32 + 80039a2: f850 1b04 ldr.w r1, [r0], #4 + 80039a6: f843 1b04 str.w r1, [r3], #4 + 80039aa: 4290 cmp r0, r2 + 80039ac: d1f9 bne.n 80039a2 + + for(int i=0; i + + int rv = ae_hmac32(KEYNUM_pin_stretch, end, end); + RET_IF_BAD(rv); + } + + return 0; + 80039b4: 2000 movs r0, #0 +} + 80039b6: bd70 pop {r4, r5, r6, pc} + if(ae_pair_unlock()) return -2; + 80039b8: f7ff fac0 bl 8002f3c + 80039bc: b940 cbnz r0, 80039d0 + int rv = ae_hmac32(KEYNUM_pin_stretch, end, end); + 80039be: 4622 mov r2, r4 + 80039c0: 4621 mov r1, r4 + 80039c2: 2002 movs r0, #2 + 80039c4: f7ff fb02 bl 8002fcc + RET_IF_BAD(rv); + 80039c8: 2800 cmp r0, #0 + 80039ca: d1f4 bne.n 80039b6 + for(int i=0; i + if(ae_pair_unlock()) return -2; + 80039d0: f06f 0001 mvn.w r0, #1 + 80039d4: e7ef b.n 80039b6 + 80039d6: bf00 nop + 80039d8: 0801046c .word 0x0801046c + +080039dc : +// Apply HMAC using secret in chip as a HMAC key, then encrypt +// the result a little because read in clear over bus. +// + int +ae_mixin_key(uint8_t keynum, const uint8_t start[32], uint8_t end[32]) +{ + 80039dc: b570 push {r4, r5, r6, lr} + 80039de: b096 sub sp, #88 ; 0x58 + ASSERT(start != end); // we can't work inplace + 80039e0: 4291 cmp r1, r2 +{ + 80039e2: 460e mov r6, r1 + 80039e4: 4614 mov r4, r2 + 80039e6: f88d 0007 strb.w r0, [sp, #7] + ASSERT(start != end); // we can't work inplace + 80039ea: d102 bne.n 80039f2 + 80039ec: 4818 ldr r0, [pc, #96] ; (8003a50 ) + 80039ee: f7fd f823 bl 8000a38 + + if(ae_pair_unlock()) return -1; + 80039f2: f7ff faa3 bl 8002f3c + 80039f6: bb40 cbnz r0, 8003a4a + + ASSERT(keynum != 0); + 80039f8: f89d 0007 ldrb.w r0, [sp, #7] + 80039fc: 2800 cmp r0, #0 + 80039fe: d0f5 beq.n 80039ec + int rv = ae_hmac32(keynum, start, end); + 8003a00: 4622 mov r2, r4 + 8003a02: 4631 mov r1, r6 + 8003a04: f7ff fae2 bl 8002fcc + RET_IF_BAD(rv); + 8003a08: 4605 mov r5, r0 + 8003a0a: b9d8 cbnz r0, 8003a44 + // use the value provided in cleartext[sic--it's not] write back shortly (to test it). + // Solution: one more SHA256, and to be safe, mixin lots of values! + + SHA256_CTX ctx; + + sha256_init(&ctx); + 8003a0c: a803 add r0, sp, #12 + 8003a0e: f001 feb5 bl 800577c + sha256_update(&ctx, rom_secrets->pairing_secret, 32); + 8003a12: 4910 ldr r1, [pc, #64] ; (8003a54 ) + 8003a14: 2220 movs r2, #32 + 8003a16: a803 add r0, sp, #12 + 8003a18: f001 febe bl 8005798 + sha256_update(&ctx, start, 32); + 8003a1c: 2220 movs r2, #32 + 8003a1e: 4631 mov r1, r6 + 8003a20: a803 add r0, sp, #12 + 8003a22: f001 feb9 bl 8005798 + sha256_update(&ctx, &keynum, 1); + 8003a26: 2201 movs r2, #1 + 8003a28: f10d 0107 add.w r1, sp, #7 + 8003a2c: a803 add r0, sp, #12 + 8003a2e: f001 feb3 bl 8005798 + sha256_update(&ctx, end, 32); + 8003a32: 4621 mov r1, r4 + 8003a34: a803 add r0, sp, #12 + 8003a36: 2220 movs r2, #32 + 8003a38: f001 feae bl 8005798 + sha256_final(&ctx, end); + 8003a3c: 4621 mov r1, r4 + 8003a3e: a803 add r0, sp, #12 + 8003a40: f001 fef0 bl 8005824 + + return 0; +} + 8003a44: 4628 mov r0, r5 + 8003a46: b016 add sp, #88 ; 0x58 + 8003a48: bd70 pop {r4, r5, r6, pc} + if(ae_pair_unlock()) return -1; + 8003a4a: f04f 35ff mov.w r5, #4294967295 ; 0xffffffff + 8003a4e: e7f9 b.n 8003a44 + 8003a50: 0801046c .word 0x0801046c + 8003a54: 0801c000 .word 0x0801c000 + +08003a58 : +// Immediately destroy the pairing secret so that we become +// a useless brick. Ignore errors but retry. +// + void +ae_brick_myself(void) +{ + 8003a58: b510 push {r4, lr} + for(int retry=0; retry<10; retry++) { + 8003a5a: 2400 movs r4, #0 + ae_reset_chip(); + 8003a5c: f7ff f86a bl 8002b34 + + if(retry) rng_delay(); + 8003a60: b10c cbz r4, 8003a66 + 8003a62: f7fe ff51 bl 8002908 + + ae_pair_unlock(); + 8003a66: f7ff fa69 bl 8002f3c + + // Concern: MitM could block this by trashing our write + // - but they have to do it without causing CRC or other comm error + // - ten times + int rv = ae_destroy_key(KEYNUM_pairing); + 8003a6a: 2001 movs r0, #1 + 8003a6c: f7ff fe54 bl 8003718 + if(rv == 0) break; + 8003a70: b120 cbz r0, 8003a7c + for(int retry=0; retry<10; retry++) { + 8003a72: 3401 adds r4, #1 + + rng_delay(); + 8003a74: f7fe ff48 bl 8002908 + for(int retry=0; retry<10; retry++) { + 8003a78: 2c0a cmp r4, #10 + 8003a7a: d1ef bne.n 8003a5c + } + + ae_reset_chip(); +} + 8003a7c: e8bd 4010 ldmia.w sp!, {r4, lr} + ae_reset_chip(); + 8003a80: f7ff b858 b.w 8002b34 + +08003a84 : +// + void +delay_ms(int ms) +{ + // Clear the COUNTFLAG and reset value to zero + SysTick->VAL = 0; + 8003a84: f04f 23e0 mov.w r3, #3758153728 ; 0xe000e000 + 8003a88: 2200 movs r2, #0 + 8003a8a: 619a str r2, [r3, #24] + //SysTick->CTRL; + + // Wait for ticks to happen + while(ms > 0) { + 8003a8c: 2800 cmp r0, #0 + 8003a8e: dc00 bgt.n 8003a92 + if(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) { + ms--; + } + } +} + 8003a90: 4770 bx lr + if(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) { + 8003a92: 691a ldr r2, [r3, #16] + 8003a94: 03d2 lsls r2, r2, #15 + ms--; + 8003a96: bf48 it mi + 8003a98: f100 30ff addmi.w r0, r0, #4294967295 ; 0xffffffff + 8003a9c: e7f6 b.n 8003a8c + +08003a9e : +// Replace HAL version which needs interrupts +// + void +HAL_Delay(uint32_t Delay) +{ + delay_ms(Delay); + 8003a9e: f7ff bff1 b.w 8003a84 + ... + +08003aa4 : + // NOTES: + // - try not to limit PCB changes for future revs; leave unused unchanged. + // - lcd.c controls some pins as well. + + // enable clock to GPIO's ... we will be using them all at some point + __HAL_RCC_GPIOA_CLK_ENABLE(); + 8003aa4: 4b67 ldr r3, [pc, #412] ; (8003c44 ) +{ + 8003aa6: b570 push {r4, r5, r6, lr} + __HAL_RCC_GPIOA_CLK_ENABLE(); + 8003aa8: 6cda ldr r2, [r3, #76] ; 0x4c + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + + { // Onewire bus pins used for ATECC608 comms + GPIO_InitTypeDef setup = { + 8003aaa: 4c67 ldr r4, [pc, #412] ; (8003c48 ) + __HAL_RCC_GPIOA_CLK_ENABLE(); + 8003aac: f042 0201 orr.w r2, r2, #1 + 8003ab0: 64da str r2, [r3, #76] ; 0x4c + 8003ab2: 6cda ldr r2, [r3, #76] ; 0x4c +{ + 8003ab4: b08a sub sp, #40 ; 0x28 + __HAL_RCC_GPIOA_CLK_ENABLE(); + 8003ab6: f002 0201 and.w r2, r2, #1 + 8003aba: 9200 str r2, [sp, #0] + 8003abc: 9a00 ldr r2, [sp, #0] + __HAL_RCC_GPIOB_CLK_ENABLE(); + 8003abe: 6cda ldr r2, [r3, #76] ; 0x4c + 8003ac0: f042 0202 orr.w r2, r2, #2 + 8003ac4: 64da str r2, [r3, #76] ; 0x4c + 8003ac6: 6cda ldr r2, [r3, #76] ; 0x4c + 8003ac8: f002 0202 and.w r2, r2, #2 + 8003acc: 9201 str r2, [sp, #4] + 8003ace: 9a01 ldr r2, [sp, #4] + __HAL_RCC_GPIOC_CLK_ENABLE(); + 8003ad0: 6cda ldr r2, [r3, #76] ; 0x4c + 8003ad2: f042 0204 orr.w r2, r2, #4 + 8003ad6: 64da str r2, [r3, #76] ; 0x4c + 8003ad8: 6cda ldr r2, [r3, #76] ; 0x4c + 8003ada: f002 0204 and.w r2, r2, #4 + 8003ade: 9202 str r2, [sp, #8] + 8003ae0: 9a02 ldr r2, [sp, #8] + __HAL_RCC_GPIOD_CLK_ENABLE(); + 8003ae2: 6cda ldr r2, [r3, #76] ; 0x4c + 8003ae4: f042 0208 orr.w r2, r2, #8 + 8003ae8: 64da str r2, [r3, #76] ; 0x4c + 8003aea: 6cda ldr r2, [r3, #76] ; 0x4c + 8003aec: f002 0208 and.w r2, r2, #8 + 8003af0: 9203 str r2, [sp, #12] + 8003af2: 9a03 ldr r2, [sp, #12] + __HAL_RCC_GPIOE_CLK_ENABLE(); + 8003af4: 6cda ldr r2, [r3, #76] ; 0x4c + 8003af6: f042 0210 orr.w r2, r2, #16 + 8003afa: 64da str r2, [r3, #76] ; 0x4c + 8003afc: 6cdb ldr r3, [r3, #76] ; 0x4c + 8003afe: f003 0310 and.w r3, r3, #16 + 8003b02: 9304 str r3, [sp, #16] + 8003b04: 9b04 ldr r3, [sp, #16] + GPIO_InitTypeDef setup = { + 8003b06: cc0f ldmia r4!, {r0, r1, r2, r3} + 8003b08: ad05 add r5, sp, #20 + 8003b0a: c50f stmia r5!, {r0, r1, r2, r3} + 8003b0c: 6823 ldr r3, [r4, #0] + 8003b0e: 602b str r3, [r5, #0] + .Mode = GPIO_MODE_AF_OD, + .Pull = GPIO_NOPULL, + .Speed = GPIO_SPEED_FREQ_MEDIUM, + .Alternate = GPIO_AF8_UART4, + }; + HAL_GPIO_Init(ONEWIRE_PORT, &setup); + 8003b10: a905 add r1, sp, #20 + 8003b12: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8003b16: f7fd fb6d bl 80011f4 + } + + // Bugfix: re-init of console port pins seems to wreck + // the mpy uart code, so avoid after first time. + if(USART1->BRR == 0) { + 8003b1a: 4b4c ldr r3, [pc, #304] ; (8003c4c ) + 8003b1c: 68de ldr r6, [r3, #12] + 8003b1e: b9ae cbnz r6, 8003b4c + // debug console: USART1 = PA9=Tx & PA10=Rx + GPIO_InitTypeDef setup = { + 8003b20: 3404 adds r4, #4 + 8003b22: cc0f ldmia r4!, {r0, r1, r2, r3} + 8003b24: ad05 add r5, sp, #20 + 8003b26: c50f stmia r5!, {r0, r1, r2, r3} + 8003b28: 6823 ldr r3, [r4, #0] + 8003b2a: 602b str r3, [r5, #0] + .Mode = GPIO_MODE_AF_PP, + .Pull = GPIO_NOPULL, + .Speed = GPIO_SPEED_FREQ_MEDIUM, + .Alternate = GPIO_AF7_USART1, + }; + HAL_GPIO_Init(GPIOA, &setup); + 8003b2c: a905 add r1, sp, #20 + 8003b2e: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + 8003b32: f7fd fb5f bl 80011f4 + + setup.Pin = GPIO_PIN_10; + 8003b36: f44f 6380 mov.w r3, #1024 ; 0x400 + setup.Mode = GPIO_MODE_INPUT; + 8003b3a: e9cd 3605 strd r3, r6, [sp, #20] + setup.Pull = GPIO_PULLUP; + HAL_GPIO_Init(GPIOA, &setup); + 8003b3e: a905 add r1, sp, #20 + setup.Pull = GPIO_PULLUP; + 8003b40: 2301 movs r3, #1 + HAL_GPIO_Init(GPIOA, &setup); + 8003b42: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + setup.Pull = GPIO_PULLUP; + 8003b46: 9307 str r3, [sp, #28] + HAL_GPIO_Init(GPIOA, &setup); + 8003b48: f7fd fb54 bl 80011f4 + } + + { // Port B - mostly unused, but want TEAR input and pwr btn + // TEAR from LCD: PB11 + // PWR_BTN: PB12 + GPIO_InitTypeDef setup = { + 8003b4c: 2400 movs r4, #0 + // Port C - Outputs + // SD1 active LED: PC7 + // USB active LED: PC6 + // TURN OFF: PC0 + // SD mux: PC13 + { GPIO_InitTypeDef setup = { + 8003b4e: 2501 movs r5, #1 + GPIO_InitTypeDef setup = { + 8003b50: f44f 53c0 mov.w r3, #6144 ; 0x1800 + HAL_GPIO_Init(GPIOB, &setup); + 8003b54: a905 add r1, sp, #20 + 8003b56: 483e ldr r0, [pc, #248] ; (8003c50 ) + GPIO_InitTypeDef setup = { + 8003b58: 9409 str r4, [sp, #36] ; 0x24 + 8003b5a: e9cd 3405 strd r3, r4, [sp, #20] + 8003b5e: e9cd 4407 strd r4, r4, [sp, #28] + HAL_GPIO_Init(GPIOB, &setup); + 8003b62: f7fd fb47 bl 80011f4 + { GPIO_InitTypeDef setup = { + 8003b66: 23c1 movs r3, #193 ; 0xc1 + .Pin = GPIO_PIN_7 | GPIO_PIN_6 | GPIO_PIN_0, GPIO_PIN_13, + .Mode = GPIO_MODE_OUTPUT_PP, + .Pull = GPIO_NOPULL, + .Speed = GPIO_SPEED_FREQ_LOW, + }; + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, 0); // keep power on! + 8003b68: 4622 mov r2, r4 + 8003b6a: 4629 mov r1, r5 + 8003b6c: 4839 ldr r0, [pc, #228] ; (8003c54 ) + { GPIO_InitTypeDef setup = { + 8003b6e: 9409 str r4, [sp, #36] ; 0x24 + 8003b70: e9cd 3505 strd r3, r5, [sp, #20] + 8003b74: e9cd 4407 strd r4, r4, [sp, #28] + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, 0); // keep power on! + 8003b78: f7fd fcb6 bl 80014e8 + HAL_GPIO_Init(GPIOC, &setup); + 8003b7c: a905 add r1, sp, #20 + 8003b7e: 4835 ldr r0, [pc, #212] ; (8003c54 ) + 8003b80: f7fd fb38 bl 80011f4 + + // turn LEDs off, SD mux to A + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7|GPIO_PIN_6|GPIO_PIN_13, 0); + 8003b84: 4622 mov r2, r4 + 8003b86: 4833 ldr r0, [pc, #204] ; (8003c54 ) + 8003b88: f44f 5103 mov.w r1, #8384 ; 0x20c0 + 8003b8c: f7fd fcac bl 80014e8 + } + + // Port C - Inputs + // SD card detect switch: PC1 battery/not + { GPIO_InitTypeDef setup = { + 8003b90: 2210 movs r2, #16 + 8003b92: 4621 mov r1, r4 + 8003b94: a806 add r0, sp, #24 + 8003b96: f009 fec5 bl 800d924 + 8003b9a: f242 0302 movw r3, #8194 ; 0x2002 + .Pin = GPIO_PIN_13 | GPIO_PIN_1, + .Mode = GPIO_MODE_INPUT, + .Pull = GPIO_PULLUP, + .Speed = GPIO_SPEED_FREQ_LOW, + }; + HAL_GPIO_Init(GPIOC, &setup); + 8003b9e: a905 add r1, sp, #20 + 8003ba0: 482c ldr r0, [pc, #176] ; (8003c54 ) + { GPIO_InitTypeDef setup = { + 8003ba2: 9305 str r3, [sp, #20] + 8003ba4: 9507 str r5, [sp, #28] + HAL_GPIO_Init(GPIOC, &setup); + 8003ba6: f7fd fb25 bl 80011f4 + .Pin = GPIO_PIN_0, + .Mode = GPIO_MODE_OUTPUT_PP, + .Pull = GPIO_NOPULL, + .Speed = GPIO_SPEED_FREQ_LOW, + }; + HAL_GPIO_Init(GPIOD, &setup); + 8003baa: a905 add r1, sp, #20 + 8003bac: 482a ldr r0, [pc, #168] ; (8003c58 ) + { GPIO_InitTypeDef setup = { + 8003bae: 9409 str r4, [sp, #36] ; 0x24 + 8003bb0: e9cd 4407 strd r4, r4, [sp, #28] + 8003bb4: e9cd 5505 strd r5, r5, [sp, #20] + HAL_GPIO_Init(GPIOD, &setup); + 8003bb8: f7fd fb1c bl 80011f4 + + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0, 0); // turn off + 8003bbc: 4622 mov r2, r4 + 8003bbe: 4629 mov r1, r5 + 8003bc0: 4825 ldr r0, [pc, #148] ; (8003c58 ) + 8003bc2: f7fd fc91 bl 80014e8 + } + + // Port D - Inputs + // SD slots detects: PD3/4 + { GPIO_InitTypeDef setup = { + 8003bc6: 2210 movs r2, #16 + 8003bc8: 4621 mov r1, r4 + 8003bca: a806 add r0, sp, #24 + 8003bcc: f009 feaa bl 800d924 + 8003bd0: 2618 movs r6, #24 + .Pin = GPIO_PIN_3 | GPIO_PIN_4, + .Mode = GPIO_MODE_INPUT, + .Pull = GPIO_PULLUP, // required + .Speed = GPIO_SPEED_FREQ_LOW, + }; + HAL_GPIO_Init(GPIOD, &setup); + 8003bd2: a905 add r1, sp, #20 + 8003bd4: 4820 ldr r0, [pc, #128] ; (8003c58 ) + { GPIO_InitTypeDef setup = { + 8003bd6: 9605 str r6, [sp, #20] + 8003bd8: 9507 str r5, [sp, #28] + HAL_GPIO_Init(GPIOD, &setup); + 8003bda: f7fd fb0b bl 80011f4 + .Pin = GPIO_PIN_3 | GPIO_PIN_4, + .Mode = GPIO_MODE_OUTPUT_PP, + .Pull = GPIO_NOPULL, + .Speed = GPIO_SPEED_FREQ_LOW, + }; + HAL_GPIO_Init(GPIOE, &setup); + 8003bde: a905 add r1, sp, #20 + 8003be0: 481e ldr r0, [pc, #120] ; (8003c5c ) + { GPIO_InitTypeDef setup = { + 8003be2: 9409 str r4, [sp, #36] ; 0x24 + 8003be4: e9cd 4407 strd r4, r4, [sp, #28] + 8003be8: e9cd 6505 strd r6, r5, [sp, #20] + HAL_GPIO_Init(GPIOE, &setup); + 8003bec: f7fd fb02 bl 80011f4 + + HAL_GPIO_WritePin(GPIOE, GPIO_PIN_4, 0); // turn off NFC LED + 8003bf0: 4622 mov r2, r4 + 8003bf2: 481a ldr r0, [pc, #104] ; (8003c5c ) + 8003bf4: 2110 movs r1, #16 + 8003bf6: f7fd fc77 bl 80014e8 + HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, 1); // turn on Backlight: 100% + 8003bfa: 462a mov r2, r5 + 8003bfc: 4817 ldr r0, [pc, #92] ; (8003c5c ) + 8003bfe: 2108 movs r1, #8 + 8003c00: f7fd fc72 bl 80014e8 + + // GPU control: Port E: PE2=G_SWCLK_BOOT0=G_BUSY, PE5=G_CTRL, PE6=G_RESET + // - want open-drain on these outputs, so the SWD debugger can override + // - and PE2 needs to be pull-down input, because active high signal and + // GPU may not be running yet + { GPIO_InitTypeDef setup = { + 8003c04: 2260 movs r2, #96 ; 0x60 + 8003c06: 2311 movs r3, #17 + .Mode = GPIO_MODE_OUTPUT_OD, + .Pull = GPIO_PULLUP, + .Speed = GPIO_SPEED_FREQ_LOW, + }; + + HAL_GPIO_Init(GPIOE, &setup); + 8003c08: a905 add r1, sp, #20 + 8003c0a: 4814 ldr r0, [pc, #80] ; (8003c5c ) + { GPIO_InitTypeDef setup = { + 8003c0c: 9507 str r5, [sp, #28] + 8003c0e: e9cd 2305 strd r2, r3, [sp, #20] + 8003c12: e9cd 4408 strd r4, r4, [sp, #32] + HAL_GPIO_Init(GPIOE, &setup); + 8003c16: f7fd faed bl 80011f4 + + // G_BUSY: input, pull down + setup.Pin = PIN_G_BUSY; + 8003c1a: 2304 movs r3, #4 + 8003c1c: 9305 str r3, [sp, #20] + setup.Pull = GPIO_PULLDOWN; + HAL_GPIO_Init(GPIOE, &setup); + 8003c1e: a905 add r1, sp, #20 + setup.Pull = GPIO_PULLDOWN; + 8003c20: 2302 movs r3, #2 + HAL_GPIO_Init(GPIOE, &setup); + 8003c22: 480e ldr r0, [pc, #56] ; (8003c5c ) + setup.Pull = GPIO_PULLDOWN; + 8003c24: 9307 str r3, [sp, #28] + HAL_GPIO_Init(GPIOE, &setup); + 8003c26: f7fd fae5 bl 80011f4 + + // assert reset, leave others high + HAL_GPIO_WritePin(GPIOE, PIN_G_CTRL, 1); + 8003c2a: 462a mov r2, r5 + 8003c2c: 480b ldr r0, [pc, #44] ; (8003c5c ) + 8003c2e: 2120 movs r1, #32 + 8003c30: f7fd fc5a bl 80014e8 + HAL_GPIO_WritePin(GPIOE, PIN_G_RESET, 0); + 8003c34: 4809 ldr r0, [pc, #36] ; (8003c5c ) + 8003c36: 4622 mov r2, r4 + 8003c38: 2140 movs r1, #64 ; 0x40 + 8003c3a: f7fd fc55 bl 80014e8 + // RCC_MCO1SOURCE_PLLCLK (PLL R output) => (same os SYSCLK) + // RCC_MCO1SOURCE_HSI48 => 48Mhz + // RCC_MCO1SOURCE_HSE => 8Mhz (correct) + __HAL_RCC_MCO1_CONFIG(RCC_MCO1SOURCE_SYSCLK, RCC_MCODIV_1); +#endif +} + 8003c3e: b00a add sp, #40 ; 0x28 + 8003c40: bd70 pop {r4, r5, r6, pc} + 8003c42: bf00 nop + 8003c44: 40021000 .word 0x40021000 + 8003c48: 08010770 .word 0x08010770 + 8003c4c: 40013800 .word 0x40013800 + 8003c50: 48000400 .word 0x48000400 + 8003c54: 48000800 .word 0x48000800 + 8003c58: 48000c00 .word 0x48000c00 + 8003c5c: 48001000 .word 0x48001000 + +08003c60 : +// +// Kill system power; instant. +// + void +turn_power_off(void) +{ + 8003c60: b508 push {r3, lr} + gpio_setup(); + 8003c62: f7ff ff1f bl 8003aa4 + + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, 1); + 8003c66: 2201 movs r2, #1 + 8003c68: 4802 ldr r0, [pc, #8] ; (8003c74 ) + 8003c6a: 4611 mov r1, r2 + 8003c6c: f7fd fc3c bl 80014e8 + + while(1) { + __WFI(); + 8003c70: bf30 wfi + while(1) { + 8003c72: e7fd b.n 8003c70 + 8003c74: 48000800 .word 0x48000800 + +08003c78 : +// Showing a fatal msg to user; power down after a long delay +// or instantly if they touch power btn. Replaces LOCKUP_FOREVER +// + void +q1_wait_powerdown(void) +{ + 8003c78: b508 push {r3, lr} + gpio_setup(); + 8003c7a: f7ff ff13 bl 8003aa4 + + // wait for release (often problem occurs close to power up) + for(uint32_t i=0; i) + gpio_setup(); + 8003c80: 2496 movs r4, #150 ; 0x96 + if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == 1) { + 8003c82: f44f 5180 mov.w r1, #4096 ; 0x1000 + 8003c86: 4628 mov r0, r5 + 8003c88: f7fd fc28 bl 80014dc + 8003c8c: 2801 cmp r0, #1 + 8003c8e: d004 beq.n 8003c9a + break; + } + + delay_ms(100); + 8003c90: 2064 movs r0, #100 ; 0x64 + 8003c92: f7ff fef7 bl 8003a84 + for(uint32_t i=0; i + } + + // wait for press + for(uint32_t i=0; i) + gpio_setup(); + 8003c9c: 2496 movs r4, #150 ; 0x96 + if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == 0) { + 8003c9e: f44f 5180 mov.w r1, #4096 ; 0x1000 + 8003ca2: 4628 mov r0, r5 + 8003ca4: f7fd fc1a bl 80014dc + 8003ca8: b120 cbz r0, 8003cb4 + break; + } + + delay_ms(100); + 8003caa: 2064 movs r0, #100 ; 0x64 + 8003cac: f7ff feea bl 8003a84 + for(uint32_t i=0; i + } + + // turn off power + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, 1); + 8003cb4: 2201 movs r2, #1 + 8003cb6: 4804 ldr r0, [pc, #16] ; (8003cc8 ) + 8003cb8: 4611 mov r1, r2 + 8003cba: f7fd fc15 bl 80014e8 + + // not reached. + while(1) { + __WFI(); + 8003cbe: bf30 wfi + while(1) { + 8003cc0: e7fd b.n 8003cbe + 8003cc2: bf00 nop + 8003cc4: 48000400 .word 0x48000400 + 8003cc8: 48000800 .word 0x48000800 + +08003ccc : + +// reboot_nonce() +// + static inline void +reboot_nonce(SHA256_CTX *ctx) +{ + 8003ccc: b537 push {r0, r1, r2, r4, r5, lr} + uint32_t a = CRC->INIT; + 8003cce: 4d09 ldr r5, [pc, #36] ; (8003cf4 ) + sha256_update(ctx, (const uint8_t *)&a, 4); + 8003cd0: 2204 movs r2, #4 + uint32_t a = CRC->INIT; + 8003cd2: 692b ldr r3, [r5, #16] + 8003cd4: 9301 str r3, [sp, #4] + sha256_update(ctx, (const uint8_t *)&a, 4); + 8003cd6: eb0d 0102 add.w r1, sp, r2 +{ + 8003cda: 4604 mov r4, r0 + sha256_update(ctx, (const uint8_t *)&a, 4); + 8003cdc: f001 fd5c bl 8005798 + + a = CRC->POL; + sha256_update(ctx, (const uint8_t *)&a, 4); + 8003ce0: 2204 movs r2, #4 + a = CRC->POL; + 8003ce2: 696b ldr r3, [r5, #20] + 8003ce4: 9301 str r3, [sp, #4] + sha256_update(ctx, (const uint8_t *)&a, 4); + 8003ce6: eb0d 0102 add.w r1, sp, r2 + 8003cea: 4620 mov r0, r4 + 8003cec: f001 fd54 bl 8005798 +} + 8003cf0: b003 add sp, #12 + 8003cf2: bd30 pop {r4, r5, pc} + 8003cf4: 40023000 .word 0x40023000 + +08003cf8 : +// +// Hash up a string of digits into 32-bytes of goodness. +// + static void +pin_hash(const char *pin, int pin_len, uint8_t result[32], uint32_t purpose) +{ + 8003cf8: b570 push {r4, r5, r6, lr} + 8003cfa: b096 sub sp, #88 ; 0x58 + ASSERT(pin_len <= MAX_PIN_LEN); + 8003cfc: 2920 cmp r1, #32 +{ + 8003cfe: 4606 mov r6, r0 + 8003d00: 460d mov r5, r1 + 8003d02: 4614 mov r4, r2 + 8003d04: 9301 str r3, [sp, #4] + ASSERT(pin_len <= MAX_PIN_LEN); + 8003d06: dd02 ble.n 8003d0e + 8003d08: 4817 ldr r0, [pc, #92] ; (8003d68 ) + 8003d0a: f7fc fe95 bl 8000a38 + + if(pin_len == 0) { + 8003d0e: b929 cbnz r1, 8003d1c + // zero-length PIN is considered the "blank" one: all zero + memset(result, 0, 32); + 8003d10: 2220 movs r2, #32 + 8003d12: 4620 mov r0, r4 + 8003d14: f009 fe06 bl 800d924 + // and run that thru SE2 as well + se2_pin_hash(result, purpose); + + // and a second-sha256 on that, just in case. + sha256_single(result, 32, result); +} + 8003d18: b016 add sp, #88 ; 0x58 + 8003d1a: bd70 pop {r4, r5, r6, pc} + sha256_init(&ctx); + 8003d1c: a803 add r0, sp, #12 + 8003d1e: f001 fd2d bl 800577c + sha256_update(&ctx, rom_secrets->hash_cache_secret, 32); + 8003d22: a803 add r0, sp, #12 + 8003d24: 4911 ldr r1, [pc, #68] ; (8003d6c ) + 8003d26: 2220 movs r2, #32 + 8003d28: f001 fd36 bl 8005798 + sha256_update(&ctx, (uint8_t *)&purpose, 4); + 8003d2c: 2204 movs r2, #4 + 8003d2e: eb0d 0102 add.w r1, sp, r2 + 8003d32: a803 add r0, sp, #12 + 8003d34: f001 fd30 bl 8005798 + sha256_update(&ctx, (uint8_t *)pin, pin_len); + 8003d38: 462a mov r2, r5 + 8003d3a: 4631 mov r1, r6 + 8003d3c: a803 add r0, sp, #12 + 8003d3e: f001 fd2b bl 8005798 + sha256_update(&ctx, rom_secrets->pairing_secret, 32); + 8003d42: 2220 movs r2, #32 + 8003d44: a803 add r0, sp, #12 + 8003d46: 490a ldr r1, [pc, #40] ; (8003d70 ) + 8003d48: f001 fd26 bl 8005798 + sha256_final(&ctx, result); + 8003d4c: 4621 mov r1, r4 + 8003d4e: a803 add r0, sp, #12 + 8003d50: f001 fd68 bl 8005824 + se2_pin_hash(result, purpose); + 8003d54: 9901 ldr r1, [sp, #4] + 8003d56: 4620 mov r0, r4 + 8003d58: f004 fc46 bl 80085e8 + sha256_single(result, 32, result); + 8003d5c: 4622 mov r2, r4 + 8003d5e: 2120 movs r1, #32 + 8003d60: 4620 mov r0, r4 + 8003d62: f001 fd73 bl 800584c + 8003d66: e7d7 b.n 8003d18 + 8003d68: 0801046c .word 0x0801046c + 8003d6c: 0801c070 .word 0x0801c070 + 8003d70: 0801c000 .word 0x0801c000 + +08003d74 <_hmac_attempt>: +// +// Maybe should be proper HMAC from fips std? Can be changed later. +// + static void +_hmac_attempt(const pinAttempt_t *args, uint8_t result[32]) +{ + 8003d74: b530 push {r4, r5, lr} + 8003d76: b095 sub sp, #84 ; 0x54 + 8003d78: 4604 mov r4, r0 + SHA256_CTX ctx; + + sha256_init(&ctx); + 8003d7a: a801 add r0, sp, #4 +{ + 8003d7c: 460d mov r5, r1 + sha256_init(&ctx); + 8003d7e: f001 fcfd bl 800577c + sha256_update(&ctx, rom_secrets->pairing_secret, 32); + 8003d82: 4911 ldr r1, [pc, #68] ; (8003dc8 <_hmac_attempt+0x54>) + 8003d84: 2220 movs r2, #32 + 8003d86: a801 add r0, sp, #4 + 8003d88: f001 fd06 bl 8005798 + reboot_nonce(&ctx); + 8003d8c: a801 add r0, sp, #4 + 8003d8e: f7ff ff9d bl 8003ccc + sha256_update(&ctx, (uint8_t *)args, offsetof(pinAttempt_t, hmac)); + 8003d92: 2244 movs r2, #68 ; 0x44 + 8003d94: 4621 mov r1, r4 + 8003d96: a801 add r0, sp, #4 + 8003d98: f001 fcfe bl 8005798 + + if(args->magic_value == PA_MAGIC_V2) { + 8003d9c: 6822 ldr r2, [r4, #0] + 8003d9e: 4b0b ldr r3, [pc, #44] ; (8003dcc <_hmac_attempt+0x58>) + 8003da0: 429a cmp r2, r3 + 8003da2: d105 bne.n 8003db0 <_hmac_attempt+0x3c> + sha256_update(&ctx, (uint8_t *)args->cached_main_pin, + 8003da4: 2220 movs r2, #32 + 8003da6: f104 01f8 add.w r1, r4, #248 ; 0xf8 + 8003daa: a801 add r0, sp, #4 + 8003dac: f001 fcf4 bl 8005798 + msizeof(pinAttempt_t, cached_main_pin)); + } + + sha256_final(&ctx, result); + 8003db0: 4629 mov r1, r5 + 8003db2: a801 add r0, sp, #4 + 8003db4: f001 fd36 bl 8005824 + + // and a second-sha256 on that, just in case. + sha256_single(result, 32, result); + 8003db8: 462a mov r2, r5 + 8003dba: 2120 movs r1, #32 + 8003dbc: 4628 mov r0, r5 + 8003dbe: f001 fd45 bl 800584c +} + 8003dc2: b015 add sp, #84 ; 0x54 + 8003dc4: bd30 pop {r4, r5, pc} + 8003dc6: bf00 nop + 8003dc8: 0801c000 .word 0x0801c000 + 8003dcc: 2eaf6312 .word 0x2eaf6312 + +08003dd0 <_validate_attempt>: + +// _validate_attempt() +// + static int +_validate_attempt(const pinAttempt_t *args, bool first_time) +{ + 8003dd0: b510 push {r4, lr} + 8003dd2: 4604 mov r4, r0 + 8003dd4: b088 sub sp, #32 + if(first_time) { + 8003dd6: b969 cbnz r1, 8003df4 <_validate_attempt+0x24> + // no hmac needed for setup call + } else { + // if hmac is defined, better be right. + uint8_t actual[32]; + + _hmac_attempt(args, actual); + 8003dd8: 4669 mov r1, sp + 8003dda: f7ff ffcb bl 8003d74 <_hmac_attempt> + + if(!check_equal(actual, args->hmac, 32)) { + 8003dde: 2220 movs r2, #32 + 8003de0: f104 0144 add.w r1, r4, #68 ; 0x44 + 8003de4: 4668 mov r0, sp + 8003de6: f7fe fd2a bl 800283e + 8003dea: b918 cbnz r0, 8003df4 <_validate_attempt+0x24> + // hmac is wrong? + return EPIN_HMAC_FAIL; + 8003dec: f06f 0063 mvn.w r0, #99 ; 0x63 + if((args->change_flags & CHANGE__MASK) != args->change_flags) return EPIN_RANGE_ERR; + + if((args->is_secondary & 0x1) != args->is_secondary) return EPIN_RANGE_ERR; + + return 0; +} + 8003df0: b008 add sp, #32 + 8003df2: bd10 pop {r4, pc} + if(args->magic_value == PA_MAGIC_V2) { + 8003df4: 6822 ldr r2, [r4, #0] + 8003df6: 4b10 ldr r3, [pc, #64] ; (8003e38 <_validate_attempt+0x68>) + 8003df8: 429a cmp r2, r3 + 8003dfa: d117 bne.n 8003e2c <_validate_attempt+0x5c> + if(args->pin_len > MAX_PIN_LEN) return EPIN_RANGE_ERR; + 8003dfc: 6aa3 ldr r3, [r4, #40] ; 0x28 + 8003dfe: 2b20 cmp r3, #32 + 8003e00: dc17 bgt.n 8003e32 <_validate_attempt+0x62> + if(args->old_pin_len > MAX_PIN_LEN) return EPIN_RANGE_ERR; + 8003e02: f8d4 3088 ldr.w r3, [r4, #136] ; 0x88 + 8003e06: 2b20 cmp r3, #32 + 8003e08: dc13 bgt.n 8003e32 <_validate_attempt+0x62> + if(args->new_pin_len > MAX_PIN_LEN) return EPIN_RANGE_ERR; + 8003e0a: f8d4 30ac ldr.w r3, [r4, #172] ; 0xac + 8003e0e: 2b20 cmp r3, #32 + 8003e10: dc0f bgt.n 8003e32 <_validate_attempt+0x62> + if((args->change_flags & CHANGE__MASK) != args->change_flags) return EPIN_RANGE_ERR; + 8003e12: 6e63 ldr r3, [r4, #100] ; 0x64 + 8003e14: f640 727f movw r2, #3967 ; 0xf7f + 8003e18: 4393 bics r3, r2 + 8003e1a: d10a bne.n 8003e32 <_validate_attempt+0x62> + if((args->is_secondary & 0x1) != args->is_secondary) return EPIN_RANGE_ERR; + 8003e1c: 6863 ldr r3, [r4, #4] + return 0; + 8003e1e: f033 0301 bics.w r3, r3, #1 + 8003e22: bf14 ite ne + 8003e24: f06f 0066 mvnne.w r0, #102 ; 0x66 + 8003e28: 2000 moveq r0, #0 + 8003e2a: e7e1 b.n 8003df0 <_validate_attempt+0x20> + return EPIN_BAD_MAGIC; + 8003e2c: f06f 0065 mvn.w r0, #101 ; 0x65 + 8003e30: e7de b.n 8003df0 <_validate_attempt+0x20> + if((args->is_secondary & 0x1) != args->is_secondary) return EPIN_RANGE_ERR; + 8003e32: f06f 0066 mvn.w r0, #102 ; 0x66 + 8003e36: e7db b.n 8003df0 <_validate_attempt+0x20> + 8003e38: 2eaf6312 .word 0x2eaf6312 + +08003e3c : + +// warmup_ae() +// + static int +warmup_ae(void) +{ + 8003e3c: b510 push {r4, lr} + ae_setup(); + 8003e3e: f7fe fe87 bl 8002b50 + 8003e42: 2405 movs r4, #5 + + for(int retry=0; retry<5; retry++) { + if(!ae_probe()) break; + 8003e44: f7ff f90c bl 8003060 + 8003e48: b108 cbz r0, 8003e4e + for(int retry=0; retry<5; retry++) { + 8003e4a: 3c01 subs r4, #1 + 8003e4c: d1fa bne.n 8003e44 + } + + if(ae_pair_unlock()) return -1; + 8003e4e: f7ff f875 bl 8002f3c + 8003e52: 4604 mov r4, r0 + 8003e54: b918 cbnz r0, 8003e5e + + // reset watchdog timer + ae_keep_alive(); + 8003e56: f7fe fead bl 8002bb4 + + return 0; +} + 8003e5a: 4620 mov r0, r4 + 8003e5c: bd10 pop {r4, pc} + if(ae_pair_unlock()) return -1; + 8003e5e: f04f 34ff mov.w r4, #4294967295 ; 0xffffffff + 8003e62: e7fa b.n 8003e5a + +08003e64 <_read_slot_as_counter>: +{ + 8003e64: b530 push {r4, r5, lr} + 8003e66: b091 sub sp, #68 ; 0x44 + uint32_t padded[32/4] = { 0 }; + 8003e68: 2220 movs r2, #32 +{ + 8003e6a: 4604 mov r4, r0 + 8003e6c: 460d mov r5, r1 + uint32_t padded[32/4] = { 0 }; + 8003e6e: 4668 mov r0, sp + 8003e70: 2100 movs r1, #0 + 8003e72: f009 fd57 bl 800d924 + ae_pair_unlock(); + 8003e76: f7ff f861 bl 8002f3c + if(ae_read_data_slot(slot, (uint8_t *)padded, 32)) return -1; + 8003e7a: 2220 movs r2, #32 + 8003e7c: 4669 mov r1, sp + 8003e7e: 4620 mov r0, r4 + 8003e80: f7ff fba2 bl 80035c8 + 8003e84: b120 cbz r0, 8003e90 <_read_slot_as_counter+0x2c> + 8003e86: f04f 34ff mov.w r4, #4294967295 ; 0xffffffff +} + 8003e8a: 4620 mov r0, r4 + 8003e8c: b011 add sp, #68 ; 0x44 + 8003e8e: bd30 pop {r4, r5, pc} + ae_pair_unlock(); + 8003e90: f7ff f854 bl 8002f3c + if(ae_gendig_slot(slot, (const uint8_t *)padded, tempkey)) return -1; + 8003e94: 4620 mov r0, r4 + 8003e96: aa08 add r2, sp, #32 + 8003e98: 4669 mov r1, sp + 8003e9a: f7ff f96f bl 800317c + 8003e9e: 4604 mov r4, r0 + 8003ea0: 2800 cmp r0, #0 + 8003ea2: d1f0 bne.n 8003e86 <_read_slot_as_counter+0x22> + if(!ae_is_correct_tempkey(tempkey)) fatal_mitm(); + 8003ea4: a808 add r0, sp, #32 + 8003ea6: f7fe ff79 bl 8002d9c + 8003eaa: b908 cbnz r0, 8003eb0 <_read_slot_as_counter+0x4c> + 8003eac: f7fc fdce bl 8000a4c + *dest = padded[0]; + 8003eb0: 9b00 ldr r3, [sp, #0] + 8003eb2: 602b str r3, [r5, #0] + return 0; + 8003eb4: e7e9 b.n 8003e8a <_read_slot_as_counter+0x26> + +08003eb6 : +{ + 8003eb6: b530 push {r4, r5, lr} + 8003eb8: b095 sub sp, #84 ; 0x54 + 8003eba: 4605 mov r5, r0 + ae_pair_unlock(); + 8003ebc: f7ff f83e bl 8002f3c + uint32_t padded[32/4] = { 0 }; + 8003ec0: 2220 movs r2, #32 + 8003ec2: 2100 movs r1, #0 + 8003ec4: a804 add r0, sp, #16 + 8003ec6: f009 fd2d bl 800d924 + if(ae_read_data_slot(slot, (uint8_t *)padded, 32)) return -1; + 8003eca: 2220 movs r2, #32 + 8003ecc: a904 add r1, sp, #16 + 8003ece: 2005 movs r0, #5 + 8003ed0: f7ff fb7a bl 80035c8 + 8003ed4: b118 cbz r0, 8003ede + 8003ed6: f04f 30ff mov.w r0, #4294967295 ; 0xffffffff +} + 8003eda: b015 add sp, #84 ; 0x54 + 8003edc: bd30 pop {r4, r5, pc} + ae_pair_unlock(); + 8003ede: f7ff f82d bl 8002f3c + if(ae_gendig_slot(slot, (const uint8_t *)padded, tempkey)) return -1; + 8003ee2: aa0c add r2, sp, #48 ; 0x30 + 8003ee4: a904 add r1, sp, #16 + 8003ee6: 2005 movs r0, #5 + 8003ee8: f7ff f948 bl 800317c + 8003eec: 4604 mov r4, r0 + 8003eee: 2800 cmp r0, #0 + 8003ef0: d1f1 bne.n 8003ed6 + if(!ae_is_correct_tempkey(tempkey)) fatal_mitm(); + 8003ef2: a80c add r0, sp, #48 ; 0x30 + 8003ef4: f7fe ff52 bl 8002d9c + 8003ef8: b908 cbnz r0, 8003efe + 8003efa: f7fc fda7 bl 8000a4c + if(_read_slot_as_counter(KEYNUM_lastgood, &lastgood)) return -1; + 8003efe: a901 add r1, sp, #4 + 8003f00: 2005 movs r0, #5 + uint32_t lastgood=0, match_count=0, counter=0; + 8003f02: e9cd 4401 strd r4, r4, [sp, #4] + 8003f06: 9403 str r4, [sp, #12] + if(_read_slot_as_counter(KEYNUM_lastgood, &lastgood)) return -1; + 8003f08: f7ff ffac bl 8003e64 <_read_slot_as_counter> + 8003f0c: 2800 cmp r0, #0 + 8003f0e: d1e2 bne.n 8003ed6 + if(_read_slot_as_counter(KEYNUM_match_count, &match_count)) return -1; + 8003f10: a902 add r1, sp, #8 + 8003f12: 2006 movs r0, #6 + 8003f14: f7ff ffa6 bl 8003e64 <_read_slot_as_counter> + 8003f18: 4601 mov r1, r0 + 8003f1a: 2800 cmp r0, #0 + 8003f1c: d1db bne.n 8003ed6 + if(ae_get_counter(&counter, 0)) return -1; + 8003f1e: a803 add r0, sp, #12 + 8003f20: f7ff fa07 bl 8003332 + 8003f24: 2800 cmp r0, #0 + 8003f26: d1d6 bne.n 8003ed6 + if(lastgood > counter) { + 8003f28: 9a01 ldr r2, [sp, #4] + 8003f2a: 9903 ldr r1, [sp, #12] + match_count &= ~31; + 8003f2c: 9b02 ldr r3, [sp, #8] + if(lastgood > counter) { + 8003f2e: 428a cmp r2, r1 + match_count &= ~31; + 8003f30: f023 031f bic.w r3, r3, #31 + args->num_fails = counter - lastgood; + 8003f34: bf94 ite ls + 8003f36: 1a8a subls r2, r1, r2 + args->num_fails = 99; + 8003f38: 2263 movhi r2, #99 ; 0x63 + if(counter < match_count) { + 8003f3a: 4299 cmp r1, r3 + args->attempts_left = match_count - counter; + 8003f3c: bf34 ite cc + 8003f3e: 1a5b subcc r3, r3, r1 + args->attempts_left = 0; + 8003f40: 2300 movcs r3, #0 + 8003f42: 636a str r2, [r5, #52] ; 0x34 + 8003f44: 63ab str r3, [r5, #56] ; 0x38 + 8003f46: e7c8 b.n 8003eda + +08003f48 : + +// updates_for_good_login() +// + static int +updates_for_good_login(uint8_t digest[32]) +{ + 8003f48: b5f0 push {r4, r5, r6, r7, lr} + 8003f4a: b08d sub sp, #52 ; 0x34 + // User got the main PIN right: update the attempt counters, + // to document this (lastgood) and also bump the match counter if needed + + uint32_t count; + int rv = ae_get_counter(&count, 0); + 8003f4c: 2100 movs r1, #0 +{ + 8003f4e: 4606 mov r6, r0 + int rv = ae_get_counter(&count, 0); + 8003f50: a802 add r0, sp, #8 + 8003f52: f7ff f9ee bl 8003332 + if(rv) goto fail; + 8003f56: 4601 mov r1, r0 + 8003f58: 2800 cmp r0, #0 + 8003f5a: d13b bne.n 8003fd4 + + // Challenge: Have to update both the counter, and the target match value because + // no other way to have exact value. + + uint32_t mc = (count + MAX_TARGET_ATTEMPTS + 32) & ~31; + 8003f5c: 9b02 ldr r3, [sp, #8] + 8003f5e: f103 042d add.w r4, r3, #45 ; 0x2d + 8003f62: f024 041f bic.w r4, r4, #31 + ASSERT(mc >= count); + 8003f66: 42a3 cmp r3, r4 + 8003f68: d902 bls.n 8003f70 + 8003f6a: 481d ldr r0, [pc, #116] ; (8003fe0 ) + 8003f6c: f7fc fd64 bl 8000a38 + + int bump = (mc - MAX_TARGET_ATTEMPTS) - count; + 8003f70: 1ae3 subs r3, r4, r3 + 8003f72: f1a3 050d sub.w r5, r3, #13 + ASSERT(bump >= 1); + 8003f76: 3b0e subs r3, #14 + 8003f78: 2b1f cmp r3, #31 + 8003f7a: d8f6 bhi.n 8003f6a + // Would rather update the counter first, so that a hostile interruption can't increase + // attempts (altho the attacker knows the pin at that point?!) .. but chip won't + // let the counter go past the match value, so that has to be first. + + // set the new "match count" + { uint32_t tmp[32/4] = {mc, mc} ; + 8003f7c: 2218 movs r2, #24 + 8003f7e: eb0d 0002 add.w r0, sp, r2 + rv = ae_encrypted_write(KEYNUM_match_count, KEYNUM_main_pin, digest, (void *)tmp, 32); + 8003f82: 2720 movs r7, #32 + { uint32_t tmp[32/4] = {mc, mc} ; + 8003f84: f009 fcce bl 800d924 + rv = ae_encrypted_write(KEYNUM_match_count, KEYNUM_main_pin, digest, (void *)tmp, 32); + 8003f88: 2103 movs r1, #3 + 8003f8a: 9700 str r7, [sp, #0] + 8003f8c: ab04 add r3, sp, #16 + 8003f8e: 4632 mov r2, r6 + 8003f90: 2006 movs r0, #6 + { uint32_t tmp[32/4] = {mc, mc} ; + 8003f92: e9cd 4404 strd r4, r4, [sp, #16] + rv = ae_encrypted_write(KEYNUM_match_count, KEYNUM_main_pin, digest, (void *)tmp, 32); + 8003f96: f7ff fae1 bl 800355c + if(rv) goto fail; + 8003f9a: 4601 mov r1, r0 + 8003f9c: b9d0 cbnz r0, 8003fd4 + } + + // incr the counter a bunch to get to that-13 + uint32_t new_count = 0; + 8003f9e: 9003 str r0, [sp, #12] + rv = ae_add_counter(&new_count, 0, bump); + 8003fa0: 462a mov r2, r5 + 8003fa2: a803 add r0, sp, #12 + 8003fa4: f7ff f9e4 bl 8003370 + if(rv) goto fail; + 8003fa8: 4601 mov r1, r0 + 8003faa: b998 cbnz r0, 8003fd4 + + ASSERT(new_count == count + bump); + 8003fac: 9b02 ldr r3, [sp, #8] + 8003fae: 441d add r5, r3 + 8003fb0: 9b03 ldr r3, [sp, #12] + 8003fb2: 429d cmp r5, r3 + 8003fb4: d1d9 bne.n 8003f6a + ASSERT(mc > new_count); + 8003fb6: 42a5 cmp r5, r4 + 8003fb8: d2d7 bcs.n 8003f6a + + // Update the "last good" counter + { uint32_t tmp[32/4] = {new_count, 0 }; + 8003fba: 221c movs r2, #28 + 8003fbc: a805 add r0, sp, #20 + 8003fbe: f009 fcb1 bl 800d924 + rv = ae_encrypted_write(KEYNUM_lastgood, KEYNUM_main_pin, digest, (void *)tmp, 32); + 8003fc2: 9700 str r7, [sp, #0] + 8003fc4: ab04 add r3, sp, #16 + 8003fc6: 4632 mov r2, r6 + 8003fc8: 2103 movs r1, #3 + 8003fca: 2005 movs r0, #5 + { uint32_t tmp[32/4] = {new_count, 0 }; + 8003fcc: 9504 str r5, [sp, #16] + rv = ae_encrypted_write(KEYNUM_lastgood, KEYNUM_main_pin, digest, (void *)tmp, 32); + 8003fce: f7ff fac5 bl 800355c + if(rv) goto fail; + 8003fd2: b118 cbz r0, 8003fdc + // just be reducing attempts. + + return 0; + +fail: + ae_reset_chip(); + 8003fd4: f7fe fdae bl 8002b34 + return EPIN_AE_FAIL; + 8003fd8: f06f 0069 mvn.w r0, #105 ; 0x69 +} + 8003fdc: b00d add sp, #52 ; 0x34 + 8003fde: bdf0 pop {r4, r5, r6, r7, pc} + 8003fe0: 0801046c .word 0x0801046c + +08003fe4 : +{ + 8003fe4: b5f0 push {r4, r5, r6, r7, lr} + 8003fe6: 4615 mov r5, r2 + 8003fe8: b089 sub sp, #36 ; 0x24 + if(pin_len == 0) { + 8003fea: 460c mov r4, r1 + 8003fec: b931 cbnz r1, 8003ffc + memset(result, 0, 32); + 8003fee: 2220 movs r2, #32 + 8003ff0: 4628 mov r0, r5 + 8003ff2: f009 fc97 bl 800d924 +} + 8003ff6: 4620 mov r0, r4 + 8003ff8: b009 add sp, #36 ; 0x24 + 8003ffa: bdf0 pop {r4, r5, r6, r7, pc} + pin_hash(pin, pin_len, tmp, PIN_PURPOSE_NORMAL); + 8003ffc: 4b0f ldr r3, [pc, #60] ; (800403c ) + 8003ffe: 466a mov r2, sp + 8004000: f7ff fe7a bl 8003cf8 + int rv = ae_stretch_iter(tmp, result, KDF_ITER_PIN); + 8004004: 2208 movs r2, #8 + 8004006: 4629 mov r1, r5 + 8004008: 4668 mov r0, sp + 800400a: f7ff fcbf bl 800398c + if(rv) return EPIN_AE_FAIL; + 800400e: 4604 mov r4, r0 + 8004010: b988 cbnz r0, 8004036 + memcpy(tmp, result, 32); + 8004012: 462b mov r3, r5 + 8004014: 466e mov r6, sp + 8004016: f105 0720 add.w r7, r5, #32 + 800401a: 6818 ldr r0, [r3, #0] + 800401c: 6859 ldr r1, [r3, #4] + 800401e: 4632 mov r2, r6 + 8004020: c203 stmia r2!, {r0, r1} + 8004022: 3308 adds r3, #8 + 8004024: 42bb cmp r3, r7 + 8004026: 4616 mov r6, r2 + 8004028: d1f7 bne.n 800401a + ae_mixin_key(KEYNUM_pin_attempt, tmp, result); + 800402a: 462a mov r2, r5 + 800402c: 4669 mov r1, sp + 800402e: 2004 movs r0, #4 + 8004030: f7ff fcd4 bl 80039dc + return 0; + 8004034: e7df b.n 8003ff6 + if(rv) return EPIN_AE_FAIL; + 8004036: f06f 0469 mvn.w r4, #105 ; 0x69 + 800403a: e7dc b.n 8003ff6 + 800403c: 334d1858 .word 0x334d1858 + +08004040 : +set_is_trick(pinAttempt_t *args, const trick_slot_t *slot) + 8004040: b5f0 push {r4, r5, r6, r7, lr} + args->delay_achieved = slot->tc_arg; + 8004042: 88cb ldrh r3, [r1, #6] + 8004044: 62c3 str r3, [r0, #44] ; 0x2c +set_is_trick(pinAttempt_t *args, const trick_slot_t *slot) + 8004046: f5ad 7d0d sub.w sp, sp, #564 ; 0x234 + memcpy(key, &args->private_state, sizeof(args->private_state)); + 800404a: 6c03 ldr r3, [r0, #64] ; 0x40 + memcpy(key+4, rom_secrets->hash_cache_secret+4, sizeof(rom_secrets->hash_cache_secret)-4); + 800404c: 4d0f ldr r5, [pc, #60] ; (800408c ) + memcpy(key, &args->private_state, sizeof(args->private_state)); + 800404e: 9303 str r3, [sp, #12] +set_is_trick(pinAttempt_t *args, const trick_slot_t *slot) + 8004050: 4606 mov r6, r0 + 8004052: 460f mov r7, r1 + memcpy(key+4, rom_secrets->hash_cache_secret+4, sizeof(rom_secrets->hash_cache_secret)-4); + 8004054: cd0f ldmia r5!, {r0, r1, r2, r3} + 8004056: ac04 add r4, sp, #16 + 8004058: c40f stmia r4!, {r0, r1, r2, r3} + 800405a: e895 0007 ldmia.w r5, {r0, r1, r2} + 800405e: e884 0007 stmia.w r4, {r0, r1, r2} + aes_init(&ctx); + 8004062: a80b add r0, sp, #44 ; 0x2c + 8004064: f004 fb6e bl 8008744 + aes_add(&ctx, (uint8_t *)slot, 32); + 8004068: 4639 mov r1, r7 + 800406a: a80b add r0, sp, #44 ; 0x2c + 800406c: 2220 movs r2, #32 + 800406e: f004 fb6f bl 8008750 + aes_done(&ctx, args->cached_main_pin, 32, key, NULL); + 8004072: 2300 movs r3, #0 + 8004074: 9300 str r3, [sp, #0] + 8004076: 2220 movs r2, #32 + 8004078: ab03 add r3, sp, #12 + 800407a: f106 01f8 add.w r1, r6, #248 ; 0xf8 + 800407e: a80b add r0, sp, #44 ; 0x2c + 8004080: f004 fb7c bl 800877c +} + 8004084: f50d 7d0d add.w sp, sp, #564 ; 0x234 + 8004088: bdf0 pop {r4, r5, r6, r7, pc} + 800408a: bf00 nop + 800408c: 0801c074 .word 0x0801c074 + +08004090 : + __HAL_RCC_CRC_CLK_ENABLE(); + 8004090: 4b09 ldr r3, [pc, #36] ; (80040b8 ) + 8004092: 6c9a ldr r2, [r3, #72] ; 0x48 +{ + 8004094: b513 push {r0, r1, r4, lr} + __HAL_RCC_CRC_CLK_ENABLE(); + 8004096: f442 5280 orr.w r2, r2, #4096 ; 0x1000 + 800409a: 649a str r2, [r3, #72] ; 0x48 + 800409c: 6c9b ldr r3, [r3, #72] ; 0x48 + CRC->INIT = rng_sample(); + 800409e: 4c07 ldr r4, [pc, #28] ; (80040bc ) + __HAL_RCC_CRC_CLK_ENABLE(); + 80040a0: f403 5380 and.w r3, r3, #4096 ; 0x1000 + 80040a4: 9301 str r3, [sp, #4] + 80040a6: 9b01 ldr r3, [sp, #4] + CRC->INIT = rng_sample(); + 80040a8: f7fe fbda bl 8002860 + 80040ac: 6120 str r0, [r4, #16] + CRC->POL = rng_sample(); + 80040ae: f7fe fbd7 bl 8002860 + 80040b2: 6160 str r0, [r4, #20] +} + 80040b4: b002 add sp, #8 + 80040b6: bd10 pop {r4, pc} + 80040b8: 40021000 .word 0x40021000 + 80040bc: 40023000 .word 0x40023000 + +080040c0 : +{ + 80040c0: b510 push {r4, lr} + 80040c2: b094 sub sp, #80 ; 0x50 + 80040c4: 4604 mov r4, r0 + sha256_init(&ctx); + 80040c6: a801 add r0, sp, #4 + 80040c8: f001 fb58 bl 800577c + reboot_nonce(&ctx); + 80040cc: a801 add r0, sp, #4 + 80040ce: f7ff fdfd bl 8003ccc + sha256_update(&ctx, rom_secrets->hash_cache_secret, 32); + 80040d2: 2220 movs r2, #32 + 80040d4: a801 add r0, sp, #4 + 80040d6: 4904 ldr r1, [pc, #16] ; (80040e8 ) + 80040d8: f001 fb5e bl 8005798 + sha256_final(&ctx, key); + 80040dc: 4621 mov r1, r4 + 80040de: a801 add r0, sp, #4 + 80040e0: f001 fba0 bl 8005824 +} + 80040e4: b014 add sp, #80 ; 0x50 + 80040e6: bd10 pop {r4, pc} + 80040e8: 0801c070 .word 0x0801c070 + +080040ec : +{ + 80040ec: b530 push {r4, r5, lr} + 80040ee: 460d mov r5, r1 + 80040f0: b089 sub sp, #36 ; 0x24 + 80040f2: 4604 mov r4, r0 + if(!check_all_zeros(digest, 32)) { + 80040f4: 2120 movs r1, #32 + 80040f6: 4628 mov r0, r5 + 80040f8: f7fe fb92 bl 8002820 + 80040fc: b9a0 cbnz r0, 8004128 + pin_cache_get_key(value); + 80040fe: 4668 mov r0, sp + 8004100: f7ff ffde bl 80040c0 + 8004104: 466b mov r3, sp + 8004106: f105 0120 add.w r1, r5, #32 + *(acc) ^= *(more); + 800410a: 781a ldrb r2, [r3, #0] + 800410c: f815 0b01 ldrb.w r0, [r5], #1 + 8004110: 4042 eors r2, r0 + for(; len; len--, more++, acc++) { + 8004112: 428d cmp r5, r1 + *(acc) ^= *(more); + 8004114: f803 2b01 strb.w r2, [r3], #1 + for(; len; len--, more++, acc++) { + 8004118: d1f7 bne.n 800410a + ASSERT(args->magic_value == PA_MAGIC_V2); + 800411a: 6822 ldr r2, [r4, #0] + 800411c: 4b0d ldr r3, [pc, #52] ; (8004154 ) + 800411e: 429a cmp r2, r3 + 8004120: d008 beq.n 8004134 + 8004122: 480d ldr r0, [pc, #52] ; (8004158 ) + 8004124: f7fc fc88 bl 8000a38 + memset(value, 0, 32); + 8004128: 2220 movs r2, #32 + 800412a: 2100 movs r1, #0 + 800412c: 4668 mov r0, sp + 800412e: f009 fbf9 bl 800d924 + 8004132: e7f2 b.n 800411a + memcpy(args->cached_main_pin, value, 32); + 8004134: 466b mov r3, sp + 8004136: f104 02f8 add.w r2, r4, #248 ; 0xf8 + 800413a: ad08 add r5, sp, #32 + 800413c: 461c mov r4, r3 + 800413e: cc03 ldmia r4!, {r0, r1} + 8004140: 42ac cmp r4, r5 + 8004142: 6010 str r0, [r2, #0] + 8004144: 6051 str r1, [r2, #4] + 8004146: 4623 mov r3, r4 + 8004148: f102 0208 add.w r2, r2, #8 + 800414c: d1f6 bne.n 800413c +} + 800414e: b009 add sp, #36 ; 0x24 + 8004150: bd30 pop {r4, r5, pc} + 8004152: bf00 nop + 8004154: 2eaf6312 .word 0x2eaf6312 + 8004158: 0801046c .word 0x0801046c + +0800415c : +{ + 800415c: b510 push {r4, lr} + ASSERT(args->magic_value == PA_MAGIC_V2); + 800415e: 6802 ldr r2, [r0, #0] + 8004160: 4b14 ldr r3, [pc, #80] ; (80041b4 ) + 8004162: 429a cmp r2, r3 +{ + 8004164: b088 sub sp, #32 + 8004166: 460c mov r4, r1 + ASSERT(args->magic_value == PA_MAGIC_V2); + 8004168: d002 beq.n 8004170 + 800416a: 4813 ldr r0, [pc, #76] ; (80041b8 ) + 800416c: f7fc fc64 bl 8000a38 + memcpy(digest, args->cached_main_pin, 32); + 8004170: f100 03f8 add.w r3, r0, #248 ; 0xf8 + 8004174: 460a mov r2, r1 + 8004176: f500 708c add.w r0, r0, #280 ; 0x118 + 800417a: f853 1b04 ldr.w r1, [r3], #4 + 800417e: f842 1b04 str.w r1, [r2], #4 + 8004182: 4283 cmp r3, r0 + 8004184: d1f9 bne.n 800417a + if(!check_all_zeros(digest, 32)) { + 8004186: 2120 movs r1, #32 + 8004188: 4620 mov r0, r4 + 800418a: f7fe fb49 bl 8002820 + 800418e: b970 cbnz r0, 80041ae + pin_cache_get_key(key); + 8004190: 4668 mov r0, sp + 8004192: f7ff ff95 bl 80040c0 + 8004196: 1e62 subs r2, r4, #1 + 8004198: 466b mov r3, sp + 800419a: 341f adds r4, #31 + *(acc) ^= *(more); + 800419c: f812 1f01 ldrb.w r1, [r2, #1]! + 80041a0: f813 0b01 ldrb.w r0, [r3], #1 + for(; len; len--, more++, acc++) { + 80041a4: 42a2 cmp r2, r4 + *(acc) ^= *(more); + 80041a6: ea81 0100 eor.w r1, r1, r0 + 80041aa: 7011 strb r1, [r2, #0] + for(; len; len--, more++, acc++) { + 80041ac: d1f6 bne.n 800419c +} + 80041ae: b008 add sp, #32 + 80041b0: bd10 pop {r4, pc} + 80041b2: bf00 nop + 80041b4: 2eaf6312 .word 0x2eaf6312 + 80041b8: 0801046c .word 0x0801046c + +080041bc : +{ + 80041bc: b530 push {r4, r5, lr} + 80041be: b091 sub sp, #68 ; 0x44 + pin_hash(pin_prefix, prefix_len, tmp, PIN_PURPOSE_WORDS); + 80041c0: 4b0b ldr r3, [pc, #44] ; (80041f0 ) +{ + 80041c2: 4615 mov r5, r2 + pin_hash(pin_prefix, prefix_len, tmp, PIN_PURPOSE_WORDS); + 80041c4: 466a mov r2, sp + 80041c6: f7ff fd97 bl 8003cf8 + ae_setup(); + 80041ca: f7fe fcc1 bl 8002b50 + int rv = ae_stretch_iter(tmp, digest, KDF_ITER_WORDS); + 80041ce: 2206 movs r2, #6 + 80041d0: a908 add r1, sp, #32 + 80041d2: 4668 mov r0, sp + 80041d4: f7ff fbda bl 800398c + 80041d8: 4604 mov r4, r0 + ae_reset_chip(); + 80041da: f7fe fcab bl 8002b34 + if(rv) return -1; + 80041de: b924 cbnz r4, 80041ea + memcpy(result, digest, 4); + 80041e0: 9b08 ldr r3, [sp, #32] + 80041e2: 602b str r3, [r5, #0] +} + 80041e4: 4620 mov r0, r4 + 80041e6: b011 add sp, #68 ; 0x44 + 80041e8: bd30 pop {r4, r5, pc} + if(rv) return -1; + 80041ea: f04f 34ff mov.w r4, #4294967295 ; 0xffffffff + 80041ee: e7f9 b.n 80041e4 + 80041f0: 2e6d6773 .word 0x2e6d6773 + +080041f4 : +} + 80041f4: 2000 movs r0, #0 + 80041f6: 4770 bx lr + +080041f8 : +{ + 80041f8: b5f0 push {r4, r5, r6, r7, lr} + int rv = _validate_attempt(args, true); + 80041fa: 2101 movs r1, #1 +{ + 80041fc: b091 sub sp, #68 ; 0x44 + 80041fe: 4605 mov r5, r0 + int rv = _validate_attempt(args, true); + 8004200: f7ff fde6 bl 8003dd0 <_validate_attempt> + if(rv) return rv; + 8004204: 4604 mov r4, r0 + 8004206: bb28 cbnz r0, 8004254 + if(args->is_secondary) { + 8004208: 686b ldr r3, [r5, #4] + 800420a: 2b00 cmp r3, #0 + 800420c: d158 bne.n 80042c0 + int pin_len = args->pin_len; + 800420e: 6aaf ldr r7, [r5, #40] ; 0x28 + memcpy(pin_copy, args->pin, pin_len); + 8004210: f105 0608 add.w r6, r5, #8 + 8004214: 463a mov r2, r7 + 8004216: 4631 mov r1, r6 + 8004218: 4668 mov r0, sp + 800421a: f009 fb75 bl 800d908 + memset(args, 0, PIN_ATTEMPT_SIZE_V2); + 800421e: f44f 728c mov.w r2, #280 ; 0x118 + 8004222: 4621 mov r1, r4 + 8004224: 4628 mov r0, r5 + 8004226: f009 fb7d bl 800d924 + args->magic_value = PA_MAGIC_V2; + 800422a: 4b28 ldr r3, [pc, #160] ; (80042cc ) + 800422c: 602b str r3, [r5, #0] + memcpy(args->pin, pin_copy, pin_len); + 800422e: 463a mov r2, r7 + 8004230: 4669 mov r1, sp + args->pin_len = pin_len; + 8004232: 62af str r7, [r5, #40] ; 0x28 + memcpy(args->pin, pin_copy, pin_len); + 8004234: 4630 mov r0, r6 + 8004236: f009 fb67 bl 800d908 + if(warmup_ae()) { + 800423a: f7ff fdff bl 8003e3c + 800423e: 2800 cmp r0, #0 + 8004240: d141 bne.n 80042c6 + if(get_last_success(args)) { + 8004242: 4628 mov r0, r5 + 8004244: f7ff fe37 bl 8003eb6 + 8004248: 4604 mov r4, r0 + 800424a: b130 cbz r0, 800425a + ae_reset_chip(); + 800424c: f7fe fc72 bl 8002b34 + return EPIN_AE_FAIL; + 8004250: f06f 0469 mvn.w r4, #105 ; 0x69 +} + 8004254: 4620 mov r0, r4 + 8004256: b011 add sp, #68 ; 0x44 + 8004258: bdf0 pop {r4, r5, r6, r7, pc} + uint8_t blank[32] = {0}; + 800425a: 4601 mov r1, r0 + 800425c: 221c movs r2, #28 + args->delay_achieved = 0; + 800425e: e9c5 000b strd r0, r0, [r5, #44] ; 0x2c + uint8_t blank[32] = {0}; + 8004262: 9008 str r0, [sp, #32] + 8004264: a809 add r0, sp, #36 ; 0x24 + 8004266: f009 fb5d bl 800d924 + ae_reset_chip(); + 800426a: f7fe fc63 bl 8002b34 + ae_pair_unlock(); + 800426e: f7fe fe65 bl 8002f3c + int is_blank = (ae_checkmac_hard(keynum, blank) == 0); + 8004272: a908 add r1, sp, #32 + 8004274: 2003 movs r0, #3 + 8004276: f7fe ffef bl 8003258 + 800427a: 4606 mov r6, r0 + ae_reset_chip(); + 800427c: f7fe fc5a bl 8002b34 + if(pin_is_blank(KEYNUM_main_pin)) { + 8004280: b9c6 cbnz r6, 80042b4 + args->state_flags |= PA_SUCCESSFUL | PA_IS_BLANK; + 8004282: 6beb ldr r3, [r5, #60] ; 0x3c + const uint8_t zeros[32] = {0}; + 8004284: 9408 str r4, [sp, #32] + args->state_flags |= PA_SUCCESSFUL | PA_IS_BLANK; + 8004286: f043 0303 orr.w r3, r3, #3 + 800428a: 63eb str r3, [r5, #60] ; 0x3c + const uint8_t zeros[32] = {0}; + 800428c: 221c movs r2, #28 + 800428e: 4621 mov r1, r4 + 8004290: a809 add r0, sp, #36 ; 0x24 + 8004292: f009 fb47 bl 800d924 + pin_cache_save(args, zeros); + 8004296: a908 add r1, sp, #32 + 8004298: 4628 mov r0, r5 + 800429a: f7ff ff27 bl 80040ec + args->private_state = ((rng_sample() & ~1) | is_trick_pin) ^ rom_secrets->hash_cache_secret[0]; + 800429e: f7fe fadf bl 8002860 + 80042a2: 4b0b ldr r3, [pc, #44] ; (80042d0 ) + 80042a4: f893 3070 ldrb.w r3, [r3, #112] ; 0x70 + 80042a8: f020 0001 bic.w r0, r0, #1 + args->delay_achieved = 0; + 80042ac: e9c5 440b strd r4, r4, [r5, #44] ; 0x2c + args->private_state = ((rng_sample() & ~1) | is_trick_pin) ^ rom_secrets->hash_cache_secret[0]; + 80042b0: 4058 eors r0, r3 + 80042b2: 6428 str r0, [r5, #64] ; 0x40 + _hmac_attempt(args, args->hmac); + 80042b4: f105 0144 add.w r1, r5, #68 ; 0x44 + 80042b8: 4628 mov r0, r5 + 80042ba: f7ff fd5b bl 8003d74 <_hmac_attempt> +} + 80042be: e7c9 b.n 8004254 + return EPIN_PRIMARY_ONLY; + 80042c0: f06f 0471 mvn.w r4, #113 ; 0x71 + 80042c4: e7c6 b.n 8004254 + return EPIN_I_AM_BRICK; + 80042c6: f06f 0468 mvn.w r4, #104 ; 0x68 + 80042ca: e7c3 b.n 8004254 + 80042cc: 2eaf6312 .word 0x2eaf6312 + 80042d0: 0801c000 .word 0x0801c000 + +080042d4 : +} + 80042d4: 2000 movs r0, #0 + 80042d6: 4770 bx lr + +080042d8 : +// +// Do the PIN check, and return a value. Or fail. +// + int +pin_login_attempt(pinAttempt_t *args) +{ + 80042d8: e92d 43f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, lr} + bool deltamode = false; + char tmp_pin[32]; + + int rv = _validate_attempt(args, false); + 80042dc: 2100 movs r1, #0 +{ + 80042de: b0c7 sub sp, #284 ; 0x11c + 80042e0: 4604 mov r4, r0 + int rv = _validate_attempt(args, false); + 80042e2: f7ff fd75 bl 8003dd0 <_validate_attempt> + if(rv) return rv; + 80042e6: 4605 mov r5, r0 + 80042e8: 2800 cmp r0, #0 + 80042ea: d179 bne.n 80043e0 + + if(args->state_flags & PA_SUCCESSFUL) { + 80042ec: 6be3 ldr r3, [r4, #60] ; 0x3c + 80042ee: 07d9 lsls r1, r3, #31 + 80042f0: f100 80c5 bmi.w 800447e + } + + // Mk4: Check SE2 first to see if this is a "trick" pin. + // - this call may have side-effects, like wiping keys, bricking, etc. + trick_slot_t slot; + bool is_trick = se2_test_trick_pin(args->pin, args->pin_len, &slot, false); + 80042f4: f104 0808 add.w r8, r4, #8 + 80042f8: 4603 mov r3, r0 + 80042fa: 6aa1 ldr r1, [r4, #40] ; 0x28 + 80042fc: aa26 add r2, sp, #152 ; 0x98 + 80042fe: 4640 mov r0, r8 + 8004300: f003 ff02 bl 8008108 + + if(is_trick) { + 8004304: 4606 mov r6, r0 + 8004306: 2800 cmp r0, #0 + 8004308: d04b beq.n 80043a2 + // Mark as success + args->state_flags = PA_SUCCESSFUL; + args->num_fails = 0; + args->attempts_left = MAX_TARGET_ATTEMPTS; + + bool wipe = (slot.tc_flags & TC_WIPE) && !(slot.tc_flags & (TC_WORD_WALLET|TC_XPRV_WALLET)); + 800430a: f9bd 209c ldrsh.w r2, [sp, #156] ; 0x9c + args->num_fails = 0; + 800430e: 6365 str r5, [r4, #52] ; 0x34 + args->state_flags = PA_SUCCESSFUL; + 8004310: 2301 movs r3, #1 + 8004312: 63e3 str r3, [r4, #60] ; 0x3c + bool wipe = (slot.tc_flags & TC_WIPE) && !(slot.tc_flags & (TC_WORD_WALLET|TC_XPRV_WALLET)); + 8004314: 2a00 cmp r2, #0 + args->attempts_left = MAX_TARGET_ATTEMPTS; + 8004316: f04f 030d mov.w r3, #13 + 800431a: 63a3 str r3, [r4, #56] ; 0x38 + bool wipe = (slot.tc_flags & TC_WIPE) && !(slot.tc_flags & (TC_WORD_WALLET|TC_XPRV_WALLET)); + 800431c: f8bd 309c ldrh.w r3, [sp, #156] ; 0x9c + 8004320: da4f bge.n 80043c2 + 8004322: f413 5fc0 tst.w r3, #6144 ; 0x1800 + 8004326: bf0c ite eq + 8004328: 2701 moveq r7, #1 + 800432a: 2700 movne r7, #0 + if(check_all_zeros(slot.xdata, 32) || wipe) { + 800432c: 2120 movs r1, #32 + 800432e: a828 add r0, sp, #160 ; 0xa0 + 8004330: f7fe fa76 bl 8002820 + 8004334: b900 cbnz r0, 8004338 + 8004336: b11f cbz r7, 8004340 + args->state_flags |= PA_ZERO_SECRET; + 8004338: 6be3 ldr r3, [r4, #60] ; 0x3c + 800433a: f043 0310 orr.w r3, r3, #16 + 800433e: 63e3 str r3, [r4, #60] ; 0x3c + args->private_state = ((rng_sample() & ~1) | is_trick_pin) ^ rom_secrets->hash_cache_secret[0]; + 8004340: f7fe fa8e bl 8002860 + 8004344: 4b51 ldr r3, [pc, #324] ; (800448c ) + 8004346: f893 3070 ldrb.w r3, [r3, #112] ; 0x70 + 800434a: f040 0001 orr.w r0, r0, #1 + 800434e: 4058 eors r0, r3 + args->delay_required = (slot->tc_flags & ~TC_HIDDEN_MASK); + 8004350: f8bd 309c ldrh.w r3, [sp, #156] ; 0x9c + args->private_state = ((rng_sample() & ~1) | is_trick_pin) ^ rom_secrets->hash_cache_secret[0]; + 8004354: 6420 str r0, [r4, #64] ; 0x40 + args->delay_required = (slot->tc_flags & ~TC_HIDDEN_MASK); + 8004356: f423 4278 bic.w r2, r3, #63488 ; 0xf800 + 800435a: 6322 str r2, [r4, #48] ; 0x30 + if(slot->tc_flags & TC_DELTA_MODE) { + 800435c: 055a lsls r2, r3, #21 + 800435e: d532 bpl.n 80043c6 + args->delay_achieved = 0; + 8004360: 2300 movs r3, #0 + 8004362: 62e3 str r3, [r4, #44] ; 0x2c + memcpy(tmp_pin, pin, pin_len); + 8004364: 6aa7 ldr r7, [r4, #40] ; 0x28 + // Thug gave wrong PIN, but we are going to let them + // past (by calculating correct PIN, up to 4 digits different), + // and the mpy firmware can do tricky stuff to protect funds + // even though the private key is known at that point. + deltamode = true; + apply_pin_delta(args->pin, args->pin_len, slot.tc_arg, tmp_pin); + 8004366: f8bd 909e ldrh.w r9, [sp, #158] ; 0x9e + memcpy(tmp_pin, pin, pin_len); + 800436a: ab04 add r3, sp, #16 + 800436c: 463a mov r2, r7 + 800436e: 4641 mov r1, r8 + 8004370: 4618 mov r0, r3 + 8004372: f009 fac9 bl 800d908 + tmp_pin[pin_len] = 0; + 8004376: 2200 movs r2, #0 + 8004378: 55c2 strb r2, [r0, r7] + char *p = &tmp_pin[pin_len-1]; + 800437a: 1e7a subs r2, r7, #1 + 800437c: 4402 add r2, r0 + 800437e: 2104 movs r1, #4 + if(*p == '-') p--; + 8004380: 7813 ldrb r3, [r2, #0] + 8004382: 2b2d cmp r3, #45 ; 0x2d + 8004384: f009 030f and.w r3, r9, #15 + 8004388: bf08 it eq + 800438a: f102 32ff addeq.w r2, r2, #4294967295 ; 0xffffffff + if((here >= 0) && (here <= 9)) { + 800438e: 2b09 cmp r3, #9 + *p = '0' + here; + 8004390: bf9c itt ls + 8004392: 3330 addls r3, #48 ; 0x30 + 8004394: 7013 strbls r3, [r2, #0] + for(int i=0; i<4; i++, p--) { + 8004396: 3901 subs r1, #1 + replacement >>= 4; + 8004398: ea4f 1919 mov.w r9, r9, lsr #4 + for(int i=0; i<4; i++, p--) { + 800439c: f102 32ff add.w r2, r2, #4294967295 ; 0xffffffff + 80043a0: d1ee bne.n 8004380 + return 0; + } + +real_login: + // unlock the AE chip + if(warmup_ae()) return EPIN_I_AM_BRICK; + 80043a2: f7ff fd4b bl 8003e3c + 80043a6: 2800 cmp r0, #0 + 80043a8: d16c bne.n 8004484 + + // hash up the pin now, assuming we'll use it on main PIN + uint8_t digest[32]; + rv = pin_hash_attempt(deltamode ? tmp_pin : args->pin, args->pin_len, digest); + 80043aa: b10e cbz r6, 80043b0 + 80043ac: f10d 0810 add.w r8, sp, #16 + 80043b0: 6aa1 ldr r1, [r4, #40] ; 0x28 + 80043b2: aa0c add r2, sp, #48 ; 0x30 + 80043b4: 4640 mov r0, r8 + 80043b6: f7ff fe15 bl 8003fe4 + if(rv) return EPIN_AE_FAIL; + 80043ba: b1a8 cbz r0, 80043e8 + + rv = ae_encrypted_read(KEYNUM_secret, KEYNUM_main_pin, digest, ts, AE_SECRET_LEN); + if(rv) { + ae_reset_chip(); + + return EPIN_AE_FAIL; + 80043bc: f06f 0569 mvn.w r5, #105 ; 0x69 + 80043c0: e00e b.n 80043e0 + bool wipe = (slot.tc_flags & TC_WIPE) && !(slot.tc_flags & (TC_WORD_WALLET|TC_XPRV_WALLET)); + 80043c2: 462f mov r7, r5 + 80043c4: e7b2 b.n 800432c + 80043c6: a926 add r1, sp, #152 ; 0x98 + 80043c8: 4620 mov r0, r4 + 80043ca: f7ff fe39 bl 8004040 + if(slot.tc_flags & TC_DELTA_MODE) { + 80043ce: f8bd 309c ldrh.w r3, [sp, #156] ; 0x9c + 80043d2: 055b lsls r3, r3, #21 + 80043d4: d4c6 bmi.n 8004364 + _hmac_attempt(args, args->hmac); + 80043d6: f104 0144 add.w r1, r4, #68 ; 0x44 + 80043da: 4620 mov r0, r4 + 80043dc: f7ff fcca bl 8003d74 <_hmac_attempt> + } + + _sign_attempt(args); + + return 0; +} + 80043e0: 4628 mov r0, r5 + 80043e2: b047 add sp, #284 ; 0x11c + 80043e4: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + ae_reset_chip(); + 80043e8: f7fe fba4 bl 8002b34 + ae_pair_unlock(); + 80043ec: f7fe fda6 bl 8002f3c + return (ae_checkmac_hard(KEYNUM_main_pin, digest) == 0); + 80043f0: a90c add r1, sp, #48 ; 0x30 + 80043f2: 2003 movs r0, #3 + 80043f4: f7fe ff30 bl 8003258 + if(!is_main_pin(digest)) { + 80043f8: b130 cbz r0, 8004408 + se2_handle_bad_pin(args->num_fails + 1); + 80043fa: 6b60 ldr r0, [r4, #52] ; 0x34 + 80043fc: 3001 adds r0, #1 + 80043fe: f003 ff5f bl 80082c0 + return EPIN_AUTH_FAIL; + 8004402: f06f 056f mvn.w r5, #111 ; 0x6f + 8004406: e7eb b.n 80043e0 + rv = updates_for_good_login(digest); + 8004408: a80c add r0, sp, #48 ; 0x30 + 800440a: f7ff fd9d bl 8003f48 + if(rv) return EPIN_AE_FAIL; + 800440e: 4607 mov r7, r0 + 8004410: 2800 cmp r0, #0 + 8004412: d1d3 bne.n 80043bc + pin_cache_save(args, digest); + 8004414: a90c add r1, sp, #48 ; 0x30 + 8004416: 4620 mov r0, r4 + 8004418: f7ff fe68 bl 80040ec + args->state_flags = PA_SUCCESSFUL; + 800441c: 2301 movs r3, #1 + 800441e: 63e3 str r3, [r4, #60] ; 0x3c + args->num_fails = 0; + 8004420: 6367 str r7, [r4, #52] ; 0x34 + args->attempts_left = MAX_TARGET_ATTEMPTS; + 8004422: 230d movs r3, #13 + rv = ae_encrypted_read(KEYNUM_secret, KEYNUM_main_pin, digest, ts, AE_SECRET_LEN); + 8004424: 2748 movs r7, #72 ; 0x48 + args->attempts_left = MAX_TARGET_ATTEMPTS; + 8004426: 63a3 str r3, [r4, #56] ; 0x38 + rv = ae_encrypted_read(KEYNUM_secret, KEYNUM_main_pin, digest, ts, AE_SECRET_LEN); + 8004428: 9700 str r7, [sp, #0] + 800442a: ab14 add r3, sp, #80 ; 0x50 + 800442c: aa0c add r2, sp, #48 ; 0x30 + 800442e: 2103 movs r1, #3 + 8004430: 2009 movs r0, #9 + 8004432: f7fe fff3 bl 800341c + if(rv) { + 8004436: b110 cbz r0, 800443e + ae_reset_chip(); + 8004438: f7fe fb7c bl 8002b34 + 800443c: e7be b.n 80043bc + ae_reset_chip(); + 800443e: f7fe fb79 bl 8002b34 + mcu_key_get(&mcu_key_valid); + 8004442: f10d 000f add.w r0, sp, #15 + 8004446: f7fe f8ad bl 80025a4 + if(check_all_zeros(ts, AE_SECRET_LEN) || !mcu_key_valid) { + 800444a: 4639 mov r1, r7 + 800444c: a814 add r0, sp, #80 ; 0x50 + 800444e: f7fe f9e7 bl 8002820 + 8004452: b910 cbnz r0, 800445a + 8004454: f89d 300f ldrb.w r3, [sp, #15] + 8004458: b91b cbnz r3, 8004462 + args->state_flags |= PA_ZERO_SECRET; + 800445a: 6be3 ldr r3, [r4, #60] ; 0x3c + 800445c: f043 0310 orr.w r3, r3, #16 + 8004460: 63e3 str r3, [r4, #60] ; 0x3c + if(!deltamode) { + 8004462: 2e00 cmp r6, #0 + 8004464: d1b7 bne.n 80043d6 + args->private_state = ((rng_sample() & ~1) | is_trick_pin) ^ rom_secrets->hash_cache_secret[0]; + 8004466: f7fe f9fb bl 8002860 + 800446a: 4b08 ldr r3, [pc, #32] ; (800448c ) + 800446c: f893 3070 ldrb.w r3, [r3, #112] ; 0x70 + 8004470: f020 0001 bic.w r0, r0, #1 + 8004474: 4058 eors r0, r3 + args->delay_achieved = 0; + 8004476: e9c4 660b strd r6, r6, [r4, #44] ; 0x2c + args->private_state = ((rng_sample() & ~1) | is_trick_pin) ^ rom_secrets->hash_cache_secret[0]; + 800447a: 6420 str r0, [r4, #64] ; 0x40 + return; + 800447c: e7ab b.n 80043d6 + return EPIN_WRONG_SUCCESS; + 800447e: f06f 056c mvn.w r5, #108 ; 0x6c + 8004482: e7ad b.n 80043e0 + if(warmup_ae()) return EPIN_I_AM_BRICK; + 8004484: f06f 0568 mvn.w r5, #104 ; 0x68 + 8004488: e7aa b.n 80043e0 + 800448a: bf00 nop + 800448c: 0801c000 .word 0x0801c000 + +08004490 : +// +// Verify we know the main PIN, but don't do anything with it. +// + int +pin_check_logged_in(const pinAttempt_t *args, bool *is_trick) +{ + 8004490: b570 push {r4, r5, r6, lr} + 8004492: 460e mov r6, r1 + 8004494: b088 sub sp, #32 + int rv = _validate_attempt(args, false); + 8004496: 2100 movs r1, #0 +{ + 8004498: 4605 mov r5, r0 + int rv = _validate_attempt(args, false); + 800449a: f7ff fc99 bl 8003dd0 <_validate_attempt> + if(rv) return rv; + 800449e: 4604 mov r4, r0 + 80044a0: b980 cbnz r0, 80044c4 + + if((args->state_flags & PA_SUCCESSFUL) != PA_SUCCESSFUL) { + 80044a2: 6beb ldr r3, [r5, #60] ; 0x3c + 80044a4: 07da lsls r2, r3, #31 + 80044a6: d520 bpl.n 80044ea + bool is_trick = ((args->private_state ^ rom_secrets->hash_cache_secret[0]) & 0x1); + 80044a8: 4b11 ldr r3, [pc, #68] ; (80044f0 ) + 80044aa: 6c2a ldr r2, [r5, #64] ; 0x40 + 80044ac: f893 3070 ldrb.w r3, [r3, #112] ; 0x70 + 80044b0: 4053 eors r3, r2 + // must come here with a successful PIN login (so it's rate limited nicely) + return EPIN_WRONG_SUCCESS; + } + + if(get_is_trick(args, NULL)) { + 80044b2: 07db lsls r3, r3, #31 + 80044b4: d509 bpl.n 80044ca + // they used a trick pin to get this far. Amuse them more. + *is_trick = true; + 80044b6: 2301 movs r3, #1 + 80044b8: 7033 strb r3, [r6, #0] + + // should calibrate this, but smart money will just look at the bus + delay_ms(10); + 80044ba: 200a movs r0, #10 + 80044bc: f7ff fae2 bl 8003a84 + rng_delay(); + 80044c0: f7fe fa22 bl 8002908 + int rv = ae_checkmac(KEYNUM_main_pin, auth_digest); + if(rv) return EPIN_AUTH_FAIL; + } + + return 0; +} + 80044c4: 4620 mov r0, r4 + 80044c6: b008 add sp, #32 + 80044c8: bd70 pop {r4, r5, r6, pc} + pin_cache_restore(args, auth_digest); + 80044ca: 4669 mov r1, sp + *is_trick = false; + 80044cc: 7030 strb r0, [r6, #0] + pin_cache_restore(args, auth_digest); + 80044ce: 4628 mov r0, r5 + 80044d0: f7ff fe44 bl 800415c + ae_pair_unlock(); + 80044d4: f7fe fd32 bl 8002f3c + int rv = ae_checkmac(KEYNUM_main_pin, auth_digest); + 80044d8: 4669 mov r1, sp + 80044da: 2003 movs r0, #3 + 80044dc: f7fe fcac bl 8002e38 + if(rv) return EPIN_AUTH_FAIL; + 80044e0: 1e04 subs r4, r0, #0 + 80044e2: bf18 it ne + 80044e4: f06f 046f mvnne.w r4, #111 ; 0x6f + 80044e8: e7ec b.n 80044c4 + return EPIN_WRONG_SUCCESS; + 80044ea: f06f 046c mvn.w r4, #108 ; 0x6c + 80044ee: e7e9 b.n 80044c4 + 80044f0: 0801c000 .word 0x0801c000 + +080044f4 : +// +// Change the PIN and/or the secret. (Must also know the previous value, or it must be blank) +// + int +pin_change(pinAttempt_t *args) +{ + 80044f4: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + // Validate args and signature + int rv = _validate_attempt(args, false); + 80044f8: 2100 movs r1, #0 +{ + 80044fa: b0a4 sub sp, #144 ; 0x90 + 80044fc: 4604 mov r4, r0 + int rv = _validate_attempt(args, false); + 80044fe: f7ff fc67 bl 8003dd0 <_validate_attempt> + if(rv) return rv; + 8004502: 4605 mov r5, r0 + 8004504: 2800 cmp r0, #0 + 8004506: f040 8094 bne.w 8004632 + + if((args->state_flags & PA_SUCCESSFUL) != PA_SUCCESSFUL) { + 800450a: 6be3 ldr r3, [r4, #60] ; 0x3c + 800450c: 07d9 lsls r1, r3, #31 + 800450e: f140 809c bpl.w 800464a + // must come here with a successful PIN login (so it's rate limited nicely) + return EPIN_WRONG_SUCCESS; + } + + if(args->state_flags & PA_IS_BLANK) { + 8004512: 079a lsls r2, r3, #30 + 8004514: d502 bpl.n 800451c + // if blank, must provide blank value + if(args->pin_len) return EPIN_RANGE_ERR; + 8004516: 6aa3 ldr r3, [r4, #40] ; 0x28 + 8004518: 2b00 cmp r3, #0 + 800451a: d158 bne.n 80045ce + } + + // Look at change flags. + const uint32_t cf = args->change_flags; + + ASSERT(!args->is_secondary); + 800451c: 6863 ldr r3, [r4, #4] + const uint32_t cf = args->change_flags; + 800451e: f8d4 9064 ldr.w r9, [r4, #100] ; 0x64 + ASSERT(!args->is_secondary); + 8004522: b113 cbz r3, 800452a + 8004524: 484c ldr r0, [pc, #304] ; (8004658 ) + 8004526: f7fc fa87 bl 8000a38 + if(cf & CHANGE_SECONDARY_WALLET_PIN) { + // obsolete secondary support, can't support. + return EPIN_BAD_REQUEST; + } + if(cf & (CHANGE_DURESS_PIN | CHANGE_DURESS_SECRET | CHANGE_BRICKME_PIN)) { + 800452a: f019 0f36 tst.w r9, #54 ; 0x36 + 800452e: d10b bne.n 8004548 + // we need some new API for trick PIN lookup/changes. + return EPIN_BAD_REQUEST; + } + if(!(cf & (CHANGE_WALLET_PIN | CHANGE_SECRET))) { + 8004530: f019 0f09 tst.w r9, #9 + 8004534: d04b beq.n 80045ce + bool is_trick = ((args->private_state ^ rom_secrets->hash_cache_secret[0]) & 0x1); + 8004536: 4b49 ldr r3, [pc, #292] ; (800465c ) + 8004538: 6c22 ldr r2, [r4, #64] ; 0x40 + 800453a: f893 3070 ldrb.w r3, [r3, #112] ; 0x70 + 800453e: 4053 eors r3, r2 + // If they authorized w/ a trick PIN, new policy is to wipe ourselves if + // they try to change PIN code or the secret. + // - it's hard to fake them out here, and they may be onto us. + // - this protects the seed, but does end the game somewhat + // - all trick PINs will still be in effect, and looks like random reset + if(get_is_trick(args, NULL)) { + 8004540: 07db lsls r3, r3, #31 + 8004542: d504 bpl.n 800454e + // User is a thug.. kill secret and reboot w/o any notice + fast_wipe(); + 8004544: f7fe f940 bl 80027c8 + return EPIN_BAD_REQUEST; + 8004548: f06f 0567 mvn.w r5, #103 ; 0x67 + 800454c: e071 b.n 8004632 + // NOT-REACHED + return EPIN_BAD_REQUEST; + } + + // unlock the AE chip + if(warmup_ae()) return EPIN_I_AM_BRICK; + 800454e: f7ff fc75 bl 8003e3c + 8004552: 4605 mov r5, r0 + 8004554: 2800 cmp r0, #0 + 8004556: d17b bne.n 8004650 + // If they tricked us to get to this point, doesn't matter as + // below SE1 validates it all again. + + // Restore cached version of PIN digest: fast + uint8_t required_digest[32]; + pin_cache_restore(args, required_digest); + 8004558: f10d 0808 add.w r8, sp, #8 + 800455c: 4641 mov r1, r8 + 800455e: 4620 mov r0, r4 + 8004560: f7ff fdfc bl 800415c + + // Calculate new PIN hashed value: will be slow to do + if(cf & CHANGE_WALLET_PIN) { + 8004564: f019 0f01 tst.w r9, #1 + 8004568: d021 beq.n 80045ae + uint8_t new_digest[32]; + rv = pin_hash_attempt(args->new_pin, args->new_pin_len, new_digest); + 800456a: f8d4 10ac ldr.w r1, [r4, #172] ; 0xac + 800456e: aa12 add r2, sp, #72 ; 0x48 + 8004570: f104 008c add.w r0, r4, #140 ; 0x8c + 8004574: f7ff fd36 bl 8003fe4 + if(rv) goto ae_fail; + 8004578: 2800 cmp r0, #0 + 800457a: d161 bne.n 8004640 + + if(ae_encrypted_write(KEYNUM_main_pin, KEYNUM_main_pin, required_digest, new_digest, 32)) { + 800457c: 2320 movs r3, #32 + 800457e: 2103 movs r1, #3 + 8004580: 9300 str r3, [sp, #0] + 8004582: 4642 mov r2, r8 + 8004584: ab12 add r3, sp, #72 ; 0x48 + 8004586: 4608 mov r0, r1 + 8004588: f7fe ffe8 bl 800355c + 800458c: 2800 cmp r0, #0 + 800458e: d157 bne.n 8004640 + goto ae_fail; + } + + memcpy(required_digest, new_digest, 32); + 8004590: af12 add r7, sp, #72 ; 0x48 + 8004592: cf0f ldmia r7!, {r0, r1, r2, r3} + 8004594: 4646 mov r6, r8 + 8004596: c60f stmia r6!, {r0, r1, r2, r3} + 8004598: e897 000f ldmia.w r7, {r0, r1, r2, r3} + 800459c: e886 000f stmia.w r6, {r0, r1, r2, r3} + + // main pin is changing; reset counter to zero (good login) and our cache + pin_cache_save(args, new_digest); + 80045a0: 4620 mov r0, r4 + 80045a2: a912 add r1, sp, #72 ; 0x48 + 80045a4: f7ff fda2 bl 80040ec + + updates_for_good_login(new_digest); + 80045a8: a812 add r0, sp, #72 ; 0x48 + 80045aa: f7ff fccd bl 8003f48 + } + + // Recording new secret. + // Note the required_digest might have just changed above. + if(cf & CHANGE_SECRET) { + 80045ae: f019 0f08 tst.w r9, #8 + 80045b2: d037 beq.n 8004624 + int which = (args->change_flags >> 8) & 0xf; + 80045b4: 6e63 ldr r3, [r4, #100] ; 0x64 + 80045b6: 121b asrs r3, r3, #8 + switch(which) { + 80045b8: f013 020c ands.w r2, r3, #12 + 80045bc: d107 bne.n 80045ce + 80045be: 4928 ldr r1, [pc, #160] ; (8004660 ) + int which = (args->change_flags >> 8) & 0xf; + 80045c0: f003 030f and.w r3, r3, #15 + 80045c4: f911 a003 ldrsb.w sl, [r1, r3] + uint8_t tmp[AE_SECRET_LEN]; + uint8_t check[32]; + + // what slot (key number) are updating? (probably: KEYNUM_secret) + int target_slot = keynum_for_secret(args); + if(target_slot < 0) return EPIN_RANGE_ERR; + 80045c8: f1ba 0f00 cmp.w sl, #0 + 80045cc: da02 bge.n 80045d4 + if(args->pin_len) return EPIN_RANGE_ERR; + 80045ce: f06f 0566 mvn.w r5, #102 ; 0x66 + 80045d2: e02e b.n 8004632 + + se2_encrypt_secret(args->secret, AE_SECRET_LEN, 0, tmp, check, required_digest); + 80045d4: f104 07b0 add.w r7, r4, #176 ; 0xb0 + 80045d8: ae0a add r6, sp, #40 ; 0x28 + 80045da: ab12 add r3, sp, #72 ; 0x48 + 80045dc: 2148 movs r1, #72 ; 0x48 + + // write into two slots + if(ae_encrypted_write(target_slot, KEYNUM_main_pin, + 80045de: f04f 0948 mov.w r9, #72 ; 0x48 + se2_encrypt_secret(args->secret, AE_SECRET_LEN, 0, tmp, check, required_digest); + 80045e2: f8cd 8004 str.w r8, [sp, #4] + 80045e6: 9600 str r6, [sp, #0] + 80045e8: 4638 mov r0, r7 + 80045ea: f003 ff47 bl 800847c + if(ae_encrypted_write(target_slot, KEYNUM_main_pin, + 80045ee: 2103 movs r1, #3 + 80045f0: f8cd 9000 str.w r9, [sp] + 80045f4: eb0d 0309 add.w r3, sp, r9 + 80045f8: 4642 mov r2, r8 + 80045fa: 4650 mov r0, sl + 80045fc: f7fe ffae bl 800355c + 8004600: 4601 mov r1, r0 + 8004602: b9e8 cbnz r0, 8004640 + required_digest, tmp, AE_SECRET_LEN)){ + goto ae_fail; + } + if(ae_encrypted_write32(KEYNUM_check_secret, 0, KEYNUM_main_pin, required_digest, check)){ + 8004604: 9600 str r6, [sp, #0] + 8004606: 4643 mov r3, r8 + 8004608: 2203 movs r2, #3 + 800460a: 200a movs r0, #10 + 800460c: f7fe ff40 bl 8003490 + 8004610: b9b0 cbnz r0, 8004640 + goto ae_fail; + } + + // update the zero-secret flag to be correct. + if(cf & CHANGE_SECRET) { + if(check_all_zeros(args->secret, AE_SECRET_LEN)) { + 8004612: 4649 mov r1, r9 + 8004614: 4638 mov r0, r7 + 8004616: f7fe f903 bl 8002820 + 800461a: 6be3 ldr r3, [r4, #60] ; 0x3c + 800461c: b168 cbz r0, 800463a + args->state_flags |= PA_ZERO_SECRET; + 800461e: f043 0310 orr.w r3, r3, #16 + 8004622: 63e3 str r3, [r4, #60] ; 0x3c + args->state_flags &= ~PA_ZERO_SECRET; + } + } + } + + ae_reset_chip(); + 8004624: f7fe fa86 bl 8002b34 + _hmac_attempt(args, args->hmac); + 8004628: f104 0144 add.w r1, r4, #68 ; 0x44 + 800462c: 4620 mov r0, r4 + 800462e: f7ff fba1 bl 8003d74 <_hmac_attempt> + +ae_fail: + ae_reset_chip(); + + return EPIN_AE_FAIL; +} + 8004632: 4628 mov r0, r5 + 8004634: b024 add sp, #144 ; 0x90 + 8004636: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + args->state_flags &= ~PA_ZERO_SECRET; + 800463a: f023 0310 bic.w r3, r3, #16 + 800463e: e7f0 b.n 8004622 + ae_reset_chip(); + 8004640: f7fe fa78 bl 8002b34 + return EPIN_AE_FAIL; + 8004644: f06f 0569 mvn.w r5, #105 ; 0x69 + 8004648: e7f3 b.n 8004632 + return EPIN_WRONG_SUCCESS; + 800464a: f06f 056c mvn.w r5, #108 ; 0x6c + 800464e: e7f0 b.n 8004632 + if(warmup_ae()) return EPIN_I_AM_BRICK; + 8004650: f06f 0568 mvn.w r5, #104 ; 0x68 + 8004654: e7ed b.n 8004632 + 8004656: bf00 nop + 8004658: 0801046c .word 0x0801046c + 800465c: 0801c000 .word 0x0801c000 + 8004660: 08010798 .word 0x08010798 + +08004664 : +// To encourage not keeping the secret in memory, a way to fetch it after you've already +// proven you know the PIN. +// + int +pin_fetch_secret(pinAttempt_t *args) +{ + 8004664: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + // Validate args and signature + int rv = _validate_attempt(args, false); + 8004668: 2100 movs r1, #0 +{ + 800466a: f5ad 7d38 sub.w sp, sp, #736 ; 0x2e0 + 800466e: 4604 mov r4, r0 + int rv = _validate_attempt(args, false); + 8004670: f7ff fbae bl 8003dd0 <_validate_attempt> + if(rv) return rv; + 8004674: 4605 mov r5, r0 + 8004676: 2800 cmp r0, #0 + 8004678: d144 bne.n 8004704 + + if((args->state_flags & PA_SUCCESSFUL) != PA_SUCCESSFUL) { + 800467a: 6be3 ldr r3, [r4, #60] ; 0x3c + 800467c: 07db lsls r3, r3, #31 + 800467e: f140 80e3 bpl.w 8004848 + // must come here with a successful PIN login (so it's rate limited nicely) + return EPIN_WRONG_SUCCESS; + } + if(args->change_flags & CHANGE_DURESS_SECRET) { + 8004682: 6e65 ldr r5, [r4, #100] ; 0x64 + 8004684: f015 0510 ands.w r5, r5, #16 + 8004688: f040 80e1 bne.w 800484e + + // fetch the already-hashed pin + // - no real need to re-prove PIN knowledge. + // - if they tricked us, doesn't matter as below the SE validates it all again + uint8_t digest[32]; + pin_cache_restore(args, digest); + 800468c: f10d 081c add.w r8, sp, #28 + 8004690: 4641 mov r1, r8 + 8004692: 4620 mov r0, r4 + 8004694: f7ff fd62 bl 800415c + bool is_trick = ((args->private_state ^ rom_secrets->hash_cache_secret[0]) & 0x1); + 8004698: 4b70 ldr r3, [pc, #448] ; (800485c ) + 800469a: 6c26 ldr r6, [r4, #64] ; 0x40 + 800469c: f893 3070 ldrb.w r3, [r3, #112] ; 0x70 + 80046a0: 4073 eors r3, r6 + if(!slot || !is_trick) return is_trick; + 80046a2: 07df lsls r7, r3, #31 + 80046a4: d577 bpl.n 8004796 + memset(slot, 0, sizeof(trick_slot_t)); + 80046a6: 2280 movs r2, #128 ; 0x80 + 80046a8: 4629 mov r1, r5 + 80046aa: a817 add r0, sp, #92 ; 0x5c + 80046ac: f009 f93a bl 800d924 + if(args->delay_required & TC_DELTA_MODE) { + 80046b0: 6b23 ldr r3, [r4, #48] ; 0x30 + 80046b2: 0558 lsls r0, r3, #21 + 80046b4: d52b bpl.n 800470e + slot->tc_flags = args->delay_required; + 80046b6: f8ad 3060 strh.w r3, [sp, #96] ; 0x60 + slot->slot_num = -1; // unknown + 80046ba: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 80046be: 9317 str r3, [sp, #92] ; 0x5c + + // determine if we should proceed under duress + trick_slot_t slot; + bool is_trick = get_is_trick(args, &slot); + + if(is_trick && !(slot.tc_flags & TC_DELTA_MODE)) { + 80046c0: f8bd 6060 ldrh.w r6, [sp, #96] ; 0x60 + 80046c4: f416 6180 ands.w r1, r6, #1024 ; 0x400 + 80046c8: d165 bne.n 8004796 + // emulate a 24-word wallet, or xprv based wallet + // see stash.py for encoding details + memset(args->secret, 0, AE_SECRET_LEN); + 80046ca: 2248 movs r2, #72 ; 0x48 + 80046cc: f104 00b0 add.w r0, r4, #176 ; 0xb0 + 80046d0: f009 f928 bl 800d924 + + if(slot.tc_flags & TC_WORD_WALLET) { + 80046d4: 04f1 lsls r1, r6, #19 + 80046d6: d54c bpl.n 8004772 + if(check_all_zeros(&slot.xdata[16], 16)) { + 80046d8: ae1d add r6, sp, #116 ; 0x74 + 80046da: 2110 movs r1, #16 + 80046dc: 4630 mov r0, r6 + 80046de: f7fe f89f bl 8002820 + // 2nd half is zeros, must be 12-word wallet + args->secret[0] = 0x80; // 12 word phrase + memcpy(&args->secret[1], slot.xdata, 16); + 80046e2: f104 03b1 add.w r3, r4, #177 ; 0xb1 + if(check_all_zeros(&slot.xdata[16], 16)) { + 80046e6: 2800 cmp r0, #0 + 80046e8: d034 beq.n 8004754 + args->secret[0] = 0x80; // 12 word phrase + 80046ea: 2280 movs r2, #128 ; 0x80 + 80046ec: f884 20b0 strb.w r2, [r4, #176] ; 0xb0 + memcpy(&args->secret[1], slot.xdata, 16); + 80046f0: ac19 add r4, sp, #100 ; 0x64 + 80046f2: 4622 mov r2, r4 + 80046f4: ca03 ldmia r2!, {r0, r1} + 80046f6: 42b2 cmp r2, r6 + 80046f8: 6018 str r0, [r3, #0] + 80046fa: 6059 str r1, [r3, #4] + 80046fc: 4614 mov r4, r2 + 80046fe: f103 0308 add.w r3, r3, #8 + 8004702: d1f6 bne.n 80046f2 + ae_reset_chip(); + + if(rv) return EPIN_AE_FAIL; + + return 0; +} + 8004704: 4628 mov r0, r5 + 8004706: f50d 7d38 add.w sp, sp, #736 ; 0x2e0 + 800470a: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + memcpy(key+4, rom_secrets->hash_cache_secret+4, sizeof(rom_secrets->hash_cache_secret)-4); + 800470e: 4f54 ldr r7, [pc, #336] ; (8004860 ) + memcpy(key, &args->private_state, sizeof(args->private_state)); + 8004710: 960f str r6, [sp, #60] ; 0x3c + memcpy(key+4, rom_secrets->hash_cache_secret+4, sizeof(rom_secrets->hash_cache_secret)-4); + 8004712: cf0f ldmia r7!, {r0, r1, r2, r3} + 8004714: ae10 add r6, sp, #64 ; 0x40 + 8004716: c60f stmia r6!, {r0, r1, r2, r3} + 8004718: e897 0007 ldmia.w r7, {r0, r1, r2} + 800471c: e886 0007 stmia.w r6, {r0, r1, r2} + aes_init(&ctx); + 8004720: a837 add r0, sp, #220 ; 0xdc + 8004722: f004 f80f bl 8008744 + aes_add(&ctx, args->cached_main_pin, 32); + 8004726: 2220 movs r2, #32 + 8004728: f104 01f8 add.w r1, r4, #248 ; 0xf8 + 800472c: a837 add r0, sp, #220 ; 0xdc + 800472e: f004 f80f bl 8008750 + aes_done(&ctx, (uint8_t *)slot, 32, key, NULL); + 8004732: a917 add r1, sp, #92 ; 0x5c + 8004734: 9500 str r5, [sp, #0] + 8004736: ab0f add r3, sp, #60 ; 0x3c + 8004738: 2220 movs r2, #32 + 800473a: a837 add r0, sp, #220 ; 0xdc + 800473c: f004 f81e bl 800877c + if(slot->tc_flags & (TC_WORD_WALLET|TC_XPRV_WALLET)) { + 8004740: f8bd 1060 ldrh.w r1, [sp, #96] ; 0x60 + 8004744: f411 5fc0 tst.w r1, #6144 ; 0x1800 + 8004748: d0ba beq.n 80046c0 + se2_read_trick_data(slot->slot_num, slot->tc_flags, slot->xdata); + 800474a: 9817 ldr r0, [sp, #92] ; 0x5c + 800474c: aa19 add r2, sp, #100 ; 0x64 + 800474e: f003 fca1 bl 8008094 + if(is_trick && !(slot.tc_flags & TC_DELTA_MODE)) { + 8004752: e7b5 b.n 80046c0 + args->secret[0] = 0x82; // 24 word phrase + 8004754: 2282 movs r2, #130 ; 0x82 + 8004756: f884 20b0 strb.w r2, [r4, #176] ; 0xb0 + memcpy(&args->secret[1], slot.xdata, 32); + 800475a: ae21 add r6, sp, #132 ; 0x84 + 800475c: aa19 add r2, sp, #100 ; 0x64 + 800475e: 4614 mov r4, r2 + 8004760: cc03 ldmia r4!, {r0, r1} + 8004762: 42b4 cmp r4, r6 + 8004764: 6018 str r0, [r3, #0] + 8004766: 6059 str r1, [r3, #4] + 8004768: 4622 mov r2, r4 + 800476a: f103 0308 add.w r3, r3, #8 + 800476e: d1f6 bne.n 800475e + 8004770: e7c8 b.n 8004704 + } else if(slot.tc_flags & TC_XPRV_WALLET) { + 8004772: 0532 lsls r2, r6, #20 + 8004774: d5c6 bpl.n 8004704 + args->secret[0] = 0x01; // XPRV mode + 8004776: 2301 movs r3, #1 + 8004778: f884 30b0 strb.w r3, [r4, #176] ; 0xb0 + memcpy(&args->secret[1], slot.xdata, 64); + 800477c: aa19 add r2, sp, #100 ; 0x64 + 800477e: 34b1 adds r4, #177 ; 0xb1 + 8004780: ae29 add r6, sp, #164 ; 0xa4 + 8004782: 4613 mov r3, r2 + 8004784: cb03 ldmia r3!, {r0, r1} + 8004786: 42b3 cmp r3, r6 + 8004788: 6020 str r0, [r4, #0] + 800478a: 6061 str r1, [r4, #4] + 800478c: 461a mov r2, r3 + 800478e: f104 0408 add.w r4, r4, #8 + 8004792: d1f6 bne.n 8004782 + 8004794: e7b6 b.n 8004704 + int which = (args->change_flags >> 8) & 0xf; + 8004796: 6e63 ldr r3, [r4, #100] ; 0x64 + 8004798: 121b asrs r3, r3, #8 + switch(which) { + 800479a: f013 0f0c tst.w r3, #12 + 800479e: d159 bne.n 8004854 + 80047a0: 4a30 ldr r2, [pc, #192] ; (8004864 ) + int which = (args->change_flags >> 8) & 0xf; + 80047a2: f003 030f and.w r3, r3, #15 + 80047a6: f912 9003 ldrsb.w r9, [r2, r3] + if(kn < 0) return EPIN_RANGE_ERR; + 80047aa: f1b9 0f00 cmp.w r9, #0 + 80047ae: db51 blt.n 8004854 + 80047b0: 2703 movs r7, #3 + rv = ae_encrypted_read(kn, KEYNUM_main_pin, digest, tmp, AE_SECRET_LEN); + 80047b2: f04f 0a48 mov.w sl, #72 ; 0x48 + 80047b6: 2103 movs r1, #3 + 80047b8: f8cd a000 str.w sl, [sp] + 80047bc: ab37 add r3, sp, #220 ; 0xdc + 80047be: 4642 mov r2, r8 + 80047c0: 4648 mov r0, r9 + 80047c2: f7fe fe2b bl 800341c + if(rv) continue; + 80047c6: 4601 mov r1, r0 + 80047c8: b130 cbz r0, 80047d8 + for(int retry=0; retry<3; retry++) { + 80047ca: 3f01 subs r7, #1 + 80047cc: d1f3 bne.n 80047b6 + ae_reset_chip(); + 80047ce: f7fe f9b1 bl 8002b34 + if(rv) return EPIN_AE_FAIL; + 80047d2: f06f 0569 mvn.w r5, #105 ; 0x69 + 80047d6: e795 b.n 8004704 + rv = ae_encrypted_read32(KEYNUM_check_secret, 0, KEYNUM_main_pin, digest, check); + 80047d8: ae0f add r6, sp, #60 ; 0x3c + 80047da: 9600 str r6, [sp, #0] + 80047dc: 4643 mov r3, r8 + 80047de: 2203 movs r2, #3 + 80047e0: 200a movs r0, #10 + 80047e2: f7fe fdf0 bl 80033c6 + if(rv) continue; + 80047e6: 4605 mov r5, r0 + 80047e8: 2800 cmp r0, #0 + 80047ea: d1ee bne.n 80047ca + se2_decrypt_secret(args->secret, AE_SECRET_LEN, 0, tmp, check, digest, &is_valid); + 80047ec: f10d 071b add.w r7, sp, #27 + 80047f0: f104 00b0 add.w r0, r4, #176 ; 0xb0 + 80047f4: ab37 add r3, sp, #220 ; 0xdc + 80047f6: e9cd 8701 strd r8, r7, [sp, #4] + 80047fa: 9600 str r6, [sp, #0] + 80047fc: 462a mov r2, r5 + 80047fe: 2148 movs r1, #72 ; 0x48 + 8004800: 9005 str r0, [sp, #20] + 8004802: f003 fe91 bl 8008528 + if(!is_valid) { + 8004806: f89d 301b ldrb.w r3, [sp, #27] + 800480a: 9805 ldr r0, [sp, #20] + 800480c: b993 cbnz r3, 8004834 + memset(args->secret, 0, AE_SECRET_LEN); + 800480e: 2248 movs r2, #72 ; 0x48 + 8004810: 4629 mov r1, r5 + 8004812: f009 f887 bl 800d924 + if(!(args->state_flags & PA_ZERO_SECRET)) { + 8004816: 6be3 ldr r3, [r4, #60] ; 0x3c + 8004818: 06db lsls r3, r3, #27 + 800481a: d408 bmi.n 800482e + args->state_flags |= PA_ZERO_SECRET; + 800481c: 6be3 ldr r3, [r4, #60] ; 0x3c + 800481e: f043 0310 orr.w r3, r3, #16 + 8004822: 63e3 str r3, [r4, #60] ; 0x3c + _hmac_attempt(args, args->hmac); + 8004824: f104 0144 add.w r1, r4, #68 ; 0x44 + 8004828: 4620 mov r0, r4 + 800482a: f7ff faa3 bl 8003d74 <_hmac_attempt> + ae_reset_chip(); + 800482e: f7fe f981 bl 8002b34 + if(rv) return EPIN_AE_FAIL; + 8004832: e767 b.n 8004704 + if(!args->secret[0] && check_all_zeros(args->secret, AE_SECRET_LEN)) { + 8004834: f894 30b0 ldrb.w r3, [r4, #176] ; 0xb0 + 8004838: 2b00 cmp r3, #0 + 800483a: d1f8 bne.n 800482e + 800483c: 2148 movs r1, #72 ; 0x48 + 800483e: f7fd ffef bl 8002820 + 8004842: 2800 cmp r0, #0 + 8004844: d0f3 beq.n 800482e + 8004846: e7e9 b.n 800481c + return EPIN_WRONG_SUCCESS; + 8004848: f06f 056c mvn.w r5, #108 ; 0x6c + 800484c: e75a b.n 8004704 + return EPIN_BAD_REQUEST; + 800484e: f06f 0567 mvn.w r5, #103 ; 0x67 + 8004852: e757 b.n 8004704 + if(kn < 0) return EPIN_RANGE_ERR; + 8004854: f06f 0566 mvn.w r5, #102 ; 0x66 + 8004858: e754 b.n 8004704 + 800485a: bf00 nop + 800485c: 0801c000 .word 0x0801c000 + 8004860: 0801c074 .word 0x0801c074 + 8004864: 08010798 .word 0x08010798 + +08004868 : +// - new API so whole thing provided in one shot? encryption issues: provide +// "dest" and all 416 bytes end up there (read case only). +// + int +pin_long_secret(pinAttempt_t *args, uint8_t *dest) +{ + 8004868: e92d 43f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, lr} + 800486c: 460f mov r7, r1 + 800486e: b099 sub sp, #100 ; 0x64 + // Validate args and signature + int rv = _validate_attempt(args, false); + 8004870: 2100 movs r1, #0 +{ + 8004872: 4606 mov r6, r0 + int rv = _validate_attempt(args, false); + 8004874: f7ff faac bl 8003dd0 <_validate_attempt> + if(rv) return rv; + 8004878: 4604 mov r4, r0 + 800487a: b9b8 cbnz r0, 80048ac + + if((args->state_flags & PA_SUCCESSFUL) != PA_SUCCESSFUL) { + 800487c: 6bf3 ldr r3, [r6, #60] ; 0x3c + 800487e: 07da lsls r2, r3, #31 + 8004880: f140 80a5 bpl.w 80049ce + bool is_trick = ((args->private_state ^ rom_secrets->hash_cache_secret[0]) & 0x1); + 8004884: 4b55 ldr r3, [pc, #340] ; (80049dc ) + 8004886: 6c32 ldr r2, [r6, #64] ; 0x40 + 8004888: f893 3070 ldrb.w r3, [r3, #112] ; 0x70 + 800488c: 4053 eors r3, r2 + } + + // determine if we should proceed under duress/in some trick way + bool is_trick = get_is_trick(args, NULL); + + if(is_trick) { + 800488e: 07db lsls r3, r3, #31 + 8004890: d510 bpl.n 80048b4 + // Not supported in trick mode. Pretend it's all zeros. Accept all writes. + memset(args->secret, 0, 32); + 8004892: 4601 mov r1, r0 + 8004894: 2220 movs r2, #32 + 8004896: f106 00b0 add.w r0, r6, #176 ; 0xb0 + 800489a: f009 f843 bl 800d924 + if(dest) memset(dest, 0, AE_LONG_SECRET_LEN); + 800489e: b12f cbz r7, 80048ac + 80048a0: f44f 72d0 mov.w r2, #416 ; 0x1a0 + 80048a4: 4621 mov r1, r4 + 80048a6: 4638 mov r0, r7 + 80048a8: f009 f83c bl 800d924 + +se2_fail: + ae_reset_chip(); + + return EPIN_SE2_FAIL; +} + 80048ac: 4620 mov r0, r4 + 80048ae: b019 add sp, #100 ; 0x64 + 80048b0: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + int blk = (args->change_flags >> 8) & 0xf; + 80048b4: 6e73 ldr r3, [r6, #100] ; 0x64 + 80048b6: f3c3 2803 ubfx r8, r3, #8, #4 + if(blk > 13) return EPIN_RANGE_ERR; + 80048ba: f1b8 0f0d cmp.w r8, #13 + 80048be: f300 8089 bgt.w 80049d4 + pin_cache_restore(args, digest); + 80048c2: a908 add r1, sp, #32 + 80048c4: 4630 mov r0, r6 + 80048c6: f7ff fc49 bl 800415c + if(!(args->change_flags & CHANGE_SECRET)) { + 80048ca: 6e71 ldr r1, [r6, #100] ; 0x64 + 80048cc: f011 0908 ands.w r9, r1, #8 + 80048d0: d156 bne.n 8004980 + if(!dest) { + 80048d2: bb27 cbnz r7, 800491e + rv = ae_encrypted_read32(KEYNUM_long_secret, blk, KEYNUM_main_pin, digest, tmp); + 80048d4: af10 add r7, sp, #64 ; 0x40 + 80048d6: 9700 str r7, [sp, #0] + 80048d8: ab08 add r3, sp, #32 + 80048da: 2203 movs r2, #3 + 80048dc: 4641 mov r1, r8 + 80048de: 2008 movs r0, #8 + 80048e0: f7fe fd71 bl 80033c6 + if(rv) goto fail; + 80048e4: 4605 mov r5, r0 + 80048e6: 2800 cmp r0, #0 + 80048e8: d16a bne.n 80049c0 + se2_decrypt_secret(args->secret, 32, blk*32, tmp, NULL, digest, &is_valid); + 80048ea: f10d 031f add.w r3, sp, #31 + 80048ee: 9302 str r3, [sp, #8] + 80048f0: ab08 add r3, sp, #32 + 80048f2: f106 00b0 add.w r0, r6, #176 ; 0xb0 + 80048f6: e9cd 4300 strd r4, r3, [sp] + 80048fa: ea4f 1248 mov.w r2, r8, lsl #5 + 80048fe: 463b mov r3, r7 + 8004900: 2120 movs r1, #32 + 8004902: 9005 str r0, [sp, #20] + 8004904: f003 fe10 bl 8008528 + if(!is_valid) { + 8004908: f89d 301f ldrb.w r3, [sp, #31] + 800490c: 9805 ldr r0, [sp, #20] + 800490e: b91b cbnz r3, 8004918 + memset(args->secret, 0, 32); + 8004910: 2220 movs r2, #32 + 8004912: 4621 mov r1, r4 + memset(dest, 0, AE_LONG_SECRET_LEN); + 8004914: f009 f806 bl 800d924 + ae_reset_chip(); + 8004918: f7fe f90c bl 8002b34 + if(rv) return EPIN_AE_FAIL; + 800491c: e7c6 b.n 80048ac + 800491e: 463e mov r6, r7 + rv = ae_encrypted_read32(KEYNUM_long_secret, blk, KEYNUM_main_pin, digest, p); + 8004920: 9600 str r6, [sp, #0] + 8004922: ab08 add r3, sp, #32 + 8004924: 2203 movs r2, #3 + 8004926: 4649 mov r1, r9 + 8004928: 2008 movs r0, #8 + 800492a: f7fe fd4c bl 80033c6 + if(rv) goto fail; + 800492e: 4605 mov r5, r0 + 8004930: 2800 cmp r0, #0 + 8004932: d145 bne.n 80049c0 + for(blk=0; blk<13; blk++, p += 32) { + 8004934: f109 0901 add.w r9, r9, #1 + 8004938: f1b9 0f0d cmp.w r9, #13 + 800493c: f106 0620 add.w r6, r6, #32 + 8004940: d1ee bne.n 8004920 + ASSERT(p == dest+AE_LONG_SECRET_LEN); + 8004942: f507 73d0 add.w r3, r7, #416 ; 0x1a0 + 8004946: 429e cmp r6, r3 + 8004948: d002 beq.n 8004950 + 800494a: 4825 ldr r0, [pc, #148] ; (80049e0 ) + 800494c: f7fc f874 bl 8000a38 + se2_decrypt_secret(dest, AE_LONG_SECRET_LEN, 0, dest, NULL, digest, &is_valid); + 8004950: ab10 add r3, sp, #64 ; 0x40 + 8004952: 9302 str r3, [sp, #8] + 8004954: ab08 add r3, sp, #32 + 8004956: e9cd 0300 strd r0, r3, [sp] + 800495a: 4602 mov r2, r0 + 800495c: 463b mov r3, r7 + 800495e: f44f 71d0 mov.w r1, #416 ; 0x1a0 + 8004962: 4638 mov r0, r7 + 8004964: f003 fde0 bl 8008528 + if(!is_valid) { + 8004968: f89d 4040 ldrb.w r4, [sp, #64] ; 0x40 + 800496c: b924 cbnz r4, 8004978 + memset(dest, 0, AE_LONG_SECRET_LEN); + 800496e: f44f 72d0 mov.w r2, #416 ; 0x1a0 + 8004972: 4621 mov r1, r4 + 8004974: 4638 mov r0, r7 + 8004976: e7cd b.n 8004914 + ae_reset_chip(); + 8004978: f7fe f8dc bl 8002b34 + return 0; + 800497c: 462c mov r4, r5 + 800497e: e795 b.n 80048ac + uint8_t tmp[32] = {0}; + 8004980: 221c movs r2, #28 + 8004982: 4621 mov r1, r4 + 8004984: a811 add r0, sp, #68 ; 0x44 + 8004986: 9410 str r4, [sp, #64] ; 0x40 + if(se2_encrypt_secret(args->secret, 32, blk*32, tmp, NULL, digest)) { + 8004988: ad10 add r5, sp, #64 ; 0x40 + uint8_t tmp[32] = {0}; + 800498a: f008 ffcb bl 800d924 + if(se2_encrypt_secret(args->secret, 32, blk*32, tmp, NULL, digest)) { + 800498e: ab08 add r3, sp, #32 + 8004990: e9cd 4300 strd r4, r3, [sp] + 8004994: ea4f 1248 mov.w r2, r8, lsl #5 + 8004998: 462b mov r3, r5 + 800499a: 2120 movs r1, #32 + 800499c: f106 00b0 add.w r0, r6, #176 ; 0xb0 + 80049a0: f003 fd6c bl 800847c + 80049a4: b120 cbz r0, 80049b0 + ae_reset_chip(); + 80049a6: f7fe f8c5 bl 8002b34 + return EPIN_SE2_FAIL; + 80049aa: f06f 0472 mvn.w r4, #114 ; 0x72 + 80049ae: e77d b.n 80048ac + rv = ae_encrypted_write32(KEYNUM_long_secret, blk, KEYNUM_main_pin, digest, tmp); + 80049b0: 9500 str r5, [sp, #0] + 80049b2: ab08 add r3, sp, #32 + 80049b4: 2203 movs r2, #3 + 80049b6: 4641 mov r1, r8 + 80049b8: 2008 movs r0, #8 + 80049ba: f7fe fd69 bl 8003490 + 80049be: 4605 mov r5, r0 + ae_reset_chip(); + 80049c0: f7fe f8b8 bl 8002b34 + if(rv) return EPIN_AE_FAIL; + 80049c4: 2d00 cmp r5, #0 + 80049c6: bf18 it ne + 80049c8: f06f 0469 mvnne.w r4, #105 ; 0x69 + 80049cc: e76e b.n 80048ac + return EPIN_WRONG_SUCCESS; + 80049ce: f06f 046c mvn.w r4, #108 ; 0x6c + 80049d2: e76b b.n 80048ac + if(blk > 13) return EPIN_RANGE_ERR; + 80049d4: f06f 0466 mvn.w r4, #102 ; 0x66 + 80049d8: e768 b.n 80048ac + 80049da: bf00 nop + 80049dc: 0801c000 .word 0x0801c000 + 80049e0: 0801046c .word 0x0801046c + +080049e4 : +// +// Record current flash checksum and make green light go on. +// + int +pin_firmware_greenlight(pinAttempt_t *args) +{ + 80049e4: b530 push {r4, r5, lr} + // Validate args and signature + int rv = _validate_attempt(args, false); + 80049e6: 2100 movs r1, #0 +{ + 80049e8: b09b sub sp, #108 ; 0x6c + 80049ea: 4604 mov r4, r0 + int rv = _validate_attempt(args, false); + 80049ec: f7ff f9f0 bl 8003dd0 <_validate_attempt> + if(rv) return rv; + 80049f0: bb20 cbnz r0, 8004a3c + + if((args->state_flags & PA_SUCCESSFUL) != PA_SUCCESSFUL) { + 80049f2: 6be3 ldr r3, [r4, #60] ; 0x3c + 80049f4: 07da lsls r2, r3, #31 + 80049f6: d529 bpl.n 8004a4c + // must come here with a successful PIN login (so it's rate limited nicely) + return EPIN_WRONG_SUCCESS; + } + + if(args->is_secondary) { + 80049f8: 6865 ldr r5, [r4, #4] + 80049fa: bb55 cbnz r5, 8004a52 + return EPIN_PRIMARY_ONLY; + } + + // load existing PIN's hash + uint8_t digest[32]; + pin_cache_restore(args, digest); + 80049fc: a902 add r1, sp, #8 + 80049fe: 4620 mov r0, r4 + 8004a00: f7ff fbac bl 800415c + + // step 1: calc the value to use + uint8_t fw_check[32], world_check[32]; + checksum_flash(fw_check, world_check, 0); + 8004a04: 462a mov r2, r5 + 8004a06: a912 add r1, sp, #72 ; 0x48 + 8004a08: a80a add r0, sp, #40 ; 0x28 + 8004a0a: f7fd f907 bl 8001c1c + + // step 2: write it out to chip. + if(warmup_ae()) return EPIN_I_AM_BRICK; + 8004a0e: f7ff fa15 bl 8003e3c + 8004a12: bb08 cbnz r0, 8004a58 + bool is_trick = ((args->private_state ^ rom_secrets->hash_cache_secret[0]) & 0x1); + 8004a14: 4b12 ldr r3, [pc, #72] ; (8004a60 ) + 8004a16: 6c22 ldr r2, [r4, #64] ; 0x40 + 8004a18: f893 3070 ldrb.w r3, [r3, #112] ; 0x70 + 8004a1c: 4053 eors r3, r2 + + // under duress, we can't fake this, but we go through the motions anyway + if(!get_is_trick(args, NULL)) { + 8004a1e: 07db lsls r3, r3, #31 + 8004a20: d40e bmi.n 8004a40 + rv = ae_encrypted_write(KEYNUM_firmware, KEYNUM_main_pin, digest, world_check, 32); + 8004a22: 2320 movs r3, #32 + 8004a24: 9300 str r3, [sp, #0] + 8004a26: aa02 add r2, sp, #8 + 8004a28: ab12 add r3, sp, #72 ; 0x48 + 8004a2a: 2103 movs r1, #3 + 8004a2c: 200e movs r0, #14 + 8004a2e: f7fe fd95 bl 800355c + + if(rv) { + 8004a32: b128 cbz r0, 8004a40 + ae_reset_chip(); + 8004a34: f7fe f87e bl 8002b34 + + return EPIN_AE_FAIL; + 8004a38: f06f 0069 mvn.w r0, #105 ; 0x69 + + return EPIN_AE_FAIL; + } + + return 0; +} + 8004a3c: b01b add sp, #108 ; 0x6c + 8004a3e: bd30 pop {r4, r5, pc} + rv = ae_set_gpio_secure(world_check); + 8004a40: a812 add r0, sp, #72 ; 0x48 + 8004a42: f7fe fe1d bl 8003680 + if(rv) { + 8004a46: 2800 cmp r0, #0 + 8004a48: d0f8 beq.n 8004a3c + 8004a4a: e7f3 b.n 8004a34 + return EPIN_WRONG_SUCCESS; + 8004a4c: f06f 006c mvn.w r0, #108 ; 0x6c + 8004a50: e7f4 b.n 8004a3c + return EPIN_PRIMARY_ONLY; + 8004a52: f06f 0071 mvn.w r0, #113 ; 0x71 + 8004a56: e7f1 b.n 8004a3c + if(warmup_ae()) return EPIN_I_AM_BRICK; + 8004a58: f06f 0068 mvn.w r0, #104 ; 0x68 + 8004a5c: e7ee b.n 8004a3c + 8004a5e: bf00 nop + 8004a60: 0801c000 .word 0x0801c000 + +08004a64 : +// Update the system firmware via file in PSRAM. Arrange for +// light to stay green through out process. +// + int +pin_firmware_upgrade(pinAttempt_t *args) +{ + 8004a64: b570 push {r4, r5, r6, lr} + // Validate args and signature + int rv = _validate_attempt(args, false); + 8004a66: 2100 movs r1, #0 +{ + 8004a68: b092 sub sp, #72 ; 0x48 + 8004a6a: 4604 mov r4, r0 + int rv = _validate_attempt(args, false); + 8004a6c: f7ff f9b0 bl 8003dd0 <_validate_attempt> + if(rv) return rv; + 8004a70: 2800 cmp r0, #0 + 8004a72: d14e bne.n 8004b12 + + if((args->state_flags & PA_SUCCESSFUL) != PA_SUCCESSFUL) { + 8004a74: 6be3 ldr r3, [r4, #60] ; 0x3c + 8004a76: 07da lsls r2, r3, #31 + 8004a78: d54d bpl.n 8004b16 + // must come here with a successful PIN login + return EPIN_WRONG_SUCCESS; + } + + if(args->change_flags != CHANGE_FIRMWARE) { + 8004a7a: 6e63 ldr r3, [r4, #100] ; 0x64 + 8004a7c: 2b40 cmp r3, #64 ; 0x40 + 8004a7e: d11c bne.n 8004aba + } + + // expecting start/length relative to psram start + uint32_t *about = (uint32_t *)args->secret; + uint32_t start = about[0]; + uint32_t len = about[1]; + 8004a80: e9d4 562c ldrd r5, r6, [r4, #176] ; 0xb0 + + if(len < 32768) return EPIN_RANGE_ERR; + 8004a84: f5a6 4300 sub.w r3, r6, #32768 ; 0x8000 + 8004a88: f5b3 1ffc cmp.w r3, #2064384 ; 0x1f8000 + 8004a8c: d846 bhi.n 8004b1c + if(len > 2<<20) return EPIN_RANGE_ERR; + if(start+len > PSRAM_SIZE) return EPIN_RANGE_ERR; + 8004a8e: 19ab adds r3, r5, r6 + 8004a90: f5b3 0f00 cmp.w r3, #8388608 ; 0x800000 + 8004a94: d842 bhi.n 8004b1c + + const uint8_t *data = (const uint8_t *)PSRAM_BASE+start; + 8004a96: f105 4510 add.w r5, r5, #2415919104 ; 0x90000000 + + // verify a firmware image that's in RAM, and calc its digest + // - also applies watermark policy, etc + uint8_t world_check[32]; + bool ok = verify_firmware_in_ram(data, len, world_check); + 8004a9a: aa02 add r2, sp, #8 + 8004a9c: 4631 mov r1, r6 + 8004a9e: 4628 mov r0, r5 + 8004aa0: f7fd f9c2 bl 8001e28 + if(!ok) { + 8004aa4: 2800 cmp r0, #0 + 8004aa6: d03c beq.n 8004b22 + bool is_trick = ((args->private_state ^ rom_secrets->hash_cache_secret[0]) & 0x1); + 8004aa8: 4b21 ldr r3, [pc, #132] ; (8004b30 ) + 8004aaa: 6c22 ldr r2, [r4, #64] ; 0x40 + 8004aac: f893 3070 ldrb.w r3, [r3, #112] ; 0x70 + 8004ab0: 4053 eors r3, r2 + return EPIN_AUTH_FAIL; + } + + // under duress, we can't fake this, so kill ourselves. + if(get_is_trick(args, NULL)) { + 8004ab2: 07db lsls r3, r3, #31 + 8004ab4: d504 bpl.n 8004ac0 + // User is a thug.. kill secret and reboot w/o any notice + fast_wipe(); + 8004ab6: f7fd fe87 bl 80027c8 + return EPIN_BAD_REQUEST; + 8004aba: f06f 0067 mvn.w r0, #103 ; 0x67 + 8004abe: e028 b.n 8004b12 + return EPIN_BAD_REQUEST; + } + + // load existing PIN's hash + uint8_t digest[32]; + pin_cache_restore(args, digest); + 8004ac0: a90a add r1, sp, #40 ; 0x28 + 8004ac2: 4620 mov r0, r4 + 8004ac4: f7ff fb4a bl 800415c + + // step 1: calc the value to use, see above + if(warmup_ae()) return EPIN_I_AM_BRICK; + 8004ac8: f7ff f9b8 bl 8003e3c + 8004acc: bb60 cbnz r0, 8004b28 + + // step 2: write it out to chip. + rv = ae_encrypted_write(KEYNUM_firmware, KEYNUM_main_pin, digest, world_check, 32); + 8004ace: 2320 movs r3, #32 + 8004ad0: 9300 str r3, [sp, #0] + 8004ad2: aa0a add r2, sp, #40 ; 0x28 + 8004ad4: ab02 add r3, sp, #8 + 8004ad6: 2103 movs r1, #3 + 8004ad8: 200e movs r0, #14 + 8004ada: f7fe fd3f bl 800355c + if(rv) goto fail; + 8004ade: b9a0 cbnz r0, 8004b0a + + // this turns on green light + rv = ae_set_gpio_secure(world_check); + 8004ae0: a802 add r0, sp, #8 + 8004ae2: f7fe fdcd bl 8003680 + if(rv) goto fail; + 8004ae6: b980 cbnz r0, 8004b0a + + // -- point of no return -- + + // burn it, shows progress + psram_do_upgrade(data, len); + 8004ae8: 4631 mov r1, r6 + 8004aea: 4628 mov r0, r5 + 8004aec: f000 fbf4 bl 80052d8 + 8004af0: f3bf 8f4f dsb sy + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 8004af4: 490f ldr r1, [pc, #60] ; (8004b34 ) + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 8004af6: 4b10 ldr r3, [pc, #64] ; (8004b38 ) + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 8004af8: 68ca ldr r2, [r1, #12] + 8004afa: f402 62e0 and.w r2, r2, #1792 ; 0x700 + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 8004afe: 4313 orrs r3, r2 + 8004b00: 60cb str r3, [r1, #12] + 8004b02: f3bf 8f4f dsb sy + __NOP(); + 8004b06: bf00 nop + for(;;) /* wait until reset */ + 8004b08: e7fd b.n 8004b06 + NVIC_SystemReset(); + + return 0; + +fail: + ae_reset_chip(); + 8004b0a: f7fe f813 bl 8002b34 + + return EPIN_AE_FAIL; + 8004b0e: f06f 0069 mvn.w r0, #105 ; 0x69 +} + 8004b12: b012 add sp, #72 ; 0x48 + 8004b14: bd70 pop {r4, r5, r6, pc} + return EPIN_WRONG_SUCCESS; + 8004b16: f06f 006c mvn.w r0, #108 ; 0x6c + 8004b1a: e7fa b.n 8004b12 + if(len < 32768) return EPIN_RANGE_ERR; + 8004b1c: f06f 0066 mvn.w r0, #102 ; 0x66 + 8004b20: e7f7 b.n 8004b12 + return EPIN_AUTH_FAIL; + 8004b22: f06f 006f mvn.w r0, #111 ; 0x6f + 8004b26: e7f4 b.n 8004b12 + if(warmup_ae()) return EPIN_I_AM_BRICK; + 8004b28: f06f 0068 mvn.w r0, #104 ; 0x68 + 8004b2c: e7f1 b.n 8004b12 + 8004b2e: bf00 nop + 8004b30: 0801c000 .word 0x0801c000 + 8004b34: e000ed00 .word 0xe000ed00 + 8004b38: 05fa0004 .word 0x05fa0004 + +08004b3c : + +// strcat_hex() +// + void +strcat_hex(char *msg, const void *d, int len) +{ + 8004b3c: b570 push {r4, r5, r6, lr} + 8004b3e: 4616 mov r6, r2 + 8004b40: 4604 mov r4, r0 + 8004b42: 460d mov r5, r1 + char *p = msg+strlen(msg); + 8004b44: f008 ff19 bl 800d97a + const uint8_t *h = (const uint8_t *)d; + + for(; len; len--, h++) { + *(p++) = hexmap[(*h>>4) & 0xf]; + 8004b48: 4a0b ldr r2, [pc, #44] ; (8004b78 ) + char *p = msg+strlen(msg); + 8004b4a: 4420 add r0, r4 + for(; len; len--, h++) { + 8004b4c: 1e69 subs r1, r5, #1 + 8004b4e: eb00 0646 add.w r6, r0, r6, lsl #1 + 8004b52: 42b0 cmp r0, r6 + 8004b54: d102 bne.n 8004b5c + *(p++) = hexmap[(*h>>0) & 0xf]; + } + + *(p++) = 0; + 8004b56: 2300 movs r3, #0 + 8004b58: 7003 strb r3, [r0, #0] +} + 8004b5a: bd70 pop {r4, r5, r6, pc} + *(p++) = hexmap[(*h>>4) & 0xf]; + 8004b5c: f811 3f01 ldrb.w r3, [r1, #1]! + 8004b60: 091b lsrs r3, r3, #4 + 8004b62: 5cd3 ldrb r3, [r2, r3] + 8004b64: f800 3b02 strb.w r3, [r0], #2 + *(p++) = hexmap[(*h>>0) & 0xf]; + 8004b68: 780b ldrb r3, [r1, #0] + 8004b6a: f003 030f and.w r3, r3, #15 + 8004b6e: 5cd3 ldrb r3, [r2, r3] + 8004b70: f800 3c01 strb.w r3, [r0, #-1] + for(; len; len--, h++) { + 8004b74: e7ed b.n 8004b52 + 8004b76: bf00 nop + 8004b78: 080107ce .word 0x080107ce + +08004b7c : + * parameters in the USART_InitTypeDef and initialize the associated handle. + * @param husart USART handle. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_USART_Init(USART_HandleTypeDef *husart) +{ + 8004b7c: b5f8 push {r3, r4, r5, r6, r7, lr} + /* Check the USART handle allocation */ + if (husart == NULL) + 8004b7e: 4604 mov r4, r0 + 8004b80: b910 cbnz r0, 8004b88 + { + return HAL_ERROR; + 8004b82: 2501 movs r5, #1 + /* Enable the Peripheral */ + __HAL_USART_ENABLE(husart); + + /* TEACK and/or REACK to check before moving husart->State to Ready */ + return (USART_CheckIdleState(husart)); +} + 8004b84: 4628 mov r0, r5 + 8004b86: bdf8 pop {r3, r4, r5, r6, r7, pc} + if (husart->State == HAL_USART_STATE_RESET) + 8004b88: f890 3059 ldrb.w r3, [r0, #89] ; 0x59 + 8004b8c: f003 02ff and.w r2, r3, #255 ; 0xff + 8004b90: b90b cbnz r3, 8004b96 + husart->Lock = HAL_UNLOCKED; + 8004b92: f880 2058 strb.w r2, [r0, #88] ; 0x58 + __HAL_USART_DISABLE(husart); + 8004b96: 6823 ldr r3, [r4, #0] + tmpreg = (uint32_t)husart->Init.WordLength | husart->Init.Parity | husart->Init.Mode | USART_CR1_OVER8; + 8004b98: 6921 ldr r1, [r4, #16] + husart->State = HAL_USART_STATE_BUSY; + 8004b9a: 2502 movs r5, #2 + 8004b9c: f884 5059 strb.w r5, [r4, #89] ; 0x59 + __HAL_USART_DISABLE(husart); + 8004ba0: 681a ldr r2, [r3, #0] + 8004ba2: f022 0201 bic.w r2, r2, #1 + 8004ba6: 601a str r2, [r3, #0] + tmpreg = (uint32_t)husart->Init.WordLength | husart->Init.Parity | husart->Init.Mode | USART_CR1_OVER8; + 8004ba8: 68a2 ldr r2, [r4, #8] + MODIFY_REG(husart->Instance->CR1, USART_CR1_FIELDS, tmpreg); + 8004baa: 6818 ldr r0, [r3, #0] + tmpreg = (uint32_t)husart->Init.WordLength | husart->Init.Parity | husart->Init.Mode | USART_CR1_OVER8; + 8004bac: 430a orrs r2, r1 + MODIFY_REG(husart->Instance->CR1, USART_CR1_FIELDS, tmpreg); + 8004bae: 49a9 ldr r1, [pc, #676] ; (8004e54 ) + 8004bb0: 4001 ands r1, r0 + 8004bb2: 430a orrs r2, r1 + 8004bb4: 6961 ldr r1, [r4, #20] + MODIFY_REG(husart->Instance->CR2, USART_CR2_FIELDS, tmpreg); + 8004bb6: 69a0 ldr r0, [r4, #24] + MODIFY_REG(husart->Instance->CR1, USART_CR1_FIELDS, tmpreg); + 8004bb8: 430a orrs r2, r1 + 8004bba: f442 4200 orr.w r2, r2, #32768 ; 0x8000 + 8004bbe: 601a str r2, [r3, #0] + MODIFY_REG(husart->Instance->CR2, USART_CR2_FIELDS, tmpreg); + 8004bc0: 6859 ldr r1, [r3, #4] + 8004bc2: 6a22 ldr r2, [r4, #32] + 8004bc4: f421 517c bic.w r1, r1, #16128 ; 0x3f00 + 8004bc8: f021 0109 bic.w r1, r1, #9 + 8004bcc: 4302 orrs r2, r0 + 8004bce: 430a orrs r2, r1 + 8004bd0: 69e1 ldr r1, [r4, #28] + 8004bd2: 430a orrs r2, r1 + 8004bd4: 68e1 ldr r1, [r4, #12] + 8004bd6: 430a orrs r2, r1 + 8004bd8: f442 6200 orr.w r2, r2, #2048 ; 0x800 + 8004bdc: 605a str r2, [r3, #4] + MODIFY_REG(husart->Instance->PRESC, USART_PRESC_PRESCALER, husart->Init.ClockPrescaler); + 8004bde: 6ad9 ldr r1, [r3, #44] ; 0x2c + 8004be0: 6a62 ldr r2, [r4, #36] ; 0x24 + 8004be2: f021 010f bic.w r1, r1, #15 + 8004be6: 4311 orrs r1, r2 + 8004be8: 62d9 str r1, [r3, #44] ; 0x2c + USART_GETCLOCKSOURCE(husart, clocksource); + 8004bea: 499b ldr r1, [pc, #620] ; (8004e58 ) + 8004bec: 428b cmp r3, r1 + 8004bee: d10e bne.n 8004c0e + 8004bf0: 4b9a ldr r3, [pc, #616] ; (8004e5c ) + 8004bf2: f8d3 3088 ldr.w r3, [r3, #136] ; 0x88 + 8004bf6: f003 0303 and.w r3, r3, #3 + 8004bfa: 42ab cmp r3, r5 + 8004bfc: f000 80cd beq.w 8004d9a + 8004c00: 2b03 cmp r3, #3 + 8004c02: d01a beq.n 8004c3a + 8004c04: 2b01 cmp r3, #1 + 8004c06: d153 bne.n 8004cb0 + pclk = HAL_RCC_GetSysClockFreq(); + 8004c08: f003 ff52 bl 8008ab0 + 8004c0c: e052 b.n 8004cb4 + USART_GETCLOCKSOURCE(husart, clocksource); + 8004c0e: 4994 ldr r1, [pc, #592] ; (8004e60 ) + 8004c10: 428b cmp r3, r1 + 8004c12: d13c bne.n 8004c8e + 8004c14: 4b91 ldr r3, [pc, #580] ; (8004e5c ) + 8004c16: f8d3 3088 ldr.w r3, [r3, #136] ; 0x88 + 8004c1a: f003 030c and.w r3, r3, #12 + 8004c1e: 2b08 cmp r3, #8 + 8004c20: f000 80bb beq.w 8004d9a + 8004c24: d807 bhi.n 8004c36 + 8004c26: 2b00 cmp r3, #0 + 8004c28: f000 80b4 beq.w 8004d94 + 8004c2c: 2b04 cmp r3, #4 + 8004c2e: d0eb beq.n 8004c08 + uint32_t usartdiv = 0x00000000; + 8004c30: 2300 movs r3, #0 + ret = HAL_ERROR; + 8004c32: 2501 movs r5, #1 + 8004c34: e06e b.n 8004d14 + USART_GETCLOCKSOURCE(husart, clocksource); + 8004c36: 2b0c cmp r3, #12 + 8004c38: d1fa bne.n 8004c30 + usartdiv = (uint32_t)(USART_DIV_SAMPLING8(LSE_VALUE, husart->Init.BaudRate, husart->Init.ClockPrescaler)); + 8004c3a: 2a00 cmp r2, #0 + 8004c3c: f000 80fb beq.w 8004e36 + 8004c40: 2a01 cmp r2, #1 + 8004c42: f000 80fa beq.w 8004e3a + 8004c46: 2a02 cmp r2, #2 + 8004c48: f000 80f9 beq.w 8004e3e + 8004c4c: 2a03 cmp r2, #3 + 8004c4e: f000 80f8 beq.w 8004e42 + 8004c52: 2a04 cmp r2, #4 + 8004c54: f000 80f7 beq.w 8004e46 + 8004c58: 2a05 cmp r2, #5 + 8004c5a: f000 80f6 beq.w 8004e4a + 8004c5e: 2a06 cmp r2, #6 + 8004c60: f000 80f5 beq.w 8004e4e + 8004c64: 2a07 cmp r2, #7 + 8004c66: f000 8101 beq.w 8004e6c + 8004c6a: 2a08 cmp r2, #8 + 8004c6c: f000 8100 beq.w 8004e70 + 8004c70: 2a09 cmp r2, #9 + 8004c72: f000 80ff beq.w 8004e74 + 8004c76: 2a0a cmp r2, #10 + 8004c78: f000 80fe beq.w 8004e78 + 8004c7c: 2a0b cmp r2, #11 + 8004c7e: bf14 ite ne + 8004c80: 2201 movne r2, #1 + 8004c82: f44f 7280 moveq.w r2, #256 ; 0x100 + 8004c86: 6861 ldr r1, [r4, #4] + 8004c88: f44f 4300 mov.w r3, #32768 ; 0x8000 + 8004c8c: e0a1 b.n 8004dd2 + USART_GETCLOCKSOURCE(husart, clocksource); + 8004c8e: 4975 ldr r1, [pc, #468] ; (8004e64 ) + 8004c90: 428b cmp r3, r1 + 8004c92: d1cd bne.n 8004c30 + 8004c94: 4b71 ldr r3, [pc, #452] ; (8004e5c ) + 8004c96: f8d3 3088 ldr.w r3, [r3, #136] ; 0x88 + 8004c9a: f003 0330 and.w r3, r3, #48 ; 0x30 + 8004c9e: 2b20 cmp r3, #32 + 8004ca0: d07b beq.n 8004d9a + 8004ca2: d803 bhi.n 8004cac + 8004ca4: 2b00 cmp r3, #0 + 8004ca6: d075 beq.n 8004d94 + 8004ca8: 2b10 cmp r3, #16 + 8004caa: e7c0 b.n 8004c2e + 8004cac: 2b30 cmp r3, #48 ; 0x30 + 8004cae: e7c3 b.n 8004c38 + pclk = HAL_RCC_GetPCLK2Freq(); + 8004cb0: f004 fb0c bl 80092cc + usartdiv = (uint32_t)(USART_DIV_SAMPLING8(pclk, husart->Init.BaudRate, husart->Init.ClockPrescaler)); + 8004cb4: 6a62 ldr r2, [r4, #36] ; 0x24 + 8004cb6: 2a00 cmp r2, #0 + 8004cb8: f000 80a7 beq.w 8004e0a + 8004cbc: 2a01 cmp r2, #1 + 8004cbe: f000 80a6 beq.w 8004e0e + 8004cc2: 2a02 cmp r2, #2 + 8004cc4: f000 80a5 beq.w 8004e12 + 8004cc8: 2a03 cmp r2, #3 + 8004cca: f000 80a4 beq.w 8004e16 + 8004cce: 2a04 cmp r2, #4 + 8004cd0: f000 80a3 beq.w 8004e1a + 8004cd4: 2a05 cmp r2, #5 + 8004cd6: f000 80a2 beq.w 8004e1e + 8004cda: 2a06 cmp r2, #6 + 8004cdc: f000 80a1 beq.w 8004e22 + 8004ce0: 2a07 cmp r2, #7 + 8004ce2: f000 80a0 beq.w 8004e26 + 8004ce6: 2a08 cmp r2, #8 + 8004ce8: f000 809f beq.w 8004e2a + 8004cec: 2a09 cmp r2, #9 + 8004cee: f000 809e beq.w 8004e2e + 8004cf2: 2a0a cmp r2, #10 + 8004cf4: f000 809d beq.w 8004e32 + 8004cf8: 2a0b cmp r2, #11 + 8004cfa: bf14 ite ne + 8004cfc: 2201 movne r2, #1 + 8004cfe: f44f 7280 moveq.w r2, #256 ; 0x100 + 8004d02: 6861 ldr r1, [r4, #4] + 8004d04: fbb0 f0f2 udiv r0, r0, r2 + 8004d08: 084b lsrs r3, r1, #1 + 8004d0a: eb03 0340 add.w r3, r3, r0, lsl #1 + HAL_StatusTypeDef ret = HAL_OK; + 8004d0e: 2500 movs r5, #0 + usartdiv = (uint32_t)(USART_DIV_SAMPLING8(LSE_VALUE, husart->Init.BaudRate, husart->Init.ClockPrescaler)); + 8004d10: fbb3 f3f1 udiv r3, r3, r1 + if ((usartdiv >= USART_BRR_MIN) && (usartdiv <= USART_BRR_MAX)) + 8004d14: f1a3 0110 sub.w r1, r3, #16 + 8004d18: f64f 72ef movw r2, #65519 ; 0xffef + 8004d1c: 4291 cmp r1, r2 + brrtemp = (uint16_t)(usartdiv & 0xFFF0U); + 8004d1e: bf9f itttt ls + 8004d20: f023 020f bicls.w r2, r3, #15 + 8004d24: b292 uxthls r2, r2 + brrtemp |= (uint16_t)((usartdiv & (uint16_t)0x000FU) >> 1U); + 8004d26: f3c3 0342 ubfxls r3, r3, #1, #3 + husart->Instance->BRR = brrtemp; + 8004d2a: 6821 ldrls r1, [r4, #0] + 8004d2c: bf9a itte ls + 8004d2e: 4313 orrls r3, r2 + 8004d30: 60cb strls r3, [r1, #12] + ret = HAL_ERROR; + 8004d32: 2501 movhi r5, #1 + husart->NbTxDataToProcess = 1U; + 8004d34: 2301 movs r3, #1 + husart->RxISR = NULL; + 8004d36: 2200 movs r2, #0 + if (USART_SetConfig(husart) == HAL_ERROR) + 8004d38: 429d cmp r5, r3 + husart->TxISR = NULL; + 8004d3a: e9c4 2212 strd r2, r2, [r4, #72] ; 0x48 + husart->NbTxDataToProcess = 1U; + 8004d3e: 87a3 strh r3, [r4, #60] ; 0x3c + husart->NbRxDataToProcess = 1U; + 8004d40: 8763 strh r3, [r4, #58] ; 0x3a + if (USART_SetConfig(husart) == HAL_ERROR) + 8004d42: f43f af1e beq.w 8004b82 + husart->Instance->CR2 &= ~USART_CR2_LINEN; + 8004d46: 6823 ldr r3, [r4, #0] + 8004d48: 6859 ldr r1, [r3, #4] + 8004d4a: f421 4180 bic.w r1, r1, #16384 ; 0x4000 + 8004d4e: 6059 str r1, [r3, #4] + husart->Instance->CR3 &= ~(USART_CR3_SCEN | USART_CR3_HDSEL | USART_CR3_IREN); + 8004d50: 6899 ldr r1, [r3, #8] + 8004d52: f021 012a bic.w r1, r1, #42 ; 0x2a + 8004d56: 6099 str r1, [r3, #8] + __HAL_USART_ENABLE(husart); + 8004d58: 6819 ldr r1, [r3, #0] + 8004d5a: f041 0101 orr.w r1, r1, #1 + 8004d5e: 6019 str r1, [r3, #0] + husart->ErrorCode = HAL_USART_ERROR_NONE; + 8004d60: 65e2 str r2, [r4, #92] ; 0x5c + tickstart = HAL_GetTick(); + 8004d62: f002 fb3b bl 80073dc + if ((husart->Instance->CR1 & USART_CR1_TE) == USART_CR1_TE) + 8004d66: 6823 ldr r3, [r4, #0] + 8004d68: 681b ldr r3, [r3, #0] + 8004d6a: 071a lsls r2, r3, #28 + tickstart = HAL_GetTick(); + 8004d6c: 4607 mov r7, r0 + if ((husart->Instance->CR1 & USART_CR1_TE) == USART_CR1_TE) + 8004d6e: f100 8085 bmi.w 8004e7c + if ((husart->Instance->CR1 & USART_CR1_RE) == USART_CR1_RE) + 8004d72: 6823 ldr r3, [r4, #0] + 8004d74: 681b ldr r3, [r3, #0] + 8004d76: 075b lsls r3, r3, #29 + 8004d78: d505 bpl.n 8004d86 + while ((__HAL_USART_GET_FLAG(husart, Flag) ? SET : RESET) == Status) + 8004d7a: 6823 ldr r3, [r4, #0] + 8004d7c: 69de ldr r6, [r3, #28] + 8004d7e: f416 0680 ands.w r6, r6, #4194304 ; 0x400000 + 8004d82: f000 808e beq.w 8004ea2 + husart->State = HAL_USART_STATE_READY; + 8004d86: 2301 movs r3, #1 + 8004d88: f884 3059 strb.w r3, [r4, #89] ; 0x59 + __HAL_UNLOCK(husart); + 8004d8c: 2300 movs r3, #0 + 8004d8e: f884 3058 strb.w r3, [r4, #88] ; 0x58 + return HAL_OK; + 8004d92: e6f7 b.n 8004b84 + pclk = HAL_RCC_GetPCLK1Freq(); + 8004d94: f004 fa88 bl 80092a8 + usartdiv = (uint32_t)(USART_DIV_SAMPLING8(pclk, husart->Init.BaudRate, husart->Init.ClockPrescaler)); + 8004d98: e78c b.n 8004cb4 + usartdiv = (uint32_t)(USART_DIV_SAMPLING8(HSI_VALUE, husart->Init.BaudRate, husart->Init.ClockPrescaler)); + 8004d9a: b302 cbz r2, 8004dde + 8004d9c: 2a01 cmp r2, #1 + 8004d9e: d020 beq.n 8004de2 + 8004da0: 2a02 cmp r2, #2 + 8004da2: d020 beq.n 8004de6 + 8004da4: 2a03 cmp r2, #3 + 8004da6: d020 beq.n 8004dea + 8004da8: 2a04 cmp r2, #4 + 8004daa: d020 beq.n 8004dee + 8004dac: 2a05 cmp r2, #5 + 8004dae: d020 beq.n 8004df2 + 8004db0: 2a06 cmp r2, #6 + 8004db2: d020 beq.n 8004df6 + 8004db4: 2a07 cmp r2, #7 + 8004db6: d020 beq.n 8004dfa + 8004db8: 2a08 cmp r2, #8 + 8004dba: d020 beq.n 8004dfe + 8004dbc: 2a09 cmp r2, #9 + 8004dbe: d020 beq.n 8004e02 + 8004dc0: 2a0a cmp r2, #10 + 8004dc2: d020 beq.n 8004e06 + 8004dc4: 2a0b cmp r2, #11 + 8004dc6: bf14 ite ne + 8004dc8: 2201 movne r2, #1 + 8004dca: f44f 7280 moveq.w r2, #256 ; 0x100 + 8004dce: 6861 ldr r1, [r4, #4] + 8004dd0: 4b25 ldr r3, [pc, #148] ; (8004e68 ) + usartdiv = (uint32_t)(USART_DIV_SAMPLING8(LSE_VALUE, husart->Init.BaudRate, husart->Init.ClockPrescaler)); + 8004dd2: fbb3 f2f2 udiv r2, r3, r2 + 8004dd6: 084b lsrs r3, r1, #1 + 8004dd8: eb03 0342 add.w r3, r3, r2, lsl #1 + 8004ddc: e797 b.n 8004d0e + usartdiv = (uint32_t)(USART_DIV_SAMPLING8(HSI_VALUE, husart->Init.BaudRate, husart->Init.ClockPrescaler)); + 8004dde: 2201 movs r2, #1 + 8004de0: e7f5 b.n 8004dce + 8004de2: 2202 movs r2, #2 + 8004de4: e7f3 b.n 8004dce + 8004de6: 2204 movs r2, #4 + 8004de8: e7f1 b.n 8004dce + 8004dea: 2206 movs r2, #6 + 8004dec: e7ef b.n 8004dce + 8004dee: 2208 movs r2, #8 + 8004df0: e7ed b.n 8004dce + 8004df2: 220a movs r2, #10 + 8004df4: e7eb b.n 8004dce + 8004df6: 220c movs r2, #12 + 8004df8: e7e9 b.n 8004dce + 8004dfa: 2210 movs r2, #16 + 8004dfc: e7e7 b.n 8004dce + 8004dfe: 2220 movs r2, #32 + 8004e00: e7e5 b.n 8004dce + 8004e02: 2240 movs r2, #64 ; 0x40 + 8004e04: e7e3 b.n 8004dce + 8004e06: 2280 movs r2, #128 ; 0x80 + 8004e08: e7e1 b.n 8004dce + usartdiv = (uint32_t)(USART_DIV_SAMPLING8(pclk, husart->Init.BaudRate, husart->Init.ClockPrescaler)); + 8004e0a: 2201 movs r2, #1 + 8004e0c: e779 b.n 8004d02 + 8004e0e: 2202 movs r2, #2 + 8004e10: e777 b.n 8004d02 + 8004e12: 2204 movs r2, #4 + 8004e14: e775 b.n 8004d02 + 8004e16: 2206 movs r2, #6 + 8004e18: e773 b.n 8004d02 + 8004e1a: 2208 movs r2, #8 + 8004e1c: e771 b.n 8004d02 + 8004e1e: 220a movs r2, #10 + 8004e20: e76f b.n 8004d02 + 8004e22: 220c movs r2, #12 + 8004e24: e76d b.n 8004d02 + 8004e26: 2210 movs r2, #16 + 8004e28: e76b b.n 8004d02 + 8004e2a: 2220 movs r2, #32 + 8004e2c: e769 b.n 8004d02 + 8004e2e: 2240 movs r2, #64 ; 0x40 + 8004e30: e767 b.n 8004d02 + 8004e32: 2280 movs r2, #128 ; 0x80 + 8004e34: e765 b.n 8004d02 + usartdiv = (uint32_t)(USART_DIV_SAMPLING8(LSE_VALUE, husart->Init.BaudRate, husart->Init.ClockPrescaler)); + 8004e36: 2201 movs r2, #1 + 8004e38: e725 b.n 8004c86 + 8004e3a: 2202 movs r2, #2 + 8004e3c: e723 b.n 8004c86 + 8004e3e: 2204 movs r2, #4 + 8004e40: e721 b.n 8004c86 + 8004e42: 2206 movs r2, #6 + 8004e44: e71f b.n 8004c86 + 8004e46: 2208 movs r2, #8 + 8004e48: e71d b.n 8004c86 + 8004e4a: 220a movs r2, #10 + 8004e4c: e71b b.n 8004c86 + 8004e4e: 220c movs r2, #12 + 8004e50: e719 b.n 8004c86 + 8004e52: bf00 nop + 8004e54: cfff69f3 .word 0xcfff69f3 + 8004e58: 40013800 .word 0x40013800 + 8004e5c: 40021000 .word 0x40021000 + 8004e60: 40004400 .word 0x40004400 + 8004e64: 40004800 .word 0x40004800 + 8004e68: 00f42400 .word 0x00f42400 + 8004e6c: 2210 movs r2, #16 + 8004e6e: e70a b.n 8004c86 + 8004e70: 2220 movs r2, #32 + 8004e72: e708 b.n 8004c86 + 8004e74: 2240 movs r2, #64 ; 0x40 + 8004e76: e706 b.n 8004c86 + 8004e78: 2280 movs r2, #128 ; 0x80 + 8004e7a: e704 b.n 8004c86 + while ((__HAL_USART_GET_FLAG(husart, Flag) ? SET : RESET) == Status) + 8004e7c: 6823 ldr r3, [r4, #0] + 8004e7e: 69de ldr r6, [r3, #28] + 8004e80: f416 1600 ands.w r6, r6, #2097152 ; 0x200000 + 8004e84: f47f af75 bne.w 8004d72 + if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U)) + 8004e88: f002 faa8 bl 80073dc + 8004e8c: 1bc0 subs r0, r0, r7 + 8004e8e: f5b0 7f7a cmp.w r0, #1000 ; 0x3e8 + 8004e92: d9f3 bls.n 8004e7c + husart->State = HAL_USART_STATE_READY; + 8004e94: 2301 movs r3, #1 + 8004e96: f884 3059 strb.w r3, [r4, #89] ; 0x59 + __HAL_UNLOCK(husart); + 8004e9a: f884 6058 strb.w r6, [r4, #88] ; 0x58 + return HAL_TIMEOUT; + 8004e9e: 2503 movs r5, #3 + 8004ea0: e670 b.n 8004b84 + if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U)) + 8004ea2: f002 fa9b bl 80073dc + 8004ea6: 1bc0 subs r0, r0, r7 + 8004ea8: f5b0 7f7a cmp.w r0, #1000 ; 0x3e8 + 8004eac: f67f af65 bls.w 8004d7a + 8004eb0: e7f0 b.n 8004e94 + 8004eb2: bf00 nop + +08004eb4 : + __HAL_RCC_USART1_CONFIG(RCC_USART1CLKSOURCE_SYSCLK); + 8004eb4: 4b14 ldr r3, [pc, #80] ; (8004f08 ) + 8004eb6: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 8004eba: f022 0203 bic.w r2, r2, #3 + 8004ebe: f042 0201 orr.w r2, r2, #1 +{ + 8004ec2: b513 push {r0, r1, r4, lr} + __HAL_RCC_USART1_CONFIG(RCC_USART1CLKSOURCE_SYSCLK); + 8004ec4: f8c3 2088 str.w r2, [r3, #136] ; 0x88 + __HAL_RCC_USART1_CLK_ENABLE(); + 8004ec8: 6e1a ldr r2, [r3, #96] ; 0x60 + memset(&con, 0, sizeof(con)); + 8004eca: 4c10 ldr r4, [pc, #64] ; (8004f0c ) + __HAL_RCC_USART1_CLK_ENABLE(); + 8004ecc: f442 4280 orr.w r2, r2, #16384 ; 0x4000 + 8004ed0: 661a str r2, [r3, #96] ; 0x60 + 8004ed2: 6e1b ldr r3, [r3, #96] ; 0x60 + 8004ed4: f403 4380 and.w r3, r3, #16384 ; 0x4000 + 8004ed8: 9301 str r3, [sp, #4] + memset(&con, 0, sizeof(con)); + 8004eda: 2258 movs r2, #88 ; 0x58 + 8004edc: 2100 movs r1, #0 + 8004ede: f104 0008 add.w r0, r4, #8 + __HAL_RCC_USART1_CLK_ENABLE(); + 8004ee2: 9b01 ldr r3, [sp, #4] + memset(&con, 0, sizeof(con)); + 8004ee4: f008 fd1e bl 800d924 + con.Init.BaudRate = 115200; + 8004ee8: 4a09 ldr r2, [pc, #36] ; (8004f10 ) + 8004eea: f44f 33e1 mov.w r3, #115200 ; 0x1c200 + 8004eee: e9c4 2300 strd r2, r3, [r4] + HAL_StatusTypeDef rv = HAL_USART_Init(&con); + 8004ef2: 4620 mov r0, r4 + con.Init.Mode = USART_MODE_TX_RX; + 8004ef4: 230c movs r3, #12 + 8004ef6: 6163 str r3, [r4, #20] + HAL_StatusTypeDef rv = HAL_USART_Init(&con); + 8004ef8: f7ff fe40 bl 8004b7c + ASSERT(rv == HAL_OK); + 8004efc: b110 cbz r0, 8004f04 + 8004efe: 4805 ldr r0, [pc, #20] ; (8004f14 ) + 8004f00: f7fb fd9a bl 8000a38 +} + 8004f04: b002 add sp, #8 + 8004f06: bd10 pop {r4, pc} + 8004f08: 40021000 .word 0x40021000 + 8004f0c: 2009e1c4 .word 0x2009e1c4 + 8004f10: 40013800 .word 0x40013800 + 8004f14: 0801046c .word 0x0801046c + +08004f18 : + * @param Timeout Timeout duration. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_USART_Transmit(USART_HandleTypeDef *husart, uint8_t *pTxData, uint16_t Size, uint32_t Timeout) +{ + while(Size > 0U) { + 8004f18: 4b0b ldr r3, [pc, #44] ; (8004f48 ) + 8004f1a: 440a add r2, r1 + 8004f1c: 4291 cmp r1, r2 + 8004f1e: d10b bne.n 8004f38 + MY_UART->TDR = *pTxData; + pTxData++; + Size --; + } + + while(!(MY_UART->ISR & UART_FLAG_TC)) { + 8004f20: 69da ldr r2, [r3, #28] + 8004f22: 0652 lsls r2, r2, #25 + 8004f24: d5fc bpl.n 8004f20 + // wait for final byte to be sent + } + + // Clear Transmission Complete Flag + MY_UART->ICR = USART_CLEAR_TCF; + 8004f26: 2240 movs r2, #64 ; 0x40 + 8004f28: 621a str r2, [r3, #32] + + // Clear overrun flag and discard the received data + MY_UART->ICR = USART_CLEAR_OREF; + 8004f2a: 2208 movs r2, #8 + 8004f2c: 621a str r2, [r3, #32] + MY_UART->RQR = USART_RXDATA_FLUSH_REQUEST; + 8004f2e: 831a strh r2, [r3, #24] + MY_UART->RQR = USART_TXDATA_FLUSH_REQUEST; + 8004f30: 2210 movs r2, #16 + 8004f32: 831a strh r2, [r3, #24] + + return HAL_OK; +} + 8004f34: 2000 movs r0, #0 + 8004f36: 4770 bx lr + while(!(MY_UART->ISR & UART_FLAG_TXE)) { + 8004f38: 69d8 ldr r0, [r3, #28] + 8004f3a: 0600 lsls r0, r0, #24 + 8004f3c: d5fc bpl.n 8004f38 + MY_UART->TDR = *pTxData; + 8004f3e: f811 0b01 ldrb.w r0, [r1], #1 + 8004f42: 8518 strh r0, [r3, #40] ; 0x28 + Size --; + 8004f44: e7ea b.n 8004f1c + 8004f46: bf00 nop + 8004f48: 40013800 .word 0x40013800 + +08004f4c : +{ + 8004f4c: b510 push {r4, lr} + 8004f4e: 4604 mov r4, r0 + rng_delay(); + 8004f50: f7fd fcda bl 8002908 + HAL_USART_Transmit(&con, (uint8_t *)msg, strlen(msg), HAL_MAX_DELAY); + 8004f54: 4620 mov r0, r4 + 8004f56: f008 fd10 bl 800d97a + 8004f5a: 4621 mov r1, r4 + 8004f5c: b282 uxth r2, r0 + 8004f5e: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 8004f62: 4803 ldr r0, [pc, #12] ; (8004f70 ) + 8004f64: f7ff ffd8 bl 8004f18 +} + 8004f68: e8bd 4010 ldmia.w sp!, {r4, lr} + rng_delay(); + 8004f6c: f7fd bccc b.w 8002908 + 8004f70: 2009e1c4 .word 0x2009e1c4 + +08004f74 : +{ + 8004f74: b513 push {r0, r1, r4, lr} + 8004f76: 4604 mov r4, r0 + uint8_t cb = c; + 8004f78: f88d 0007 strb.w r0, [sp, #7] + rng_delay(); + 8004f7c: f7fd fcc4 bl 8002908 + if(cb != '\n') { + 8004f80: f89d 3007 ldrb.w r3, [sp, #7] + HAL_USART_Transmit(&con, (uint8_t *)CRLF, 2, HAL_MAX_DELAY); + 8004f84: 4808 ldr r0, [pc, #32] ; (8004fa8 ) + if(cb != '\n') { + 8004f86: 2b0a cmp r3, #10 + HAL_USART_Transmit(&con, (uint8_t *)CRLF, 2, HAL_MAX_DELAY); + 8004f88: bf08 it eq + 8004f8a: 4908 ldreq r1, [pc, #32] ; (8004fac ) + HAL_USART_Transmit(&con, &cb, 1, HAL_MAX_DELAY); + 8004f8c: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 8004f90: bf1a itte ne + 8004f92: 2201 movne r2, #1 + 8004f94: f10d 0107 addne.w r1, sp, #7 + HAL_USART_Transmit(&con, (uint8_t *)CRLF, 2, HAL_MAX_DELAY); + 8004f98: 2202 moveq r2, #2 + 8004f9a: f7ff ffbd bl 8004f18 + rng_delay(); + 8004f9e: f7fd fcb3 bl 8002908 +} + 8004fa2: 4620 mov r0, r4 + 8004fa4: b002 add sp, #8 + 8004fa6: bd10 pop {r4, pc} + 8004fa8: 2009e1c4 .word 0x2009e1c4 + 8004fac: 080107cb .word 0x080107cb + +08004fb0 : +{ + 8004fb0: b538 push {r3, r4, r5, lr} + putchar(hexmap[(b>>4) & 0xf]); + 8004fb2: 4d06 ldr r5, [pc, #24] ; (8004fcc ) + 8004fb4: 0903 lsrs r3, r0, #4 +{ + 8004fb6: 4604 mov r4, r0 + putchar(hexmap[(b>>0) & 0xf]); + 8004fb8: f004 040f and.w r4, r4, #15 + putchar(hexmap[(b>>4) & 0xf]); + 8004fbc: 5ce8 ldrb r0, [r5, r3] + 8004fbe: f7ff ffd9 bl 8004f74 + putchar(hexmap[(b>>0) & 0xf]); + 8004fc2: 5d28 ldrb r0, [r5, r4] +} + 8004fc4: e8bd 4038 ldmia.w sp!, {r3, r4, r5, lr} + putchar(hexmap[(b>>0) & 0xf]); + 8004fc8: f7ff bfd4 b.w 8004f74 + 8004fcc: 080107ce .word 0x080107ce + +08004fd0 : +{ + 8004fd0: b538 push {r3, r4, r5, lr} + putchar(hexmap[(w>>12) & 0xf]); + 8004fd2: 4d0b ldr r5, [pc, #44] ; (8005000 ) + 8004fd4: 0b03 lsrs r3, r0, #12 +{ + 8004fd6: 4604 mov r4, r0 + putchar(hexmap[(w>>12) & 0xf]); + 8004fd8: 5ce8 ldrb r0, [r5, r3] + 8004fda: f7ff ffcb bl 8004f74 + putchar(hexmap[(w>>8) & 0xf]); + 8004fde: f3c4 2303 ubfx r3, r4, #8, #4 + 8004fe2: 5ce8 ldrb r0, [r5, r3] + 8004fe4: f7ff ffc6 bl 8004f74 + putchar(hexmap[(w>>4) & 0xf]); + 8004fe8: f3c4 1303 ubfx r3, r4, #4, #4 + putchar(hexmap[(w>>0) & 0xf]); + 8004fec: f004 040f and.w r4, r4, #15 + putchar(hexmap[(w>>4) & 0xf]); + 8004ff0: 5ce8 ldrb r0, [r5, r3] + 8004ff2: f7ff ffbf bl 8004f74 + putchar(hexmap[(w>>0) & 0xf]); + 8004ff6: 5d28 ldrb r0, [r5, r4] +} + 8004ff8: e8bd 4038 ldmia.w sp!, {r3, r4, r5, lr} + putchar(hexmap[(w>>0) & 0xf]); + 8004ffc: f7ff bfba b.w 8004f74 + 8005000: 080107ce .word 0x080107ce + +08005004 : +{ + 8005004: b510 push {r4, lr} + 8005006: 4604 mov r4, r0 + puthex4(w >> 16); + 8005008: 0c00 lsrs r0, r0, #16 + 800500a: f7ff ffe1 bl 8004fd0 + puthex4(w & 0xffff); + 800500e: b2a0 uxth r0, r4 +} + 8005010: e8bd 4010 ldmia.w sp!, {r4, lr} + puthex4(w & 0xffff); + 8005014: f7ff bfdc b.w 8004fd0 + +08005018 : +{ + 8005018: b5f8 push {r3, r4, r5, r6, r7, lr} + 800501a: 4605 mov r5, r0 + 800501c: 2604 movs r6, #4 + for(int m=1000; m; m /= 10) { + 800501e: f44f 747a mov.w r4, #1000 ; 0x3e8 + char n = '0' + ((w / m) % 10); + 8005022: 270a movs r7, #10 + if(w >= m) { + 8005024: 42a5 cmp r5, r4 + 8005026: db09 blt.n 800503c + char n = '0' + ((w / m) % 10); + 8005028: fb95 f3f4 sdiv r3, r5, r4 + 800502c: fb93 f0f7 sdiv r0, r3, r7 + 8005030: fb07 3310 mls r3, r7, r0, r3 + 8005034: 3330 adds r3, #48 ; 0x30 + putchar(n); + 8005036: b2d8 uxtb r0, r3 + 8005038: f7ff ff9c bl 8004f74 + for(int m=1000; m; m /= 10) { + 800503c: fb94 f4f7 sdiv r4, r4, r7 + 8005040: 3e01 subs r6, #1 + 8005042: d1ef bne.n 8005024 +} + 8005044: bdf8 pop {r3, r4, r5, r6, r7, pc} + +08005046 : +{ + 8005046: b570 push {r4, r5, r6, lr} + 8005048: 4606 mov r6, r0 + 800504a: 460d mov r5, r1 + for(int i=0; i +} + 8005052: e8bd 4070 ldmia.w sp!, {r4, r5, r6, lr} + putchar('\n'); + 8005056: 200a movs r0, #10 + 8005058: f7ff bf8c b.w 8004f74 + puthex2(data[i]); + 800505c: 5d30 ldrb r0, [r6, r4] + 800505e: f7ff ffa7 bl 8004fb0 + for(int i=0; i + ... + +08005068 : +{ + 8005068: b513 push {r0, r1, r4, lr} + 800506a: 9001 str r0, [sp, #4] + int ln = strlen(msg); + 800506c: f008 fc85 bl 800d97a + 8005070: 4604 mov r4, r0 + rng_delay(); + 8005072: f7fd fc49 bl 8002908 + if(ln) HAL_USART_Transmit(&con, (uint8_t *)msg, ln, HAL_MAX_DELAY); + 8005076: 9901 ldr r1, [sp, #4] + 8005078: b12c cbz r4, 8005086 + 800507a: 4809 ldr r0, [pc, #36] ; (80050a0 ) + 800507c: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 8005080: b2a2 uxth r2, r4 + 8005082: f7ff ff49 bl 8004f18 + HAL_USART_Transmit(&con, (uint8_t *)CRLF, 2, HAL_MAX_DELAY); + 8005086: 4907 ldr r1, [pc, #28] ; (80050a4 ) + 8005088: 4805 ldr r0, [pc, #20] ; (80050a0 ) + 800508a: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 800508e: 2202 movs r2, #2 + 8005090: f7ff ff42 bl 8004f18 + rng_delay(); + 8005094: f7fd fc38 bl 8002908 +} + 8005098: 2001 movs r0, #1 + 800509a: b002 add sp, #8 + 800509c: bd10 pop {r4, pc} + 800509e: bf00 nop + 80050a0: 2009e1c4 .word 0x2009e1c4 + 80050a4: 080107cb .word 0x080107cb + +080050a8 : + +// psram_send_byte() +// + void +psram_send_byte(OSPI_HandleTypeDef *qh, uint8_t cmd_byte, bool is_quad) +{ + 80050a8: b570 push {r4, r5, r6, lr} + 80050aa: b094 sub sp, #80 ; 0x50 + 80050ac: 4604 mov r4, r0 + 80050ae: 460e mov r6, r1 + 80050b0: 4615 mov r5, r2 + // Send single-byte commands to the PSRAM chip. Quad mode or normal SPI. + + OSPI_RegularCmdTypeDef cmd = { + 80050b2: 2100 movs r1, #0 + 80050b4: 2250 movs r2, #80 ; 0x50 + 80050b6: 4668 mov r0, sp + 80050b8: f008 fc34 bl 800d924 + .OperationType = HAL_OSPI_OPTYPE_COMMON_CFG, + .Instruction = cmd_byte, // Exit Quad Mode + .InstructionMode = is_quad ? HAL_OSPI_INSTRUCTION_4_LINES : HAL_OSPI_INSTRUCTION_1_LINE, + 80050bc: 2d00 cmp r5, #0 + 80050be: bf14 ite ne + 80050c0: 2303 movne r3, #3 + 80050c2: 2301 moveq r3, #1 + .DataMode = HAL_OSPI_DATA_NONE, + .NbData = 0, // how much to read in bytes + }; + + // Start and finish a "Indirection functional mode" request + HAL_OSPI_Command(qh, &cmd, HAL_MAX_DELAY); + 80050c4: f04f 32ff mov.w r2, #4294967295 ; 0xffffffff + 80050c8: 4669 mov r1, sp + 80050ca: 4620 mov r0, r4 + OSPI_RegularCmdTypeDef cmd = { + 80050cc: 9602 str r6, [sp, #8] + 80050ce: 9303 str r3, [sp, #12] + HAL_OSPI_Command(qh, &cmd, HAL_MAX_DELAY); + 80050d0: f006 f898 bl 800b204 +} + 80050d4: b014 add sp, #80 ; 0x50 + 80050d6: bd70 pop {r4, r5, r6, pc} + +080050d8 : + +// psram_setup() +// + void +psram_setup(void) +{ + 80050d8: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + 80050dc: b0c6 sub sp, #280 ; 0x118 + // Using OSPI1 block + OSPI_HandleTypeDef qh = { 0 }; + 80050de: 2250 movs r2, #80 ; 0x50 + 80050e0: 2100 movs r1, #0 + 80050e2: a80a add r0, sp, #40 ; 0x28 + 80050e4: f008 fc1e bl 800d924 + + // enable clocks + __HAL_RCC_OSPI1_CLK_ENABLE(); + 80050e8: 4b6a ldr r3, [pc, #424] ; (8005294 ) + // reset module + __HAL_RCC_OSPI1_FORCE_RESET(); + __HAL_RCC_OSPI1_RELEASE_RESET(); + + // configure pins: Port E PE10-PE15 + GPIO_InitTypeDef setup = { + 80050ea: 4c6b ldr r4, [pc, #428] ; (8005298 ) + __HAL_RCC_OSPI1_CLK_ENABLE(); + 80050ec: 6d1a ldr r2, [r3, #80] ; 0x50 + 80050ee: f442 7280 orr.w r2, r2, #256 ; 0x100 + 80050f2: 651a str r2, [r3, #80] ; 0x50 + 80050f4: 6d1a ldr r2, [r3, #80] ; 0x50 + 80050f6: f402 7280 and.w r2, r2, #256 ; 0x100 + 80050fa: 9201 str r2, [sp, #4] + 80050fc: 9a01 ldr r2, [sp, #4] + __HAL_RCC_GPIOE_CLK_ENABLE(); + 80050fe: 6cda ldr r2, [r3, #76] ; 0x4c + 8005100: f042 0210 orr.w r2, r2, #16 + 8005104: 64da str r2, [r3, #76] ; 0x4c + 8005106: 6cda ldr r2, [r3, #76] ; 0x4c + 8005108: f002 0210 and.w r2, r2, #16 + 800510c: 9202 str r2, [sp, #8] + 800510e: 9a02 ldr r2, [sp, #8] + __HAL_RCC_OSPI1_FORCE_RESET(); + 8005110: 6b1a ldr r2, [r3, #48] ; 0x30 + 8005112: f442 7280 orr.w r2, r2, #256 ; 0x100 + 8005116: 631a str r2, [r3, #48] ; 0x30 + __HAL_RCC_OSPI1_RELEASE_RESET(); + 8005118: 6b1a ldr r2, [r3, #48] ; 0x30 + 800511a: f422 7280 bic.w r2, r2, #256 ; 0x100 + 800511e: 631a str r2, [r3, #48] ; 0x30 + GPIO_InitTypeDef setup = { + 8005120: cc0f ldmia r4!, {r0, r1, r2, r3} + 8005122: ad05 add r5, sp, #20 + 8005124: c50f stmia r5!, {r0, r1, r2, r3} + 8005126: 6823 ldr r3, [r4, #0] + .Mode = GPIO_MODE_AF_PP, // not sure + .Pull = GPIO_NOPULL, // not sure + .Speed = GPIO_SPEED_FREQ_VERY_HIGH, + .Alternate = GPIO_AF10_OCTOSPIM_P1, + }; + HAL_GPIO_Init(GPIOE, &setup); + 8005128: 485c ldr r0, [pc, #368] ; (800529c ) + GPIO_InitTypeDef setup = { + 800512a: 602b str r3, [r5, #0] + HAL_GPIO_Init(GPIOE, &setup); + 800512c: a905 add r1, sp, #20 + 800512e: f7fc f861 bl 80011f4 + + + // Config operational values + qh.Instance = OCTOSPI1; + qh.Init.FifoThreshold = 1; // ?? unused + 8005132: 4b5b ldr r3, [pc, #364] ; (80052a0 ) + 8005134: 2701 movs r7, #1 + qh.Init.DualQuad = HAL_OSPI_DUALQUAD_DISABLE; + qh.Init.MemoryType = HAL_OSPI_MEMTYPE_MICRON; // want standard mode (but octo only?) + qh.Init.DeviceSize = 24; // assume max size, actual is 8Mbyte + 8005136: 2218 movs r2, #24 + qh.Init.FifoThreshold = 1; // ?? unused + 8005138: e9cd 370a strd r3, r7, [sp, #40] ; 0x28 + qh.Init.ChipSelectHighTime = 1; // 1, maxed out, seems to work + 800513c: e9cd 270e strd r2, r7, [sp, #56] ; 0x38 + qh.Init.DualQuad = HAL_OSPI_DUALQUAD_DISABLE; + 8005140: 2300 movs r3, #0 + qh.Init.DelayHoldQuarterCycle = HAL_OSPI_DHQC_ENABLE; // maybe? + 8005142: f04f 5280 mov.w r2, #268435456 ; 0x10000000 + qh.Init.FreeRunningClock = HAL_OSPI_FREERUNCLK_DISABLE; // required! + qh.Init.ClockMode = HAL_OSPI_CLOCK_MODE_0; // low clock between ops (required, see errata) +#if HCLK_FREQUENCY == 80000000 + qh.Init.ClockPrescaler = 1; // prescaler (1=>80Mhz, 2=>40Mhz, etc) +#elif HCLK_FREQUENCY == 120000000 + qh.Init.ClockPrescaler = 2; // prescaler (1=>120Mhz, 2=>60Mhz, etc) + 8005146: f04f 0802 mov.w r8, #2 +#else +# error "testing needed" +#endif + qh.Init.DelayBlockBypass = HAL_OSPI_DELAY_BLOCK_BYPASSED; // dont need it? + 800514a: f04f 0908 mov.w r9, #8 + // - (during reads) 3 => 400ns 4 => 660ns 5+ => 1us + // - LATER: Errata 2.8.1 => says shall not use + qh.Init.ChipSelectBoundary = 0; + + // module init + HAL_StatusTypeDef rv = HAL_OSPI_Init(&qh); + 800514e: a80a add r0, sp, #40 ; 0x28 + qh.Init.MemoryType = HAL_OSPI_MEMTYPE_MICRON; // want standard mode (but octo only?) + 8005150: e9cd 330c strd r3, r3, [sp, #48] ; 0x30 + qh.Init.ClockMode = HAL_OSPI_CLOCK_MODE_0; // low clock between ops (required, see errata) + 8005154: e9cd 3310 strd r3, r3, [sp, #64] ; 0x40 + qh.Init.ChipSelectBoundary = 0; + 8005158: e9cd 3915 strd r3, r9, [sp, #84] ; 0x54 + qh.Init.DelayHoldQuarterCycle = HAL_OSPI_DHQC_ENABLE; // maybe? + 800515c: 9214 str r2, [sp, #80] ; 0x50 + qh.Init.ClockPrescaler = 2; // prescaler (1=>120Mhz, 2=>60Mhz, etc) + 800515e: f8cd 8048 str.w r8, [sp, #72] ; 0x48 + HAL_StatusTypeDef rv = HAL_OSPI_Init(&qh); + 8005162: f005 ffe5 bl 800b130 + ASSERT(rv == HAL_OK); + 8005166: 4606 mov r6, r0 + 8005168: b110 cbz r0, 8005170 + 800516a: 484e ldr r0, [pc, #312] ; (80052a4 ) + 800516c: f7fb fc64 bl 8000a38 + + // do some SPI commands first + + // Exit Quad mode, to get to a known state, after first power-up + psram_send_byte(&qh, 0xf5, true); + 8005170: 463a mov r2, r7 + 8005172: 21f5 movs r1, #245 ; 0xf5 + 8005174: a80a add r0, sp, #40 ; 0x28 + 8005176: f7ff ff97 bl 80050a8 + + // Chip Reset sequence + psram_send_byte(&qh, 0x66, false); // reset enable + 800517a: 4632 mov r2, r6 + 800517c: 2166 movs r1, #102 ; 0x66 + 800517e: a80a add r0, sp, #40 ; 0x28 + 8005180: f7ff ff92 bl 80050a8 + + // Read Electronic ID + // - length not clear from datasheet, but repeats after 8 bytes + uint8_t psram_chip_eid[8]; + + { OSPI_RegularCmdTypeDef cmd = { + 8005184: ad32 add r5, sp, #200 ; 0xc8 + psram_send_byte(&qh, 0x99, false); // reset + 8005186: 4632 mov r2, r6 + 8005188: 2199 movs r1, #153 ; 0x99 + 800518a: a80a add r0, sp, #40 ; 0x28 + 800518c: f7ff ff8c bl 80050a8 + { OSPI_RegularCmdTypeDef cmd = { + 8005190: 2250 movs r2, #80 ; 0x50 + 8005192: 4631 mov r1, r6 + 8005194: 4628 mov r0, r5 + 8005196: f008 fbc5 bl 800d924 + 800519a: 239f movs r3, #159 ; 0x9f + 800519c: e9cd 3734 strd r3, r7, [sp, #208] ; 0xd0 + 80051a0: f44f 5a00 mov.w sl, #8192 ; 0x2000 + 80051a4: f44f 7380 mov.w r3, #256 ; 0x100 + 80051a8: e9cd 3a39 strd r3, sl, [sp, #228] ; 0xe4 + .DataMode = HAL_OSPI_DATA_1_LINE, + .NbData = sizeof(psram_chip_eid), // how much to read in bytes + }; + + // Start a "Indirection functional mode" request + rv = HAL_OSPI_Command(&qh, &cmd, HAL_MAX_DELAY); + 80051ac: f04f 32ff mov.w r2, #4294967295 ; 0xffffffff + { OSPI_RegularCmdTypeDef cmd = { + 80051b0: f04f 7380 mov.w r3, #16777216 ; 0x1000000 + rv = HAL_OSPI_Command(&qh, &cmd, HAL_MAX_DELAY); + 80051b4: 4629 mov r1, r5 + 80051b6: a80a add r0, sp, #40 ; 0x28 + { OSPI_RegularCmdTypeDef cmd = { + 80051b8: e9cd 3940 strd r3, r9, [sp, #256] ; 0x100 + rv = HAL_OSPI_Command(&qh, &cmd, HAL_MAX_DELAY); + 80051bc: f006 f822 bl 800b204 + if(rv != HAL_OK) goto fail; + 80051c0: 2800 cmp r0, #0 + 80051c2: d15d bne.n 8005280 + + rv = HAL_OSPI_Receive(&qh, psram_chip_eid, HAL_MAX_DELAY); + 80051c4: f04f 32ff mov.w r2, #4294967295 ; 0xffffffff + 80051c8: a903 add r1, sp, #12 + 80051ca: a80a add r0, sp, #40 ; 0x28 + 80051cc: f006 f94c bl 800b468 + if(rv != HAL_OK) goto fail; + 80051d0: 4606 mov r6, r0 + 80051d2: 2800 cmp r0, #0 + 80051d4: d154 bne.n 8005280 + } + + //puts2("PSRAM EID: "); + //hex_dump(psram_chip_eid, sizeof(psram_chip_eid)); + ASSERT(psram_chip_eid[0] == 0x0d); + 80051d6: f89d 300c ldrb.w r3, [sp, #12] + 80051da: 2b0d cmp r3, #13 + 80051dc: d1c5 bne.n 800516a + ASSERT(psram_chip_eid[1] == 0x5d); + 80051de: f89d 300d ldrb.w r3, [sp, #13] + 80051e2: 2b5d cmp r3, #93 ; 0x5d + 80051e4: d1c1 bne.n 800516a + // .. other bits seem pretty similar between devices, they don't claim they are UUID + + // Put into Quad mode + psram_send_byte(&qh, 0x35, false); // 0x35 = Enter Quad Mode + 80051e6: 4602 mov r2, r0 + 80051e8: 2135 movs r1, #53 ; 0x35 + 80051ea: a80a add r0, sp, #40 ; 0x28 + 80051ec: f7ff ff5c bl 80050a8 + + // Configure read/write cycles for mem-mapped mode + { OSPI_RegularCmdTypeDef cmd = { + 80051f0: 4631 mov r1, r6 + 80051f2: 224c movs r2, #76 ; 0x4c + 80051f4: a81f add r0, sp, #124 ; 0x7c + 80051f6: f008 fb95 bl 800d924 + 80051fa: f04f 0903 mov.w r9, #3 + 80051fe: f8cd 8078 str.w r8, [sp, #120] ; 0x78 + 8005202: f8cd 8080 str.w r8, [sp, #128] ; 0x80 + .DataMode = HAL_OSPI_DATA_4_LINES, + .NbData = 0, // don't care / TBD? + }; + + // Config for write + rv = HAL_OSPI_Command(&qh, &cmd, HAL_MAX_DELAY); + 8005206: a91e add r1, sp, #120 ; 0x78 + { OSPI_RegularCmdTypeDef cmd = { + 8005208: f44f 7840 mov.w r8, #768 ; 0x300 + 800520c: f04f 7640 mov.w r6, #50331648 ; 0x3000000 + rv = HAL_OSPI_Command(&qh, &cmd, HAL_MAX_DELAY); + 8005210: f04f 32ff mov.w r2, #4294967295 ; 0xffffffff + 8005214: a80a add r0, sp, #40 ; 0x28 + { OSPI_RegularCmdTypeDef cmd = { + 8005216: e9cd 8a25 strd r8, sl, [sp, #148] ; 0x94 + 800521a: f8cd 9084 str.w r9, [sp, #132] ; 0x84 + 800521e: 962c str r6, [sp, #176] ; 0xb0 + rv = HAL_OSPI_Command(&qh, &cmd, HAL_MAX_DELAY); + 8005220: f005 fff0 bl 800b204 + if(rv != HAL_OK) goto fail; + 8005224: 4601 mov r1, r0 + 8005226: bb58 cbnz r0, 8005280 + + // .. for read + OSPI_RegularCmdTypeDef cmd2 = { + 8005228: 224c movs r2, #76 ; 0x4c + 800522a: a833 add r0, sp, #204 ; 0xcc + 800522c: f008 fb7a bl 800d924 + 8005230: 23eb movs r3, #235 ; 0xeb + 8005232: e9cd 3934 strd r3, r9, [sp, #208] ; 0xd0 + .DataMode = HAL_OSPI_DATA_4_LINES, + .NbData = 0, // don't care / TBD? + }; + + // Config for read + rv = HAL_OSPI_Command(&qh, &cmd2, HAL_MAX_DELAY); + 8005236: f04f 32ff mov.w r2, #4294967295 ; 0xffffffff + OSPI_RegularCmdTypeDef cmd2 = { + 800523a: 2306 movs r3, #6 + rv = HAL_OSPI_Command(&qh, &cmd2, HAL_MAX_DELAY); + 800523c: 4629 mov r1, r5 + 800523e: a80a add r0, sp, #40 ; 0x28 + OSPI_RegularCmdTypeDef cmd2 = { + 8005240: e9cd 8a39 strd r8, sl, [sp, #228] ; 0xe4 + 8005244: 9732 str r7, [sp, #200] ; 0xc8 + 8005246: 9640 str r6, [sp, #256] ; 0x100 + 8005248: 9343 str r3, [sp, #268] ; 0x10c + rv = HAL_OSPI_Command(&qh, &cmd2, HAL_MAX_DELAY); + 800524a: f005 ffdb bl 800b204 + if(rv != HAL_OK) goto fail; + 800524e: b9b8 cbnz r0, 8005280 + } + + // config for memmap + { OSPI_MemoryMappedTypeDef mmap = { + 8005250: e9d4 0101 ldrd r0, r1, [r4, #4] + 8005254: e885 0003 stmia.w r5, {r0, r1} + // Need this so that CS lines returns to inactive sometimes. + .TimeOutActivation = HAL_OSPI_TIMEOUT_COUNTER_ENABLE, + .TimeOutPeriod = 16, // no idea, max value 0xffff + }; + + rv = HAL_OSPI_MemoryMapped(&qh, &mmap); + 8005258: 4629 mov r1, r5 + 800525a: a80a add r0, sp, #40 ; 0x28 + 800525c: f006 f9ea bl 800b634 + if(rv != HAL_OK) goto fail; + 8005260: b970 cbnz r0, 8005280 +#else + // Only a quick operational check only here. Non-destructive. + { __IO uint32_t *ptr = (uint32_t *)(PSRAM_BASE+PSRAM_SIZE-4); + uint32_t tmp; + + tmp = *ptr; + 8005262: 4b11 ldr r3, [pc, #68] ; (80052a8 ) + *ptr = 0x55aa1234; + 8005264: 4a11 ldr r2, [pc, #68] ; (80052ac ) + tmp = *ptr; + 8005266: f8d3 1ffc ldr.w r1, [r3, #4092] ; 0xffc + *ptr = 0x55aa1234; + 800526a: f8c3 2ffc str.w r2, [r3, #4092] ; 0xffc + if(*ptr != 0x55aa1234) goto fail; + 800526e: f8d3 0ffc ldr.w r0, [r3, #4092] ; 0xffc + 8005272: 4290 cmp r0, r2 + 8005274: d104 bne.n 8005280 + *ptr = tmp; + 8005276: f8c3 1ffc str.w r1, [r3, #4092] ; 0xffc + + oled_setup(); + oled_show(screen_fatal); + + LOCKUP_FOREVER(); +} + 800527a: b046 add sp, #280 ; 0x118 + 800527c: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + puts("PSRAM fail"); + 8005280: 480b ldr r0, [pc, #44] ; (80052b0 ) + 8005282: f7ff fef1 bl 8005068 + oled_setup(); + 8005286: f7fb fd75 bl 8000d74 + oled_show(screen_fatal); + 800528a: 480a ldr r0, [pc, #40] ; (80052b4 ) + 800528c: f7fb fef2 bl 8001074 + LOCKUP_FOREVER(); + 8005290: f7fe fcf2 bl 8003c78 + 8005294: 40021000 .word 0x40021000 + 8005298: 0801080c .word 0x0801080c + 800529c: 48001000 .word 0x48001000 + 80052a0: a0001000 .word 0xa0001000 + 80052a4: 0801046c .word 0x0801046c + 80052a8: 907ff000 .word 0x907ff000 + 80052ac: 55aa1234 .word 0x55aa1234 + 80052b0: 080107de .word 0x080107de + 80052b4: 0800e58d .word 0x0800e58d + +080052b8 : + +// psram_wipe() +// + void +psram_wipe(void) +{ + 80052b8: b508 push {r3, lr} + if(OCTOSPI1->CR == 0) return; // PSRAM not enabled (yet?) + 80052ba: 4b06 ldr r3, [pc, #24] ; (80052d4 ) + 80052bc: 681b ldr r3, [r3, #0] + 80052be: b143 cbz r3, 80052d2 + + // Fast! But real; maybe 150ms + //puts2("PSRAM Wipe: "); + memset4((uint32_t *)PSRAM_BASE, rng_sample(), PSRAM_SIZE); + 80052c0: f7fd face bl 8002860 + 80052c4: f04f 4310 mov.w r3, #2415919104 ; 0x90000000 + *dest = value; + 80052c8: f843 0b04 str.w r0, [r3], #4 + for(; byte_len; byte_len-=4, dest++) { + 80052cc: f113 4fdf cmn.w r3, #1870659584 ; 0x6f800000 + 80052d0: d1fa bne.n 80052c8 + //puts("done"); +} + 80052d2: bd08 pop {r3, pc} + 80052d4: a0001000 .word 0xa0001000 + +080052d8 : +// NOTE: Incoming start address is typically not aligned. +// + void +psram_do_upgrade(const uint8_t *start, uint32_t size) +{ + ASSERT(size >= FW_MIN_LENGTH); + 80052d8: f5b1 2f80 cmp.w r1, #262144 ; 0x40000 +{ + 80052dc: e92d 43f7 stmdb sp!, {r0, r1, r2, r4, r5, r6, r7, r8, r9, lr} + 80052e0: 4606 mov r6, r0 + 80052e2: 460d mov r5, r1 + ASSERT(size >= FW_MIN_LENGTH); + 80052e4: d202 bcs.n 80052ec + 80052e6: 481e ldr r0, [pc, #120] ; (8005360 ) + 80052e8: f7fb fba6 bl 8000a38 + + // In case of reset/crash, we can recover, so save + // what we need for that -- yes, we will re-verify signatures + volatile recovery_header_t *h = RECHDR_POS; + h->start = start; + 80052ec: 4b1d ldr r3, [pc, #116] ; (8005364 ) + h->size = size; + h->magic1 = RECHDR_MAGIC1; + 80052ee: 4a1e ldr r2, [pc, #120] ; (8005368 ) + h->start = start; + 80052f0: 6058 str r0, [r3, #4] + h->size = size; + 80052f2: 6099 str r1, [r3, #8] + h->magic1 = RECHDR_MAGIC1; + 80052f4: 601a str r2, [r3, #0] + h->magic2 = RECHDR_MAGIC2; + 80052f6: 4a1d ldr r2, [pc, #116] ; (800536c ) + 80052f8: 60da str r2, [r3, #12] + + flash_setup0(); + 80052fa: f7fc ff4f bl 800219c + flash_unlock(); + 80052fe: f7fc ff71 bl 80021e4 + for(uint32_t pos=0; pos < size; pos += 8) { + uint32_t dest = FIRMWARE_START+pos; + + if(dest % (4*FLASH_ERASE_SIZE) == 0) { + // show some progress + oled_show_progress(screen_upgrading, pos*100/size); + 8005302: f8df 906c ldr.w r9, [pc, #108] ; 8005370 + for(uint32_t pos=0; pos < size; pos += 8) { + 8005306: 2400 movs r4, #0 + oled_show_progress(screen_upgrading, pos*100/size); + 8005308: f04f 0864 mov.w r8, #100 ; 0x64 + uint32_t dest = FIRMWARE_START+pos; + 800530c: f104 6700 add.w r7, r4, #134217728 ; 0x8000000 + if(dest % (4*FLASH_ERASE_SIZE) == 0) { + 8005310: f3c4 030d ubfx r3, r4, #0, #14 + 8005314: f507 3700 add.w r7, r7, #131072 ; 0x20000 + 8005318: b933 cbnz r3, 8005328 + oled_show_progress(screen_upgrading, pos*100/size); + 800531a: fb08 f104 mul.w r1, r8, r4 + 800531e: 4648 mov r0, r9 + 8005320: fbb1 f1f5 udiv r1, r1, r5 + 8005324: f7fb ff20 bl 8001168 + } + + if(dest % FLASH_ERASE_SIZE == 0) { + 8005328: f3c7 030b ubfx r3, r7, #0, #12 + 800532c: b923 cbnz r3, 8005338 + // page erase as we go + rv = flash_page_erase(dest); + 800532e: 4638 mov r0, r7 + 8005330: f008 fb32 bl 800d998 <__flash_page_erase_veneer> + puts2("erase rv="); + puthex2(rv); + putchar('\n'); + } +#endif + ASSERT(rv == 0); + 8005334: 2800 cmp r0, #0 + 8005336: d1d6 bne.n 80052e6 + } + + memcpy(&tmp, start+pos, 8); + 8005338: 1932 adds r2, r6, r4 + 800533a: 5930 ldr r0, [r6, r4] + 800533c: 6851 ldr r1, [r2, #4] + 800533e: 466b mov r3, sp + 8005340: c303 stmia r3!, {r0, r1} + rv = flash_burn(dest, tmp); + 8005342: 4638 mov r0, r7 + 8005344: e9dd 2300 ldrd r2, r3, [sp] + 8005348: f008 fb22 bl 800d990 <__flash_burn_veneer> + puts2(" addr="); + puthex8(dest); + putchar('\n'); + } +#endif + ASSERT(rv == 0); + 800534c: 2800 cmp r0, #0 + 800534e: d1ca bne.n 80052e6 + for(uint32_t pos=0; pos < size; pos += 8) { + 8005350: 3408 adds r4, #8 + 8005352: 42a5 cmp r5, r4 + 8005354: d8da bhi.n 800530c + } + + flash_lock(); +} + 8005356: b003 add sp, #12 + 8005358: e8bd 43f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, lr} + flash_lock(); + 800535c: f7fc bf3a b.w 80021d4 + 8005360: 0801046c .word 0x0801046c + 8005364: 907ff800 .word 0x907ff800 + 8005368: dbcc8350 .word 0xdbcc8350 + 800536c: bafcfba3 .word 0xbafcfba3 + 8005370: 0800ff35 .word 0x0800ff35 + +08005374 : +{ + 8005374: b510 push {r4, lr} + if( (h->magic1 != RECHDR_MAGIC1) + 8005376: 4c1f ldr r4, [pc, #124] ; (80053f4 ) + 8005378: 4b1f ldr r3, [pc, #124] ; (80053f8 ) + 800537a: 6822 ldr r2, [r4, #0] + 800537c: 429a cmp r2, r3 +{ + 800537e: b088 sub sp, #32 + if( (h->magic1 != RECHDR_MAGIC1) + 8005380: d113 bne.n 80053aa + || (h->magic2 != RECHDR_MAGIC2) + 8005382: 68e2 ldr r2, [r4, #12] + 8005384: 4b1d ldr r3, [pc, #116] ; (80053fc ) + 8005386: 429a cmp r2, r3 + 8005388: d10f bne.n 80053aa + || ((uint32_t)h->start < PSRAM_BASE) + 800538a: 6863 ldr r3, [r4, #4] + 800538c: f1b3 4f10 cmp.w r3, #2415919104 ; 0x90000000 + 8005390: d30b bcc.n 80053aa + || ((uint32_t)h->start >= PSRAM_BASE+(PSRAM_SIZE/2)) + 8005392: 6862 ldr r2, [r4, #4] + 8005394: 4b1a ldr r3, [pc, #104] ; (8005400 ) + 8005396: 429a cmp r2, r3 + 8005398: d807 bhi.n 80053aa + || (h->size > FW_MAX_LENGTH_MK4) + 800539a: 68a3 ldr r3, [r4, #8] + 800539c: f5b3 1ff0 cmp.w r3, #1966080 ; 0x1e0000 + 80053a0: d803 bhi.n 80053aa + || (h->size < FW_MIN_LENGTH) + 80053a2: 68a3 ldr r3, [r4, #8] + 80053a4: f5b3 2f80 cmp.w r3, #262144 ; 0x40000 + 80053a8: d205 bcs.n 80053b6 + puts("PSR: nada"); + 80053aa: 4816 ldr r0, [pc, #88] ; (8005404 ) + puts("PSR: version"); + 80053ac: f7ff fe5c bl 8005068 +} + 80053b0: 2000 movs r0, #0 + 80053b2: b008 add sp, #32 + 80053b4: bd10 pop {r4, pc} + bool ok = verify_firmware_in_ram(h->start, h->size, world_check); + 80053b6: 6860 ldr r0, [r4, #4] + 80053b8: 68a1 ldr r1, [r4, #8] + 80053ba: 466a mov r2, sp + 80053bc: f7fc fd34 bl 8001e28 + if(!ok) { + 80053c0: b908 cbnz r0, 80053c6 + puts("PSR: !check"); + 80053c2: 4811 ldr r0, [pc, #68] ; (8005408 ) + 80053c4: e7f2 b.n 80053ac + if(!verify_world_checksum(world_check)) { + 80053c6: 4668 mov r0, sp + 80053c8: f7fc fd82 bl 8001ed0 + 80053cc: b908 cbnz r0, 80053d2 + puts("PSR: version"); + 80053ce: 480f ldr r0, [pc, #60] ; (800540c ) + 80053d0: e7ec b.n 80053ac + psram_do_upgrade(h->start, h->size); + 80053d2: 6860 ldr r0, [r4, #4] + 80053d4: 68a1 ldr r1, [r4, #8] + 80053d6: f7ff ff7f bl 80052d8 + 80053da: f3bf 8f4f dsb sy + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 80053de: 490c ldr r1, [pc, #48] ; (8005410 ) + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 80053e0: 4b0c ldr r3, [pc, #48] ; (8005414 ) + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 80053e2: 68ca ldr r2, [r1, #12] + 80053e4: f402 62e0 and.w r2, r2, #1792 ; 0x700 + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 80053e8: 4313 orrs r3, r2 + 80053ea: 60cb str r3, [r1, #12] + 80053ec: f3bf 8f4f dsb sy + __NOP(); + 80053f0: bf00 nop + for(;;) /* wait until reset */ + 80053f2: e7fd b.n 80053f0 + 80053f4: 907ff800 .word 0x907ff800 + 80053f8: dbcc8350 .word 0xdbcc8350 + 80053fc: bafcfba3 .word 0xbafcfba3 + 8005400: 903fffff .word 0x903fffff + 8005404: 080107e9 .word 0x080107e9 + 8005408: 080107f3 .word 0x080107f3 + 800540c: 080107ff .word 0x080107ff + 8005410: e000ed00 .word 0xe000ed00 + 8005414: 05fa0004 .word 0x05fa0004 + +08005418 : + +// sdcard_light() +// + void inline +sdcard_light(bool on) +{ + 8005418: 4602 mov r2, r0 + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, !!on); // turn LED off + 800541a: 2180 movs r1, #128 ; 0x80 + 800541c: 4801 ldr r0, [pc, #4] ; (8005424 ) + 800541e: f7fc b863 b.w 80014e8 + 8005422: bf00 nop + 8005424: 48000800 .word 0x48000800 + +08005428 : + +// sdcard_is_inserted() +// + bool +sdcard_is_inserted(void) +{ + 8005428: b508 push {r3, lr} +#ifdef FOR_Q1_ONLY + return !HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_3); // PD3 - inserted when low (Q) + 800542a: 2108 movs r1, #8 + 800542c: 4803 ldr r0, [pc, #12] ; (800543c ) + 800542e: f7fc f855 bl 80014dc +#else + return !!HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13); // PC13 - inserted when high (Mk4) +#endif +} + 8005432: fab0 f080 clz r0, r0 + 8005436: 0940 lsrs r0, r0, #5 + 8005438: bd08 pop {r3, pc} + 800543a: bf00 nop + 800543c: 48000c00 .word 0x48000c00 + +08005440 : + +// sdcard_try_file() +// + void +sdcard_try_file(uint32_t blk_pos) +{ + 8005440: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + 8005444: 4606 mov r6, r0 + 8005446: f5ad 7d0a sub.w sp, sp, #552 ; 0x228 + oled_show(screen_verify); + 800544a: 4832 ldr r0, [pc, #200] ; (8005514 ) + uint8_t *ps = (uint8_t *)PSRAM_BASE; + //uint8_t buf[512*8]; // half of all our SRAM 0x00002000 + uint8_t buf[512]; // slower, but works. + + for(uint32_t off = 0; off < FW_MAX_LENGTH_MK4; off += sizeof(buf)) { + int rv = HAL_SD_ReadBlocks(&hsd, buf, blk_pos+(off/512), sizeof(buf)/512, 60000); + 800544c: f8df 80e4 ldr.w r8, [pc, #228] ; 8005534 + oled_show(screen_verify); + 8005450: f7fb fe10 bl 8001074 + for(uint32_t off = 0; off < FW_MAX_LENGTH_MK4; off += sizeof(buf)) { + 8005454: 2500 movs r5, #0 + int rv = HAL_SD_ReadBlocks(&hsd, buf, blk_pos+(off/512), sizeof(buf)/512, 60000); + 8005456: f64e 2760 movw r7, #60000 ; 0xea60 + 800545a: 9700 str r7, [sp, #0] + 800545c: 2301 movs r3, #1 + 800545e: eb06 2255 add.w r2, r6, r5, lsr #9 + 8005462: a90a add r1, sp, #40 ; 0x28 + 8005464: 4640 mov r0, r8 + 8005466: f006 fe61 bl 800c12c + if(rv != HAL_OK) { + 800546a: 4604 mov r4, r0 + 800546c: b130 cbz r0, 800547c + puts("long read fail"); + 800546e: 482a ldr r0, [pc, #168] ; (8005518 ) + + // Check we have the **right** firmware, based on the world check sum + // but don't set the light at this point. + // - this includes check over bootrom (ourselves) + if(!verify_world_checksum(world_check)) { + puts("wrong world"); + 8005470: f7ff fdfa bl 8005068 + // Do the upgrade, using PSRAM data. + psram_do_upgrade(start, len); + + // done + NVIC_SystemReset(); +} + 8005474: f50d 7d0a add.w sp, sp, #552 ; 0x228 + 8005478: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + memcpy(ps + off, buf, sizeof(buf)); + 800547c: f105 4010 add.w r0, r5, #2415919104 ; 0x90000000 + 8005480: f44f 7200 mov.w r2, #512 ; 0x200 + 8005484: a90a add r1, sp, #40 ; 0x28 + for(uint32_t off = 0; off < FW_MAX_LENGTH_MK4; off += sizeof(buf)) { + 8005486: f505 7500 add.w r5, r5, #512 ; 0x200 + memcpy(ps + off, buf, sizeof(buf)); + 800548a: f008 fa3d bl 800d908 + for(uint32_t off = 0; off < FW_MAX_LENGTH_MK4; off += sizeof(buf)) { + 800548e: f5b5 1ff0 cmp.w r5, #1966080 ; 0x1e0000 + 8005492: d1e2 bne.n 800545a + for(int idx=0; idxtargets; idx++) { + 8005494: f04f 4310 mov.w r3, #2415919104 ; 0x90000000 + if(elem->addr == FIRMWARE_START) { + 8005498: 4d20 ldr r5, [pc, #128] ; (800551c ) + for(int idx=0; idxtargets; idx++) { + 800549a: 7a99 ldrb r1, [r3, #10] + 800549c: 4620 mov r0, r4 + ptr += sizeof(DFUFile_t); + 800549e: 330b adds r3, #11 + for(int idx=0; idxtargets; idx++) { + 80054a0: 4288 cmp r0, r1 + 80054a2: db01 blt.n 80054a8 + puts("DFU parse fail"); + 80054a4: 481e ldr r0, [pc, #120] ; (8005520 ) + 80054a6: e7e3 b.n 8005470 + for(int ei=0; eielements; ei++) { + 80054a8: f8d3 610e ldr.w r6, [r3, #270] ; 0x10e + 80054ac: 2200 movs r2, #0 + ptr += sizeof(DFUTarget_t); + 80054ae: f503 7389 add.w r3, r3, #274 ; 0x112 + for(int ei=0; eielements; ei++) { + 80054b2: 42b2 cmp r2, r6 + 80054b4: d101 bne.n 80054ba + for(int idx=0; idxtargets; idx++) { + 80054b6: 3001 adds r0, #1 + 80054b8: e7f2 b.n 80054a0 + ptr += sizeof(DFUElement_t); + 80054ba: 461c mov r4, r3 + if(elem->addr == FIRMWARE_START) { + 80054bc: f854 7b08 ldr.w r7, [r4], #8 + 80054c0: 42af cmp r7, r5 + 80054c2: d110 bne.n 80054e6 + *target_size = elem->size; + 80054c4: 685d ldr r5, [r3, #4] + bool ok = verify_firmware_in_ram(start, len, world_check); + 80054c6: aa02 add r2, sp, #8 + 80054c8: 4629 mov r1, r5 + 80054ca: 4620 mov r0, r4 + 80054cc: f7fc fcac bl 8001e28 + if(!ok) return; + 80054d0: 2800 cmp r0, #0 + 80054d2: d0cf beq.n 8005474 + puts("good firmware"); + 80054d4: 4813 ldr r0, [pc, #76] ; (8005524 ) + 80054d6: f7ff fdc7 bl 8005068 + if(!verify_world_checksum(world_check)) { + 80054da: a802 add r0, sp, #8 + 80054dc: f7fc fcf8 bl 8001ed0 + 80054e0: b920 cbnz r0, 80054ec + puts("wrong world"); + 80054e2: 4811 ldr r0, [pc, #68] ; (8005528 ) + 80054e4: e7c4 b.n 8005470 + for(int ei=0; eielements; ei++) { + 80054e6: 3201 adds r2, #1 + ptr += sizeof(DFUElement_t); + 80054e8: 4623 mov r3, r4 + 80054ea: e7e2 b.n 80054b2 + sdcard_light(false); + 80054ec: 2000 movs r0, #0 + 80054ee: f7ff ff93 bl 8005418 + psram_do_upgrade(start, len); + 80054f2: 4629 mov r1, r5 + 80054f4: 4620 mov r0, r4 + 80054f6: f7ff feef bl 80052d8 + 80054fa: f3bf 8f4f dsb sy + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 80054fe: 490b ldr r1, [pc, #44] ; (800552c ) + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 8005500: 4b0b ldr r3, [pc, #44] ; (8005530 ) + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 8005502: 68ca ldr r2, [r1, #12] + 8005504: f402 62e0 and.w r2, r2, #1792 ; 0x700 + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 8005508: 4313 orrs r3, r2 + 800550a: 60cb str r3, [r1, #12] + 800550c: f3bf 8f4f dsb sy + __NOP(); + 8005510: bf00 nop + for(;;) /* wait until reset */ + 8005512: e7fd b.n 8005510 + 8005514: 0801004d .word 0x0801004d + 8005518: 08010828 .word 0x08010828 + 800551c: 08020000 .word 0x08020000 + 8005520: 08010837 .word 0x08010837 + 8005524: 08010846 .word 0x08010846 + 8005528: 08010854 .word 0x08010854 + 800552c: e000ed00 .word 0xe000ed00 + 8005530: 05fa0004 .word 0x05fa0004 + 8005534: 2009e224 .word 0x2009e224 + +08005538 : + +// sdcard_search() +// + void +sdcard_search(void) +{ + 8005538: e92d 43f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, lr} + oled_show(screen_search); + 800553c: 4861 ldr r0, [pc, #388] ; (80056c4 ) +{ + 800553e: f5ad 7d05 sub.w sp, sp, #532 ; 0x214 + oled_show(screen_search); + 8005542: f7fb fd97 bl 8001074 + + if(!sdcard_is_inserted()) return; + 8005546: f7ff ff6f bl 8005428 + 800554a: 2800 cmp r0, #0 + 800554c: f000 8095 beq.w 800567a + __HAL_RCC_SDMMC1_CLK_ENABLE(); + 8005550: f8df 81b0 ldr.w r8, [pc, #432] ; 8005704 + + uint32_t num_blocks; + + // open card (power it) and get details, do setup + puts2("sdcard_search: "); + 8005554: 485c ldr r0, [pc, #368] ; (80056c8 ) + { GPIO_InitTypeDef setup = { + 8005556: 4c5d ldr r4, [pc, #372] ; (80056cc ) + puts2("sdcard_search: "); + 8005558: f7ff fcf8 bl 8004f4c + __HAL_RCC_SDMMC1_CLK_ENABLE(); + 800555c: f8d8 304c ldr.w r3, [r8, #76] ; 0x4c + 8005560: f443 0380 orr.w r3, r3, #4194304 ; 0x400000 + 8005564: f8c8 304c str.w r3, [r8, #76] ; 0x4c + 8005568: f8d8 304c ldr.w r3, [r8, #76] ; 0x4c + 800556c: f403 0380 and.w r3, r3, #4194304 ; 0x400000 + 8005570: 9303 str r3, [sp, #12] + 8005572: 9b03 ldr r3, [sp, #12] + { GPIO_InitTypeDef setup = { + 8005574: cc0f ldmia r4!, {r0, r1, r2, r3} + 8005576: ad04 add r5, sp, #16 + 8005578: c50f stmia r5!, {r0, r1, r2, r3} + 800557a: f854 3b04 ldr.w r3, [r4], #4 + 800557e: 602b str r3, [r5, #0] + HAL_GPIO_Init(GPIOC, &setup); + 8005580: 4853 ldr r0, [pc, #332] ; (80056d0 ) + 8005582: a904 add r1, sp, #16 + 8005584: f7fb fe36 bl 80011f4 + GPIO_InitTypeDef setup = { + 8005588: 2700 movs r7, #0 + 800558a: f44f 5600 mov.w r6, #8192 ; 0x2000 + HAL_GPIO_Init(GPIOC, &setup); + 800558e: 4850 ldr r0, [pc, #320] ; (80056d0 ) + GPIO_InitTypeDef setup = { + 8005590: 9708 str r7, [sp, #32] + HAL_GPIO_Init(GPIOC, &setup); + 8005592: a904 add r1, sp, #16 + GPIO_InitTypeDef setup = { + 8005594: f04f 0901 mov.w r9, #1 + 8005598: e9cd 6904 strd r6, r9, [sp, #16] + 800559c: e9cd 7706 strd r7, r7, [sp, #24] + HAL_GPIO_Init(GPIOC, &setup); + 80055a0: f7fb fe28 bl 80011f4 + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, 0); // select A + 80055a4: 4631 mov r1, r6 + 80055a6: 484a ldr r0, [pc, #296] ; (80056d0 ) + 80055a8: 463a mov r2, r7 + 80055aa: f7fb ff9d bl 80014e8 + { GPIO_InitTypeDef setup = { + 80055ae: cc0f ldmia r4!, {r0, r1, r2, r3} + 80055b0: ae04 add r6, sp, #16 + 80055b2: c60f stmia r6!, {r0, r1, r2, r3} + 80055b4: 6823 ldr r3, [r4, #0] + 80055b6: 602b str r3, [r5, #0] + HAL_GPIO_Init(GPIOD, &setup); + 80055b8: a904 add r1, sp, #16 + 80055ba: 4846 ldr r0, [pc, #280] ; (80056d4 ) + memset(&hsd, 0, sizeof(SD_HandleTypeDef)); + 80055bc: 4d46 ldr r5, [pc, #280] ; (80056d8 ) + HAL_GPIO_Init(GPIOD, &setup); + 80055be: f7fb fe19 bl 80011f4 + __HAL_RCC_SDMMC1_FORCE_RESET(); + 80055c2: f8d8 302c ldr.w r3, [r8, #44] ; 0x2c + 80055c6: f443 0380 orr.w r3, r3, #4194304 ; 0x400000 + 80055ca: f8c8 302c str.w r3, [r8, #44] ; 0x2c + __HAL_RCC_SDMMC1_RELEASE_RESET(); + 80055ce: f8d8 302c ldr.w r3, [r8, #44] ; 0x2c + 80055d2: f423 0380 bic.w r3, r3, #4194304 ; 0x400000 + 80055d6: f8c8 302c str.w r3, [r8, #44] ; 0x2c + sdcard_setup(); + delay_ms(100); + 80055da: 2064 movs r0, #100 ; 0x64 + 80055dc: f7fe fa52 bl 8003a84 + memset(&hsd, 0, sizeof(SD_HandleTypeDef)); + 80055e0: 2280 movs r2, #128 ; 0x80 + 80055e2: 4639 mov r1, r7 + 80055e4: 4628 mov r0, r5 + 80055e6: f008 f99d bl 800d924 + puts2("sdcard_probe: "); + 80055ea: 483c ldr r0, [pc, #240] ; (80056dc ) + 80055ec: f7ff fcae bl 8004f4c + hsd.Instance = SDMMC1; + 80055f0: 4b3b ldr r3, [pc, #236] ; (80056e0 ) + hsd.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; + 80055f2: 612f str r7, [r5, #16] + hsd.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING; + 80055f4: e9c5 3700 strd r3, r7, [r5] + hsd.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_ENABLE; + 80055f8: f44f 5380 mov.w r3, #4096 ; 0x1000 + hsd.Init.BusWide = SDMMC_BUS_WIDE_1B; + 80055fc: e9c5 3702 strd r3, r7, [r5, #8] + int rv = HAL_SD_Init(&hsd); + 8005600: 4628 mov r0, r5 + hsd.Init.ClockDiv = SDMMC_TRANSFER_CLK_DIV; + 8005602: 2303 movs r3, #3 + 8005604: 616b str r3, [r5, #20] + int rv = HAL_SD_Init(&hsd); + 8005606: f007 fb0b bl 800cc20 + if(rv != HAL_OK) { + 800560a: 4604 mov r4, r0 + 800560c: b130 cbz r0, 800561c + puts("init fail"); + 800560e: 4835 ldr r0, [pc, #212] ; (80056e4 ) + oled_show_progress(screen_search, pos*100 / num_blocks); + sdcard_light(true); + } + } + +} + 8005610: f50d 7d05 add.w sp, sp, #532 ; 0x214 + 8005614: e8bd 43f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, lr} + puts("bsize?"); + 8005618: f7ff bd26 b.w 8005068 + sdcard_light(true); + 800561c: 4648 mov r0, r9 + 800561e: f7ff fefb bl 8005418 + rv = HAL_SD_ConfigSpeedBusOperation(&hsd, SDMMC_SPEED_MODE_AUTO); + 8005622: 4621 mov r1, r4 + 8005624: 4628 mov r0, r5 + 8005626: f007 fbd3 bl 800cdd0 + if(rv != HAL_OK) { + 800562a: b108 cbz r0, 8005630 + puts("speed"); + 800562c: 482e ldr r0, [pc, #184] ; (80056e8 ) + 800562e: e7ef b.n 8005610 + rv = HAL_SD_ConfigWideBusOperation(&hsd, SDMMC_BUS_WIDE_4B); + 8005630: f44f 4180 mov.w r1, #16384 ; 0x4000 + 8005634: 4628 mov r0, r5 + 8005636: f007 fa1d bl 800ca74 + if(rv != HAL_OK) { + 800563a: 4604 mov r4, r0 + 800563c: b108 cbz r0, 8005642 + puts("wide"); + 800563e: 482b ldr r0, [pc, #172] ; (80056ec ) + 8005640: e7e6 b.n 8005610 + if(hsd.SdCard.BlockSize != 512) { + 8005642: 6d2b ldr r3, [r5, #80] ; 0x50 + 8005644: f5b3 7f00 cmp.w r3, #512 ; 0x200 + 8005648: d001 beq.n 800564e + puts("bsize?"); + 800564a: 4829 ldr r0, [pc, #164] ; (80056f0 ) + 800564c: e7e0 b.n 8005610 + puts("ok"); + 800564e: 4829 ldr r0, [pc, #164] ; (80056f4 ) + *num_blocks = hsd.SdCard.BlockNbr; + 8005650: 6cee ldr r6, [r5, #76] ; 0x4c + if(memcmp(blk, "DfuSe", 5) == 0) { + 8005652: 4f29 ldr r7, [pc, #164] ; (80056f8 ) + oled_show_progress(screen_search, pos*100 / num_blocks); + 8005654: f8df 806c ldr.w r8, [pc, #108] ; 80056c4 + puts("ok"); + 8005658: f7ff fd06 bl 8005068 + for(int pos=0; pos + int rv = HAL_SD_ReadBlocks(&hsd, blk, pos, 1, 60000); + 8005660: f64e 2360 movw r3, #60000 ; 0xea60 + 8005664: 9300 str r3, [sp, #0] + 8005666: 4622 mov r2, r4 + 8005668: 2301 movs r3, #1 + 800566a: a904 add r1, sp, #16 + 800566c: 4628 mov r0, r5 + 800566e: f006 fd5d bl 800c12c + if(rv != HAL_OK) { + 8005672: b130 cbz r0, 8005682 + puts("fail read"); + 8005674: 4821 ldr r0, [pc, #132] ; (80056fc ) + 8005676: f7ff fcf7 bl 8005068 +} + 800567a: f50d 7d05 add.w sp, sp, #532 ; 0x214 + 800567e: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + if(memcmp(blk, "DfuSe", 5) == 0) { + 8005682: 2205 movs r2, #5 + 8005684: 4639 mov r1, r7 + 8005686: a804 add r0, sp, #16 + 8005688: f008 f92e bl 800d8e8 + 800568c: b9b0 cbnz r0, 80056bc + puts2("found @ "); + 800568e: 481c ldr r0, [pc, #112] ; (8005700 ) + 8005690: f7ff fc5c bl 8004f4c + puthex8(pos); + 8005694: 4620 mov r0, r4 + 8005696: f7ff fcb5 bl 8005004 + putchar('\n'); + 800569a: 200a movs r0, #10 + 800569c: f7ff fc6a bl 8004f74 + sdcard_try_file(pos); + 80056a0: 4620 mov r0, r4 + 80056a2: f7ff fecd bl 8005440 + oled_show_progress(screen_search, pos*100 / num_blocks); + 80056a6: 2164 movs r1, #100 ; 0x64 + 80056a8: 4640 mov r0, r8 + 80056aa: 4361 muls r1, r4 + 80056ac: fbb1 f1f6 udiv r1, r1, r6 + 80056b0: f7fb fd5a bl 8001168 + sdcard_light(true); + 80056b4: 2001 movs r0, #1 + 80056b6: f7ff feaf bl 8005418 + 80056ba: e001 b.n 80056c0 + if(pos % 128 == 0) { + 80056bc: 0663 lsls r3, r4, #25 + 80056be: d0f2 beq.n 80056a6 + for(int pos=0; pos + 80056c4: 0800fa95 .word 0x0800fa95 + 80056c8: 08010860 .word 0x08010860 + 80056cc: 080108c8 .word 0x080108c8 + 80056d0: 48000800 .word 0x48000800 + 80056d4: 48000c00 .word 0x48000c00 + 80056d8: 2009e224 .word 0x2009e224 + 80056dc: 08010870 .word 0x08010870 + 80056e0: 50062400 .word 0x50062400 + 80056e4: 0801087f .word 0x0801087f + 80056e8: 08010889 .word 0x08010889 + 80056ec: 0801088f .word 0x0801088f + 80056f0: 08010894 .word 0x08010894 + 80056f4: 0801089b .word 0x0801089b + 80056f8: 080108a8 .word 0x080108a8 + 80056fc: 0801089e .word 0x0801089e + 8005700: 080108ae .word 0x080108ae + 8005704: 40021000 .word 0x40021000 + +08005708 : + +// sdcard_recovery() +// + void +sdcard_recovery(void) +{ + 8005708: b508 push {r3, lr} + // Use SDCard to recover. Must be precise version they tried to + // install before, and will be slow AF. + + puts("Recovery mode."); + 800570a: 480b ldr r0, [pc, #44] ; (8005738 ) + while(1) { + // .. need them to insert a card + + sdcard_light(false); + while(!sdcard_is_inserted()) { + oled_show(screen_recovery); + 800570c: 4c0b ldr r4, [pc, #44] ; (800573c ) + puts("Recovery mode."); + 800570e: f7ff fcab bl 8005068 + sdcard_light(false); + 8005712: 2000 movs r0, #0 + 8005714: f7ff fe80 bl 8005418 + while(!sdcard_is_inserted()) { + 8005718: f7ff fe86 bl 8005428 + 800571c: b128 cbz r0, 800572a + delay_ms(200); + } + + // look for binary, will reset system if successful + sdcard_light(true); + 800571e: 2001 movs r0, #1 + 8005720: f7ff fe7a bl 8005418 + sdcard_search(); + 8005724: f7ff ff08 bl 8005538 + sdcard_light(false); + 8005728: e7f3 b.n 8005712 + oled_show(screen_recovery); + 800572a: 4620 mov r0, r4 + 800572c: f7fb fca2 bl 8001074 + delay_ms(200); + 8005730: 20c8 movs r0, #200 ; 0xc8 + 8005732: f7fe f9a7 bl 8003a84 + 8005736: e7ef b.n 8005718 + 8005738: 080108b7 .word 0x080108b7 + 800573c: 0800e85f .word 0x0800e85f + +08005740 : +#include + +// so we don't need stm32l4xx_hal_hash_ex.c +HAL_StatusTypeDef HAL_HASHEx_SHA256_Accmlt(HASH_HandleTypeDef *hhash, uint8_t *pInBuffer, uint32_t Size) +{ + return HASH_Accumulate(hhash, pInBuffer, Size,HASH_ALGOSELECTION_SHA256); + 8005740: 4b01 ldr r3, [pc, #4] ; (8005748 ) + 8005742: f005 ba3b b.w 800abbc + 8005746: bf00 nop + 8005748: 00040080 .word 0x00040080 + +0800574c : +} + +HAL_StatusTypeDef HAL_HASHEx_SHA256_Start(HASH_HandleTypeDef *hhash, uint8_t *pInBuffer, uint32_t Size, uint8_t* pOutBuffer, uint32_t Timeout) +{ + 800574c: b513 push {r0, r1, r4, lr} + return HASH_Start(hhash, pInBuffer, Size, pOutBuffer, Timeout, HASH_ALGOSELECTION_SHA256); + 800574e: 4c04 ldr r4, [pc, #16] ; (8005760 ) + 8005750: 9401 str r4, [sp, #4] + 8005752: 9c04 ldr r4, [sp, #16] + 8005754: 9400 str r4, [sp, #0] + 8005756: f005 f98d bl 800aa74 +} + 800575a: b002 add sp, #8 + 800575c: bd10 pop {r4, pc} + 800575e: bf00 nop + 8005760: 00040080 .word 0x00040080 + +08005764 : + +HAL_StatusTypeDef HAL_HMACEx_SHA256_Start(HASH_HandleTypeDef *hhash, uint8_t *pInBuffer, uint32_t Size, uint8_t* pOutBuffer, uint32_t Timeout) +{ + 8005764: b513 push {r0, r1, r4, lr} + return HMAC_Start(hhash, pInBuffer, Size, pOutBuffer, Timeout, HASH_ALGOSELECTION_SHA256); + 8005766: 4c04 ldr r4, [pc, #16] ; (8005778 ) + 8005768: 9401 str r4, [sp, #4] + 800576a: 9c04 ldr r4, [sp, #16] + 800576c: 9400 str r4, [sp, #0] + 800576e: f005 fbc3 bl 800aef8 +} + 8005772: b002 add sp, #8 + 8005774: bd10 pop {r4, pc} + 8005776: bf00 nop + 8005778: 00040080 .word 0x00040080 + +0800577c : + +void sha256_init(SHA256_CTX *ctx) +{ + 800577c: b510 push {r4, lr} + memset(ctx, 0, sizeof(SHA256_CTX)); + 800577e: 2248 movs r2, #72 ; 0x48 +{ + 8005780: 4604 mov r4, r0 + memset(ctx, 0, sizeof(SHA256_CTX)); + 8005782: 2100 movs r1, #0 + 8005784: 3004 adds r0, #4 + 8005786: f008 f8cd bl 800d924 + +#if 1 + ctx->num_pending = 0; + ctx->hh.Init.DataType = HASH_DATATYPE_8B; + 800578a: 2320 movs r3, #32 + 800578c: 6023 str r3, [r4, #0] + HAL_HASH_Init(&ctx->hh); + 800578e: 4620 mov r0, r4 + __HAL_HASH_RESET_MDMAT(); + + MODIFY_REG(HASH->CR, HASH_CR_LKEY|HASH_CR_ALGO|HASH_CR_MODE|HASH_CR_INIT, + HASH_ALGOSELECTION_SHA256 | HASH_CR_INIT); +#endif +} + 8005790: e8bd 4010 ldmia.w sp!, {r4, lr} + HAL_HASH_Init(&ctx->hh); + 8005794: f004 bffc b.w 800a790 + +08005798 : + +void sha256_update(SHA256_CTX *ctx, const uint8_t data[], uint32_t len) +{ + 8005798: b5f8 push {r3, r4, r5, r6, r7, lr} + HAL_StatusTypeDef rv; + + // clear out any pending bytes + if(ctx->num_pending + len >= 4) { + 800579a: f890 3048 ldrb.w r3, [r0, #72] ; 0x48 + 800579e: 4413 add r3, r2 + 80057a0: 2b03 cmp r3, #3 +{ + 80057a2: 4605 mov r5, r0 + 80057a4: 460e mov r6, r1 + 80057a6: 4614 mov r4, r2 + if(ctx->num_pending + len >= 4) { + 80057a8: d818 bhi.n 80057dc + } + } + + // write full blocks + uint32_t blocks = len / 4; + if(blocks) { + 80057aa: 2c03 cmp r4, #3 + 80057ac: d926 bls.n 80057fc +#if 1 + rv = HAL_HASHEx_SHA256_Accumulate(&ctx->hh, (uint8_t *)data, blocks*4); + 80057ae: f024 0703 bic.w r7, r4, #3 + 80057b2: 463a mov r2, r7 + 80057b4: 4631 mov r1, r6 + 80057b6: 4628 mov r0, r5 + 80057b8: f7ff ffc2 bl 8005740 + ASSERT(rv == HAL_OK); + 80057bc: b9c8 cbnz r0, 80057f2 + uint32_t tmp; + memcpy(&tmp, data, 4); + HASH->DIN = tmp; + } +#endif + len -= blocks*4; + 80057be: f004 0403 and.w r4, r4, #3 + data += blocks*4; + 80057c2: 443e add r6, r7 + 80057c4: e01a b.n 80057fc + ctx->pending[ctx->num_pending++] = *data; + 80057c6: 1c5a adds r2, r3, #1 + 80057c8: b2d2 uxtb r2, r2 + 80057ca: f885 2048 strb.w r2, [r5, #72] ; 0x48 + 80057ce: 442b add r3, r5 + 80057d0: f816 1b01 ldrb.w r1, [r6], #1 + 80057d4: f883 1044 strb.w r1, [r3, #68] ; 0x44 + if(!len) break; + 80057d8: 3c01 subs r4, #1 + 80057da: d00d beq.n 80057f8 + while(ctx->num_pending != 4) { + 80057dc: f895 3048 ldrb.w r3, [r5, #72] ; 0x48 + 80057e0: 2b04 cmp r3, #4 + 80057e2: d1f0 bne.n 80057c6 + rv = HAL_HASHEx_SHA256_Accumulate(&ctx->hh, ctx->pending, 4); + 80057e4: 2204 movs r2, #4 + 80057e6: f105 0144 add.w r1, r5, #68 ; 0x44 + 80057ea: 4628 mov r0, r5 + 80057ec: f7ff ffa8 bl 8005740 + ASSERT(rv == HAL_OK); + 80057f0: b140 cbz r0, 8005804 + 80057f2: 480b ldr r0, [pc, #44] ; (8005820 ) + 80057f4: f7fb f920 bl 8000a38 + if(ctx->num_pending == 4) { + 80057f8: 2a04 cmp r2, #4 + 80057fa: d0f3 beq.n 80057e4 + 80057fc: 4434 add r4, r6 + } + + // save runt for later + ASSERT(len <= 3); + while(len) { + 80057fe: 42b4 cmp r4, r6 + 8005800: d103 bne.n 800580a + ctx->pending[ctx->num_pending++] = *data; + data++; + len--; + } +} + 8005802: bdf8 pop {r3, r4, r5, r6, r7, pc} + ctx->num_pending = 0; + 8005804: f885 0048 strb.w r0, [r5, #72] ; 0x48 + 8005808: e7cf b.n 80057aa + ctx->pending[ctx->num_pending++] = *data; + 800580a: f895 3048 ldrb.w r3, [r5, #72] ; 0x48 + 800580e: 1c5a adds r2, r3, #1 + 8005810: f885 2048 strb.w r2, [r5, #72] ; 0x48 + 8005814: 442b add r3, r5 + 8005816: f816 2b01 ldrb.w r2, [r6], #1 + 800581a: f883 2044 strb.w r2, [r3, #68] ; 0x44 + len--; + 800581e: e7ee b.n 80057fe + 8005820: 0801046c .word 0x0801046c + +08005824 : + +void sha256_final(SHA256_CTX *ctx, uint8_t digest[32]) +{ + 8005824: b513 push {r0, r1, r4, lr} + // Do final 0-3 bytes, pad and return digest. +#if 1 + HAL_StatusTypeDef rv = HAL_HASHEx_SHA256_Start(&ctx->hh, + 8005826: f04f 32ff mov.w r2, #4294967295 ; 0xffffffff + 800582a: 9200 str r2, [sp, #0] +{ + 800582c: 460b mov r3, r1 + HAL_StatusTypeDef rv = HAL_HASHEx_SHA256_Start(&ctx->hh, + 800582e: f890 2048 ldrb.w r2, [r0, #72] ; 0x48 + 8005832: f100 0144 add.w r1, r0, #68 ; 0x44 + 8005836: f7ff ff89 bl 800574c + ctx->pending, ctx->num_pending, digest, HAL_MAX_DELAY); + ASSERT(rv == HAL_OK); + 800583a: b110 cbz r0, 8005842 + 800583c: 4802 ldr r0, [pc, #8] ; (8005848 ) + 800583e: f7fb f8fb bl 8000a38 + tmp = __REV(HASH_DIGEST->HR[6]); + memcpy(out, &tmp, 4); out += 4; + tmp = __REV(HASH_DIGEST->HR[7]); + memcpy(out, &tmp, 4); +#endif +} + 8005842: b002 add sp, #8 + 8005844: bd10 pop {r4, pc} + 8005846: bf00 nop + 8005848: 0801046c .word 0x0801046c + +0800584c : +// +// single-shot version (best) +// + void +sha256_single(const uint8_t data[], uint32_t len, uint8_t digest[32]) +{ + 800584c: b530 push {r4, r5, lr} + 800584e: b097 sub sp, #92 ; 0x5c + 8005850: 4604 mov r4, r0 + 8005852: 460d mov r5, r1 + 8005854: 9203 str r2, [sp, #12] + HASH_HandleTypeDef hh = {0}; + 8005856: 2100 movs r1, #0 + 8005858: 2240 movs r2, #64 ; 0x40 + 800585a: a806 add r0, sp, #24 + 800585c: f008 f862 bl 800d924 + + hh.Init.DataType = HASH_DATATYPE_8B; + 8005860: 2220 movs r2, #32 + + HAL_HASH_Init(&hh); + 8005862: a805 add r0, sp, #20 + hh.Init.DataType = HASH_DATATYPE_8B; + 8005864: 9205 str r2, [sp, #20] + HAL_HASH_Init(&hh); + 8005866: f004 ff93 bl 800a790 + + // It's called "Start" but it handles the runt packet, so really can only + // be used once at end of message, or for whole message. + HAL_StatusTypeDef rv = HAL_HASHEx_SHA256_Start(&hh, (uint8_t *)data, len, + 800586a: f04f 32ff mov.w r2, #4294967295 ; 0xffffffff + 800586e: 9200 str r2, [sp, #0] + 8005870: 9b03 ldr r3, [sp, #12] + 8005872: 462a mov r2, r5 + 8005874: 4621 mov r1, r4 + 8005876: a805 add r0, sp, #20 + 8005878: f7ff ff68 bl 800574c + digest, HAL_MAX_DELAY); + ASSERT(rv == HAL_OK); + 800587c: b110 cbz r0, 8005884 + 800587e: 4802 ldr r0, [pc, #8] ; (8005888 ) + 8005880: f7fb f8da bl 8000a38 +} + 8005884: b017 add sp, #92 ; 0x5c + 8005886: bd30 pop {r4, r5, pc} + 8005888: 0801046c .word 0x0801046c + +0800588c : +// hmac_sha256_init() +// + void +hmac_sha256_init(HMAC_CTX *ctx) +{ + memset(ctx, 0, sizeof(HMAC_CTX)); + 800588c: f44f 7282 mov.w r2, #260 ; 0x104 + 8005890: 2100 movs r1, #0 + 8005892: f008 b847 b.w 800d924 + ... + +08005898 : + +// hmac_sha256_update() +// + void +hmac_sha256_update(HMAC_CTX *ctx, const uint8_t data[], uint32_t len) +{ + 8005898: b538 push {r3, r4, r5, lr} + 800589a: 4604 mov r4, r0 + // simple append + ASSERT(ctx->num_pending + len < sizeof(ctx->pending)); + 800589c: f8d0 0100 ldr.w r0, [r0, #256] ; 0x100 + 80058a0: 1883 adds r3, r0, r2 + 80058a2: 2bff cmp r3, #255 ; 0xff +{ + 80058a4: 4615 mov r5, r2 + ASSERT(ctx->num_pending + len < sizeof(ctx->pending)); + 80058a6: d902 bls.n 80058ae + 80058a8: 4805 ldr r0, [pc, #20] ; (80058c0 ) + 80058aa: f7fb f8c5 bl 8000a38 + + memcpy(ctx->pending+ctx->num_pending, data, len); + 80058ae: 4420 add r0, r4 + 80058b0: f008 f82a bl 800d908 + + ctx->num_pending += len; + 80058b4: f8d4 2100 ldr.w r2, [r4, #256] ; 0x100 + 80058b8: 442a add r2, r5 + 80058ba: f8c4 2100 str.w r2, [r4, #256] ; 0x100 +} + 80058be: bd38 pop {r3, r4, r5, pc} + 80058c0: 0801046c .word 0x0801046c + +080058c4 : + +// hmac_sha256_final() +// + void +hmac_sha256_final(HMAC_CTX *ctx, const uint8_t key[32], uint8_t digest[32]) +{ + 80058c4: b530 push {r4, r5, lr} + 80058c6: b097 sub sp, #92 ; 0x5c + 80058c8: 4604 mov r4, r0 + 80058ca: 460d mov r5, r1 + 80058cc: 9203 str r2, [sp, #12] + HASH_HandleTypeDef hh = {0}; + 80058ce: 2100 movs r1, #0 + 80058d0: 2238 movs r2, #56 ; 0x38 + 80058d2: a808 add r0, sp, #32 + 80058d4: f008 f826 bl 800d924 + + hh.Init.DataType = HASH_DATATYPE_8B; + 80058d8: 2220 movs r2, #32 + hh.Init.pKey = (uint8_t *)key; // const viol due to API dumbness + hh.Init.KeySize = 32; + + HAL_HASH_Init(&hh); + 80058da: a805 add r0, sp, #20 + hh.Init.KeySize = 32; + 80058dc: e9cd 2506 strd r2, r5, [sp, #24] + hh.Init.DataType = HASH_DATATYPE_8B; + 80058e0: 9205 str r2, [sp, #20] + HAL_HASH_Init(&hh); + 80058e2: f004 ff55 bl 800a790 + + HAL_StatusTypeDef rv = HAL_HMACEx_SHA256_Start(&hh, + 80058e6: f04f 32ff mov.w r2, #4294967295 ; 0xffffffff + 80058ea: 9200 str r2, [sp, #0] + 80058ec: 9b03 ldr r3, [sp, #12] + 80058ee: f8d4 2100 ldr.w r2, [r4, #256] ; 0x100 + 80058f2: 4621 mov r1, r4 + 80058f4: a805 add r0, sp, #20 + 80058f6: f7ff ff35 bl 8005764 + ctx->pending, ctx->num_pending, digest, HAL_MAX_DELAY); + ASSERT(rv == HAL_OK); + 80058fa: b110 cbz r0, 8005902 + 80058fc: 4802 ldr r0, [pc, #8] ; (8005908 ) + 80058fe: f7fb f89b bl 8000a38 +} + 8005902: b017 add sp, #92 ; 0x5c + 8005904: bd30 pop {r4, r5, pc} + 8005906: bf00 nop + 8005908: 0801046c .word 0x0801046c + +0800590c : + +#if !asm_mult +uECC_VLI_API void uECC_vli_mult(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + wordcount_t num_words) { + 800590c: e92d 43f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, lr} + ); + +#else /* Thumb-1 */ + uint32_t r4, r5, r6, r7; + + __asm__ volatile ( + 8005910: 3b01 subs r3, #1 + 8005912: 009b lsls r3, r3, #2 + 8005914: 4698 mov r8, r3 + 8005916: 005b lsls r3, r3, #1 + 8005918: 4699 mov r9, r3 + 800591a: 2300 movs r3, #0 + 800591c: 2400 movs r4, #0 + 800591e: 2500 movs r5, #0 + 8005920: 2600 movs r6, #0 + 8005922: b401 push {r0} + 8005924: 2700 movs r7, #0 + 8005926: e002 b.n 800592e + 8005928: 0037 movs r7, r6 + 800592a: 4640 mov r0, r8 + 800592c: 1a3f subs r7, r7, r0 + 800592e: b478 push {r3, r4, r5, r6} + 8005930: 1bf0 subs r0, r6, r7 + 8005932: 5814 ldr r4, [r2, r0] + 8005934: 59c8 ldr r0, [r1, r7] + 8005936: 0c03 lsrs r3, r0, #16 + 8005938: b280 uxth r0, r0 + 800593a: 0c25 lsrs r5, r4, #16 + 800593c: b2a4 uxth r4, r4 + 800593e: 001e movs r6, r3 + 8005940: 436e muls r6, r5 + 8005942: 4363 muls r3, r4 + 8005944: 4345 muls r5, r0 + 8005946: 4360 muls r0, r4 + 8005948: 2400 movs r4, #0 + 800594a: 195b adds r3, r3, r5 + 800594c: 4164 adcs r4, r4 + 800594e: 0424 lsls r4, r4, #16 + 8005950: 1936 adds r6, r6, r4 + 8005952: 041c lsls r4, r3, #16 + 8005954: 0c1b lsrs r3, r3, #16 + 8005956: 1900 adds r0, r0, r4 + 8005958: 415e adcs r6, r3 + 800595a: bc38 pop {r3, r4, r5} + 800595c: 181b adds r3, r3, r0 + 800595e: 4174 adcs r4, r6 + 8005960: 2000 movs r0, #0 + 8005962: 4145 adcs r5, r0 + 8005964: bc40 pop {r6} + 8005966: 3704 adds r7, #4 + 8005968: 4547 cmp r7, r8 + 800596a: dc01 bgt.n 8005970 + 800596c: 42b7 cmp r7, r6 + 800596e: ddde ble.n 800592e + 8005970: 9800 ldr r0, [sp, #0] + 8005972: 5183 str r3, [r0, r6] + 8005974: 4623 mov r3, r4 + 8005976: 462c mov r4, r5 + 8005978: 2500 movs r5, #0 + 800597a: 3604 adds r6, #4 + 800597c: 4546 cmp r6, r8 + 800597e: ddd1 ble.n 8005924 + 8005980: 454e cmp r6, r9 + 8005982: ddd1 ble.n 8005928 + 8005984: 5183 str r3, [r0, r6] + 8005986: bc01 pop {r0} + [r5] "=&l" (r5), [r6] "=&l" (r6), [r7] "=&l" (r7) + : [r0] "l" (result), [r1] "l" (left), [r2] "l" (right) + : "r8", "r9", "cc", "memory" + ); +#endif +} + 8005988: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + +0800598c : + +#if !asm_clear +uECC_VLI_API void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words) { + wordcount_t i; + for (i = 0; i < num_words; ++i) { + vli[i] = 0; + 800598c: ea21 71e1 bic.w r1, r1, r1, asr #31 + 8005990: 008a lsls r2, r1, #2 + 8005992: 2100 movs r1, #0 + 8005994: f007 bfc6 b.w 800d924 + +08005998 : +} +#endif /* !asm_clear */ + +/* Constant-time comparison to zero - secure way to compare long integers */ +/* Returns 1 if vli == 0, 0 otherwise. */ +uECC_VLI_API uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words) { + 8005998: b510 push {r4, lr} + uECC_word_t bits = 0; + wordcount_t i; + for (i = 0; i < num_words; ++i) { + 800599a: 2300 movs r3, #0 + uECC_word_t bits = 0; + 800599c: 461a mov r2, r3 + for (i = 0; i < num_words; ++i) { + 800599e: b25c sxtb r4, r3 + 80059a0: 42a1 cmp r1, r4 + 80059a2: dc03 bgt.n 80059ac + bits |= vli[i]; + } + return (bits == 0); +} + 80059a4: fab2 f082 clz r0, r2 + 80059a8: 0940 lsrs r0, r0, #5 + 80059aa: bd10 pop {r4, pc} + bits |= vli[i]; + 80059ac: f850 4023 ldr.w r4, [r0, r3, lsl #2] + 80059b0: 3301 adds r3, #1 + 80059b2: 4322 orrs r2, r4 + for (i = 0; i < num_words; ++i) { + 80059b4: e7f3 b.n 800599e + +080059b6 : + +/* Returns nonzero if bit 'bit' of vli is set. */ +uECC_VLI_API uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit) { + return (vli[bit >> uECC_WORD_BITS_SHIFT] & ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK))); + 80059b6: 114a asrs r2, r1, #5 + 80059b8: 2301 movs r3, #1 + 80059ba: f850 0022 ldr.w r0, [r0, r2, lsl #2] + 80059be: f001 011f and.w r1, r1, #31 + 80059c2: fa03 f101 lsl.w r1, r3, r1 +} + 80059c6: 4008 ands r0, r1 + 80059c8: 4770 bx lr + +080059ca : +/* Counts the number of words in vli. */ +static wordcount_t vli_numDigits(const uECC_word_t *vli, const wordcount_t max_words) { + wordcount_t i; + /* Search from the end until we find a non-zero digit. + We do it in reverse because we expect that most digits will be nonzero. */ + for (i = max_words - 1; i >= 0 && vli[i] == 0; --i) { + 80059ca: 3901 subs r1, #1 + + return (i + 1); +} + +/* Counts the number of bits required to represent vli. */ +uECC_VLI_API bitcount_t uECC_vli_numBits(const uECC_word_t *vli, const wordcount_t max_words) { + 80059cc: b510 push {r4, lr} + 80059ce: b249 sxtb r1, r1 + for (i = max_words - 1; i >= 0 && vli[i] == 0; --i) { + 80059d0: 1d04 adds r4, r0, #4 + 80059d2: 060a lsls r2, r1, #24 + 80059d4: b2cb uxtb r3, r1 + 80059d6: d404 bmi.n 80059e2 + 80059d8: 3901 subs r1, #1 + 80059da: f854 2021 ldr.w r2, [r4, r1, lsl #2] + 80059de: 2a00 cmp r2, #0 + 80059e0: d0f7 beq.n 80059d2 + return (i + 1); + 80059e2: 3301 adds r3, #1 + 80059e4: b25b sxtb r3, r3 + uECC_word_t i; + uECC_word_t digit; + + wordcount_t num_digits = vli_numDigits(vli, max_words); + if (num_digits == 0) { + 80059e6: b173 cbz r3, 8005a06 + return 0; + } + + digit = vli[num_digits - 1]; + 80059e8: f103 4280 add.w r2, r3, #1073741824 ; 0x40000000 + 80059ec: 3a01 subs r2, #1 + 80059ee: f850 2022 ldr.w r2, [r0, r2, lsl #2] + for (i = 0; digit; ++i) { + 80059f2: 2000 movs r0, #0 + 80059f4: b922 cbnz r2, 8005a00 + digit >>= 1; + } + + return (((bitcount_t)(num_digits - 1) << uECC_WORD_BITS_SHIFT) + i); + 80059f6: 3b01 subs r3, #1 + 80059f8: eb00 1343 add.w r3, r0, r3, lsl #5 + 80059fc: b218 sxth r0, r3 +} + 80059fe: bd10 pop {r4, pc} + digit >>= 1; + 8005a00: 0852 lsrs r2, r2, #1 + for (i = 0; digit; ++i) { + 8005a02: 3001 adds r0, #1 + 8005a04: e7f6 b.n 80059f4 + return 0; + 8005a06: 4618 mov r0, r3 + 8005a08: e7f9 b.n 80059fe + +08005a0a : + +/* Sets dest = src. */ +#if !asm_set +uECC_VLI_API void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src, wordcount_t num_words) { + 8005a0a: b510 push {r4, lr} + wordcount_t i; + for (i = 0; i < num_words; ++i) { + 8005a0c: 2300 movs r3, #0 + 8005a0e: b25c sxtb r4, r3 + 8005a10: 42a2 cmp r2, r4 + 8005a12: dc00 bgt.n 8005a16 + dest[i] = src[i]; + } +} + 8005a14: bd10 pop {r4, pc} + dest[i] = src[i]; + 8005a16: f851 4023 ldr.w r4, [r1, r3, lsl #2] + 8005a1a: f840 4023 str.w r4, [r0, r3, lsl #2] + for (i = 0; i < num_words; ++i) { + 8005a1e: 3301 adds r3, #1 + 8005a20: e7f5 b.n 8005a0e + +08005a22 : +#endif /* !asm_set */ + +/* Returns sign of left - right. */ +static cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left, + const uECC_word_t *right, + wordcount_t num_words) { + 8005a22: b510 push {r4, lr} + wordcount_t i; + for (i = num_words - 1; i >= 0; --i) { + 8005a24: 3a01 subs r2, #1 + 8005a26: b252 sxtb r2, r2 + 8005a28: 0613 lsls r3, r2, #24 + 8005a2a: d501 bpl.n 8005a30 + return 1; + } else if (left[i] < right[i]) { + return -1; + } + } + return 0; + 8005a2c: 2000 movs r0, #0 +} + 8005a2e: bd10 pop {r4, pc} + if (left[i] > right[i]) { + 8005a30: f850 4022 ldr.w r4, [r0, r2, lsl #2] + 8005a34: f851 3022 ldr.w r3, [r1, r2, lsl #2] + 8005a38: 429c cmp r4, r3 + 8005a3a: d805 bhi.n 8005a48 + } else if (left[i] < right[i]) { + 8005a3c: f102 32ff add.w r2, r2, #4294967295 ; 0xffffffff + 8005a40: d2f2 bcs.n 8005a28 + return -1; + 8005a42: f04f 30ff mov.w r0, #4294967295 ; 0xffffffff + 8005a46: e7f2 b.n 8005a2e + return 1; + 8005a48: 2001 movs r0, #1 + 8005a4a: e7f0 b.n 8005a2e + +08005a4c : +#if !asm_rshift1 +uECC_VLI_API void uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words) { + uECC_word_t *end = vli; + uECC_word_t carry = 0; + + vli += num_words; + 8005a4c: eb00 0181 add.w r1, r0, r1, lsl #2 + uECC_word_t carry = 0; + 8005a50: 2300 movs r3, #0 + while (vli-- > end) { + 8005a52: 4288 cmp r0, r1 + 8005a54: d300 bcc.n 8005a58 + uECC_word_t temp = *vli; + *vli = (temp >> 1) | carry; + carry = temp << (uECC_WORD_BITS - 1); + } +} + 8005a56: 4770 bx lr + uECC_word_t temp = *vli; + 8005a58: f851 2d04 ldr.w r2, [r1, #-4]! + *vli = (temp >> 1) | carry; + 8005a5c: ea43 0352 orr.w r3, r3, r2, lsr #1 + 8005a60: 600b str r3, [r1, #0] + carry = temp << (uECC_WORD_BITS - 1); + 8005a62: 07d3 lsls r3, r2, #31 + 8005a64: e7f5 b.n 8005a52 + +08005a66 : +/* Computes result = (left * right) % mod. */ +uECC_VLI_API void uECC_vli_modMult(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + const uECC_word_t *mod, + wordcount_t num_words) { + 8005a66: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + 8005a6a: b0b5 sub sp, #212 ; 0xd4 + 8005a6c: 461f mov r7, r3 + 8005a6e: f99d 50f8 ldrsb.w r5, [sp, #248] ; 0xf8 + 8005a72: 4680 mov r8, r0 + uECC_word_t product[2 * uECC_MAX_WORDS]; + uECC_vli_mult(product, left, right, num_words); + 8005a74: 462b mov r3, r5 + 8005a76: a804 add r0, sp, #16 + 8005a78: f7ff ff48 bl 800590c + uECC_word_t *v[2] = {tmp, product}; + 8005a7c: ab24 add r3, sp, #144 ; 0x90 + 8005a7e: e9cd 3002 strd r3, r0, [sp, #8] + bitcount_t shift = (num_words * 2 * uECC_WORD_BITS) - uECC_vli_numBits(mod, num_words); + 8005a82: 4629 mov r1, r5 + 8005a84: 4638 mov r0, r7 + 8005a86: f7ff ffa0 bl 80059ca + 8005a8a: ebc0 1085 rsb r0, r0, r5, lsl #6 + 8005a8e: b204 sxth r4, r0 + wordcount_t word_shift = shift / uECC_WORD_BITS; + 8005a90: 2c00 cmp r4, #0 + 8005a92: 4626 mov r6, r4 + 8005a94: bfb8 it lt + 8005a96: f104 061f addlt.w r6, r4, #31 + wordcount_t bit_shift = shift % uECC_WORD_BITS; + 8005a9a: 4263 negs r3, r4 + wordcount_t word_shift = shift / uECC_WORD_BITS; + 8005a9c: f346 1647 sbfx r6, r6, #5, #8 + wordcount_t bit_shift = shift % uECC_WORD_BITS; + 8005aa0: f003 031f and.w r3, r3, #31 + 8005aa4: f004 091f and.w r9, r4, #31 + uECC_vli_clear(mod_multiple, word_shift); + 8005aa8: 4631 mov r1, r6 + wordcount_t bit_shift = shift % uECC_WORD_BITS; + 8005aaa: bf58 it pl + 8005aac: f1c3 0900 rsbpl r9, r3, #0 + uECC_vli_clear(mod_multiple, word_shift); + 8005ab0: a814 add r0, sp, #80 ; 0x50 + 8005ab2: f7ff ff6b bl 800598c + if (bit_shift > 0) { + 8005ab6: f1b9 0f00 cmp.w r9, #0 + 8005aba: b236 sxth r6, r6 + 8005abc: dd2b ble.n 8005b16 + 8005abe: ab14 add r3, sp, #80 ; 0x50 + uECC_word_t carry = 0; + 8005ac0: 2200 movs r2, #0 + 8005ac2: eb03 0686 add.w r6, r3, r6, lsl #2 + carry = mod[index] >> (uECC_WORD_BITS - bit_shift); + 8005ac6: f1c9 0c20 rsb ip, r9, #32 + for(index = 0; index < (uECC_word_t)num_words; ++index) { + 8005aca: 4613 mov r3, r2 + 8005acc: 42ab cmp r3, r5 + 8005ace: d317 bcc.n 8005b00 + for (i = 0; i < num_words * 2; ++i) { + 8005ad0: 006b lsls r3, r5, #1 + 8005ad2: 9301 str r3, [sp, #4] + uECC_vli_rshift1(mod_multiple + num_words, num_words); + 8005ad4: ab14 add r3, sp, #80 ; 0x50 + 8005ad6: eb03 0985 add.w r9, r3, r5, lsl #2 + mod_multiple[num_words - 1] |= mod_multiple[num_words] << (uECC_WORD_BITS - 1); + 8005ada: 1e6f subs r7, r5, #1 + 8005adc: ab34 add r3, sp, #208 ; 0xd0 + uECC_vli_rshift1(mod_multiple + num_words, num_words); + 8005ade: 2601 movs r6, #1 + mod_multiple[num_words - 1] |= mod_multiple[num_words] << (uECC_WORD_BITS - 1); + 8005ae0: eb03 0787 add.w r7, r3, r7, lsl #2 + for (index = 1; shift >= 0; --shift) { + 8005ae4: 2c00 cmp r4, #0 + 8005ae6: da54 bge.n 8005b92 + uECC_vli_set(result, v[index], num_words); + 8005ae8: ab34 add r3, sp, #208 ; 0xd0 + 8005aea: eb03 0686 add.w r6, r3, r6, lsl #2 + 8005aee: 462a mov r2, r5 + 8005af0: f856 1cc8 ldr.w r1, [r6, #-200] + 8005af4: 4640 mov r0, r8 + 8005af6: f7ff ff88 bl 8005a0a + uECC_vli_mmod(result, product, mod, num_words); +} + 8005afa: b035 add sp, #212 ; 0xd4 + 8005afc: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + mod_multiple[word_shift + index] = (mod[index] << bit_shift) | carry; + 8005b00: f857 0023 ldr.w r0, [r7, r3, lsl #2] + 8005b04: fa00 f109 lsl.w r1, r0, r9 + 8005b08: 430a orrs r2, r1 + 8005b0a: f846 2b04 str.w r2, [r6], #4 + for(index = 0; index < (uECC_word_t)num_words; ++index) { + 8005b0e: 3301 adds r3, #1 + carry = mod[index] >> (uECC_WORD_BITS - bit_shift); + 8005b10: fa20 f20c lsr.w r2, r0, ip + for(index = 0; index < (uECC_word_t)num_words; ++index) { + 8005b14: e7da b.n 8005acc + uECC_vli_set(mod_multiple + word_shift, mod, num_words); + 8005b16: ab14 add r3, sp, #80 ; 0x50 + 8005b18: 462a mov r2, r5 + 8005b1a: 4639 mov r1, r7 + 8005b1c: eb03 0086 add.w r0, r3, r6, lsl #2 + 8005b20: f7ff ff73 bl 8005a0a + 8005b24: e7d4 b.n 8005ad0 + uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow; + 8005b26: fa0f fe82 sxth.w lr, r2 + 8005b2a: f85a 3cc8 ldr.w r3, [sl, #-200] + 8005b2e: f853 b02e ldr.w fp, [r3, lr, lsl #2] + 8005b32: ab34 add r3, sp, #208 ; 0xd0 + 8005b34: eb03 0282 add.w r2, r3, r2, lsl #2 + 8005b38: 3001 adds r0, #1 + 8005b3a: f852 3c80 ldr.w r3, [r2, #-128] + 8005b3e: 440b add r3, r1 + 8005b40: ebbb 0303 subs.w r3, fp, r3 + 8005b44: bf34 ite cc + 8005b46: 2201 movcc r2, #1 + 8005b48: 2200 movcs r2, #0 + if (diff != v[index][i]) { + 8005b4a: 459b cmp fp, r3 + borrow = (diff > v[index][i]); + 8005b4c: bf18 it ne + 8005b4e: 4611 movne r1, r2 + v[1 - index][i] = diff; + 8005b50: f85c 2cc8 ldr.w r2, [ip, #-200] + 8005b54: f842 302e str.w r3, [r2, lr, lsl #2] + for (i = 0; i < num_words * 2; ++i) { + 8005b58: 9b01 ldr r3, [sp, #4] + 8005b5a: b242 sxtb r2, r0 + 8005b5c: 429a cmp r2, r3 + 8005b5e: dbe2 blt.n 8005b26 + index = !(index ^ borrow); /* Swap the index if there was no borrow */ + 8005b60: 1a73 subs r3, r6, r1 + 8005b62: 425e negs r6, r3 + uECC_vli_rshift1(mod_multiple, num_words); + 8005b64: 4629 mov r1, r5 + 8005b66: a814 add r0, sp, #80 ; 0x50 + index = !(index ^ borrow); /* Swap the index if there was no borrow */ + 8005b68: 415e adcs r6, r3 + uECC_vli_rshift1(mod_multiple, num_words); + 8005b6a: f7ff ff6f bl 8005a4c + mod_multiple[num_words - 1] |= mod_multiple[num_words] << (uECC_WORD_BITS - 1); + 8005b6e: ab34 add r3, sp, #208 ; 0xd0 + 8005b70: eb03 0385 add.w r3, r3, r5, lsl #2 + uECC_vli_rshift1(mod_multiple + num_words, num_words); + 8005b74: 4629 mov r1, r5 + mod_multiple[num_words - 1] |= mod_multiple[num_words] << (uECC_WORD_BITS - 1); + 8005b76: f853 2c80 ldr.w r2, [r3, #-128] + 8005b7a: f857 3c80 ldr.w r3, [r7, #-128] + 8005b7e: ea43 73c2 orr.w r3, r3, r2, lsl #31 + 8005b82: f847 3c80 str.w r3, [r7, #-128] + uECC_vli_rshift1(mod_multiple + num_words, num_words); + 8005b86: 4648 mov r0, r9 + 8005b88: 3c01 subs r4, #1 + 8005b8a: f7ff ff5f bl 8005a4c + for (index = 1; shift >= 0; --shift) { + 8005b8e: b224 sxth r4, r4 + 8005b90: e7a8 b.n 8005ae4 + uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow; + 8005b92: ab34 add r3, sp, #208 ; 0xd0 + 8005b94: 2000 movs r0, #0 + v[1 - index][i] = diff; + 8005b96: f1c6 0c01 rsb ip, r6, #1 + uECC_word_t borrow = 0; + 8005b9a: 4601 mov r1, r0 + uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow; + 8005b9c: eb03 0a86 add.w sl, r3, r6, lsl #2 + v[1 - index][i] = diff; + 8005ba0: eb03 0c8c add.w ip, r3, ip, lsl #2 + 8005ba4: e7d8 b.n 8005b58 + +08005ba6 : + +uECC_VLI_API void uECC_vli_modMult_fast(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + uECC_Curve curve) { + 8005ba6: b530 push {r4, r5, lr} + 8005ba8: 461c mov r4, r3 + 8005baa: b091 sub sp, #68 ; 0x44 + 8005bac: 4605 mov r5, r0 + uECC_word_t product[2 * uECC_MAX_WORDS]; + uECC_vli_mult(product, left, right, curve->num_words); + 8005bae: f993 3000 ldrsb.w r3, [r3] + 8005bb2: 4668 mov r0, sp + 8005bb4: f7ff feaa bl 800590c +#if (uECC_OPTIMIZATION_LEVEL > 0) + curve->mmod_fast(result, product); + 8005bb8: 4601 mov r1, r0 + 8005bba: f8d4 30b0 ldr.w r3, [r4, #176] ; 0xb0 + 8005bbe: 4628 mov r0, r5 + 8005bc0: 4798 blx r3 +#else + uECC_vli_mmod(result, product, curve->p, curve->num_words); +#endif +} + 8005bc2: b011 add sp, #68 ; 0x44 + 8005bc4: bd30 pop {r4, r5, pc} + +08005bc6 : +} +#endif /* uECC_ENABLE_VLI_API */ + +uECC_VLI_API void uECC_vli_modSquare_fast(uECC_word_t *result, + const uECC_word_t *left, + uECC_Curve curve) { + 8005bc6: 4613 mov r3, r2 + uECC_vli_modMult_fast(result, left, left, curve); + 8005bc8: 460a mov r2, r1 + 8005bca: f7ff bfec b.w 8005ba6 + +08005bce : + +/* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */ +static void apply_z(uECC_word_t * X1, + uECC_word_t * Y1, + const uECC_word_t * const Z, + uECC_Curve curve) { + 8005bce: b570 push {r4, r5, r6, lr} + 8005bd0: 4614 mov r4, r2 + 8005bd2: b08a sub sp, #40 ; 0x28 + 8005bd4: 4606 mov r6, r0 + 8005bd6: 460d mov r5, r1 + uECC_word_t t1[uECC_MAX_WORDS]; + + uECC_vli_modSquare_fast(t1, Z, curve); /* z^2 */ + 8005bd8: 461a mov r2, r3 + 8005bda: 4621 mov r1, r4 + 8005bdc: a802 add r0, sp, #8 + 8005bde: 9301 str r3, [sp, #4] + 8005be0: f7ff fff1 bl 8005bc6 + uECC_vli_modMult_fast(X1, X1, t1, curve); /* x1 * z^2 */ + 8005be4: 9b01 ldr r3, [sp, #4] + 8005be6: aa02 add r2, sp, #8 + 8005be8: 4631 mov r1, r6 + 8005bea: 4630 mov r0, r6 + 8005bec: f7ff ffdb bl 8005ba6 + uECC_vli_modMult_fast(t1, t1, Z, curve); /* z^3 */ + 8005bf0: a902 add r1, sp, #8 + 8005bf2: 9b01 ldr r3, [sp, #4] + 8005bf4: 4622 mov r2, r4 + 8005bf6: 4608 mov r0, r1 + 8005bf8: f7ff ffd5 bl 8005ba6 + uECC_vli_modMult_fast(Y1, Y1, t1, curve); /* y1 * z^3 */ + 8005bfc: 9b01 ldr r3, [sp, #4] + 8005bfe: aa02 add r2, sp, #8 + 8005c00: 4629 mov r1, r5 + 8005c02: 4628 mov r0, r5 + 8005c04: f7ff ffcf bl 8005ba6 +} + 8005c08: b00a add sp, #40 ; 0x28 + 8005c0a: bd70 pop {r4, r5, r6, pc} + +08005c0c : + +#else + +uECC_VLI_API void uECC_vli_nativeToBytes(uint8_t *bytes, + int num_bytes, + const uECC_word_t *native) { + 8005c0c: b5f0 push {r4, r5, r6, r7, lr} + wordcount_t i; + for (i = 0; i < num_bytes; ++i) { + 8005c0e: 2500 movs r5, #0 + unsigned b = num_bytes - 1 - i; + 8005c10: 1e4f subs r7, r1, #1 + 8005c12: b26c sxtb r4, r5 + for (i = 0; i < num_bytes; ++i) { + 8005c14: 428c cmp r4, r1 + 8005c16: f105 0501 add.w r5, r5, #1 + 8005c1a: db00 blt.n 8005c1e + bytes[i] = native[b / uECC_WORD_SIZE] >> (8 * (b % uECC_WORD_SIZE)); + } +} + 8005c1c: bdf0 pop {r4, r5, r6, r7, pc} + unsigned b = num_bytes - 1 - i; + 8005c1e: 1b3b subs r3, r7, r4 + bytes[i] = native[b / uECC_WORD_SIZE] >> (8 * (b % uECC_WORD_SIZE)); + 8005c20: f023 0603 bic.w r6, r3, #3 + 8005c24: f003 0303 and.w r3, r3, #3 + 8005c28: 5996 ldr r6, [r2, r6] + 8005c2a: 00db lsls r3, r3, #3 + 8005c2c: fa26 f303 lsr.w r3, r6, r3 + 8005c30: 5503 strb r3, [r0, r4] + for (i = 0; i < num_bytes; ++i) { + 8005c32: e7ee b.n 8005c12 + +08005c34 : + +uECC_VLI_API void uECC_vli_bytesToNative(uECC_word_t *native, + const uint8_t *bytes, + int num_bytes) { + 8005c34: b5f8 push {r3, r4, r5, r6, r7, lr} + 8005c36: 460e mov r6, r1 + wordcount_t i; + uECC_vli_clear(native, (num_bytes + (uECC_WORD_SIZE - 1)) / uECC_WORD_SIZE); + 8005c38: 1cd1 adds r1, r2, #3 + 8005c3a: bf48 it mi + 8005c3c: 1d91 addmi r1, r2, #6 + int num_bytes) { + 8005c3e: 4614 mov r4, r2 + uECC_vli_clear(native, (num_bytes + (uECC_WORD_SIZE - 1)) / uECC_WORD_SIZE); + 8005c40: f341 0187 sbfx r1, r1, #2, #8 + int num_bytes) { + 8005c44: 4605 mov r5, r0 + for (i = 0; i < num_bytes; ++i) { + unsigned b = num_bytes - 1 - i; + 8005c46: 1e67 subs r7, r4, #1 + uECC_vli_clear(native, (num_bytes + (uECC_WORD_SIZE - 1)) / uECC_WORD_SIZE); + 8005c48: f7ff fea0 bl 800598c + for (i = 0; i < num_bytes; ++i) { + 8005c4c: 2000 movs r0, #0 + 8005c4e: b242 sxtb r2, r0 + 8005c50: 42a2 cmp r2, r4 + 8005c52: f100 0001 add.w r0, r0, #1 + 8005c56: db00 blt.n 8005c5a + native[b / uECC_WORD_SIZE] |= + (uECC_word_t)bytes[i] << (8 * (b % uECC_WORD_SIZE)); + } +} + 8005c58: bdf8 pop {r3, r4, r5, r6, r7, pc} + unsigned b = num_bytes - 1 - i; + 8005c5a: 1abb subs r3, r7, r2 + native[b / uECC_WORD_SIZE] |= + 8005c5c: f023 0103 bic.w r1, r3, #3 + (uECC_word_t)bytes[i] << (8 * (b % uECC_WORD_SIZE)); + 8005c60: 5cb2 ldrb r2, [r6, r2] + 8005c62: f003 0303 and.w r3, r3, #3 + 8005c66: 00db lsls r3, r3, #3 + 8005c68: fa02 f303 lsl.w r3, r2, r3 + native[b / uECC_WORD_SIZE] |= + 8005c6c: 586a ldr r2, [r5, r1] + 8005c6e: 431a orrs r2, r3 + 8005c70: 506a str r2, [r5, r1] + for (i = 0; i < num_bytes; ++i) { + 8005c72: e7ec b.n 8005c4e + +08005c74 : + return 0; +} + +/* Compute an HMAC using K as a key (as in RFC 6979). Note that K is always + the same size as the hash result size. */ +static void HMAC_init(uECC_HashContext *hash_context, const uint8_t *K) { + 8005c74: b570 push {r4, r5, r6, lr} + uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size; + 8005c76: e9d0 3504 ldrd r3, r5, [r0, #16] +static void HMAC_init(uECC_HashContext *hash_context, const uint8_t *K) { + 8005c7a: 4604 mov r4, r0 + uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size; + 8005c7c: eb05 0543 add.w r5, r5, r3, lsl #1 + unsigned i; + for (i = 0; i < hash_context->result_size; ++i) + 8005c80: 2300 movs r3, #0 + 8005c82: 6922 ldr r2, [r4, #16] + 8005c84: 429a cmp r2, r3 + 8005c86: d80d bhi.n 8005ca4 + pad[i] = K[i] ^ 0x36; + for (; i < hash_context->block_size; ++i) + pad[i] = 0x36; + 8005c88: 2136 movs r1, #54 ; 0x36 + for (; i < hash_context->block_size; ++i) + 8005c8a: 68e2 ldr r2, [r4, #12] + 8005c8c: 429a cmp r2, r3 + 8005c8e: d80f bhi.n 8005cb0 + + hash_context->init_hash(hash_context); + 8005c90: 6823 ldr r3, [r4, #0] + 8005c92: 4620 mov r0, r4 + 8005c94: 4798 blx r3 + hash_context->update_hash(hash_context, pad, hash_context->block_size); + 8005c96: 6863 ldr r3, [r4, #4] + 8005c98: 68e2 ldr r2, [r4, #12] + 8005c9a: 4629 mov r1, r5 + 8005c9c: 4620 mov r0, r4 +} + 8005c9e: e8bd 4070 ldmia.w sp!, {r4, r5, r6, lr} + hash_context->update_hash(hash_context, pad, hash_context->block_size); + 8005ca2: 4718 bx r3 + pad[i] = K[i] ^ 0x36; + 8005ca4: 5cca ldrb r2, [r1, r3] + 8005ca6: f082 0236 eor.w r2, r2, #54 ; 0x36 + 8005caa: 54ea strb r2, [r5, r3] + for (i = 0; i < hash_context->result_size; ++i) + 8005cac: 3301 adds r3, #1 + 8005cae: e7e8 b.n 8005c82 + pad[i] = 0x36; + 8005cb0: 54e9 strb r1, [r5, r3] + for (; i < hash_context->block_size; ++i) + 8005cb2: 3301 adds r3, #1 + 8005cb4: e7e9 b.n 8005c8a + +08005cb6 : + +static void HMAC_update(uECC_HashContext *hash_context, + const uint8_t *message, + unsigned message_size) { + hash_context->update_hash(hash_context, message, message_size); + 8005cb6: 6843 ldr r3, [r0, #4] + 8005cb8: 4718 bx r3 + +08005cba : +} + +static void HMAC_finish(uECC_HashContext *hash_context, const uint8_t *K, uint8_t *result) { + 8005cba: b570 push {r4, r5, r6, lr} + uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size; + 8005cbc: e9d0 3604 ldrd r3, r6, [r0, #16] +static void HMAC_finish(uECC_HashContext *hash_context, const uint8_t *K, uint8_t *result) { + 8005cc0: 4604 mov r4, r0 + uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size; + 8005cc2: eb06 0643 add.w r6, r6, r3, lsl #1 +static void HMAC_finish(uECC_HashContext *hash_context, const uint8_t *K, uint8_t *result) { + 8005cc6: 4615 mov r5, r2 + unsigned i; + for (i = 0; i < hash_context->result_size; ++i) + 8005cc8: 2300 movs r3, #0 + 8005cca: 6922 ldr r2, [r4, #16] + 8005ccc: 429a cmp r2, r3 + 8005cce: d81a bhi.n 8005d06 + pad[i] = K[i] ^ 0x5c; + for (; i < hash_context->block_size; ++i) + pad[i] = 0x5c; + 8005cd0: 215c movs r1, #92 ; 0x5c + for (; i < hash_context->block_size; ++i) + 8005cd2: 68e2 ldr r2, [r4, #12] + 8005cd4: 429a cmp r2, r3 + 8005cd6: d81c bhi.n 8005d12 + + hash_context->finish_hash(hash_context, result); + 8005cd8: 4629 mov r1, r5 + 8005cda: 68a3 ldr r3, [r4, #8] + 8005cdc: 4620 mov r0, r4 + 8005cde: 4798 blx r3 + + hash_context->init_hash(hash_context); + 8005ce0: 6823 ldr r3, [r4, #0] + 8005ce2: 4620 mov r0, r4 + 8005ce4: 4798 blx r3 + hash_context->update_hash(hash_context, pad, hash_context->block_size); + 8005ce6: 6863 ldr r3, [r4, #4] + 8005ce8: 68e2 ldr r2, [r4, #12] + 8005cea: 4631 mov r1, r6 + 8005cec: 4620 mov r0, r4 + 8005cee: 4798 blx r3 + hash_context->update_hash(hash_context, result, hash_context->result_size); + 8005cf0: 6863 ldr r3, [r4, #4] + 8005cf2: 6922 ldr r2, [r4, #16] + 8005cf4: 4629 mov r1, r5 + 8005cf6: 4620 mov r0, r4 + 8005cf8: 4798 blx r3 + hash_context->finish_hash(hash_context, result); + 8005cfa: 68a3 ldr r3, [r4, #8] + 8005cfc: 4629 mov r1, r5 + 8005cfe: 4620 mov r0, r4 +} + 8005d00: e8bd 4070 ldmia.w sp!, {r4, r5, r6, lr} + hash_context->finish_hash(hash_context, result); + 8005d04: 4718 bx r3 + pad[i] = K[i] ^ 0x5c; + 8005d06: 5cca ldrb r2, [r1, r3] + 8005d08: f082 025c eor.w r2, r2, #92 ; 0x5c + 8005d0c: 54f2 strb r2, [r6, r3] + for (i = 0; i < hash_context->result_size; ++i) + 8005d0e: 3301 adds r3, #1 + 8005d10: e7db b.n 8005cca + pad[i] = 0x5c; + 8005d12: 54f1 strb r1, [r6, r3] + for (; i < hash_context->block_size; ++i) + 8005d14: 3301 adds r3, #1 + 8005d16: e7dc b.n 8005cd2 + +08005d18 : + +/* V = HMAC_K(V) */ +static void update_V(uECC_HashContext *hash_context, uint8_t *K, uint8_t *V) { + 8005d18: b570 push {r4, r5, r6, lr} + 8005d1a: 4604 mov r4, r0 + 8005d1c: 4615 mov r5, r2 + 8005d1e: 460e mov r6, r1 + HMAC_init(hash_context, K); + 8005d20: f7ff ffa8 bl 8005c74 + HMAC_update(hash_context, V, hash_context->result_size); + 8005d24: 6922 ldr r2, [r4, #16] + 8005d26: 4629 mov r1, r5 + 8005d28: 4620 mov r0, r4 + 8005d2a: f7ff ffc4 bl 8005cb6 + HMAC_finish(hash_context, K, V); + 8005d2e: 462a mov r2, r5 + 8005d30: 4631 mov r1, r6 + 8005d32: 4620 mov r0, r4 +} + 8005d34: e8bd 4070 ldmia.w sp!, {r4, r5, r6, lr} + HMAC_finish(hash_context, K, V); + 8005d38: f7ff bfbf b.w 8005cba + +08005d3c : +uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result, + 8005d3c: b530 push {r4, r5, lr} + __asm__ volatile ( + 8005d3e: 2300 movs r3, #0 + 8005d40: c910 ldmia r1!, {r4} + 8005d42: ca20 ldmia r2!, {r5} + 8005d44: 1b64 subs r4, r4, r5 + 8005d46: c010 stmia r0!, {r4} + 8005d48: c910 ldmia r1!, {r4} + 8005d4a: ca20 ldmia r2!, {r5} + 8005d4c: 41ac sbcs r4, r5 + 8005d4e: c010 stmia r0!, {r4} + 8005d50: c910 ldmia r1!, {r4} + 8005d52: ca20 ldmia r2!, {r5} + 8005d54: 41ac sbcs r4, r5 + 8005d56: c010 stmia r0!, {r4} + 8005d58: c910 ldmia r1!, {r4} + 8005d5a: ca20 ldmia r2!, {r5} + 8005d5c: 41ac sbcs r4, r5 + 8005d5e: c010 stmia r0!, {r4} + 8005d60: c910 ldmia r1!, {r4} + 8005d62: ca20 ldmia r2!, {r5} + 8005d64: 41ac sbcs r4, r5 + 8005d66: c010 stmia r0!, {r4} + 8005d68: c910 ldmia r1!, {r4} + 8005d6a: ca20 ldmia r2!, {r5} + 8005d6c: 41ac sbcs r4, r5 + 8005d6e: c010 stmia r0!, {r4} + 8005d70: c910 ldmia r1!, {r4} + 8005d72: ca20 ldmia r2!, {r5} + 8005d74: 41ac sbcs r4, r5 + 8005d76: c010 stmia r0!, {r4} + 8005d78: c910 ldmia r1!, {r4} + 8005d7a: ca20 ldmia r2!, {r5} + 8005d7c: 41ac sbcs r4, r5 + 8005d7e: c010 stmia r0!, {r4} + 8005d80: 415b adcs r3, r3 +} + 8005d82: fab3 f083 clz r0, r3 + 8005d86: 0940 lsrs r0, r0, #5 + 8005d88: bd30 pop {r4, r5, pc} + +08005d8a : + uECC_Curve curve) { + 8005d8a: e92d 43f8 stmdb sp!, {r3, r4, r5, r6, r7, r8, r9, lr} + 8005d8e: 4698 mov r8, r3 + unsigned num_n_bytes = BITS_TO_BYTES(curve->num_n_bits); + 8005d90: f9b3 3002 ldrsh.w r3, [r3, #2] + unsigned num_n_words = BITS_TO_WORDS(curve->num_n_bits); + 8005d94: f113 041f adds.w r4, r3, #31 + 8005d98: bf48 it mi + 8005d9a: f103 043e addmi.w r4, r3, #62 ; 0x3e + unsigned num_n_bytes = BITS_TO_BYTES(curve->num_n_bits); + 8005d9e: 1ddd adds r5, r3, #7 + 8005da0: bf48 it mi + 8005da2: f103 050e addmi.w r5, r3, #14 + unsigned num_n_words = BITS_TO_WORDS(curve->num_n_bits); + 8005da6: 1166 asrs r6, r4, #5 + unsigned num_n_bytes = BITS_TO_BYTES(curve->num_n_bits); + 8005da8: 10ec asrs r4, r5, #3 + 8005daa: 4294 cmp r4, r2 + uECC_vli_clear(native, num_n_words); + 8005dac: b275 sxtb r5, r6 + 8005dae: bf28 it cs + 8005db0: 4614 movcs r4, r2 + uECC_Curve curve) { + 8005db2: 4607 mov r7, r0 + 8005db4: 4689 mov r9, r1 + uECC_vli_clear(native, num_n_words); + 8005db6: 4629 mov r1, r5 + 8005db8: f7ff fde8 bl 800598c + uECC_vli_bytesToNative(native, bits, bits_size); + 8005dbc: 4622 mov r2, r4 + 8005dbe: 4649 mov r1, r9 + 8005dc0: 4638 mov r0, r7 + 8005dc2: f7ff ff37 bl 8005c34 + if (bits_size * 8 <= (unsigned)curve->num_n_bits) { + 8005dc6: f9b8 2002 ldrsh.w r2, [r8, #2] + 8005dca: ebb2 0fc4 cmp.w r2, r4, lsl #3 + 8005dce: ea4f 03c4 mov.w r3, r4, lsl #3 + 8005dd2: d21f bcs.n 8005e14 + int shift = bits_size * 8 - curve->num_n_bits; + 8005dd4: 1a9b subs r3, r3, r2 + uECC_word_t *ptr = native + num_n_words; + 8005dd6: eb07 0486 add.w r4, r7, r6, lsl #2 + uECC_word_t carry = 0; + 8005dda: 2100 movs r1, #0 + carry = temp << (uECC_WORD_BITS - shift); + 8005ddc: f1c3 0620 rsb r6, r3, #32 + while (ptr-- > native) { + 8005de0: 42a7 cmp r7, r4 + 8005de2: d30e bcc.n 8005e02 + if (uECC_vli_cmp_unsafe(curve->n, native, num_n_words) != 1) { + 8005de4: f108 0824 add.w r8, r8, #36 ; 0x24 + 8005de8: 462a mov r2, r5 + 8005dea: 4639 mov r1, r7 + 8005dec: 4640 mov r0, r8 + 8005dee: f7ff fe18 bl 8005a22 + 8005df2: 2801 cmp r0, #1 + 8005df4: d00e beq.n 8005e14 + uECC_vli_sub(native, native, curve->n, num_n_words); + 8005df6: 4642 mov r2, r8 + 8005df8: 4638 mov r0, r7 +} + 8005dfa: e8bd 43f8 ldmia.w sp!, {r3, r4, r5, r6, r7, r8, r9, lr} + uECC_vli_sub(native, native, curve->n, num_n_words); + 8005dfe: f7ff bf9d b.w 8005d3c + uECC_word_t temp = *ptr; + 8005e02: f854 0d04 ldr.w r0, [r4, #-4]! + *ptr = (temp >> shift) | carry; + 8005e06: fa20 f203 lsr.w r2, r0, r3 + 8005e0a: 430a orrs r2, r1 + 8005e0c: 6022 str r2, [r4, #0] + carry = temp << (uECC_WORD_BITS - shift); + 8005e0e: fa00 f106 lsl.w r1, r0, r6 + 8005e12: e7e5 b.n 8005de0 +} + 8005e14: e8bd 83f8 ldmia.w sp!, {r3, r4, r5, r6, r7, r8, r9, pc} + +08005e18 : + wordcount_t num_words) { + 8005e18: b530 push {r4, r5, lr} + 8005e1a: b089 sub sp, #36 ; 0x24 + 8005e1c: 4615 mov r5, r2 + uECC_word_t neg = !!uECC_vli_sub(tmp, left, right, num_words); + 8005e1e: 460a mov r2, r1 + 8005e20: 4601 mov r1, r0 + 8005e22: 4668 mov r0, sp + 8005e24: f7ff ff8a bl 8005d3c + uECC_word_t equal = uECC_vli_isZero(tmp, num_words); + 8005e28: 4629 mov r1, r5 + uECC_word_t neg = !!uECC_vli_sub(tmp, left, right, num_words); + 8005e2a: 4604 mov r4, r0 + uECC_word_t equal = uECC_vli_isZero(tmp, num_words); + 8005e2c: 4668 mov r0, sp + 8005e2e: f7ff fdb3 bl 8005998 + uECC_word_t neg = !!uECC_vli_sub(tmp, left, right, num_words); + 8005e32: 3c00 subs r4, #0 + 8005e34: bf18 it ne + 8005e36: 2401 movne r4, #1 + return (!equal - 2 * neg); + 8005e38: 0064 lsls r4, r4, #1 +} + 8005e3a: 2800 cmp r0, #0 + 8005e3c: bf14 ite ne + 8005e3e: 4260 negne r0, r4 + 8005e40: f1c4 0001 rsbeq r0, r4, #1 + 8005e44: b009 add sp, #36 ; 0x24 + 8005e46: bd30 pop {r4, r5, pc} + +08005e48 : + wordcount_t num_words) { + 8005e48: e92d 4ff8 stmdb sp!, {r3, r4, r5, r6, r7, r8, r9, sl, fp, lr} + 8005e4c: 460f mov r7, r1 + if (!g_rng_function) { + 8005e4e: f8df a06c ldr.w sl, [pc, #108] ; 8005ebc + wordcount_t num_words) { + 8005e52: 4606 mov r6, r0 + bitcount_t num_bits = uECC_vli_numBits(top, num_words); + 8005e54: 4611 mov r1, r2 + 8005e56: 4638 mov r0, r7 + wordcount_t num_words) { + 8005e58: 4614 mov r4, r2 + bitcount_t num_bits = uECC_vli_numBits(top, num_words); + 8005e5a: f7ff fdb6 bl 80059ca + if (!g_rng_function) { + 8005e5e: f8da 3000 ldr.w r3, [sl] + 8005e62: b303 cbz r3, 8005ea6 + if (!g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE)) { + 8005e64: 2504 movs r5, #4 + random[num_words - 1] &= mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits)); + 8005e66: ebc0 1044 rsb r0, r0, r4, lsl #5 + if (!g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE)) { + 8005e6a: fb14 fb05 smulbb fp, r4, r5 + random[num_words - 1] &= mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits)); + 8005e6e: b200 sxth r0, r0 + 8005e70: fb05 6504 mla r5, r5, r4, r6 + 8005e74: f04f 38ff mov.w r8, #4294967295 ; 0xffffffff + 8005e78: 3d04 subs r5, #4 + 8005e7a: fa28 f800 lsr.w r8, r8, r0 + 8005e7e: f04f 0940 mov.w r9, #64 ; 0x40 + if (!g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE)) { + 8005e82: f8da 3000 ldr.w r3, [sl] + 8005e86: 4659 mov r1, fp + 8005e88: 4630 mov r0, r6 + 8005e8a: 4798 blx r3 + 8005e8c: b158 cbz r0, 8005ea6 + random[num_words - 1] &= mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits)); + 8005e8e: 682b ldr r3, [r5, #0] + 8005e90: ea03 0308 and.w r3, r3, r8 + 8005e94: 602b str r3, [r5, #0] + if (!uECC_vli_isZero(random, num_words) && + 8005e96: 4621 mov r1, r4 + 8005e98: 4630 mov r0, r6 + 8005e9a: f7ff fd7d bl 8005998 + 8005e9e: b120 cbz r0, 8005eaa + for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { + 8005ea0: f1b9 0901 subs.w r9, r9, #1 + 8005ea4: d1ed bne.n 8005e82 + return 0; + 8005ea6: 2000 movs r0, #0 + 8005ea8: e006 b.n 8005eb8 + uECC_vli_cmp(top, random, num_words) == 1) { + 8005eaa: 4622 mov r2, r4 + 8005eac: 4631 mov r1, r6 + 8005eae: 4638 mov r0, r7 + 8005eb0: f7ff ffb2 bl 8005e18 + if (!uECC_vli_isZero(random, num_words) && + 8005eb4: 2801 cmp r0, #1 + 8005eb6: d1f3 bne.n 8005ea0 +} + 8005eb8: e8bd 8ff8 ldmia.w sp!, {r3, r4, r5, r6, r7, r8, r9, sl, fp, pc} + 8005ebc: 2009e2a4 .word 0x2009e2a4 + +08005ec0 : +uECC_VLI_API uECC_word_t uECC_vli_add(uECC_word_t *result, + 8005ec0: b530 push {r4, r5, lr} + __asm__ volatile ( + 8005ec2: 4603 mov r3, r0 + 8005ec4: 2000 movs r0, #0 + 8005ec6: c910 ldmia r1!, {r4} + 8005ec8: ca20 ldmia r2!, {r5} + 8005eca: 1964 adds r4, r4, r5 + 8005ecc: c310 stmia r3!, {r4} + 8005ece: c910 ldmia r1!, {r4} + 8005ed0: ca20 ldmia r2!, {r5} + 8005ed2: 416c adcs r4, r5 + 8005ed4: c310 stmia r3!, {r4} + 8005ed6: c910 ldmia r1!, {r4} + 8005ed8: ca20 ldmia r2!, {r5} + 8005eda: 416c adcs r4, r5 + 8005edc: c310 stmia r3!, {r4} + 8005ede: c910 ldmia r1!, {r4} + 8005ee0: ca20 ldmia r2!, {r5} + 8005ee2: 416c adcs r4, r5 + 8005ee4: c310 stmia r3!, {r4} + 8005ee6: c910 ldmia r1!, {r4} + 8005ee8: ca20 ldmia r2!, {r5} + 8005eea: 416c adcs r4, r5 + 8005eec: c310 stmia r3!, {r4} + 8005eee: c910 ldmia r1!, {r4} + 8005ef0: ca20 ldmia r2!, {r5} + 8005ef2: 416c adcs r4, r5 + 8005ef4: c310 stmia r3!, {r4} + 8005ef6: c910 ldmia r1!, {r4} + 8005ef8: ca20 ldmia r2!, {r5} + 8005efa: 416c adcs r4, r5 + 8005efc: c310 stmia r3!, {r4} + 8005efe: c910 ldmia r1!, {r4} + 8005f00: ca20 ldmia r2!, {r5} + 8005f02: 416c adcs r4, r5 + 8005f04: c310 stmia r3!, {r4} + 8005f06: 4140 adcs r0, r0 +} + 8005f08: bd30 pop {r4, r5, pc} + +08005f0a : + uECC_Curve curve) { + 8005f0a: b573 push {r0, r1, r4, r5, r6, lr} + 8005f0c: 460d mov r5, r1 + 8005f0e: 4616 mov r6, r2 + uECC_word_t carry = uECC_vli_add(k0, k, curve->n, num_n_words) || + 8005f10: 4601 mov r1, r0 + 8005f12: f103 0224 add.w r2, r3, #36 ; 0x24 + 8005f16: 4628 mov r0, r5 + 8005f18: 9201 str r2, [sp, #4] + wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); + 8005f1a: f9b3 4002 ldrsh.w r4, [r3, #2] + uECC_word_t carry = uECC_vli_add(k0, k, curve->n, num_n_words) || + 8005f1e: f7ff ffcf bl 8005ec0 + 8005f22: 9a01 ldr r2, [sp, #4] + 8005f24: b9c8 cbnz r0, 8005f5a + wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); + 8005f26: f114 031f adds.w r3, r4, #31 + 8005f2a: bf48 it mi + 8005f2c: f104 033e addmi.w r3, r4, #62 ; 0x3e + (num_n_bits < ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8) && + 8005f30: f343 1347 sbfx r3, r3, #5, #8 + uECC_word_t carry = uECC_vli_add(k0, k, curve->n, num_n_words) || + 8005f34: ebb4 1f43 cmp.w r4, r3, lsl #5 + 8005f38: da11 bge.n 8005f5e + uECC_vli_testBit(k0, num_n_bits)); + 8005f3a: 4621 mov r1, r4 + 8005f3c: 4628 mov r0, r5 + 8005f3e: 9201 str r2, [sp, #4] + 8005f40: f7ff fd39 bl 80059b6 + 8005f44: 9a01 ldr r2, [sp, #4] + (num_n_bits < ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8) && + 8005f46: 1e04 subs r4, r0, #0 + 8005f48: bf18 it ne + 8005f4a: 2401 movne r4, #1 + uECC_vli_add(k1, k0, curve->n, num_n_words); + 8005f4c: 4629 mov r1, r5 + 8005f4e: 4630 mov r0, r6 + 8005f50: f7ff ffb6 bl 8005ec0 +} + 8005f54: 4620 mov r0, r4 + 8005f56: b002 add sp, #8 + 8005f58: bd70 pop {r4, r5, r6, pc} + uECC_word_t carry = uECC_vli_add(k0, k, curve->n, num_n_words) || + 8005f5a: 2401 movs r4, #1 + 8005f5c: e7f6 b.n 8005f4c + 8005f5e: 2400 movs r4, #0 + 8005f60: e7f4 b.n 8005f4c + +08005f62 : + /* add the 2^32 multiple */ + result[4 + num_words_secp256k1] = + uECC_vli_add(result + 4, result + 4, right, num_words_secp256k1); +} +#elif uECC_WORD_SIZE == 4 +static void omega_mult_secp256k1(uint32_t * result, const uint32_t * right) { + 8005f62: b5f8 push {r3, r4, r5, r6, r7, lr} + 8005f64: 460a mov r2, r1 + /* Multiply by (2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */ + uint32_t carry = 0; + 8005f66: 2300 movs r3, #0 +static void omega_mult_secp256k1(uint32_t * result, const uint32_t * right) { + 8005f68: 4604 mov r4, r0 + 8005f6a: 3904 subs r1, #4 + 8005f6c: 3804 subs r0, #4 + 8005f6e: f102 071c add.w r7, r2, #28 + wordcount_t k; + + for (k = 0; k < num_words_secp256k1; ++k) { + uint64_t p = (uint64_t)0x3D1 * right[k] + carry; + 8005f72: 469e mov lr, r3 + 8005f74: f240 35d1 movw r5, #977 ; 0x3d1 + 8005f78: f851 6f04 ldr.w r6, [r1, #4]! + 8005f7c: 46f4 mov ip, lr + 8005f7e: fbe6 3c05 umlal r3, ip, r6, r5 + for (k = 0; k < num_words_secp256k1; ++k) { + 8005f82: 428f cmp r7, r1 + result[k] = p; + 8005f84: f840 3f04 str.w r3, [r0, #4]! + carry = p >> 32; + 8005f88: 4663 mov r3, ip + for (k = 0; k < num_words_secp256k1; ++k) { + 8005f8a: d1f5 bne.n 8005f78 + } + result[num_words_secp256k1] = carry; + /* add the 2^32 multiple */ + result[1 + num_words_secp256k1] = + uECC_vli_add(result + 1, result + 1, right, num_words_secp256k1); + 8005f8c: 1d21 adds r1, r4, #4 + result[num_words_secp256k1] = carry; + 8005f8e: f8c4 c020 str.w ip, [r4, #32] + uECC_vli_add(result + 1, result + 1, right, num_words_secp256k1); + 8005f92: 4608 mov r0, r1 + 8005f94: f7ff ff94 bl 8005ec0 + result[1 + num_words_secp256k1] = + 8005f98: 6260 str r0, [r4, #36] ; 0x24 +} + 8005f9a: bdf8 pop {r3, r4, r5, r6, r7, pc} + +08005f9c : +static void vli_mmod_fast_secp256k1(uECC_word_t *result, uECC_word_t *product) { + 8005f9c: b570 push {r4, r5, r6, lr} + 8005f9e: b090 sub sp, #64 ; 0x40 + 8005fa0: 460e mov r6, r1 + 8005fa2: 4604 mov r4, r0 + uECC_vli_clear(tmp, num_words_secp256k1); + 8005fa4: 2108 movs r1, #8 + 8005fa6: 4668 mov r0, sp + 8005fa8: f7ff fcf0 bl 800598c + uECC_vli_clear(tmp + num_words_secp256k1, num_words_secp256k1); + 8005fac: 2108 movs r1, #8 + 8005fae: a808 add r0, sp, #32 + 8005fb0: f7ff fcec bl 800598c + omega_mult_secp256k1(tmp, product + num_words_secp256k1); /* (Rq, q) = q * c */ + 8005fb4: f106 0120 add.w r1, r6, #32 + 8005fb8: 4668 mov r0, sp + 8005fba: f7ff ffd2 bl 8005f62 + carry = uECC_vli_add(result, product, tmp, num_words_secp256k1); /* (C, r) = r + q */ + 8005fbe: 466a mov r2, sp + 8005fc0: 4631 mov r1, r6 + 8005fc2: 4620 mov r0, r4 + 8005fc4: f7ff ff7c bl 8005ec0 + uECC_vli_clear(product, num_words_secp256k1); + 8005fc8: 2108 movs r1, #8 + carry = uECC_vli_add(result, product, tmp, num_words_secp256k1); /* (C, r) = r + q */ + 8005fca: 4605 mov r5, r0 + uECC_vli_clear(product, num_words_secp256k1); + 8005fcc: 4630 mov r0, r6 + 8005fce: f7ff fcdd bl 800598c + omega_mult_secp256k1(product, tmp + num_words_secp256k1); /* Rq*c */ + 8005fd2: 4630 mov r0, r6 + 8005fd4: a908 add r1, sp, #32 + 8005fd6: f7ff ffc4 bl 8005f62 + carry += uECC_vli_add(result, result, product, num_words_secp256k1); /* (C1, r) = r + Rq*c */ + 8005fda: 4632 mov r2, r6 + 8005fdc: 4621 mov r1, r4 + 8005fde: 4620 mov r0, r4 + 8005fe0: f7ff ff6e bl 8005ec0 + uECC_vli_sub(result, result, curve_secp256k1.p, num_words_secp256k1); + 8005fe4: 4e0b ldr r6, [pc, #44] ; (8006014 ) + carry += uECC_vli_add(result, result, product, num_words_secp256k1); /* (C1, r) = r + Rq*c */ + 8005fe6: 4405 add r5, r0 + while (carry > 0) { + 8005fe8: b96d cbnz r5, 8006006 + if (uECC_vli_cmp_unsafe(result, curve_secp256k1.p, num_words_secp256k1) > 0) { + 8005fea: 490a ldr r1, [pc, #40] ; (8006014 ) + 8005fec: 2208 movs r2, #8 + 8005fee: 4620 mov r0, r4 + 8005ff0: f7ff fd17 bl 8005a22 + 8005ff4: 2800 cmp r0, #0 + 8005ff6: dd04 ble.n 8006002 + uECC_vli_sub(result, result, curve_secp256k1.p, num_words_secp256k1); + 8005ff8: 460a mov r2, r1 + 8005ffa: 4620 mov r0, r4 + 8005ffc: 4621 mov r1, r4 + 8005ffe: f7ff fe9d bl 8005d3c +} + 8006002: b010 add sp, #64 ; 0x40 + 8006004: bd70 pop {r4, r5, r6, pc} + uECC_vli_sub(result, result, curve_secp256k1.p, num_words_secp256k1); + 8006006: 4632 mov r2, r6 + 8006008: 4621 mov r1, r4 + 800600a: 4620 mov r0, r4 + --carry; + 800600c: 3d01 subs r5, #1 + uECC_vli_sub(result, result, curve_secp256k1.p, num_words_secp256k1); + 800600e: f7ff fe95 bl 8005d3c + 8006012: e7e9 b.n 8005fe8 + 8006014: 080108f4 .word 0x080108f4 + +08006018 : +static void vli_mmod_fast_secp256r1(uint32_t *result, uint32_t *product) { + 8006018: e92d 44f0 stmdb sp!, {r4, r5, r6, r7, sl, lr} + uECC_vli_set(result, product, num_words_secp256r1); + 800601c: 2208 movs r2, #8 +static void vli_mmod_fast_secp256r1(uint32_t *result, uint32_t *product) { + 800601e: b088 sub sp, #32 + uECC_vli_set(result, product, num_words_secp256r1); + 8006020: f7ff fcf3 bl 8005a0a + tmp[3] = product[11]; + 8006024: 6acb ldr r3, [r1, #44] ; 0x2c + 8006026: 9303 str r3, [sp, #12] + tmp[4] = product[12]; + 8006028: 6b0b ldr r3, [r1, #48] ; 0x30 + 800602a: 9304 str r3, [sp, #16] + tmp[5] = product[13]; + 800602c: 6b4b ldr r3, [r1, #52] ; 0x34 + 800602e: 9305 str r3, [sp, #20] + tmp[6] = product[14]; + 8006030: 6b8b ldr r3, [r1, #56] ; 0x38 + 8006032: 9306 str r3, [sp, #24] +static void vli_mmod_fast_secp256r1(uint32_t *result, uint32_t *product) { + 8006034: 460c mov r4, r1 + 8006036: 4682 mov sl, r0 + tmp[0] = tmp[1] = tmp[2] = 0; + 8006038: 2700 movs r7, #0 + tmp[7] = product[15]; + 800603a: 6bcb ldr r3, [r1, #60] ; 0x3c + 800603c: 9307 str r3, [sp, #28] + carry = uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); + 800603e: 466a mov r2, sp + 8006040: 4669 mov r1, sp + 8006042: 4668 mov r0, sp + tmp[0] = tmp[1] = tmp[2] = 0; + 8006044: e9cd 7701 strd r7, r7, [sp, #4] + 8006048: 9700 str r7, [sp, #0] + carry = uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); + 800604a: f7ff ff39 bl 8005ec0 + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + 800604e: 466a mov r2, sp + carry = uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); + 8006050: 4605 mov r5, r0 + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + 8006052: 4651 mov r1, sl + 8006054: 4650 mov r0, sl + 8006056: f7ff ff33 bl 8005ec0 + tmp[3] = product[12]; + 800605a: 6b23 ldr r3, [r4, #48] ; 0x30 + 800605c: 9303 str r3, [sp, #12] + tmp[4] = product[13]; + 800605e: 6b63 ldr r3, [r4, #52] ; 0x34 + 8006060: 9304 str r3, [sp, #16] + tmp[5] = product[14]; + 8006062: 6ba3 ldr r3, [r4, #56] ; 0x38 + 8006064: 9305 str r3, [sp, #20] + tmp[6] = product[15]; + 8006066: 6be3 ldr r3, [r4, #60] ; 0x3c + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + 8006068: 4405 add r5, r0 + carry += uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); + 800606a: 466a mov r2, sp + 800606c: 4669 mov r1, sp + 800606e: 4668 mov r0, sp + tmp[7] = 0; + 8006070: e9cd 3706 strd r3, r7, [sp, #24] + carry += uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); + 8006074: f7ff ff24 bl 8005ec0 + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + 8006078: 466a mov r2, sp + carry += uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); + 800607a: 4405 add r5, r0 + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + 800607c: 4651 mov r1, sl + 800607e: 4650 mov r0, sl + 8006080: f7ff ff1e bl 8005ec0 + tmp[0] = product[8]; + 8006084: 6a23 ldr r3, [r4, #32] + 8006086: 9300 str r3, [sp, #0] + tmp[1] = product[9]; + 8006088: 6a63 ldr r3, [r4, #36] ; 0x24 + 800608a: 9301 str r3, [sp, #4] + tmp[2] = product[10]; + 800608c: 6aa3 ldr r3, [r4, #40] ; 0x28 + 800608e: 9302 str r3, [sp, #8] + tmp[6] = product[14]; + 8006090: 6ba3 ldr r3, [r4, #56] ; 0x38 + 8006092: 9306 str r3, [sp, #24] + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + 8006094: 4405 add r5, r0 + tmp[7] = product[15]; + 8006096: 6be3 ldr r3, [r4, #60] ; 0x3c + 8006098: 9307 str r3, [sp, #28] + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + 800609a: 466a mov r2, sp + 800609c: 4651 mov r1, sl + 800609e: 4650 mov r0, sl + tmp[3] = tmp[4] = tmp[5] = 0; + 80060a0: e9cd 7704 strd r7, r7, [sp, #16] + 80060a4: 9703 str r7, [sp, #12] + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + 80060a6: f7ff ff0b bl 8005ec0 + tmp[0] = product[9]; + 80060aa: 6a63 ldr r3, [r4, #36] ; 0x24 + 80060ac: 9300 str r3, [sp, #0] + tmp[1] = product[10]; + 80060ae: 6aa3 ldr r3, [r4, #40] ; 0x28 + tmp[4] = product[14]; + 80060b0: 6ba2 ldr r2, [r4, #56] ; 0x38 + tmp[1] = product[10]; + 80060b2: 9301 str r3, [sp, #4] + tmp[2] = product[11]; + 80060b4: 6ae3 ldr r3, [r4, #44] ; 0x2c + 80060b6: 9302 str r3, [sp, #8] + tmp[4] = product[14]; + 80060b8: 9204 str r2, [sp, #16] + tmp[3] = product[13]; + 80060ba: 6b63 ldr r3, [r4, #52] ; 0x34 + tmp[5] = product[15]; + 80060bc: 6be2 ldr r2, [r4, #60] ; 0x3c + tmp[3] = product[13]; + 80060be: 9303 str r3, [sp, #12] + tmp[6] = product[13]; + 80060c0: e9cd 2305 strd r2, r3, [sp, #20] + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + 80060c4: 182e adds r6, r5, r0 + tmp[7] = product[8]; + 80060c6: 6a23 ldr r3, [r4, #32] + 80060c8: 9307 str r3, [sp, #28] + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + 80060ca: 466a mov r2, sp + 80060cc: 4651 mov r1, sl + 80060ce: 4650 mov r0, sl + 80060d0: f7ff fef6 bl 8005ec0 + tmp[0] = product[11]; + 80060d4: 6ae3 ldr r3, [r4, #44] ; 0x2c + 80060d6: 9300 str r3, [sp, #0] + tmp[1] = product[12]; + 80060d8: 6b23 ldr r3, [r4, #48] ; 0x30 + 80060da: 9301 str r3, [sp, #4] + tmp[2] = product[13]; + 80060dc: 6b63 ldr r3, [r4, #52] ; 0x34 + 80060de: 9302 str r3, [sp, #8] + tmp[6] = product[8]; + 80060e0: 6a23 ldr r3, [r4, #32] + 80060e2: 9306 str r3, [sp, #24] + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + 80060e4: 1835 adds r5, r6, r0 + tmp[7] = product[10]; + 80060e6: 6aa3 ldr r3, [r4, #40] ; 0x28 + 80060e8: 9307 str r3, [sp, #28] + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + 80060ea: 466a mov r2, sp + 80060ec: 4651 mov r1, sl + 80060ee: 4650 mov r0, sl + tmp[3] = tmp[4] = tmp[5] = 0; + 80060f0: e9cd 7704 strd r7, r7, [sp, #16] + 80060f4: 9703 str r7, [sp, #12] + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + 80060f6: f7ff fe21 bl 8005d3c + tmp[0] = product[12]; + 80060fa: 6b23 ldr r3, [r4, #48] ; 0x30 + 80060fc: 9300 str r3, [sp, #0] + tmp[1] = product[13]; + 80060fe: 6b63 ldr r3, [r4, #52] ; 0x34 + 8006100: 9301 str r3, [sp, #4] + tmp[2] = product[14]; + 8006102: 6ba3 ldr r3, [r4, #56] ; 0x38 + 8006104: 9302 str r3, [sp, #8] + tmp[3] = product[15]; + 8006106: 6be3 ldr r3, [r4, #60] ; 0x3c + 8006108: 9303 str r3, [sp, #12] + tmp[6] = product[9]; + 800610a: 6a63 ldr r3, [r4, #36] ; 0x24 + 800610c: 9306 str r3, [sp, #24] + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + 800610e: 1a2e subs r6, r5, r0 + tmp[7] = product[11]; + 8006110: 6ae3 ldr r3, [r4, #44] ; 0x2c + 8006112: 9307 str r3, [sp, #28] + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + 8006114: 466a mov r2, sp + 8006116: 4651 mov r1, sl + 8006118: 4650 mov r0, sl + tmp[4] = tmp[5] = 0; + 800611a: e9cd 7704 strd r7, r7, [sp, #16] + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + 800611e: f7ff fe0d bl 8005d3c + tmp[0] = product[13]; + 8006122: 6b63 ldr r3, [r4, #52] ; 0x34 + 8006124: 9300 str r3, [sp, #0] + tmp[1] = product[14]; + 8006126: 6ba3 ldr r3, [r4, #56] ; 0x38 + 8006128: 9301 str r3, [sp, #4] + tmp[2] = product[15]; + 800612a: 6be3 ldr r3, [r4, #60] ; 0x3c + 800612c: 9302 str r3, [sp, #8] + tmp[3] = product[8]; + 800612e: 6a23 ldr r3, [r4, #32] + 8006130: 9303 str r3, [sp, #12] + tmp[4] = product[9]; + 8006132: 6a63 ldr r3, [r4, #36] ; 0x24 + 8006134: 9304 str r3, [sp, #16] + tmp[5] = product[10]; + 8006136: 6aa3 ldr r3, [r4, #40] ; 0x28 + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + 8006138: 1a36 subs r6, r6, r0 + tmp[6] = 0; + 800613a: e9cd 3705 strd r3, r7, [sp, #20] + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + 800613e: 466a mov r2, sp + tmp[7] = product[12]; + 8006140: 6b23 ldr r3, [r4, #48] ; 0x30 + 8006142: 9307 str r3, [sp, #28] + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + 8006144: 4651 mov r1, sl + 8006146: 4650 mov r0, sl + 8006148: f7ff fdf8 bl 8005d3c + tmp[0] = product[14]; + 800614c: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800614e: 9300 str r3, [sp, #0] + tmp[1] = product[15]; + 8006150: 6be3 ldr r3, [r4, #60] ; 0x3c + tmp[2] = 0; + 8006152: e9cd 3701 strd r3, r7, [sp, #4] + tmp[3] = product[9]; + 8006156: 6a63 ldr r3, [r4, #36] ; 0x24 + 8006158: 9303 str r3, [sp, #12] + tmp[4] = product[10]; + 800615a: 6aa3 ldr r3, [r4, #40] ; 0x28 + 800615c: 9304 str r3, [sp, #16] + tmp[5] = product[11]; + 800615e: 6ae3 ldr r3, [r4, #44] ; 0x2c + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + 8006160: 1a36 subs r6, r6, r0 + tmp[6] = 0; + 8006162: e9cd 3705 strd r3, r7, [sp, #20] + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + 8006166: 466a mov r2, sp + tmp[7] = product[13]; + 8006168: 6b63 ldr r3, [r4, #52] ; 0x34 + 800616a: 9307 str r3, [sp, #28] + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + 800616c: 4651 mov r1, sl + 800616e: 4650 mov r0, sl + 8006170: f7ff fde4 bl 8005d3c + if (carry < 0) { + 8006174: 1a36 subs r6, r6, r0 + carry += uECC_vli_add(result, result, curve_secp256r1.p, num_words_secp256r1); + 8006176: 4c0d ldr r4, [pc, #52] ; (80061ac ) + if (carry < 0) { + 8006178: d40e bmi.n 8006198 + while (carry || uECC_vli_cmp_unsafe(curve_secp256r1.p, result, num_words_secp256r1) != 1) { + 800617a: b936 cbnz r6, 800618a + 800617c: 2208 movs r2, #8 + 800617e: 4651 mov r1, sl + 8006180: 4620 mov r0, r4 + 8006182: f7ff fc4e bl 8005a22 + 8006186: 2801 cmp r0, #1 + 8006188: d00d beq.n 80061a6 + carry -= uECC_vli_sub(result, result, curve_secp256r1.p, num_words_secp256r1); + 800618a: 4622 mov r2, r4 + 800618c: 4651 mov r1, sl + 800618e: 4650 mov r0, sl + 8006190: f7ff fdd4 bl 8005d3c + 8006194: 1a36 subs r6, r6, r0 + 8006196: e7f0 b.n 800617a + carry += uECC_vli_add(result, result, curve_secp256r1.p, num_words_secp256r1); + 8006198: 4622 mov r2, r4 + 800619a: 4651 mov r1, sl + 800619c: 4650 mov r0, sl + 800619e: f7ff fe8f bl 8005ec0 + } while (carry < 0); + 80061a2: 1836 adds r6, r6, r0 + 80061a4: d4f8 bmi.n 8006198 +} + 80061a6: b008 add sp, #32 + 80061a8: e8bd 84f0 ldmia.w sp!, {r4, r5, r6, r7, sl, pc} + 80061ac: 080109a8 .word 0x080109a8 + +080061b0 : +static void mod_sqrt_default(uECC_word_t *a, uECC_Curve curve) { + 80061b0: b5f0 push {r4, r5, r6, r7, lr} + 80061b2: b091 sub sp, #68 ; 0x44 + 80061b4: 460d mov r5, r1 + uECC_word_t p1[uECC_MAX_WORDS] = {1}; + 80061b6: 221c movs r2, #28 + 80061b8: 2100 movs r1, #0 +static void mod_sqrt_default(uECC_word_t *a, uECC_Curve curve) { + 80061ba: 4606 mov r6, r0 + uECC_word_t p1[uECC_MAX_WORDS] = {1}; + 80061bc: a801 add r0, sp, #4 + 80061be: f007 fbb1 bl 800d924 + 80061c2: 2401 movs r4, #1 + uECC_word_t l_result[uECC_MAX_WORDS] = {1}; + 80061c4: 221c movs r2, #28 + 80061c6: 2100 movs r1, #0 + 80061c8: a809 add r0, sp, #36 ; 0x24 + uECC_word_t p1[uECC_MAX_WORDS] = {1}; + 80061ca: 9400 str r4, [sp, #0] + uECC_word_t l_result[uECC_MAX_WORDS] = {1}; + 80061cc: f007 fbaa bl 800d924 + wordcount_t num_words = curve->num_words; + 80061d0: 4629 mov r1, r5 + uECC_vli_add(p1, curve->p, p1, num_words); /* p1 = curve_p + 1 */ + 80061d2: 466a mov r2, sp + wordcount_t num_words = curve->num_words; + 80061d4: f911 7b04 ldrsb.w r7, [r1], #4 + uECC_word_t l_result[uECC_MAX_WORDS] = {1}; + 80061d8: 9408 str r4, [sp, #32] + uECC_vli_add(p1, curve->p, p1, num_words); /* p1 = curve_p + 1 */ + 80061da: 4668 mov r0, sp + 80061dc: f7ff fe70 bl 8005ec0 + for (i = uECC_vli_numBits(p1, num_words) - 1; i > 1; --i) { + 80061e0: 4639 mov r1, r7 + 80061e2: 4668 mov r0, sp + 80061e4: f7ff fbf1 bl 80059ca + 80061e8: 1e44 subs r4, r0, #1 + 80061ea: b224 sxth r4, r4 + 80061ec: 2c01 cmp r4, #1 + 80061ee: dc06 bgt.n 80061fe + uECC_vli_set(a, l_result, num_words); + 80061f0: 463a mov r2, r7 + 80061f2: a908 add r1, sp, #32 + 80061f4: 4630 mov r0, r6 + 80061f6: f7ff fc08 bl 8005a0a +} + 80061fa: b011 add sp, #68 ; 0x44 + 80061fc: bdf0 pop {r4, r5, r6, r7, pc} + uECC_vli_modSquare_fast(l_result, l_result, curve); + 80061fe: a908 add r1, sp, #32 + 8006200: 4608 mov r0, r1 + 8006202: 462a mov r2, r5 + 8006204: f7ff fcdf bl 8005bc6 + if (uECC_vli_testBit(p1, i)) { + 8006208: 4621 mov r1, r4 + 800620a: 4668 mov r0, sp + 800620c: f7ff fbd3 bl 80059b6 + 8006210: b128 cbz r0, 800621e + uECC_vli_modMult_fast(l_result, l_result, a, curve); + 8006212: a908 add r1, sp, #32 + 8006214: 462b mov r3, r5 + 8006216: 4632 mov r2, r6 + 8006218: 4608 mov r0, r1 + 800621a: f7ff fcc4 bl 8005ba6 + for (i = uECC_vli_numBits(p1, num_words) - 1; i > 1; --i) { + 800621e: 3c01 subs r4, #1 + 8006220: e7e3 b.n 80061ea + +08006222 : + if (!EVEN(uv)) { + 8006222: 6803 ldr r3, [r0, #0] + wordcount_t num_words) { + 8006224: b570 push {r4, r5, r6, lr} + if (!EVEN(uv)) { + 8006226: f013 0601 ands.w r6, r3, #1 + wordcount_t num_words) { + 800622a: 4605 mov r5, r0 + 800622c: 4614 mov r4, r2 + if (!EVEN(uv)) { + 800622e: d004 beq.n 800623a + carry = uECC_vli_add(uv, uv, mod, num_words); + 8006230: 460a mov r2, r1 + 8006232: 4601 mov r1, r0 + 8006234: f7ff fe44 bl 8005ec0 + 8006238: 4606 mov r6, r0 + uECC_vli_rshift1(uv, num_words); + 800623a: 4621 mov r1, r4 + 800623c: 4628 mov r0, r5 + 800623e: f7ff fc05 bl 8005a4c + if (carry) { + 8006242: b146 cbz r6, 8006256 + uv[num_words - 1] |= HIGH_BIT_SET; + 8006244: f104 4280 add.w r2, r4, #1073741824 ; 0x40000000 + 8006248: 3a01 subs r2, #1 + 800624a: f855 3022 ldr.w r3, [r5, r2, lsl #2] + 800624e: f043 4300 orr.w r3, r3, #2147483648 ; 0x80000000 + 8006252: f845 3022 str.w r3, [r5, r2, lsl #2] +} + 8006256: bd70 pop {r4, r5, r6, pc} + +08006258 : + wordcount_t num_words) { + 8006258: b5f0 push {r4, r5, r6, r7, lr} + 800625a: 460f mov r7, r1 + 800625c: b0a1 sub sp, #132 ; 0x84 + 800625e: 4606 mov r6, r0 + if (uECC_vli_isZero(input, num_words)) { + 8006260: 4619 mov r1, r3 + 8006262: 4638 mov r0, r7 + wordcount_t num_words) { + 8006264: 4615 mov r5, r2 + 8006266: 461c mov r4, r3 + if (uECC_vli_isZero(input, num_words)) { + 8006268: f7ff fb96 bl 8005998 + 800626c: b128 cbz r0, 800627a + uECC_vli_clear(result, num_words); + 800626e: 4630 mov r0, r6 +} + 8006270: b021 add sp, #132 ; 0x84 + 8006272: e8bd 40f0 ldmia.w sp!, {r4, r5, r6, r7, lr} + uECC_vli_clear(result, num_words); + 8006276: f7ff bb89 b.w 800598c + uECC_vli_set(a, input, num_words); + 800627a: 4622 mov r2, r4 + 800627c: 4639 mov r1, r7 + 800627e: 4668 mov r0, sp + 8006280: f7ff fbc3 bl 8005a0a + uECC_vli_set(b, mod, num_words); + 8006284: 4629 mov r1, r5 + 8006286: a808 add r0, sp, #32 + 8006288: f7ff fbbf bl 8005a0a + uECC_vli_clear(u, num_words); + 800628c: 4621 mov r1, r4 + 800628e: a810 add r0, sp, #64 ; 0x40 + 8006290: f7ff fb7c bl 800598c + u[0] = 1; + 8006294: 2301 movs r3, #1 + uECC_vli_clear(v, num_words); + 8006296: 4621 mov r1, r4 + 8006298: a818 add r0, sp, #96 ; 0x60 + u[0] = 1; + 800629a: 9310 str r3, [sp, #64] ; 0x40 + uECC_vli_clear(v, num_words); + 800629c: f7ff fb76 bl 800598c + while ((cmpResult = uECC_vli_cmp_unsafe(a, b, num_words)) != 0) { + 80062a0: 4622 mov r2, r4 + 80062a2: a908 add r1, sp, #32 + 80062a4: 4668 mov r0, sp + 80062a6: f7ff fbbc bl 8005a22 + 80062aa: b930 cbnz r0, 80062ba + uECC_vli_set(result, u, num_words); + 80062ac: 4622 mov r2, r4 + 80062ae: a910 add r1, sp, #64 ; 0x40 + 80062b0: 4630 mov r0, r6 + 80062b2: f7ff fbaa bl 8005a0a +} + 80062b6: b021 add sp, #132 ; 0x84 + 80062b8: bdf0 pop {r4, r5, r6, r7, pc} + if (EVEN(a)) { + 80062ba: 9b00 ldr r3, [sp, #0] + 80062bc: 07da lsls r2, r3, #31 + 80062be: d409 bmi.n 80062d4 + uECC_vli_rshift1(a, num_words); + 80062c0: 4621 mov r1, r4 + 80062c2: 4668 mov r0, sp + 80062c4: f7ff fbc2 bl 8005a4c + vli_modInv_update(u, mod, num_words); + 80062c8: 4622 mov r2, r4 + 80062ca: 4629 mov r1, r5 + 80062cc: a810 add r0, sp, #64 ; 0x40 + vli_modInv_update(v, mod, num_words); + 80062ce: f7ff ffa8 bl 8006222 + 80062d2: e7e5 b.n 80062a0 + } else if (EVEN(b)) { + 80062d4: 9b08 ldr r3, [sp, #32] + 80062d6: 07db lsls r3, r3, #31 + 80062d8: d407 bmi.n 80062ea + uECC_vli_rshift1(b, num_words); + 80062da: 4621 mov r1, r4 + 80062dc: a808 add r0, sp, #32 + 80062de: f7ff fbb5 bl 8005a4c + vli_modInv_update(v, mod, num_words); + 80062e2: 4622 mov r2, r4 + 80062e4: 4629 mov r1, r5 + 80062e6: a818 add r0, sp, #96 ; 0x60 + 80062e8: e7f1 b.n 80062ce + } else if (cmpResult > 0) { + 80062ea: 2800 cmp r0, #0 + 80062ec: dd1a ble.n 8006324 + uECC_vli_sub(a, a, b, num_words); + 80062ee: aa08 add r2, sp, #32 + 80062f0: 4669 mov r1, sp + 80062f2: 4668 mov r0, sp + 80062f4: f7ff fd22 bl 8005d3c + uECC_vli_rshift1(a, num_words); + 80062f8: 4621 mov r1, r4 + 80062fa: 4668 mov r0, sp + 80062fc: f7ff fba6 bl 8005a4c + if (uECC_vli_cmp_unsafe(u, v, num_words) < 0) { + 8006300: 4622 mov r2, r4 + 8006302: a918 add r1, sp, #96 ; 0x60 + 8006304: a810 add r0, sp, #64 ; 0x40 + 8006306: f7ff fb8c bl 8005a22 + 800630a: 2800 cmp r0, #0 + 800630c: da04 bge.n 8006318 + uECC_vli_add(u, u, mod, num_words); + 800630e: a910 add r1, sp, #64 ; 0x40 + 8006310: 462a mov r2, r5 + 8006312: 4608 mov r0, r1 + 8006314: f7ff fdd4 bl 8005ec0 + uECC_vli_sub(u, u, v, num_words); + 8006318: a910 add r1, sp, #64 ; 0x40 + 800631a: aa18 add r2, sp, #96 ; 0x60 + 800631c: 4608 mov r0, r1 + 800631e: f7ff fd0d bl 8005d3c + 8006322: e7d1 b.n 80062c8 + uECC_vli_sub(b, b, a, num_words); + 8006324: 466a mov r2, sp + 8006326: a808 add r0, sp, #32 + 8006328: f7ff fd08 bl 8005d3c + uECC_vli_rshift1(b, num_words); + 800632c: 4621 mov r1, r4 + 800632e: a808 add r0, sp, #32 + 8006330: f7ff fb8c bl 8005a4c + if (uECC_vli_cmp_unsafe(v, u, num_words) < 0) { + 8006334: 4622 mov r2, r4 + 8006336: a910 add r1, sp, #64 ; 0x40 + 8006338: a818 add r0, sp, #96 ; 0x60 + 800633a: f7ff fb72 bl 8005a22 + 800633e: 2800 cmp r0, #0 + 8006340: da04 bge.n 800634c + uECC_vli_add(v, v, mod, num_words); + 8006342: a918 add r1, sp, #96 ; 0x60 + 8006344: 462a mov r2, r5 + 8006346: 4608 mov r0, r1 + 8006348: f7ff fdba bl 8005ec0 + uECC_vli_sub(v, v, u, num_words); + 800634c: a918 add r1, sp, #96 ; 0x60 + 800634e: aa10 add r2, sp, #64 ; 0x40 + 8006350: 4608 mov r0, r1 + 8006352: f7ff fcf3 bl 8005d3c + 8006356: e7c4 b.n 80062e2 + +08006358 : + wordcount_t num_words) { + 8006358: b570 push {r4, r5, r6, lr} + 800635a: 4604 mov r4, r0 + 800635c: f99d 6010 ldrsb.w r6, [sp, #16] + 8006360: 461d mov r5, r3 + uECC_word_t carry = uECC_vli_add(result, left, right, num_words); + 8006362: f7ff fdad bl 8005ec0 + if (carry || uECC_vli_cmp_unsafe(mod, result, num_words) != 1) { + 8006366: b930 cbnz r0, 8006376 + 8006368: 4632 mov r2, r6 + 800636a: 4621 mov r1, r4 + 800636c: 4628 mov r0, r5 + 800636e: f7ff fb58 bl 8005a22 + 8006372: 2801 cmp r0, #1 + 8006374: d006 beq.n 8006384 + uECC_vli_sub(result, result, mod, num_words); + 8006376: 462a mov r2, r5 + 8006378: 4621 mov r1, r4 + 800637a: 4620 mov r0, r4 +} + 800637c: e8bd 4070 ldmia.w sp!, {r4, r5, r6, lr} + uECC_vli_sub(result, result, mod, num_words); + 8006380: f7ff bcdc b.w 8005d3c +} + 8006384: bd70 pop {r4, r5, r6, pc} + +08006386 : +static void x_side_secp256k1(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve) { + 8006386: b573 push {r0, r1, r4, r5, r6, lr} + 8006388: 4604 mov r4, r0 + 800638a: 4615 mov r5, r2 + 800638c: 460e mov r6, r1 + uECC_vli_modSquare_fast(result, x, curve); /* r = x^2 */ + 800638e: f7ff fc1a bl 8005bc6 + uECC_vli_modMult_fast(result, result, x, curve); /* r = x^3 */ + 8006392: 462b mov r3, r5 + 8006394: 4632 mov r2, r6 + 8006396: 4621 mov r1, r4 + 8006398: 4620 mov r0, r4 + 800639a: f7ff fc04 bl 8005ba6 + uECC_vli_modAdd(result, result, curve->b, curve->p, num_words_secp256k1); /* r = x^3 + b */ + 800639e: 2308 movs r3, #8 + 80063a0: 9300 str r3, [sp, #0] + 80063a2: f105 0284 add.w r2, r5, #132 ; 0x84 + 80063a6: 1d2b adds r3, r5, #4 + 80063a8: 4621 mov r1, r4 + 80063aa: 4620 mov r0, r4 + 80063ac: f7ff ffd4 bl 8006358 +} + 80063b0: b002 add sp, #8 + 80063b2: bd70 pop {r4, r5, r6, pc} + +080063b4 : +uECC_VLI_API void uECC_vli_modSub(uECC_word_t *result, + 80063b4: b538 push {r3, r4, r5, lr} + 80063b6: 4604 mov r4, r0 + 80063b8: 461d mov r5, r3 + uECC_word_t l_borrow = uECC_vli_sub(result, left, right, num_words); + 80063ba: f7ff fcbf bl 8005d3c + if (l_borrow) { + 80063be: b130 cbz r0, 80063ce + uECC_vli_add(result, result, mod, num_words); + 80063c0: 462a mov r2, r5 + 80063c2: 4621 mov r1, r4 + 80063c4: 4620 mov r0, r4 +} + 80063c6: e8bd 4038 ldmia.w sp!, {r3, r4, r5, lr} + uECC_vli_add(result, result, mod, num_words); + 80063ca: f7ff bd79 b.w 8005ec0 +} + 80063ce: bd38 pop {r3, r4, r5, pc} + +080063d0 : + uECC_Curve curve) { + 80063d0: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + 80063d4: b09a sub sp, #104 ; 0x68 + 80063d6: 4615 mov r5, r2 + 80063d8: 9f22 ldr r7, [sp, #136] ; 0x88 + wordcount_t num_words = curve->num_words; + 80063da: 463c mov r4, r7 + uECC_Curve curve) { + 80063dc: 4698 mov r8, r3 + wordcount_t num_words = curve->num_words; + 80063de: f914 ab04 ldrsb.w sl, [r4], #4 + uECC_Curve curve) { + 80063e2: 4606 mov r6, r0 + 80063e4: 4689 mov r9, r1 + uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */ + 80063e6: 4623 mov r3, r4 + 80063e8: 4602 mov r2, r0 + 80063ea: 4629 mov r1, r5 + 80063ec: a802 add r0, sp, #8 + 80063ee: f7ff ffe1 bl 80063b4 + uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */ + 80063f2: a902 add r1, sp, #8 + 80063f4: 463a mov r2, r7 + 80063f6: 4608 mov r0, r1 + 80063f8: f7ff fbe5 bl 8005bc6 + uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */ + 80063fc: 463b mov r3, r7 + 80063fe: aa02 add r2, sp, #8 + 8006400: 4631 mov r1, r6 + 8006402: 4630 mov r0, r6 + 8006404: f7ff fbcf bl 8005ba6 + uECC_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */ + 8006408: 463b mov r3, r7 + 800640a: aa02 add r2, sp, #8 + 800640c: 4629 mov r1, r5 + 800640e: 4628 mov r0, r5 + 8006410: f7ff fbc9 bl 8005ba6 + uECC_vli_modAdd(t5, Y2, Y1, curve->p, num_words); /* t5 = y2 + y1 */ + 8006414: 4623 mov r3, r4 + 8006416: 464a mov r2, r9 + 8006418: 4641 mov r1, r8 + 800641a: a802 add r0, sp, #8 + 800641c: f8cd a000 str.w sl, [sp] + 8006420: f7ff ff9a bl 8006358 + uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */ + 8006424: 4623 mov r3, r4 + 8006426: 464a mov r2, r9 + 8006428: 4641 mov r1, r8 + 800642a: 4640 mov r0, r8 + 800642c: f7ff ffc2 bl 80063b4 + uECC_vli_modSub(t6, X2, X1, curve->p, num_words); /* t6 = C - B */ + 8006430: 4623 mov r3, r4 + 8006432: 4632 mov r2, r6 + 8006434: 4629 mov r1, r5 + 8006436: a80a add r0, sp, #40 ; 0x28 + 8006438: f7ff ffbc bl 80063b4 + uECC_vli_modMult_fast(Y1, Y1, t6, curve); /* t2 = y1 * (C - B) = E */ + 800643c: 463b mov r3, r7 + 800643e: aa0a add r2, sp, #40 ; 0x28 + 8006440: 4649 mov r1, r9 + 8006442: 4648 mov r0, r9 + 8006444: f7ff fbaf bl 8005ba6 + uECC_vli_modAdd(t6, X1, X2, curve->p, num_words); /* t6 = B + C */ + 8006448: 4623 mov r3, r4 + 800644a: 462a mov r2, r5 + 800644c: 4631 mov r1, r6 + 800644e: a80a add r0, sp, #40 ; 0x28 + 8006450: f8cd a000 str.w sl, [sp] + 8006454: f7ff ff80 bl 8006358 + uECC_vli_modSquare_fast(X2, Y2, curve); /* t3 = (y2 - y1)^2 = D */ + 8006458: 463a mov r2, r7 + 800645a: 4641 mov r1, r8 + 800645c: 4628 mov r0, r5 + 800645e: f7ff fbb2 bl 8005bc6 + uECC_vli_modSub(X2, X2, t6, curve->p, num_words); /* t3 = D - (B + C) = x3 */ + 8006462: 4623 mov r3, r4 + 8006464: aa0a add r2, sp, #40 ; 0x28 + 8006466: 4629 mov r1, r5 + 8006468: 4628 mov r0, r5 + 800646a: f7ff ffa3 bl 80063b4 + uECC_vli_modSub(t7, X1, X2, curve->p, num_words); /* t7 = B - x3 */ + 800646e: 4623 mov r3, r4 + 8006470: 462a mov r2, r5 + 8006472: 4631 mov r1, r6 + 8006474: a812 add r0, sp, #72 ; 0x48 + 8006476: f7ff ff9d bl 80063b4 + uECC_vli_modMult_fast(Y2, Y2, t7, curve); /* t4 = (y2 - y1)*(B - x3) */ + 800647a: 463b mov r3, r7 + 800647c: aa12 add r2, sp, #72 ; 0x48 + 800647e: 4641 mov r1, r8 + 8006480: 4640 mov r0, r8 + 8006482: f7ff fb90 bl 8005ba6 + uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = (y2 - y1)*(B - x3) - E = y3 */ + 8006486: 4623 mov r3, r4 + 8006488: 464a mov r2, r9 + 800648a: 4641 mov r1, r8 + 800648c: 4640 mov r0, r8 + 800648e: f7ff ff91 bl 80063b4 + uECC_vli_modSquare_fast(t7, t5, curve); /* t7 = (y2 + y1)^2 = F */ + 8006492: 463a mov r2, r7 + 8006494: a902 add r1, sp, #8 + 8006496: a812 add r0, sp, #72 ; 0x48 + 8006498: f7ff fb95 bl 8005bc6 + uECC_vli_modSub(t7, t7, t6, curve->p, num_words); /* t7 = F - (B + C) = x3' */ + 800649c: a912 add r1, sp, #72 ; 0x48 + 800649e: 4623 mov r3, r4 + 80064a0: aa0a add r2, sp, #40 ; 0x28 + 80064a2: 4608 mov r0, r1 + 80064a4: f7ff ff86 bl 80063b4 + uECC_vli_modSub(t6, t7, X1, curve->p, num_words); /* t6 = x3' - B */ + 80064a8: 4623 mov r3, r4 + 80064aa: 4632 mov r2, r6 + 80064ac: a912 add r1, sp, #72 ; 0x48 + 80064ae: a80a add r0, sp, #40 ; 0x28 + 80064b0: f7ff ff80 bl 80063b4 + uECC_vli_modMult_fast(t6, t6, t5, curve); /* t6 = (y2+y1)*(x3' - B) */ + 80064b4: a90a add r1, sp, #40 ; 0x28 + 80064b6: 463b mov r3, r7 + 80064b8: aa02 add r2, sp, #8 + 80064ba: 4608 mov r0, r1 + 80064bc: f7ff fb73 bl 8005ba6 + uECC_vli_modSub(Y1, t6, Y1, curve->p, num_words); /* t2 = (y2+y1)*(x3' - B) - E = y3' */ + 80064c0: 4623 mov r3, r4 + 80064c2: 464a mov r2, r9 + 80064c4: a90a add r1, sp, #40 ; 0x28 + 80064c6: 4648 mov r0, r9 + 80064c8: f7ff ff74 bl 80063b4 + uECC_vli_set(X1, t7, num_words); + 80064cc: 4652 mov r2, sl + 80064ce: a912 add r1, sp, #72 ; 0x48 + 80064d0: 4630 mov r0, r6 + 80064d2: f7ff fa9a bl 8005a0a +} + 80064d6: b01a add sp, #104 ; 0x68 + 80064d8: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + +080064dc : + uECC_Curve curve) { + 80064dc: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + 80064e0: b088 sub sp, #32 + 80064e2: 4614 mov r4, r2 + 80064e4: f8dd 8040 ldr.w r8, [sp, #64] ; 0x40 + wordcount_t num_words = curve->num_words; + 80064e8: 4645 mov r5, r8 + uECC_Curve curve) { + 80064ea: 461e mov r6, r3 + wordcount_t num_words = curve->num_words; + 80064ec: f915 ab04 ldrsb.w sl, [r5], #4 + uECC_Curve curve) { + 80064f0: 4607 mov r7, r0 + 80064f2: 4689 mov r9, r1 + uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */ + 80064f4: 462b mov r3, r5 + 80064f6: 4602 mov r2, r0 + 80064f8: 4621 mov r1, r4 + 80064fa: 4668 mov r0, sp + 80064fc: f7ff ff5a bl 80063b4 + uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */ + 8006500: 4642 mov r2, r8 + 8006502: 4669 mov r1, sp + 8006504: 4668 mov r0, sp + 8006506: f7ff fb5e bl 8005bc6 + uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */ + 800650a: 4643 mov r3, r8 + 800650c: 466a mov r2, sp + 800650e: 4639 mov r1, r7 + 8006510: 4638 mov r0, r7 + 8006512: f7ff fb48 bl 8005ba6 + uECC_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */ + 8006516: 4643 mov r3, r8 + 8006518: 466a mov r2, sp + 800651a: 4621 mov r1, r4 + 800651c: 4620 mov r0, r4 + 800651e: f7ff fb42 bl 8005ba6 + uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */ + 8006522: 462b mov r3, r5 + 8006524: 464a mov r2, r9 + 8006526: 4631 mov r1, r6 + 8006528: 4630 mov r0, r6 + 800652a: f7ff ff43 bl 80063b4 + uECC_vli_modSquare_fast(t5, Y2, curve); /* t5 = (y2 - y1)^2 = D */ + 800652e: 4642 mov r2, r8 + 8006530: 4631 mov r1, r6 + 8006532: 4668 mov r0, sp + 8006534: f7ff fb47 bl 8005bc6 + uECC_vli_modSub(t5, t5, X1, curve->p, num_words); /* t5 = D - B */ + 8006538: 462b mov r3, r5 + 800653a: 463a mov r2, r7 + 800653c: 4669 mov r1, sp + 800653e: 4668 mov r0, sp + 8006540: f7ff ff38 bl 80063b4 + uECC_vli_modSub(t5, t5, X2, curve->p, num_words); /* t5 = D - B - C = x3 */ + 8006544: 462b mov r3, r5 + 8006546: 4622 mov r2, r4 + 8006548: 4669 mov r1, sp + 800654a: 4668 mov r0, sp + 800654c: f7ff ff32 bl 80063b4 + uECC_vli_modSub(X2, X2, X1, curve->p, num_words); /* t3 = C - B */ + 8006550: 462b mov r3, r5 + 8006552: 463a mov r2, r7 + 8006554: 4621 mov r1, r4 + 8006556: 4620 mov r0, r4 + 8006558: f7ff ff2c bl 80063b4 + uECC_vli_modMult_fast(Y1, Y1, X2, curve); /* t2 = y1*(C - B) */ + 800655c: 4643 mov r3, r8 + 800655e: 4622 mov r2, r4 + 8006560: 4649 mov r1, r9 + 8006562: 4648 mov r0, r9 + 8006564: f7ff fb1f bl 8005ba6 + uECC_vli_modSub(X2, X1, t5, curve->p, num_words); /* t3 = B - x3 */ + 8006568: 462b mov r3, r5 + 800656a: 466a mov r2, sp + 800656c: 4639 mov r1, r7 + 800656e: 4620 mov r0, r4 + 8006570: f7ff ff20 bl 80063b4 + uECC_vli_modMult_fast(Y2, Y2, X2, curve); /* t4 = (y2 - y1)*(B - x3) */ + 8006574: 4643 mov r3, r8 + 8006576: 4622 mov r2, r4 + 8006578: 4631 mov r1, r6 + 800657a: 4630 mov r0, r6 + 800657c: f7ff fb13 bl 8005ba6 + uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y3 */ + 8006580: 462b mov r3, r5 + 8006582: 464a mov r2, r9 + 8006584: 4631 mov r1, r6 + 8006586: 4630 mov r0, r6 + 8006588: f7ff ff14 bl 80063b4 + uECC_vli_set(X2, t5, num_words); + 800658c: 4652 mov r2, sl + 800658e: 4669 mov r1, sp + 8006590: 4620 mov r0, r4 + 8006592: f7ff fa3a bl 8005a0a +} + 8006596: b008 add sp, #32 + 8006598: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + +0800659c : + uECC_Curve curve) { + 800659c: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + 80065a0: b0b1 sub sp, #196 ; 0xc4 + 80065a2: e9cd 0102 strd r0, r1, [sp, #8] + 80065a6: 9c3b ldr r4, [sp, #236] ; 0xec + 80065a8: 9204 str r2, [sp, #16] + wordcount_t num_words = curve->num_words; + 80065aa: f994 9000 ldrsb.w r9, [r4] + uECC_vli_set(Rx[1], point, num_words); + 80065ae: a818 add r0, sp, #96 ; 0x60 + 80065b0: 464a mov r2, r9 + uECC_Curve curve) { + 80065b2: 461d mov r5, r3 + uECC_vli_set(Rx[1], point, num_words); + 80065b4: f7ff fa29 bl 8005a0a + uECC_vli_set(Ry[1], point + num_words, num_words); + 80065b8: ea4f 0389 mov.w r3, r9, lsl #2 + 80065bc: 9305 str r3, [sp, #20] + 80065be: 9b03 ldr r3, [sp, #12] + 80065c0: eb03 0a89 add.w sl, r3, r9, lsl #2 + 80065c4: 4651 mov r1, sl + 80065c6: a828 add r0, sp, #160 ; 0xa0 + 80065c8: f7ff fa1f bl 8005a0a + wordcount_t num_words = curve->num_words; + 80065cc: f994 2000 ldrsb.w r2, [r4] + if (initial_Z) { + 80065d0: 2d00 cmp r5, #0 + 80065d2: f000 8082 beq.w 80066da + uECC_vli_set(z, initial_Z, num_words); + 80065d6: 4629 mov r1, r5 + 80065d8: a808 add r0, sp, #32 + 80065da: f7ff fa16 bl 8005a0a + uECC_vli_set(X2, X1, num_words); + 80065de: af10 add r7, sp, #64 ; 0x40 + 80065e0: a918 add r1, sp, #96 ; 0x60 + 80065e2: 4638 mov r0, r7 + uECC_vli_set(Y2, Y1, num_words); + 80065e4: f10d 0880 add.w r8, sp, #128 ; 0x80 + uECC_vli_set(X2, X1, num_words); + 80065e8: f7ff fa0f bl 8005a0a + uECC_vli_set(Y2, Y1, num_words); + 80065ec: a928 add r1, sp, #160 ; 0xa0 + 80065ee: 4640 mov r0, r8 + 80065f0: f7ff fa0b bl 8005a0a + apply_z(X1, Y1, z, curve); + 80065f4: 4623 mov r3, r4 + 80065f6: aa08 add r2, sp, #32 + 80065f8: a818 add r0, sp, #96 ; 0x60 + 80065fa: f7ff fae8 bl 8005bce + curve->double_jacobian(X1, Y1, z, curve); + 80065fe: f8d4 50a4 ldr.w r5, [r4, #164] ; 0xa4 + 8006602: 4623 mov r3, r4 + 8006604: aa08 add r2, sp, #32 + 8006606: a928 add r1, sp, #160 ; 0xa0 + 8006608: a818 add r0, sp, #96 ; 0x60 + 800660a: 47a8 blx r5 + apply_z(X2, Y2, z, curve); + 800660c: 4623 mov r3, r4 + 800660e: aa08 add r2, sp, #32 + 8006610: 4641 mov r1, r8 + 8006612: 4638 mov r0, r7 + 8006614: f7ff fadb bl 8005bce + for (i = num_bits - 2; i > 0; --i) { + 8006618: f9bd 50e8 ldrsh.w r5, [sp, #232] ; 0xe8 + 800661c: 3d02 subs r5, #2 + 800661e: b22d sxth r5, r5 + 8006620: 2d00 cmp r5, #0 + 8006622: dc63 bgt.n 80066ec + return (vli[bit >> uECC_WORD_BITS_SHIFT] & ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK))); + 8006624: 9b04 ldr r3, [sp, #16] + 8006626: 681d ldr r5, [r3, #0] + XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve); + 8006628: 9400 str r4, [sp, #0] + return (vli[bit >> uECC_WORD_BITS_SHIFT] & ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK))); + 800662a: f005 0601 and.w r6, r5, #1 + XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve); + 800662e: ab10 add r3, sp, #64 ; 0x40 + 8006630: eb03 1746 add.w r7, r3, r6, lsl #5 + 8006634: 43ed mvns r5, r5 + 8006636: ab20 add r3, sp, #128 ; 0x80 + 8006638: eb03 1646 add.w r6, r3, r6, lsl #5 + 800663c: f005 0501 and.w r5, r5, #1 + 8006640: ab10 add r3, sp, #64 ; 0x40 + 8006642: eb03 1845 add.w r8, r3, r5, lsl #5 + 8006646: ab20 add r3, sp, #128 ; 0x80 + 8006648: eb03 1545 add.w r5, r3, r5, lsl #5 + 800664c: 462b mov r3, r5 + 800664e: 4642 mov r2, r8 + 8006650: 4631 mov r1, r6 + 8006652: 4638 mov r0, r7 + uECC_vli_modSub(z, Rx[1], Rx[0], curve->p, num_words); /* X1 - X0 */ + 8006654: f104 0b04 add.w fp, r4, #4 + XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve); + 8006658: f7ff feba bl 80063d0 + uECC_vli_modSub(z, Rx[1], Rx[0], curve->p, num_words); /* X1 - X0 */ + 800665c: 465b mov r3, fp + 800665e: aa10 add r2, sp, #64 ; 0x40 + 8006660: a918 add r1, sp, #96 ; 0x60 + 8006662: a808 add r0, sp, #32 + 8006664: f7ff fea6 bl 80063b4 + uECC_vli_modMult_fast(z, z, Ry[1 - nb], curve); /* Yb * (X1 - X0) */ + 8006668: a908 add r1, sp, #32 + 800666a: 4623 mov r3, r4 + 800666c: 4632 mov r2, r6 + 800666e: 4608 mov r0, r1 + 8006670: f7ff fa99 bl 8005ba6 + uECC_vli_modMult_fast(z, z, point, curve); /* xP * Yb * (X1 - X0) */ + 8006674: a908 add r1, sp, #32 + 8006676: 9a03 ldr r2, [sp, #12] + 8006678: 4623 mov r3, r4 + 800667a: 4608 mov r0, r1 + 800667c: f7ff fa93 bl 8005ba6 + uECC_vli_modInv(z, z, curve->p, num_words); /* 1 / (xP * Yb * (X1 - X0)) */ + 8006680: a908 add r1, sp, #32 + 8006682: 464b mov r3, r9 + 8006684: 465a mov r2, fp + 8006686: 4608 mov r0, r1 + 8006688: f7ff fde6 bl 8006258 + uECC_vli_modMult_fast(z, z, point + num_words, curve); + 800668c: a908 add r1, sp, #32 + 800668e: 4623 mov r3, r4 + 8006690: 4652 mov r2, sl + 8006692: 4608 mov r0, r1 + 8006694: f7ff fa87 bl 8005ba6 + uECC_vli_modMult_fast(z, z, Rx[1 - nb], curve); /* Xb * yP / (xP * Yb * (X1 - X0)) */ + 8006698: a908 add r1, sp, #32 + 800669a: 4623 mov r3, r4 + 800669c: 463a mov r2, r7 + 800669e: 4608 mov r0, r1 + 80066a0: f7ff fa81 bl 8005ba6 + XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve); + 80066a4: 4633 mov r3, r6 + 80066a6: 463a mov r2, r7 + 80066a8: 4629 mov r1, r5 + 80066aa: 4640 mov r0, r8 + 80066ac: 9400 str r4, [sp, #0] + 80066ae: f7ff ff15 bl 80064dc + apply_z(Rx[0], Ry[0], z, curve); + 80066b2: 4623 mov r3, r4 + 80066b4: aa08 add r2, sp, #32 + 80066b6: a920 add r1, sp, #128 ; 0x80 + 80066b8: a810 add r0, sp, #64 ; 0x40 + 80066ba: f7ff fa88 bl 8005bce + uECC_vli_set(result, Rx[0], num_words); + 80066be: 9802 ldr r0, [sp, #8] + 80066c0: 464a mov r2, r9 + 80066c2: a910 add r1, sp, #64 ; 0x40 + 80066c4: f7ff f9a1 bl 8005a0a + uECC_vli_set(result + num_words, Ry[0], num_words); + 80066c8: 9802 ldr r0, [sp, #8] + 80066ca: 9b05 ldr r3, [sp, #20] + 80066cc: a920 add r1, sp, #128 ; 0x80 + 80066ce: 4418 add r0, r3 + 80066d0: f7ff f99b bl 8005a0a +} + 80066d4: b031 add sp, #196 ; 0xc4 + 80066d6: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + uECC_vli_clear(z, num_words); + 80066da: 4611 mov r1, r2 + 80066dc: a808 add r0, sp, #32 + 80066de: 9206 str r2, [sp, #24] + 80066e0: f7ff f954 bl 800598c + z[0] = 1; + 80066e4: 2301 movs r3, #1 + 80066e6: 9a06 ldr r2, [sp, #24] + 80066e8: 9308 str r3, [sp, #32] + 80066ea: e778 b.n 80065de + nb = !uECC_vli_testBit(scalar, i); + 80066ec: 4629 mov r1, r5 + 80066ee: 9804 ldr r0, [sp, #16] + 80066f0: f7ff f961 bl 80059b6 + 80066f4: fab0 f680 clz r6, r0 + 80066f8: 0976 lsrs r6, r6, #5 + XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve); + 80066fa: f1c6 0101 rsb r1, r6, #1 + 80066fe: eb07 1b46 add.w fp, r7, r6, lsl #5 + 8006702: eb08 1646 add.w r6, r8, r6, lsl #5 + 8006706: eb07 1041 add.w r0, r7, r1, lsl #5 + 800670a: 4633 mov r3, r6 + 800670c: eb08 1141 add.w r1, r8, r1, lsl #5 + 8006710: 465a mov r2, fp + 8006712: 9400 str r4, [sp, #0] + 8006714: e9cd 0106 strd r0, r1, [sp, #24] + 8006718: f7ff fe5a bl 80063d0 + XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve); + 800671c: 9907 ldr r1, [sp, #28] + 800671e: 9806 ldr r0, [sp, #24] + 8006720: 9400 str r4, [sp, #0] + 8006722: 460b mov r3, r1 + 8006724: 4602 mov r2, r0 + 8006726: 4631 mov r1, r6 + 8006728: 4658 mov r0, fp + 800672a: f7ff fed7 bl 80064dc + for (i = num_bits - 2; i > 0; --i) { + 800672e: 3d01 subs r5, #1 + 8006730: e775 b.n 800661e + +08006732 : + uECC_Curve curve) { + 8006732: b530 push {r4, r5, lr} + 8006734: 4614 mov r4, r2 + 8006736: b095 sub sp, #84 ; 0x54 + 8006738: 4605 mov r5, r0 + uECC_word_t *p2[2] = {tmp1, tmp2}; + 800673a: aa0c add r2, sp, #48 ; 0x30 + carry = regularize_k(private, tmp1, tmp2, curve); + 800673c: 4623 mov r3, r4 + uECC_Curve curve) { + 800673e: 4608 mov r0, r1 + uECC_word_t *p2[2] = {tmp1, tmp2}; + 8006740: a904 add r1, sp, #16 + 8006742: 9102 str r1, [sp, #8] + 8006744: 9203 str r2, [sp, #12] + carry = regularize_k(private, tmp1, tmp2, curve); + 8006746: f7ff fbe0 bl 8005f0a + EccPoint_mult(result, curve->G, p2[!carry], 0, curve->num_n_bits + 1, curve); + 800674a: fab0 f380 clz r3, r0 + 800674e: 095b lsrs r3, r3, #5 + 8006750: aa14 add r2, sp, #80 ; 0x50 + 8006752: eb02 0283 add.w r2, r2, r3, lsl #2 + 8006756: 8863 ldrh r3, [r4, #2] + 8006758: 9401 str r4, [sp, #4] + 800675a: 3301 adds r3, #1 + 800675c: b21b sxth r3, r3 + 800675e: 9300 str r3, [sp, #0] + 8006760: f852 2c48 ldr.w r2, [r2, #-72] + 8006764: 2300 movs r3, #0 + 8006766: f104 0144 add.w r1, r4, #68 ; 0x44 + 800676a: 4628 mov r0, r5 + 800676c: f7ff ff16 bl 800659c + if (EccPoint_isZero(result, curve)) { + 8006770: 7821 ldrb r1, [r4, #0] + 8006772: 0049 lsls r1, r1, #1 + 8006774: b249 sxtb r1, r1 + 8006776: 4628 mov r0, r5 + 8006778: f7ff f90e bl 8005998 +} + 800677c: fab0 f080 clz r0, r0 + 8006780: 0940 lsrs r0, r0, #5 + 8006782: b015 add sp, #84 ; 0x54 + 8006784: bd30 pop {r4, r5, pc} + ... + +08006788 : + uECC_Curve curve) { + 8006788: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + 800678c: ed2d 8b02 vpush {d8} + 8006790: b0a7 sub sp, #156 ; 0x9c + 8006792: 461e mov r6, r3 + 8006794: 9d33 ldr r5, [sp, #204] ; 0xcc + wordcount_t num_words = curve->num_words; + 8006796: f995 a000 ldrsb.w sl, [r5] + uECC_Curve curve) { + 800679a: ee08 1a10 vmov s16, r1 + 800679e: 4683 mov fp, r0 + uECC_word_t *k2[2] = {tmp, s}; + 80067a0: f10d 0918 add.w r9, sp, #24 + 80067a4: ab0e add r3, sp, #56 ; 0x38 + if (uECC_vli_isZero(k, num_words) || uECC_vli_cmp(curve->n, k, num_n_words) != 1) { + 80067a6: 4651 mov r1, sl + 80067a8: 4630 mov r0, r6 + uECC_Curve curve) { + 80067aa: ee08 2a90 vmov s17, r2 + uECC_word_t *k2[2] = {tmp, s}; + 80067ae: f8cd 9010 str.w r9, [sp, #16] + 80067b2: 9305 str r3, [sp, #20] + if (uECC_vli_isZero(k, num_words) || uECC_vli_cmp(curve->n, k, num_n_words) != 1) { + 80067b4: f7ff f8f0 bl 8005998 + 80067b8: b128 cbz r0, 80067c6 + return 0; + 80067ba: 2000 movs r0, #0 +} + 80067bc: b027 add sp, #156 ; 0x9c + 80067be: ecbd 8b02 vpop {d8} + 80067c2: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); + 80067c6: f9b5 8002 ldrsh.w r8, [r5, #2] + 80067ca: f118 041f adds.w r4, r8, #31 + 80067ce: bf48 it mi + 80067d0: f108 043e addmi.w r4, r8, #62 ; 0x3e + 80067d4: f344 1447 sbfx r4, r4, #5, #8 + if (uECC_vli_isZero(k, num_words) || uECC_vli_cmp(curve->n, k, num_n_words) != 1) { + 80067d8: f105 0724 add.w r7, r5, #36 ; 0x24 + 80067dc: 4622 mov r2, r4 + 80067de: 4631 mov r1, r6 + 80067e0: 4638 mov r0, r7 + 80067e2: f7ff fb19 bl 8005e18 + 80067e6: 2801 cmp r0, #1 + 80067e8: 9003 str r0, [sp, #12] + 80067ea: d1e6 bne.n 80067ba + carry = regularize_k(k, tmp, s, curve); + 80067ec: 462b mov r3, r5 + 80067ee: aa0e add r2, sp, #56 ; 0x38 + 80067f0: 4649 mov r1, r9 + 80067f2: 4630 mov r0, r6 + 80067f4: f7ff fb89 bl 8005f0a + EccPoint_mult(p, curve->G, k2[!carry], 0, num_n_bits + 1, curve); + 80067f8: fab0 f080 clz r0, r0 + 80067fc: ab26 add r3, sp, #152 ; 0x98 + 80067fe: 0940 lsrs r0, r0, #5 + 8006800: f108 0801 add.w r8, r8, #1 + 8006804: eb03 0080 add.w r0, r3, r0, lsl #2 + 8006808: fa0f f388 sxth.w r3, r8 + 800680c: 9300 str r3, [sp, #0] + 800680e: 9501 str r5, [sp, #4] + 8006810: f850 2c88 ldr.w r2, [r0, #-136] + 8006814: f105 0144 add.w r1, r5, #68 ; 0x44 + 8006818: a816 add r0, sp, #88 ; 0x58 + 800681a: 2300 movs r3, #0 + 800681c: f7ff febe bl 800659c + if (uECC_vli_isZero(p, num_words)) { + 8006820: 4651 mov r1, sl + 8006822: a816 add r0, sp, #88 ; 0x58 + 8006824: f7ff f8b8 bl 8005998 + 8006828: 2800 cmp r0, #0 + 800682a: d1c6 bne.n 80067ba + uECC_recid = (p[curve->num_words] & 0x01); + 800682c: f995 3000 ldrsb.w r3, [r5] + 8006830: aa26 add r2, sp, #152 ; 0x98 + 8006832: eb02 0383 add.w r3, r2, r3, lsl #2 + 8006836: 4a3b ldr r2, [pc, #236] ; (8006924 ) + 8006838: f853 3c40 ldr.w r3, [r3, #-64] + 800683c: f003 0301 and.w r3, r3, #1 + 8006840: 7013 strb r3, [r2, #0] + if (!g_rng_function) { + 8006842: 4b39 ldr r3, [pc, #228] ; (8006928 ) + 8006844: 681b ldr r3, [r3, #0] + 8006846: 2b00 cmp r3, #0 + 8006848: d163 bne.n 8006912 + uECC_vli_clear(tmp, num_n_words); + 800684a: 4621 mov r1, r4 + 800684c: 4648 mov r0, r9 + 800684e: f7ff f89d bl 800598c + tmp[0] = 1; + 8006852: 9b03 ldr r3, [sp, #12] + 8006854: 9306 str r3, [sp, #24] + uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k' = rand * k */ + 8006856: 463b mov r3, r7 + 8006858: aa06 add r2, sp, #24 + 800685a: 4631 mov r1, r6 + 800685c: 4630 mov r0, r6 + 800685e: 9400 str r4, [sp, #0] + 8006860: f7ff f901 bl 8005a66 + uECC_vli_modInv(k, k, curve->n, num_n_words); /* k = 1 / k' */ + 8006864: 4623 mov r3, r4 + 8006866: 463a mov r2, r7 + 8006868: 4631 mov r1, r6 + 800686a: 4630 mov r0, r6 + 800686c: f7ff fcf4 bl 8006258 + uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k = 1 / k */ + 8006870: 463b mov r3, r7 + 8006872: aa06 add r2, sp, #24 + 8006874: 4631 mov r1, r6 + 8006876: 4630 mov r0, r6 + 8006878: 9400 str r4, [sp, #0] + 800687a: f7ff f8f4 bl 8005a66 + uECC_vli_nativeToBytes(signature, curve->num_bytes, p); /* store r */ + 800687e: f995 1001 ldrsb.w r1, [r5, #1] + 8006882: 9832 ldr r0, [sp, #200] ; 0xc8 + 8006884: aa16 add r2, sp, #88 ; 0x58 + 8006886: f7ff f9c1 bl 8005c0c + uECC_vli_bytesToNative(tmp, private_key, BITS_TO_BYTES(curve->num_n_bits)); /* tmp = d */ + 800688a: f9b5 3002 ldrsh.w r3, [r5, #2] + 800688e: 1dda adds r2, r3, #7 + 8006890: bf48 it mi + 8006892: f103 020e addmi.w r2, r3, #14 + 8006896: 10d2 asrs r2, r2, #3 + 8006898: 4659 mov r1, fp + 800689a: a806 add r0, sp, #24 + 800689c: f7ff f9ca bl 8005c34 + s[num_n_words - 1] = 0; + 80068a0: aa26 add r2, sp, #152 ; 0x98 + 80068a2: 1e63 subs r3, r4, #1 + 80068a4: eb02 0383 add.w r3, r2, r3, lsl #2 + 80068a8: 2200 movs r2, #0 + uECC_vli_set(s, p, num_words); + 80068aa: a80e add r0, sp, #56 ; 0x38 + s[num_n_words - 1] = 0; + 80068ac: f843 2c60 str.w r2, [r3, #-96] + uECC_vli_set(s, p, num_words); + 80068b0: a916 add r1, sp, #88 ; 0x58 + 80068b2: 4652 mov r2, sl + 80068b4: f7ff f8a9 bl 8005a0a + uECC_vli_modMult(s, tmp, s, curve->n, num_n_words); /* s = r*d */ + 80068b8: 4602 mov r2, r0 + 80068ba: 463b mov r3, r7 + 80068bc: a906 add r1, sp, #24 + 80068be: 9400 str r4, [sp, #0] + 80068c0: f7ff f8d1 bl 8005a66 + bits2int(tmp, message_hash, hash_size, curve); + 80068c4: ee18 2a90 vmov r2, s17 + 80068c8: ee18 1a10 vmov r1, s16 + 80068cc: 462b mov r3, r5 + 80068ce: a806 add r0, sp, #24 + 80068d0: f7ff fa5b bl 8005d8a + uECC_vli_modAdd(s, tmp, s, curve->n, num_n_words); /* s = e + r*d */ + 80068d4: aa0e add r2, sp, #56 ; 0x38 + 80068d6: 4610 mov r0, r2 + 80068d8: 463b mov r3, r7 + 80068da: a906 add r1, sp, #24 + 80068dc: 9400 str r4, [sp, #0] + 80068de: f7ff fd3b bl 8006358 + uECC_vli_modMult(s, s, k, curve->n, num_n_words); /* s = (e + r*d) / k */ + 80068e2: a90e add r1, sp, #56 ; 0x38 + 80068e4: 4608 mov r0, r1 + 80068e6: 463b mov r3, r7 + 80068e8: 4632 mov r2, r6 + 80068ea: 9400 str r4, [sp, #0] + 80068ec: f7ff f8bb bl 8005a66 + if (uECC_vli_numBits(s, num_n_words) > (bitcount_t)curve->num_bytes * 8) { + 80068f0: 4621 mov r1, r4 + 80068f2: a80e add r0, sp, #56 ; 0x38 + 80068f4: f7ff f869 bl 80059ca + 80068f8: f995 1001 ldrsb.w r1, [r5, #1] + 80068fc: ebb0 0fc1 cmp.w r0, r1, lsl #3 + 8006900: f73f af5b bgt.w 80067ba + uECC_vli_nativeToBytes(signature + curve->num_bytes, curve->num_bytes, s); + 8006904: 9b32 ldr r3, [sp, #200] ; 0xc8 + 8006906: aa0e add r2, sp, #56 ; 0x38 + 8006908: 1858 adds r0, r3, r1 + 800690a: f7ff f97f bl 8005c0c + return 1; + 800690e: 2001 movs r0, #1 + 8006910: e754 b.n 80067bc + } else if (!uECC_generate_random_int(tmp, curve->n, num_n_words)) { + 8006912: 4622 mov r2, r4 + 8006914: 4639 mov r1, r7 + 8006916: 4648 mov r0, r9 + 8006918: f7ff fa96 bl 8005e48 + 800691c: 2800 cmp r0, #0 + 800691e: d19a bne.n 8006856 + 8006920: e74b b.n 80067ba + 8006922: bf00 nop + 8006924: 2009e2a8 .word 0x2009e2a8 + 8006928: 2009e2a4 .word 0x2009e2a4 + +0800692c : + uECC_Curve curve) { + 800692c: e92d 43f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, lr} + 8006930: 4605 mov r5, r0 + 8006932: b093 sub sp, #76 ; 0x4c + 8006934: 460c mov r4, r1 + if (uECC_vli_isZero(Z1, num_words_secp256k1)) { + 8006936: 4610 mov r0, r2 + 8006938: 2108 movs r1, #8 + uECC_Curve curve) { + 800693a: 4617 mov r7, r2 + 800693c: 461e mov r6, r3 + if (uECC_vli_isZero(Z1, num_words_secp256k1)) { + 800693e: f7ff f82b bl 8005998 + 8006942: 2800 cmp r0, #0 + 8006944: d161 bne.n 8006a0a + uECC_vli_modSquare_fast(t5, Y1, curve); /* t5 = y1^2 */ + 8006946: 4632 mov r2, r6 + 8006948: 4621 mov r1, r4 + 800694a: a80a add r0, sp, #40 ; 0x28 + 800694c: f7ff f93b bl 8005bc6 + uECC_vli_modMult_fast(t4, X1, t5, curve); /* t4 = x1*y1^2 = A */ + 8006950: 4633 mov r3, r6 + 8006952: aa0a add r2, sp, #40 ; 0x28 + 8006954: 4629 mov r1, r5 + 8006956: a802 add r0, sp, #8 + 8006958: f7ff f925 bl 8005ba6 + uECC_vli_modSquare_fast(X1, X1, curve); /* t1 = x1^2 */ + 800695c: 4632 mov r2, r6 + 800695e: 4629 mov r1, r5 + 8006960: 4628 mov r0, r5 + 8006962: f7ff f930 bl 8005bc6 + uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = y1^4 */ + 8006966: a90a add r1, sp, #40 ; 0x28 + 8006968: 4608 mov r0, r1 + 800696a: 4632 mov r2, r6 + 800696c: f7ff f92b bl 8005bc6 + uECC_vli_modAdd(Y1, X1, X1, curve->p, num_words_secp256k1); /* t2 = 2*x1^2 */ + 8006970: f04f 0808 mov.w r8, #8 + uECC_vli_modMult_fast(Z1, Y1, Z1, curve); /* t3 = y1*z1 = z3 */ + 8006974: 463a mov r2, r7 + 8006976: 4638 mov r0, r7 + 8006978: 4633 mov r3, r6 + 800697a: 4621 mov r1, r4 + uECC_vli_modAdd(Y1, X1, X1, curve->p, num_words_secp256k1); /* t2 = 2*x1^2 */ + 800697c: 1d37 adds r7, r6, #4 + uECC_vli_modMult_fast(Z1, Y1, Z1, curve); /* t3 = y1*z1 = z3 */ + 800697e: f7ff f912 bl 8005ba6 + uECC_vli_modAdd(Y1, X1, X1, curve->p, num_words_secp256k1); /* t2 = 2*x1^2 */ + 8006982: 463b mov r3, r7 + 8006984: 462a mov r2, r5 + 8006986: 4629 mov r1, r5 + 8006988: 4620 mov r0, r4 + 800698a: f8cd 8000 str.w r8, [sp] + 800698e: f7ff fce3 bl 8006358 + uECC_vli_modAdd(Y1, Y1, X1, curve->p, num_words_secp256k1); /* t2 = 3*x1^2 */ + 8006992: 463b mov r3, r7 + 8006994: f8cd 8000 str.w r8, [sp] + 8006998: 462a mov r2, r5 + 800699a: 4621 mov r1, r4 + 800699c: 4620 mov r0, r4 + 800699e: f7ff fcdb bl 8006358 + return (vli[bit >> uECC_WORD_BITS_SHIFT] & ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK))); + 80069a2: 6823 ldr r3, [r4, #0] + if (uECC_vli_testBit(Y1, 0)) { + 80069a4: 07db lsls r3, r3, #31 + 80069a6: d533 bpl.n 8006a10 + uECC_word_t carry = uECC_vli_add(Y1, Y1, curve->p, num_words_secp256k1); + 80069a8: 463a mov r2, r7 + 80069aa: 4621 mov r1, r4 + 80069ac: 4620 mov r0, r4 + 80069ae: f7ff fa87 bl 8005ec0 + uECC_vli_rshift1(Y1, num_words_secp256k1); + 80069b2: 4641 mov r1, r8 + uECC_word_t carry = uECC_vli_add(Y1, Y1, curve->p, num_words_secp256k1); + 80069b4: 4681 mov r9, r0 + uECC_vli_rshift1(Y1, num_words_secp256k1); + 80069b6: 4620 mov r0, r4 + 80069b8: f7ff f848 bl 8005a4c + Y1[num_words_secp256k1 - 1] |= carry << (uECC_WORD_BITS - 1); + 80069bc: 69e3 ldr r3, [r4, #28] + 80069be: ea43 73c9 orr.w r3, r3, r9, lsl #31 + 80069c2: 61e3 str r3, [r4, #28] + uECC_vli_modSquare_fast(X1, Y1, curve); /* t1 = B^2 */ + 80069c4: 4632 mov r2, r6 + 80069c6: 4621 mov r1, r4 + 80069c8: 4628 mov r0, r5 + 80069ca: f7ff f8fc bl 8005bc6 + uECC_vli_modSub(X1, X1, t4, curve->p, num_words_secp256k1); /* t1 = B^2 - A */ + 80069ce: 463b mov r3, r7 + 80069d0: aa02 add r2, sp, #8 + 80069d2: 4629 mov r1, r5 + 80069d4: 4628 mov r0, r5 + 80069d6: f7ff fced bl 80063b4 + uECC_vli_modSub(X1, X1, t4, curve->p, num_words_secp256k1); /* t1 = B^2 - 2A = x3 */ + 80069da: 463b mov r3, r7 + 80069dc: aa02 add r2, sp, #8 + 80069de: 4629 mov r1, r5 + 80069e0: 4628 mov r0, r5 + 80069e2: f7ff fce7 bl 80063b4 + uECC_vli_modSub(t4, t4, X1, curve->p, num_words_secp256k1); /* t4 = A - x3 */ + 80069e6: a902 add r1, sp, #8 + 80069e8: 4608 mov r0, r1 + 80069ea: 463b mov r3, r7 + 80069ec: 462a mov r2, r5 + 80069ee: f7ff fce1 bl 80063b4 + uECC_vli_modMult_fast(Y1, Y1, t4, curve); /* t2 = B * (A - x3) */ + 80069f2: 4633 mov r3, r6 + 80069f4: aa02 add r2, sp, #8 + 80069f6: 4621 mov r1, r4 + 80069f8: 4620 mov r0, r4 + 80069fa: f7ff f8d4 bl 8005ba6 + uECC_vli_modSub(Y1, Y1, t5, curve->p, num_words_secp256k1); /* t2 = B * (A - x3) - y1^4 = y3 */ + 80069fe: 463b mov r3, r7 + 8006a00: aa0a add r2, sp, #40 ; 0x28 + 8006a02: 4621 mov r1, r4 + 8006a04: 4620 mov r0, r4 + 8006a06: f7ff fcd5 bl 80063b4 +} + 8006a0a: b013 add sp, #76 ; 0x4c + 8006a0c: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + uECC_vli_rshift1(Y1, num_words_secp256k1); + 8006a10: 4641 mov r1, r8 + 8006a12: 4620 mov r0, r4 + 8006a14: f7ff f81a bl 8005a4c + 8006a18: e7d4 b.n 80069c4 + +08006a1a : +static void x_side_default(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve) { + 8006a1a: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + 8006a1e: b08a sub sp, #40 ; 0x28 + 8006a20: 4604 mov r4, r0 + 8006a22: 4615 mov r5, r2 + 8006a24: 460e mov r6, r1 + uECC_word_t _3[uECC_MAX_WORDS] = {3}; /* -a = 3 */ + 8006a26: 221c movs r2, #28 + 8006a28: 2100 movs r1, #0 + 8006a2a: a803 add r0, sp, #12 + 8006a2c: f006 ff7a bl 800d924 + uECC_vli_modSub(result, result, _3, curve->p, num_words); /* r = x^2 - 3 */ + 8006a30: 1d2f adds r7, r5, #4 + uECC_word_t _3[uECC_MAX_WORDS] = {3}; /* -a = 3 */ + 8006a32: 2303 movs r3, #3 + uECC_vli_modSquare_fast(result, x, curve); /* r = x^2 */ + 8006a34: 462a mov r2, r5 + 8006a36: 4631 mov r1, r6 + 8006a38: 4620 mov r0, r4 + wordcount_t num_words = curve->num_words; + 8006a3a: f995 8000 ldrsb.w r8, [r5] + uECC_word_t _3[uECC_MAX_WORDS] = {3}; /* -a = 3 */ + 8006a3e: 9302 str r3, [sp, #8] + uECC_vli_modSquare_fast(result, x, curve); /* r = x^2 */ + 8006a40: f7ff f8c1 bl 8005bc6 + uECC_vli_modSub(result, result, _3, curve->p, num_words); /* r = x^2 - 3 */ + 8006a44: 463b mov r3, r7 + 8006a46: aa02 add r2, sp, #8 + 8006a48: 4621 mov r1, r4 + 8006a4a: 4620 mov r0, r4 + 8006a4c: f7ff fcb2 bl 80063b4 + uECC_vli_modMult_fast(result, result, x, curve); /* r = x^3 - 3x */ + 8006a50: 462b mov r3, r5 + 8006a52: 4632 mov r2, r6 + 8006a54: 4621 mov r1, r4 + 8006a56: 4620 mov r0, r4 + 8006a58: f7ff f8a5 bl 8005ba6 + uECC_vli_modAdd(result, result, curve->b, curve->p, num_words); /* r = x^3 - 3x + b */ + 8006a5c: f8cd 8000 str.w r8, [sp] + 8006a60: 463b mov r3, r7 + 8006a62: f105 0284 add.w r2, r5, #132 ; 0x84 + 8006a66: 4621 mov r1, r4 + 8006a68: 4620 mov r0, r4 + 8006a6a: f7ff fc75 bl 8006358 +} + 8006a6e: b00a add sp, #40 ; 0x28 + 8006a70: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + +08006a74 : + uECC_Curve curve) { + 8006a74: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + wordcount_t num_words = curve->num_words; + 8006a78: f993 8000 ldrsb.w r8, [r3] + uECC_Curve curve) { + 8006a7c: b092 sub sp, #72 ; 0x48 + 8006a7e: 4604 mov r4, r0 + 8006a80: 4689 mov r9, r1 + if (uECC_vli_isZero(Z1, num_words)) { + 8006a82: 4610 mov r0, r2 + 8006a84: 4641 mov r1, r8 + uECC_Curve curve) { + 8006a86: 4615 mov r5, r2 + 8006a88: 461e mov r6, r3 + if (uECC_vli_isZero(Z1, num_words)) { + 8006a8a: f7fe ff85 bl 8005998 + 8006a8e: 2800 cmp r0, #0 + 8006a90: f040 808e bne.w 8006bb0 + uECC_vli_modSquare_fast(t4, Y1, curve); /* t4 = y1^2 */ + 8006a94: 4632 mov r2, r6 + 8006a96: 4649 mov r1, r9 + 8006a98: a802 add r0, sp, #8 + 8006a9a: f7ff f894 bl 8005bc6 + uECC_vli_modMult_fast(t5, X1, t4, curve); /* t5 = x1*y1^2 = A */ + 8006a9e: 4633 mov r3, r6 + 8006aa0: aa02 add r2, sp, #8 + 8006aa2: 4621 mov r1, r4 + 8006aa4: a80a add r0, sp, #40 ; 0x28 + 8006aa6: f7ff f87e bl 8005ba6 + uECC_vli_modSquare_fast(t4, t4, curve); /* t4 = y1^4 */ + 8006aaa: a902 add r1, sp, #8 + 8006aac: 4608 mov r0, r1 + 8006aae: 4632 mov r2, r6 + 8006ab0: f7ff f889 bl 8005bc6 + uECC_vli_modMult_fast(Y1, Y1, Z1, curve); /* t2 = y1*z1 = z3 */ + 8006ab4: 4633 mov r3, r6 + 8006ab6: 462a mov r2, r5 + 8006ab8: 4649 mov r1, r9 + 8006aba: 4648 mov r0, r9 + 8006abc: f7ff f873 bl 8005ba6 + uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = x1 + z1^2 */ + 8006ac0: 1d37 adds r7, r6, #4 + uECC_vli_modSquare_fast(Z1, Z1, curve); /* t3 = z1^2 */ + 8006ac2: 4632 mov r2, r6 + 8006ac4: 4629 mov r1, r5 + 8006ac6: 4628 mov r0, r5 + 8006ac8: f7ff f87d bl 8005bc6 + uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = x1 + z1^2 */ + 8006acc: 463b mov r3, r7 + 8006ace: 462a mov r2, r5 + 8006ad0: 4621 mov r1, r4 + 8006ad2: 4620 mov r0, r4 + 8006ad4: f8cd 8000 str.w r8, [sp] + 8006ad8: f7ff fc3e bl 8006358 + uECC_vli_modAdd(Z1, Z1, Z1, curve->p, num_words); /* t3 = 2*z1^2 */ + 8006adc: 463b mov r3, r7 + 8006ade: 462a mov r2, r5 + 8006ae0: 4629 mov r1, r5 + 8006ae2: 4628 mov r0, r5 + 8006ae4: f8cd 8000 str.w r8, [sp] + 8006ae8: f7ff fc36 bl 8006358 + uECC_vli_modSub(Z1, X1, Z1, curve->p, num_words); /* t3 = x1 - z1^2 */ + 8006aec: 463b mov r3, r7 + 8006aee: 462a mov r2, r5 + 8006af0: 4621 mov r1, r4 + 8006af2: 4628 mov r0, r5 + 8006af4: f7ff fc5e bl 80063b4 + uECC_vli_modMult_fast(X1, X1, Z1, curve); /* t1 = x1^2 - z1^4 */ + 8006af8: 4633 mov r3, r6 + 8006afa: 462a mov r2, r5 + 8006afc: 4621 mov r1, r4 + 8006afe: 4620 mov r0, r4 + 8006b00: f7ff f851 bl 8005ba6 + uECC_vli_modAdd(Z1, X1, X1, curve->p, num_words); /* t3 = 2*(x1^2 - z1^4) */ + 8006b04: 463b mov r3, r7 + 8006b06: 4622 mov r2, r4 + 8006b08: 4621 mov r1, r4 + 8006b0a: 4628 mov r0, r5 + 8006b0c: f8cd 8000 str.w r8, [sp] + 8006b10: f7ff fc22 bl 8006358 + uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = 3*(x1^2 - z1^4) */ + 8006b14: 463b mov r3, r7 + 8006b16: f8cd 8000 str.w r8, [sp] + 8006b1a: 462a mov r2, r5 + 8006b1c: 4621 mov r1, r4 + 8006b1e: 4620 mov r0, r4 + 8006b20: f7ff fc1a bl 8006358 + 8006b24: 6823 ldr r3, [r4, #0] + if (uECC_vli_testBit(X1, 0)) { + 8006b26: 07db lsls r3, r3, #31 + 8006b28: d545 bpl.n 8006bb6 + uECC_word_t l_carry = uECC_vli_add(X1, X1, curve->p, num_words); + 8006b2a: 463a mov r2, r7 + 8006b2c: 4621 mov r1, r4 + 8006b2e: 4620 mov r0, r4 + 8006b30: f7ff f9c6 bl 8005ec0 + uECC_vli_rshift1(X1, num_words); + 8006b34: 4641 mov r1, r8 + uECC_word_t l_carry = uECC_vli_add(X1, X1, curve->p, num_words); + 8006b36: 4682 mov sl, r0 + uECC_vli_rshift1(X1, num_words); + 8006b38: 4620 mov r0, r4 + 8006b3a: f7fe ff87 bl 8005a4c + X1[num_words - 1] |= l_carry << (uECC_WORD_BITS - 1); + 8006b3e: f108 4380 add.w r3, r8, #1073741824 ; 0x40000000 + 8006b42: 3b01 subs r3, #1 + 8006b44: f854 2023 ldr.w r2, [r4, r3, lsl #2] + 8006b48: ea42 72ca orr.w r2, r2, sl, lsl #31 + 8006b4c: f844 2023 str.w r2, [r4, r3, lsl #2] + uECC_vli_modSquare_fast(Z1, X1, curve); /* t3 = B^2 */ + 8006b50: 4632 mov r2, r6 + 8006b52: 4621 mov r1, r4 + 8006b54: 4628 mov r0, r5 + 8006b56: f7ff f836 bl 8005bc6 + uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - A */ + 8006b5a: 463b mov r3, r7 + 8006b5c: aa0a add r2, sp, #40 ; 0x28 + 8006b5e: 4629 mov r1, r5 + 8006b60: 4628 mov r0, r5 + 8006b62: f7ff fc27 bl 80063b4 + uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - 2A = x3 */ + 8006b66: 463b mov r3, r7 + 8006b68: aa0a add r2, sp, #40 ; 0x28 + 8006b6a: 4629 mov r1, r5 + 8006b6c: 4628 mov r0, r5 + 8006b6e: f7ff fc21 bl 80063b4 + uECC_vli_modSub(t5, t5, Z1, curve->p, num_words); /* t5 = A - x3 */ + 8006b72: a90a add r1, sp, #40 ; 0x28 + 8006b74: 4608 mov r0, r1 + 8006b76: 463b mov r3, r7 + 8006b78: 462a mov r2, r5 + 8006b7a: f7ff fc1b bl 80063b4 + uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = B * (A - x3) */ + 8006b7e: 4633 mov r3, r6 + 8006b80: aa0a add r2, sp, #40 ; 0x28 + 8006b82: 4621 mov r1, r4 + 8006b84: 4620 mov r0, r4 + 8006b86: f7ff f80e bl 8005ba6 + uECC_vli_modSub(t4, X1, t4, curve->p, num_words); /* t4 = B * (A - x3) - y1^4 = y3 */ + 8006b8a: aa02 add r2, sp, #8 + 8006b8c: 463b mov r3, r7 + 8006b8e: 4610 mov r0, r2 + 8006b90: 4621 mov r1, r4 + 8006b92: f7ff fc0f bl 80063b4 + uECC_vli_set(X1, Z1, num_words); + 8006b96: 4642 mov r2, r8 + 8006b98: 4629 mov r1, r5 + 8006b9a: 4620 mov r0, r4 + 8006b9c: f7fe ff35 bl 8005a0a + uECC_vli_set(Z1, Y1, num_words); + 8006ba0: 4649 mov r1, r9 + 8006ba2: 4628 mov r0, r5 + 8006ba4: f7fe ff31 bl 8005a0a + uECC_vli_set(Y1, t4, num_words); + 8006ba8: a902 add r1, sp, #8 + 8006baa: 4648 mov r0, r9 + 8006bac: f7fe ff2d bl 8005a0a +} + 8006bb0: b012 add sp, #72 ; 0x48 + 8006bb2: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + uECC_vli_rshift1(X1, num_words); + 8006bb6: 4641 mov r1, r8 + 8006bb8: 4620 mov r0, r4 + 8006bba: f7fe ff47 bl 8005a4c + 8006bbe: e7c7 b.n 8006b50 + +08006bc0 : + g_rng_function = rng_function; + 8006bc0: 4b01 ldr r3, [pc, #4] ; (8006bc8 ) + 8006bc2: 6018 str r0, [r3, #0] +} + 8006bc4: 4770 bx lr + 8006bc6: bf00 nop + 8006bc8: 2009e2a4 .word 0x2009e2a4 + +08006bcc : +uECC_Curve uECC_secp256r1(void) { return &curve_secp256r1; } + 8006bcc: 4800 ldr r0, [pc, #0] ; (8006bd0 ) + 8006bce: 4770 bx lr + 8006bd0: 080109a4 .word 0x080109a4 + +08006bd4 : +uECC_Curve uECC_secp256k1(void) { return &curve_secp256k1; } + 8006bd4: 4800 ldr r0, [pc, #0] ; (8006bd8 ) + 8006bd6: 4770 bx lr + 8006bd8: 080108f0 .word 0x080108f0 + +08006bdc : + uECC_Curve curve) { + 8006bdc: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + 8006be0: 4605 mov r5, r0 + 8006be2: b098 sub sp, #96 ; 0x60 + 8006be4: 460f mov r7, r1 + 8006be6: 4614 mov r4, r2 + 8006be8: 2640 movs r6, #64 ; 0x40 + if (!uECC_generate_random_int(private, curve->n, BITS_TO_WORDS(curve->num_n_bits))) { + 8006bea: f102 0824 add.w r8, r2, #36 ; 0x24 + 8006bee: f9b4 3002 ldrsh.w r3, [r4, #2] + 8006bf2: f113 021f adds.w r2, r3, #31 + 8006bf6: bf48 it mi + 8006bf8: f103 023e addmi.w r2, r3, #62 ; 0x3e + 8006bfc: f342 1247 sbfx r2, r2, #5, #8 + 8006c00: 4641 mov r1, r8 + 8006c02: 4668 mov r0, sp + 8006c04: f7ff f920 bl 8005e48 + 8006c08: b330 cbz r0, 8006c58 + if (EccPoint_compute_public_key(public, private, curve)) { + 8006c0a: 4622 mov r2, r4 + 8006c0c: 4669 mov r1, sp + 8006c0e: a808 add r0, sp, #32 + 8006c10: f7ff fd8f bl 8006732 + 8006c14: b1f0 cbz r0, 8006c54 + uECC_vli_nativeToBytes(private_key, BITS_TO_BYTES(curve->num_n_bits), private); + 8006c16: f9b4 3002 ldrsh.w r3, [r4, #2] + 8006c1a: 1dd9 adds r1, r3, #7 + 8006c1c: bf48 it mi + 8006c1e: f103 010e addmi.w r1, r3, #14 + 8006c22: 466a mov r2, sp + 8006c24: 10c9 asrs r1, r1, #3 + 8006c26: 4638 mov r0, r7 + 8006c28: f7fe fff0 bl 8005c0c + uECC_vli_nativeToBytes(public_key, curve->num_bytes, public); + 8006c2c: f994 1001 ldrsb.w r1, [r4, #1] + 8006c30: aa08 add r2, sp, #32 + 8006c32: 4628 mov r0, r5 + 8006c34: f7fe ffea bl 8005c0c + public_key + curve->num_bytes, curve->num_bytes, public + curve->num_words); + 8006c38: f994 1001 ldrsb.w r1, [r4, #1] + 8006c3c: f994 2000 ldrsb.w r2, [r4] + uECC_vli_nativeToBytes( + 8006c40: ab08 add r3, sp, #32 + 8006c42: 1868 adds r0, r5, r1 + 8006c44: eb03 0282 add.w r2, r3, r2, lsl #2 + 8006c48: f7fe ffe0 bl 8005c0c + return 1; + 8006c4c: 2001 movs r0, #1 +} + 8006c4e: b018 add sp, #96 ; 0x60 + 8006c50: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { + 8006c54: 3e01 subs r6, #1 + 8006c56: d1ca bne.n 8006bee + return 0; + 8006c58: 2000 movs r0, #0 + 8006c5a: e7f8 b.n 8006c4e + +08006c5c : + uECC_Curve curve) { + 8006c5c: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + 8006c60: 461c mov r4, r3 + wordcount_t num_bytes = curve->num_bytes; + 8006c62: f993 6001 ldrsb.w r6, [r3, #1] + wordcount_t num_words = curve->num_words; + 8006c66: f993 9000 ldrsb.w r9, [r3] + uECC_vli_bytesToNative(private, private_key, BITS_TO_BYTES(curve->num_n_bits)); + 8006c6a: f9b3 3002 ldrsh.w r3, [r3, #2] + uECC_Curve curve) { + 8006c6e: b0a6 sub sp, #152 ; 0x98 + 8006c70: 4617 mov r7, r2 + uECC_vli_bytesToNative(private, private_key, BITS_TO_BYTES(curve->num_n_bits)); + 8006c72: 1dda adds r2, r3, #7 + 8006c74: bf48 it mi + 8006c76: f103 020e addmi.w r2, r3, #14 + uECC_word_t *p2[2] = {private, tmp}; + 8006c7a: f10d 0818 add.w r8, sp, #24 + uECC_Curve curve) { + 8006c7e: 4605 mov r5, r0 + uECC_word_t *p2[2] = {private, tmp}; + 8006c80: f10d 0a38 add.w sl, sp, #56 ; 0x38 + uECC_vli_bytesToNative(private, private_key, BITS_TO_BYTES(curve->num_n_bits)); + 8006c84: 10d2 asrs r2, r2, #3 + 8006c86: 4640 mov r0, r8 + uECC_word_t *p2[2] = {private, tmp}; + 8006c88: f8cd 8010 str.w r8, [sp, #16] + 8006c8c: f8cd a014 str.w sl, [sp, #20] + uECC_vli_bytesToNative(private, private_key, BITS_TO_BYTES(curve->num_n_bits)); + 8006c90: f7fe ffd0 bl 8005c34 + uECC_vli_bytesToNative(public, public_key, num_bytes); + 8006c94: 4629 mov r1, r5 + 8006c96: 4632 mov r2, r6 + 8006c98: a816 add r0, sp, #88 ; 0x58 + 8006c9a: f7fe ffcb bl 8005c34 + uECC_vli_bytesToNative(public + num_words, public_key + num_bytes, num_bytes); + 8006c9e: ab16 add r3, sp, #88 ; 0x58 + 8006ca0: 19a9 adds r1, r5, r6 + 8006ca2: eb03 0089 add.w r0, r3, r9, lsl #2 + 8006ca6: 4632 mov r2, r6 + 8006ca8: f7fe ffc4 bl 8005c34 + carry = regularize_k(private, private, tmp, curve); + 8006cac: 4623 mov r3, r4 + 8006cae: 4652 mov r2, sl + 8006cb0: 4641 mov r1, r8 + 8006cb2: 4640 mov r0, r8 + 8006cb4: f7ff f929 bl 8005f0a + if (g_rng_function) { + 8006cb8: 4b19 ldr r3, [pc, #100] ; (8006d20 ) + 8006cba: 681b ldr r3, [r3, #0] + carry = regularize_k(private, private, tmp, curve); + 8006cbc: 4605 mov r5, r0 + if (g_rng_function) { + 8006cbe: b163 cbz r3, 8006cda + if (!uECC_generate_random_int(p2[carry], curve->p, num_words)) { + 8006cc0: ab26 add r3, sp, #152 ; 0x98 + 8006cc2: eb03 0380 add.w r3, r3, r0, lsl #2 + 8006cc6: 464a mov r2, r9 + 8006cc8: f853 3c88 ldr.w r3, [r3, #-136] + 8006ccc: 9303 str r3, [sp, #12] + 8006cce: 4618 mov r0, r3 + 8006cd0: 1d21 adds r1, r4, #4 + 8006cd2: f7ff f8b9 bl 8005e48 + 8006cd6: 9b03 ldr r3, [sp, #12] + 8006cd8: b1f0 cbz r0, 8006d18 + EccPoint_mult(public, public, p2[!carry], initial_Z, curve->num_n_bits + 1, curve); + 8006cda: fab5 f185 clz r1, r5 + 8006cde: aa26 add r2, sp, #152 ; 0x98 + 8006ce0: 0949 lsrs r1, r1, #5 + 8006ce2: eb02 0181 add.w r1, r2, r1, lsl #2 + 8006ce6: 8862 ldrh r2, [r4, #2] + 8006ce8: 9401 str r4, [sp, #4] + 8006cea: 3201 adds r2, #1 + 8006cec: b212 sxth r2, r2 + 8006cee: 9200 str r2, [sp, #0] + 8006cf0: f851 2c88 ldr.w r2, [r1, #-136] + 8006cf4: a916 add r1, sp, #88 ; 0x58 + 8006cf6: 4608 mov r0, r1 + 8006cf8: f7ff fc50 bl 800659c + uECC_vli_nativeToBytes(secret, num_bytes, public); + 8006cfc: aa16 add r2, sp, #88 ; 0x58 + 8006cfe: 4631 mov r1, r6 + 8006d00: 4638 mov r0, r7 + 8006d02: f7fe ff83 bl 8005c0c + return !EccPoint_isZero(public, curve); + 8006d06: 7821 ldrb r1, [r4, #0] + 8006d08: 0049 lsls r1, r1, #1 + 8006d0a: b249 sxtb r1, r1 + 8006d0c: 4610 mov r0, r2 + 8006d0e: f7fe fe43 bl 8005998 + 8006d12: fab0 f080 clz r0, r0 + 8006d16: 0940 lsrs r0, r0, #5 +} + 8006d18: b026 add sp, #152 ; 0x98 + 8006d1a: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + 8006d1e: bf00 nop + 8006d20: 2009e2a4 .word 0x2009e2a4 + +08006d24 : +void uECC_compress(const uint8_t *public_key, uint8_t *compressed, uECC_Curve curve) { + 8006d24: b530 push {r4, r5, lr} + for (i = 0; i < curve->num_bytes; ++i) { + 8006d26: 2400 movs r4, #0 + 8006d28: f992 5001 ldrsb.w r5, [r2, #1] + 8006d2c: b263 sxtb r3, r4 + 8006d2e: 429d cmp r5, r3 + 8006d30: dc08 bgt.n 8006d44 + compressed[0] = 2 + (public_key[curve->num_bytes * 2 - 1] & 0x01); + 8006d32: eb00 0045 add.w r0, r0, r5, lsl #1 + 8006d36: f810 3c01 ldrb.w r3, [r0, #-1] + 8006d3a: f003 0301 and.w r3, r3, #1 + 8006d3e: 3302 adds r3, #2 + 8006d40: 700b strb r3, [r1, #0] +} + 8006d42: bd30 pop {r4, r5, pc} + compressed[i+1] = public_key[i]; + 8006d44: 5cc5 ldrb r5, [r0, r3] + 8006d46: 440b add r3, r1 + 8006d48: 3401 adds r4, #1 + 8006d4a: 705d strb r5, [r3, #1] + for (i = 0; i < curve->num_bytes; ++i) { + 8006d4c: e7ec b.n 8006d28 + +08006d4e : +void uECC_decompress(const uint8_t *compressed, uint8_t *public_key, uECC_Curve curve) { + 8006d4e: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + uECC_word_t *y = point + curve->num_words; + 8006d52: f992 8000 ldrsb.w r8, [r2] +void uECC_decompress(const uint8_t *compressed, uint8_t *public_key, uECC_Curve curve) { + 8006d56: b090 sub sp, #64 ; 0x40 + 8006d58: 4614 mov r4, r2 + 8006d5a: 4607 mov r7, r0 + uECC_vli_bytesToNative(point, compressed + 1, curve->num_bytes); + 8006d5c: f992 2001 ldrsb.w r2, [r2, #1] + uECC_word_t *y = point + curve->num_words; + 8006d60: eb0d 0588 add.w r5, sp, r8, lsl #2 +void uECC_decompress(const uint8_t *compressed, uint8_t *public_key, uECC_Curve curve) { + 8006d64: 460e mov r6, r1 + uECC_vli_bytesToNative(point, compressed + 1, curve->num_bytes); + 8006d66: 1c41 adds r1, r0, #1 + 8006d68: 4668 mov r0, sp + 8006d6a: f7fe ff63 bl 8005c34 + curve->x_side(y, point, curve); + 8006d6e: 4622 mov r2, r4 + 8006d70: f8d4 30ac ldr.w r3, [r4, #172] ; 0xac + 8006d74: 4669 mov r1, sp + 8006d76: 4628 mov r0, r5 + 8006d78: 4798 blx r3 + curve->mod_sqrt(y, curve); + 8006d7a: f8d4 30a8 ldr.w r3, [r4, #168] ; 0xa8 + 8006d7e: 4621 mov r1, r4 + 8006d80: 4628 mov r0, r5 + 8006d82: 4798 blx r3 + if ((y[0] & 0x01) != (compressed[0] & 0x01)) { + 8006d84: 783b ldrb r3, [r7, #0] + 8006d86: f85d 2028 ldr.w r2, [sp, r8, lsl #2] + 8006d8a: 4053 eors r3, r2 + 8006d8c: 07db lsls r3, r3, #31 + 8006d8e: d504 bpl.n 8006d9a + uECC_vli_sub(y, curve->p, y, curve->num_words); + 8006d90: 462a mov r2, r5 + 8006d92: 1d21 adds r1, r4, #4 + 8006d94: 4628 mov r0, r5 + 8006d96: f7fe ffd1 bl 8005d3c + uECC_vli_nativeToBytes(public_key, curve->num_bytes, point); + 8006d9a: f994 1001 ldrsb.w r1, [r4, #1] + 8006d9e: 466a mov r2, sp + 8006da0: 4630 mov r0, r6 + 8006da2: f7fe ff33 bl 8005c0c + uECC_vli_nativeToBytes(public_key + curve->num_bytes, curve->num_bytes, y); + 8006da6: f994 1001 ldrsb.w r1, [r4, #1] + 8006daa: 462a mov r2, r5 + 8006dac: 1870 adds r0, r6, r1 + 8006dae: f7fe ff2d bl 8005c0c +} + 8006db2: b010 add sp, #64 ; 0x40 + 8006db4: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + +08006db8 : +int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve) { + 8006db8: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + if (EccPoint_isZero(point, curve)) { + 8006dbc: 780d ldrb r5, [r1, #0] + wordcount_t num_words = curve->num_words; + 8006dbe: f991 2000 ldrsb.w r2, [r1] +int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve) { + 8006dc2: b092 sub sp, #72 ; 0x48 + 8006dc4: 460e mov r6, r1 + if (EccPoint_isZero(point, curve)) { + 8006dc6: 0069 lsls r1, r5, #1 + 8006dc8: b249 sxtb r1, r1 +int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve) { + 8006dca: 4607 mov r7, r0 + wordcount_t num_words = curve->num_words; + 8006dcc: 9201 str r2, [sp, #4] + if (EccPoint_isZero(point, curve)) { + 8006dce: f7fe fde3 bl 8005998 + 8006dd2: 4604 mov r4, r0 + 8006dd4: bb80 cbnz r0, 8006e38 + if (uECC_vli_cmp_unsafe(curve->p, point, num_words) != 1 || + 8006dd6: f106 0804 add.w r8, r6, #4 + 8006dda: 9a01 ldr r2, [sp, #4] + 8006ddc: 4639 mov r1, r7 + 8006dde: 4640 mov r0, r8 + 8006de0: f7fe fe1f bl 8005a22 + 8006de4: 2801 cmp r0, #1 + 8006de6: d11a bne.n 8006e1e + uECC_vli_cmp_unsafe(curve->p, point + num_words, num_words) != 1) { + 8006de8: 9a01 ldr r2, [sp, #4] + 8006dea: 4640 mov r0, r8 + 8006dec: eb07 0182 add.w r1, r7, r2, lsl #2 + 8006df0: f7fe fe17 bl 8005a22 + if (uECC_vli_cmp_unsafe(curve->p, point, num_words) != 1 || + 8006df4: 2801 cmp r0, #1 + 8006df6: d112 bne.n 8006e1e + uECC_vli_modSquare_fast(tmp1, point + num_words, curve); + 8006df8: 4632 mov r2, r6 + 8006dfa: a802 add r0, sp, #8 + curve->x_side(tmp2, point, curve); /* tmp2 = x^3 + ax + b */ + 8006dfc: f10d 0828 add.w r8, sp, #40 ; 0x28 + uECC_vli_modSquare_fast(tmp1, point + num_words, curve); + 8006e00: f7fe fee1 bl 8005bc6 + curve->x_side(tmp2, point, curve); /* tmp2 = x^3 + ax + b */ + 8006e04: f8d6 30ac ldr.w r3, [r6, #172] ; 0xac + 8006e08: 4632 mov r2, r6 + 8006e0a: 4639 mov r1, r7 + 8006e0c: 4640 mov r0, r8 + 8006e0e: 4798 blx r3 + for (i = num_words - 1; i >= 0; --i) { + 8006e10: 1e6b subs r3, r5, #1 + 8006e12: b25b sxtb r3, r3 + 8006e14: 061a lsls r2, r3, #24 + 8006e16: d506 bpl.n 8006e26 + return (diff == 0); + 8006e18: fab4 f484 clz r4, r4 + 8006e1c: 0964 lsrs r4, r4, #5 +} + 8006e1e: 4620 mov r0, r4 + 8006e20: b012 add sp, #72 ; 0x48 + 8006e22: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + diff |= (left[i] ^ right[i]); + 8006e26: aa02 add r2, sp, #8 + 8006e28: f858 1023 ldr.w r1, [r8, r3, lsl #2] + 8006e2c: f852 2023 ldr.w r2, [r2, r3, lsl #2] + 8006e30: 404a eors r2, r1 + 8006e32: 4314 orrs r4, r2 + for (i = num_words - 1; i >= 0; --i) { + 8006e34: 3b01 subs r3, #1 + 8006e36: e7ed b.n 8006e14 + return 0; + 8006e38: 2400 movs r4, #0 + 8006e3a: e7f0 b.n 8006e1e + +08006e3c : +int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve) { + 8006e3c: b530 push {r4, r5, lr} + 8006e3e: 460c mov r4, r1 + 8006e40: b091 sub sp, #68 ; 0x44 + uECC_vli_bytesToNative(public, public_key, curve->num_bytes); + 8006e42: f991 2001 ldrsb.w r2, [r1, #1] +int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve) { + 8006e46: 4605 mov r5, r0 + uECC_vli_bytesToNative(public, public_key, curve->num_bytes); + 8006e48: 4601 mov r1, r0 + 8006e4a: 4668 mov r0, sp + 8006e4c: f7fe fef2 bl 8005c34 + public + curve->num_words, public_key + curve->num_bytes, curve->num_bytes); + 8006e50: f994 2001 ldrsb.w r2, [r4, #1] + 8006e54: f994 0000 ldrsb.w r0, [r4] + uECC_vli_bytesToNative( + 8006e58: 18a9 adds r1, r5, r2 + 8006e5a: eb0d 0080 add.w r0, sp, r0, lsl #2 + 8006e5e: f7fe fee9 bl 8005c34 + return uECC_valid_point(public, curve); + 8006e62: 4621 mov r1, r4 + 8006e64: 4668 mov r0, sp + 8006e66: f7ff ffa7 bl 8006db8 +} + 8006e6a: b011 add sp, #68 ; 0x44 + 8006e6c: bd30 pop {r4, r5, pc} + +08006e6e : +int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve) { + 8006e6e: b570 push {r4, r5, r6, lr} + uECC_vli_bytesToNative(private, private_key, BITS_TO_BYTES(curve->num_n_bits)); + 8006e70: f9b2 3002 ldrsh.w r3, [r2, #2] +int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve) { + 8006e74: 4614 mov r4, r2 + uECC_vli_bytesToNative(private, private_key, BITS_TO_BYTES(curve->num_n_bits)); + 8006e76: 1dda adds r2, r3, #7 + 8006e78: bf48 it mi + 8006e7a: f103 020e addmi.w r2, r3, #14 +int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve) { + 8006e7e: b098 sub sp, #96 ; 0x60 + uECC_vli_bytesToNative(private, private_key, BITS_TO_BYTES(curve->num_n_bits)); + 8006e80: 10d2 asrs r2, r2, #3 +int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve) { + 8006e82: 460e mov r6, r1 + uECC_vli_bytesToNative(private, private_key, BITS_TO_BYTES(curve->num_n_bits)); + 8006e84: 4601 mov r1, r0 + 8006e86: 4668 mov r0, sp + 8006e88: f7fe fed4 bl 8005c34 + if (uECC_vli_isZero(private, BITS_TO_WORDS(curve->num_n_bits))) { + 8006e8c: f9b4 3002 ldrsh.w r3, [r4, #2] + 8006e90: f113 021f adds.w r2, r3, #31 + 8006e94: bf48 it mi + 8006e96: f103 023e addmi.w r2, r3, #62 ; 0x3e + 8006e9a: f342 1147 sbfx r1, r2, #5, #8 + 8006e9e: 4668 mov r0, sp + 8006ea0: f7fe fd7a bl 8005998 + 8006ea4: b110 cbz r0, 8006eac + return 0; + 8006ea6: 2000 movs r0, #0 +} + 8006ea8: b018 add sp, #96 ; 0x60 + 8006eaa: bd70 pop {r4, r5, r6, pc} + if (uECC_vli_cmp(curve->n, private, BITS_TO_WORDS(curve->num_n_bits)) != 1) { + 8006eac: 460a mov r2, r1 + 8006eae: f104 0024 add.w r0, r4, #36 ; 0x24 + 8006eb2: 4669 mov r1, sp + 8006eb4: f7fe ffb0 bl 8005e18 + 8006eb8: 2801 cmp r0, #1 + 8006eba: 4605 mov r5, r0 + 8006ebc: d1f3 bne.n 8006ea6 + if (!EccPoint_compute_public_key(public, private, curve)) { + 8006ebe: 4622 mov r2, r4 + 8006ec0: 4669 mov r1, sp + 8006ec2: a808 add r0, sp, #32 + 8006ec4: f7ff fc35 bl 8006732 + 8006ec8: 2800 cmp r0, #0 + 8006eca: d0ec beq.n 8006ea6 + uECC_vli_nativeToBytes(public_key, curve->num_bytes, public); + 8006ecc: f994 1001 ldrsb.w r1, [r4, #1] + 8006ed0: aa08 add r2, sp, #32 + 8006ed2: 4630 mov r0, r6 + 8006ed4: f7fe fe9a bl 8005c0c + public_key + curve->num_bytes, curve->num_bytes, public + curve->num_words); + 8006ed8: f994 1001 ldrsb.w r1, [r4, #1] + 8006edc: f994 2000 ldrsb.w r2, [r4] + uECC_vli_nativeToBytes( + 8006ee0: ab08 add r3, sp, #32 + 8006ee2: 1870 adds r0, r6, r1 + 8006ee4: eb03 0282 add.w r2, r3, r2, lsl #2 + 8006ee8: f7fe fe90 bl 8005c0c + return 1; + 8006eec: 4628 mov r0, r5 + 8006eee: e7db b.n 8006ea8 + +08006ef0 : + uECC_Curve curve) { + 8006ef0: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + 8006ef4: b08a sub sp, #40 ; 0x28 + 8006ef6: 4605 mov r5, r0 + 8006ef8: f8dd 9048 ldr.w r9, [sp, #72] ; 0x48 + 8006efc: 460e mov r6, r1 + 8006efe: 4617 mov r7, r2 + 8006f00: 4698 mov r8, r3 + 8006f02: 2440 movs r4, #64 ; 0x40 + if (!uECC_generate_random_int(k, curve->n, BITS_TO_WORDS(curve->num_n_bits))) { + 8006f04: f109 0a24 add.w sl, r9, #36 ; 0x24 + 8006f08: f9b9 3002 ldrsh.w r3, [r9, #2] + 8006f0c: f113 021f adds.w r2, r3, #31 + 8006f10: bf48 it mi + 8006f12: f103 023e addmi.w r2, r3, #62 ; 0x3e + 8006f16: f342 1247 sbfx r2, r2, #5, #8 + 8006f1a: 4651 mov r1, sl + 8006f1c: a802 add r0, sp, #8 + 8006f1e: f7fe ff93 bl 8005e48 + 8006f22: b150 cbz r0, 8006f3a + if (uECC_sign_with_k(private_key, message_hash, hash_size, k, signature, curve)) { + 8006f24: e9cd 8900 strd r8, r9, [sp] + 8006f28: ab02 add r3, sp, #8 + 8006f2a: 463a mov r2, r7 + 8006f2c: 4631 mov r1, r6 + 8006f2e: 4628 mov r0, r5 + 8006f30: f7ff fc2a bl 8006788 + 8006f34: b928 cbnz r0, 8006f42 + for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { + 8006f36: 3c01 subs r4, #1 + 8006f38: d1e6 bne.n 8006f08 + return 0; + 8006f3a: 2000 movs r0, #0 +} + 8006f3c: b00a add sp, #40 ; 0x28 + 8006f3e: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + return 1; + 8006f42: 2001 movs r0, #1 + 8006f44: e7fa b.n 8006f3c + +08006f46 : +int uECC_sign_deterministic(const uint8_t *private_key, + const uint8_t *message_hash, + unsigned hash_size, + uECC_HashContext *hash_context, + uint8_t *signature, + uECC_Curve curve) { + 8006f46: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + 8006f4a: b091 sub sp, #68 ; 0x44 + 8006f4c: 4693 mov fp, r2 + uint8_t *K = hash_context->tmp; + uint8_t *V = K + hash_context->result_size; + wordcount_t num_bytes = curve->num_bytes; + wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); + 8006f4e: 9a1b ldr r2, [sp, #108] ; 0x6c + 8006f50: f9b2 8002 ldrsh.w r8, [r2, #2] + uint8_t *V = K + hash_context->result_size; + 8006f54: e9d3 6504 ldrd r6, r5, [r3, #16] + uECC_Curve curve) { + 8006f58: 461c mov r4, r3 + wordcount_t num_bytes = curve->num_bytes; + 8006f5a: 9b1b ldr r3, [sp, #108] ; 0x6c + wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); + 8006f5c: f118 071f adds.w r7, r8, #31 + 8006f60: bf48 it mi + 8006f62: f108 073e addmi.w r7, r8, #62 ; 0x3e + bitcount_t num_n_bits = curve->num_n_bits; + uECC_word_t tries; + unsigned i; + for (i = 0; i < hash_context->result_size; ++i) { + 8006f66: 2200 movs r2, #0 + wordcount_t num_bytes = curve->num_bytes; + 8006f68: f993 3001 ldrsb.w r3, [r3, #1] + uECC_Curve curve) { + 8006f6c: 4681 mov r9, r0 + 8006f6e: 468a mov sl, r1 + uint8_t *V = K + hash_context->result_size; + 8006f70: 442e add r6, r5 + wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); + 8006f72: f347 1747 sbfx r7, r7, #5, #8 + V[i] = 0x01; + 8006f76: 2001 movs r0, #1 + K[i] = 0; + 8006f78: 4694 mov ip, r2 + for (i = 0; i < hash_context->result_size; ++i) { + 8006f7a: 6921 ldr r1, [r4, #16] + 8006f7c: 4291 cmp r1, r2 + 8006f7e: f200 8086 bhi.w 800708e + } + + /* K = HMAC_K(V || 0x00 || int2octets(x) || h(m)) */ + HMAC_init(hash_context, K); + 8006f82: 4629 mov r1, r5 + 8006f84: 4620 mov r0, r4 + 8006f86: 9303 str r3, [sp, #12] + 8006f88: f7fe fe74 bl 8005c74 + V[hash_context->result_size] = 0x00; + 8006f8c: 6922 ldr r2, [r4, #16] + 8006f8e: 2100 movs r1, #0 + 8006f90: 54b1 strb r1, [r6, r2] + HMAC_update(hash_context, V, hash_context->result_size + 1); + 8006f92: 6922 ldr r2, [r4, #16] + 8006f94: 4631 mov r1, r6 + 8006f96: 3201 adds r2, #1 + 8006f98: 4620 mov r0, r4 + 8006f9a: f7fe fe8c bl 8005cb6 + HMAC_update(hash_context, private_key, num_bytes); + 8006f9e: 9b03 ldr r3, [sp, #12] + 8006fa0: 4649 mov r1, r9 + 8006fa2: 461a mov r2, r3 + 8006fa4: 4620 mov r0, r4 + 8006fa6: f7fe fe86 bl 8005cb6 + HMAC_update(hash_context, message_hash, hash_size); + 8006faa: 465a mov r2, fp + 8006fac: 4651 mov r1, sl + 8006fae: 4620 mov r0, r4 + 8006fb0: f7fe fe81 bl 8005cb6 + HMAC_finish(hash_context, K, K); + 8006fb4: 462a mov r2, r5 + 8006fb6: 4629 mov r1, r5 + 8006fb8: 4620 mov r0, r4 + 8006fba: f7fe fe7e bl 8005cba + + update_V(hash_context, K, V); + 8006fbe: 4632 mov r2, r6 + 8006fc0: 4629 mov r1, r5 + 8006fc2: 4620 mov r0, r4 + 8006fc4: f7fe fea8 bl 8005d18 + + /* K = HMAC_K(V || 0x01 || int2octets(x) || h(m)) */ + HMAC_init(hash_context, K); + 8006fc8: 4629 mov r1, r5 + 8006fca: 4620 mov r0, r4 + 8006fcc: f7fe fe52 bl 8005c74 + V[hash_context->result_size] = 0x01; + 8006fd0: 6922 ldr r2, [r4, #16] + 8006fd2: 2101 movs r1, #1 + 8006fd4: 54b1 strb r1, [r6, r2] + HMAC_update(hash_context, V, hash_context->result_size + 1); + 8006fd6: 6922 ldr r2, [r4, #16] + 8006fd8: 4620 mov r0, r4 + 8006fda: 440a add r2, r1 + 8006fdc: 4631 mov r1, r6 + 8006fde: f7fe fe6a bl 8005cb6 + HMAC_update(hash_context, private_key, num_bytes); + 8006fe2: 9b03 ldr r3, [sp, #12] + 8006fe4: 4649 mov r1, r9 + 8006fe6: 461a mov r2, r3 + 8006fe8: 4620 mov r0, r4 + 8006fea: f7fe fe64 bl 8005cb6 + HMAC_update(hash_context, message_hash, hash_size); + 8006fee: 465a mov r2, fp + 8006ff0: 4651 mov r1, sl + 8006ff2: 4620 mov r0, r4 + 8006ff4: f7fe fe5f bl 8005cb6 + HMAC_finish(hash_context, K, K); + 8006ff8: 462a mov r2, r5 + 8006ffa: 4629 mov r1, r5 + 8006ffc: 4620 mov r0, r4 + 8006ffe: f7fe fe5c bl 8005cba + + update_V(hash_context, K, V); + 8007002: 4632 mov r2, r6 + 8007004: 4629 mov r1, r5 + 8007006: 4620 mov r0, r4 + 8007008: f7fe fe86 bl 8005d18 + wordcount_t T_bytes = 0; + for (;;) { + update_V(hash_context, K, V); + for (i = 0; i < hash_context->result_size; ++i) { + T_ptr[T_bytes++] = V[i]; + if (T_bytes >= num_n_words * uECC_WORD_SIZE) { + 800700c: 00bb lsls r3, r7, #2 + 800700e: 9304 str r3, [sp, #16] + goto filled; + } + } + } + filled: + if ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8 > num_n_bits) { + 8007010: 017b lsls r3, r7, #5 + 8007012: 9305 str r3, [sp, #20] + uECC_word_t mask = (uECC_word_t)-1; + T[num_n_words - 1] &= + mask >> ((bitcount_t)(num_n_words * uECC_WORD_SIZE * 8 - num_n_bits)); + 8007014: ebc8 1347 rsb r3, r8, r7, lsl #5 + 8007018: f04f 32ff mov.w r2, #4294967295 ; 0xffffffff + 800701c: b21b sxth r3, r3 + 800701e: fa22 f303 lsr.w r3, r2, r3 + 8007022: 9306 str r3, [sp, #24] + 8007024: 2340 movs r3, #64 ; 0x40 + 8007026: 9303 str r3, [sp, #12] + T[num_n_words - 1] &= + 8007028: 4417 add r7, r2 + 800702a: 446b add r3, sp + 800702c: eb03 0787 add.w r7, r3, r7, lsl #2 + wordcount_t T_bytes = 0; + 8007030: 2300 movs r3, #0 + update_V(hash_context, K, V); + 8007032: 4632 mov r2, r6 + 8007034: 4629 mov r1, r5 + 8007036: 4620 mov r0, r4 + 8007038: 9307 str r3, [sp, #28] + 800703a: f7fe fe6d bl 8005d18 + for (i = 0; i < hash_context->result_size; ++i) { + 800703e: 6920 ldr r0, [r4, #16] + 8007040: 9b07 ldr r3, [sp, #28] + 8007042: 4631 mov r1, r6 + 8007044: 4430 add r0, r6 + 8007046: 461a mov r2, r3 + T_ptr[T_bytes++] = V[i]; + 8007048: ab08 add r3, sp, #32 + 800704a: eb03 0c02 add.w ip, r3, r2 + for (i = 0; i < hash_context->result_size; ++i) { + 800704e: 4288 cmp r0, r1 + 8007050: 4613 mov r3, r2 + 8007052: f102 0201 add.w r2, r2, #1 + 8007056: b252 sxtb r2, r2 + 8007058: d0eb beq.n 8007032 + T_ptr[T_bytes++] = V[i]; + 800705a: f811 3b01 ldrb.w r3, [r1], #1 + 800705e: f88c 3000 strb.w r3, [ip] + if (T_bytes >= num_n_words * uECC_WORD_SIZE) { + 8007062: 9b04 ldr r3, [sp, #16] + 8007064: 4293 cmp r3, r2 + 8007066: dcef bgt.n 8007048 + if ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8 > num_n_bits) { + 8007068: 9b05 ldr r3, [sp, #20] + 800706a: 4598 cmp r8, r3 + 800706c: db14 blt.n 8007098 + } + + if (uECC_sign_with_k(private_key, message_hash, hash_size, T, signature, curve)) { + 800706e: 9b1b ldr r3, [sp, #108] ; 0x6c + 8007070: 9301 str r3, [sp, #4] + 8007072: 9b1a ldr r3, [sp, #104] ; 0x68 + 8007074: 9300 str r3, [sp, #0] + 8007076: 465a mov r2, fp + 8007078: ab08 add r3, sp, #32 + 800707a: 4651 mov r1, sl + 800707c: 4648 mov r0, r9 + 800707e: f7ff fb83 bl 8006788 + 8007082: b180 cbz r0, 80070a6 + return 1; + 8007084: 2301 movs r3, #1 + HMAC_finish(hash_context, K, K); + + update_V(hash_context, K, V); + } + return 0; +} + 8007086: 4618 mov r0, r3 + 8007088: b011 add sp, #68 ; 0x44 + 800708a: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + V[i] = 0x01; + 800708e: 54b0 strb r0, [r6, r2] + K[i] = 0; + 8007090: f805 c002 strb.w ip, [r5, r2] + for (i = 0; i < hash_context->result_size; ++i) { + 8007094: 3201 adds r2, #1 + 8007096: e770 b.n 8006f7a + T[num_n_words - 1] &= + 8007098: f857 3c20 ldr.w r3, [r7, #-32] + 800709c: 9a06 ldr r2, [sp, #24] + 800709e: 4013 ands r3, r2 + 80070a0: f847 3c20 str.w r3, [r7, #-32] + 80070a4: e7e3 b.n 800706e + 80070a6: 9007 str r0, [sp, #28] + HMAC_init(hash_context, K); + 80070a8: 4629 mov r1, r5 + 80070aa: 4620 mov r0, r4 + 80070ac: f7fe fde2 bl 8005c74 + V[hash_context->result_size] = 0x00; + 80070b0: 6922 ldr r2, [r4, #16] + 80070b2: 9b07 ldr r3, [sp, #28] + 80070b4: 54b3 strb r3, [r6, r2] + HMAC_update(hash_context, V, hash_context->result_size + 1); + 80070b6: 6922 ldr r2, [r4, #16] + 80070b8: 4631 mov r1, r6 + 80070ba: 3201 adds r2, #1 + 80070bc: 4620 mov r0, r4 + 80070be: f7fe fdfa bl 8005cb6 + HMAC_finish(hash_context, K, K); + 80070c2: 462a mov r2, r5 + 80070c4: 4629 mov r1, r5 + 80070c6: 4620 mov r0, r4 + 80070c8: f7fe fdf7 bl 8005cba + update_V(hash_context, K, V); + 80070cc: 4632 mov r2, r6 + 80070ce: 4629 mov r1, r5 + 80070d0: 4620 mov r0, r4 + 80070d2: f7fe fe21 bl 8005d18 + for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { + 80070d6: 9b03 ldr r3, [sp, #12] + 80070d8: 3b01 subs r3, #1 + 80070da: 9303 str r3, [sp, #12] + 80070dc: 9b07 ldr r3, [sp, #28] + 80070de: d1a7 bne.n 8007030 + 80070e0: e7d1 b.n 8007086 + +080070e2 : + +int uECC_verify(const uint8_t *public_key, + const uint8_t *message_hash, + unsigned hash_size, + const uint8_t *signature, + uECC_Curve curve) { + 80070e2: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + 80070e6: ed2d 8b02 vpush {d8} + 80070ea: b0fb sub sp, #492 ; 0x1ec + 80070ec: 461c mov r4, r3 + 80070ee: 9d86 ldr r5, [sp, #536] ; 0x218 + const uECC_word_t *point; + bitcount_t num_bits; + bitcount_t i; + uECC_word_t r[uECC_MAX_WORDS], s[uECC_MAX_WORDS]; + wordcount_t num_words = curve->num_words; + wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); + 80070f0: f9b5 3002 ldrsh.w r3, [r5, #2] + wordcount_t num_words = curve->num_words; + 80070f4: f995 8000 ldrsb.w r8, [r5] + wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); + 80070f8: f113 061f adds.w r6, r3, #31 + 80070fc: bf48 it mi + 80070fe: f103 063e addmi.w r6, r3, #62 ; 0x3e + 8007102: f346 1647 sbfx r6, r6, #5, #8 + + rx[num_n_words - 1] = 0; + 8007106: f106 3aff add.w sl, r6, #4294967295 ; 0xffffffff + uECC_Curve curve) { + 800710a: 4691 mov r9, r2 + rx[num_n_words - 1] = 0; + 800710c: aa22 add r2, sp, #136 ; 0x88 + 800710e: 2300 movs r3, #0 + 8007110: f842 302a str.w r3, [r2, sl, lsl #2] + r[num_n_words - 1] = 0; + 8007114: aa7a add r2, sp, #488 ; 0x1e8 + 8007116: eb02 028a add.w r2, r2, sl, lsl #2 + uECC_Curve curve) { + 800711a: 4607 mov r7, r0 + r[num_n_words - 1] = 0; + 800711c: f842 3cc0 str.w r3, [r2, #-192] + s[num_n_words - 1] = 0; + 8007120: f842 3ca0 str.w r3, [r2, #-160] + uECC_Curve curve) { + 8007124: ee08 1a90 vmov s17, r1 + + uECC_vli_bytesToNative(public, public_key, curve->num_bytes); + 8007128: f995 2001 ldrsb.w r2, [r5, #1] + 800712c: 4601 mov r1, r0 + 800712e: a85a add r0, sp, #360 ; 0x168 + 8007130: f7fe fd80 bl 8005c34 + uECC_vli_bytesToNative( + public + num_words, public_key + curve->num_bytes, curve->num_bytes); + 8007134: ea4f 0388 mov.w r3, r8, lsl #2 + 8007138: f995 2001 ldrsb.w r2, [r5, #1] + 800713c: 9304 str r3, [sp, #16] + uECC_vli_bytesToNative( + 800713e: ab5a add r3, sp, #360 ; 0x168 + 8007140: eb03 0388 add.w r3, r3, r8, lsl #2 + 8007144: 4618 mov r0, r3 + 8007146: 18b9 adds r1, r7, r2 + 8007148: ee08 3a10 vmov s16, r3 + 800714c: f7fe fd72 bl 8005c34 + uECC_vli_bytesToNative(r, signature, curve->num_bytes); + 8007150: 4621 mov r1, r4 + 8007152: f995 2001 ldrsb.w r2, [r5, #1] + 8007156: a84a add r0, sp, #296 ; 0x128 + 8007158: f7fe fd6c bl 8005c34 + uECC_vli_bytesToNative(s, signature + curve->num_bytes, curve->num_bytes); + 800715c: f995 2001 ldrsb.w r2, [r5, #1] + 8007160: a852 add r0, sp, #328 ; 0x148 + 8007162: 18a1 adds r1, r4, r2 + 8007164: f7fe fd66 bl 8005c34 + + /* r, s must not be 0. */ + if (uECC_vli_isZero(r, num_words) || uECC_vli_isZero(s, num_words)) { + 8007168: 4641 mov r1, r8 + 800716a: a84a add r0, sp, #296 ; 0x128 + 800716c: f7fe fc14 bl 8005998 + 8007170: 2300 movs r3, #0 + 8007172: 4604 mov r4, r0 + 8007174: 2800 cmp r0, #0 + 8007176: f040 812b bne.w 80073d0 + 800717a: a852 add r0, sp, #328 ; 0x148 + 800717c: f7fe fc0c bl 8005998 + 8007180: 9002 str r0, [sp, #8] + 8007182: 2800 cmp r0, #0 + 8007184: f040 8126 bne.w 80073d4 + return 0; + } + + /* r, s must be < n. */ + if (uECC_vli_cmp_unsafe(curve->n, r, num_n_words) != 1 || + 8007188: f105 0b24 add.w fp, r5, #36 ; 0x24 + 800718c: 4632 mov r2, r6 + 800718e: a94a add r1, sp, #296 ; 0x128 + 8007190: 4658 mov r0, fp + 8007192: f7fe fc46 bl 8005a22 + 8007196: 2801 cmp r0, #1 + 8007198: f040 811e bne.w 80073d8 + uECC_vli_cmp_unsafe(curve->n, s, num_n_words) != 1) { + 800719c: 4632 mov r2, r6 + 800719e: a952 add r1, sp, #328 ; 0x148 + 80071a0: 4658 mov r0, fp + 80071a2: f7fe fc3e bl 8005a22 + if (uECC_vli_cmp_unsafe(curve->n, r, num_n_words) != 1 || + 80071a6: 2801 cmp r0, #1 + uECC_vli_cmp_unsafe(curve->n, s, num_n_words) != 1) { + 80071a8: 9005 str r0, [sp, #20] + if (uECC_vli_cmp_unsafe(curve->n, r, num_n_words) != 1 || + 80071aa: f040 8115 bne.w 80073d8 + return 0; + } + + /* Calculate u1 and u2. */ + uECC_vli_modInv(z, s, curve->n, num_n_words); /* z = 1/s */ + 80071ae: ac1a add r4, sp, #104 ; 0x68 + u1[num_n_words - 1] = 0; + 80071b0: af0a add r7, sp, #40 ; 0x28 + uECC_vli_modInv(z, s, curve->n, num_n_words); /* z = 1/s */ + 80071b2: 4633 mov r3, r6 + 80071b4: 465a mov r2, fp + 80071b6: 4620 mov r0, r4 + 80071b8: f7ff f84e bl 8006258 + u1[num_n_words - 1] = 0; + 80071bc: 9b02 ldr r3, [sp, #8] + 80071be: f847 302a str.w r3, [r7, sl, lsl #2] + bits2int(u1, message_hash, hash_size, curve); + 80071c2: 464a mov r2, r9 + 80071c4: 4638 mov r0, r7 + 80071c6: ee18 1a90 vmov r1, s17 + 80071ca: 462b mov r3, r5 + 80071cc: f7fe fddd bl 8005d8a + uECC_vli_modMult(u1, u1, z, curve->n, num_n_words); /* u1 = e/s */ + 80071d0: 4639 mov r1, r7 + 80071d2: 4638 mov r0, r7 + 80071d4: 465b mov r3, fp + 80071d6: 4622 mov r2, r4 + 80071d8: 9600 str r6, [sp, #0] + 80071da: f7fe fc44 bl 8005a66 + uECC_vli_modMult(u2, r, z, curve->n, num_n_words); /* u2 = r/s */ + + /* Calculate sum = G + Q. */ + uECC_vli_set(sum, public, num_words); + 80071de: f50d 7ad4 add.w sl, sp, #424 ; 0x1a8 + uECC_vli_modMult(u2, r, z, curve->n, num_n_words); /* u2 = r/s */ + 80071e2: 465b mov r3, fp + 80071e4: 4622 mov r2, r4 + 80071e6: a94a add r1, sp, #296 ; 0x128 + 80071e8: a812 add r0, sp, #72 ; 0x48 + 80071ea: 9600 str r6, [sp, #0] + 80071ec: f7fe fc3b bl 8005a66 + uECC_vli_set(sum, public, num_words); + 80071f0: 4642 mov r2, r8 + 80071f2: 4650 mov r0, sl + 80071f4: a95a add r1, sp, #360 ; 0x168 + 80071f6: f7fe fc08 bl 8005a0a + uECC_vli_set(sum + num_words, public + num_words, num_words); + 80071fa: 9b04 ldr r3, [sp, #16] + 80071fc: eb0a 0903 add.w r9, sl, r3 + 8007200: ee18 1a10 vmov r1, s16 + 8007204: 4648 mov r0, r9 + 8007206: f7fe fc00 bl 8005a0a + uECC_vli_set(tx, curve->G, num_words); + 800720a: f105 0344 add.w r3, r5, #68 ; 0x44 + 800720e: 4619 mov r1, r3 + 8007210: a832 add r0, sp, #200 ; 0xc8 + 8007212: 9303 str r3, [sp, #12] + 8007214: f7fe fbf9 bl 8005a0a + uECC_vli_set(ty, curve->G + num_words, num_words); + 8007218: e9dd 3103 ldrd r3, r1, [sp, #12] + 800721c: a83a add r0, sp, #232 ; 0xe8 + 800721e: 1859 adds r1, r3, r1 + 8007220: f7fe fbf3 bl 8005a0a + uECC_vli_modSub(z, sum, tx, curve->p, num_words); /* z = x2 - x1 */ + 8007224: 1d2b adds r3, r5, #4 + 8007226: ee08 3a10 vmov s16, r3 + 800722a: 4651 mov r1, sl + 800722c: aa32 add r2, sp, #200 ; 0xc8 + 800722e: 4620 mov r0, r4 + 8007230: f7ff f8c0 bl 80063b4 + XYcZ_add(tx, ty, sum, sum + num_words, curve); + 8007234: 464b mov r3, r9 + 8007236: 4652 mov r2, sl + 8007238: a93a add r1, sp, #232 ; 0xe8 + 800723a: a832 add r0, sp, #200 ; 0xc8 + 800723c: 9500 str r5, [sp, #0] + 800723e: f7ff f94d bl 80064dc + uECC_vli_modInv(z, z, curve->p, num_words); /* z = 1/z */ + 8007242: ee18 2a10 vmov r2, s16 + 8007246: 4643 mov r3, r8 + 8007248: 4621 mov r1, r4 + 800724a: 4620 mov r0, r4 + 800724c: f7ff f804 bl 8006258 + apply_z(sum, sum + num_words, z, curve); + 8007250: 462b mov r3, r5 + 8007252: 4649 mov r1, r9 + 8007254: 4650 mov r0, sl + 8007256: 4622 mov r2, r4 + 8007258: f7fe fcb9 bl 8005bce + + /* Use Shamir's trick to calculate u1*G + u2*Q */ + points[0] = 0; + 800725c: 9a02 ldr r2, [sp, #8] + 800725e: 9206 str r2, [sp, #24] + points[1] = curve->G; + 8007260: 9a03 ldr r2, [sp, #12] + 8007262: 9207 str r2, [sp, #28] + points[2] = public; + points[3] = sum; + num_bits = smax(uECC_vli_numBits(u1, num_n_words), + 8007264: 4631 mov r1, r6 + points[2] = public; + 8007266: aa5a add r2, sp, #360 ; 0x168 + num_bits = smax(uECC_vli_numBits(u1, num_n_words), + 8007268: 4638 mov r0, r7 + points[3] = sum; + 800726a: e9cd 2a08 strd r2, sl, [sp, #32] + num_bits = smax(uECC_vli_numBits(u1, num_n_words), + 800726e: f7fe fbac bl 80059ca + 8007272: 4631 mov r1, r6 + 8007274: 4682 mov sl, r0 + 8007276: a812 add r0, sp, #72 ; 0x48 + 8007278: f7fe fba7 bl 80059ca + return (a > b ? a : b); + 800727c: 4550 cmp r0, sl + 800727e: bfb8 it lt + 8007280: 4650 movlt r0, sl + uECC_vli_numBits(u2, num_n_words)); + + point = points[(!!uECC_vli_testBit(u1, num_bits - 1)) | + 8007282: fa1f f980 uxth.w r9, r0 + 8007286: f109 31ff add.w r1, r9, #4294967295 ; 0xffffffff + 800728a: b209 sxth r1, r1 + 800728c: 4638 mov r0, r7 + 800728e: 9103 str r1, [sp, #12] + 8007290: f7fe fb91 bl 80059b6 + ((!!uECC_vli_testBit(u2, num_bits - 1)) << 1)]; + 8007294: 9903 ldr r1, [sp, #12] + point = points[(!!uECC_vli_testBit(u1, num_bits - 1)) | + 8007296: 1e07 subs r7, r0, #0 + ((!!uECC_vli_testBit(u2, num_bits - 1)) << 1)]; + 8007298: a812 add r0, sp, #72 ; 0x48 + point = points[(!!uECC_vli_testBit(u1, num_bits - 1)) | + 800729a: bf18 it ne + 800729c: 2701 movne r7, #1 + ((!!uECC_vli_testBit(u2, num_bits - 1)) << 1)]; + 800729e: f7fe fb8a bl 80059b6 + 80072a2: 2800 cmp r0, #0 + 80072a4: bf14 ite ne + 80072a6: 2002 movne r0, #2 + 80072a8: 2000 moveq r0, #0 + point = points[(!!uECC_vli_testBit(u1, num_bits - 1)) | + 80072aa: ab06 add r3, sp, #24 + 80072ac: 4307 orrs r7, r0 + uECC_vli_set(rx, point, num_words); + 80072ae: 4642 mov r2, r8 + point = points[(!!uECC_vli_testBit(u1, num_bits - 1)) | + 80072b0: f853 1027 ldr.w r1, [r3, r7, lsl #2] + uECC_vli_set(rx, point, num_words); + 80072b4: a822 add r0, sp, #136 ; 0x88 + 80072b6: f7fe fba8 bl 8005a0a + uECC_vli_set(ry, point + num_words, num_words); + 80072ba: 9b04 ldr r3, [sp, #16] + 80072bc: f10d 0aa8 add.w sl, sp, #168 ; 0xa8 + 80072c0: 4419 add r1, r3 + 80072c2: 4650 mov r0, sl + 80072c4: f7fe fba1 bl 8005a0a + uECC_vli_clear(z, num_words); + 80072c8: 4641 mov r1, r8 + 80072ca: 4620 mov r0, r4 + 80072cc: f7fe fb5e bl 800598c + z[0] = 1; + 80072d0: 9b05 ldr r3, [sp, #20] + 80072d2: 6023 str r3, [r4, #0] + + for (i = num_bits - 2; i >= 0; --i) { + 80072d4: f1a9 0902 sub.w r9, r9, #2 + 80072d8: ab22 add r3, sp, #136 ; 0x88 + 80072da: fa0f f989 sxth.w r9, r9 + 80072de: 9303 str r3, [sp, #12] + 80072e0: f1b9 0f00 cmp.w r9, #0 + 80072e4: da26 bge.n 8007334 + XYcZ_add(tx, ty, rx, ry, curve); + uECC_vli_modMult_fast(z, z, tz, curve); + } + } + + uECC_vli_modInv(z, z, curve->p, num_words); /* Z = 1/Z */ + 80072e6: ee18 2a10 vmov r2, s16 + 80072ea: 4643 mov r3, r8 + 80072ec: 4621 mov r1, r4 + 80072ee: 4620 mov r0, r4 + 80072f0: f7fe ffb2 bl 8006258 + apply_z(rx, ry, z, curve); + 80072f4: 9803 ldr r0, [sp, #12] + 80072f6: 462b mov r3, r5 + 80072f8: 4622 mov r2, r4 + 80072fa: 4651 mov r1, sl + 80072fc: f7fe fc67 bl 8005bce + + /* v = x1 (mod n) */ + if (uECC_vli_cmp_unsafe(curve->n, rx, num_n_words) != 1) { + 8007300: 9903 ldr r1, [sp, #12] + 8007302: 4632 mov r2, r6 + 8007304: 4658 mov r0, fp + 8007306: f7fe fb8c bl 8005a22 + 800730a: 2801 cmp r0, #1 + 800730c: d003 beq.n 8007316 + uECC_vli_sub(rx, rx, curve->n, num_n_words); + 800730e: 465a mov r2, fp + 8007310: 4608 mov r0, r1 + 8007312: f7fe fd13 bl 8005d3c + for (i = num_words - 1; i >= 0; --i) { + 8007316: f108 33ff add.w r3, r8, #4294967295 ; 0xffffffff + 800731a: b25b sxtb r3, r3 + diff |= (left[i] ^ right[i]); + 800731c: a94a add r1, sp, #296 ; 0x128 + for (i = num_words - 1; i >= 0; --i) { + 800731e: 061a lsls r2, r3, #24 + 8007320: d54b bpl.n 80073ba + return (diff == 0); + 8007322: 9b02 ldr r3, [sp, #8] + 8007324: fab3 f083 clz r0, r3 + 8007328: 0940 lsrs r0, r0, #5 + } + + /* Accept only if v == r. */ + return (int)(uECC_vli_equal(rx, r, num_words)); +} + 800732a: b07b add sp, #492 ; 0x1ec + 800732c: ecbd 8b02 vpop {d8} + 8007330: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + curve->double_jacobian(rx, ry, z, curve); + 8007334: 462b mov r3, r5 + 8007336: 4622 mov r2, r4 + 8007338: f8d5 70a4 ldr.w r7, [r5, #164] ; 0xa4 + 800733c: 9803 ldr r0, [sp, #12] + 800733e: 4651 mov r1, sl + 8007340: 47b8 blx r7 + index = (!!uECC_vli_testBit(u1, i)) | ((!!uECC_vli_testBit(u2, i)) << 1); + 8007342: 4649 mov r1, r9 + 8007344: a80a add r0, sp, #40 ; 0x28 + 8007346: f7fe fb36 bl 80059b6 + 800734a: 4649 mov r1, r9 + 800734c: 1e07 subs r7, r0, #0 + 800734e: a812 add r0, sp, #72 ; 0x48 + 8007350: bf18 it ne + 8007352: 2701 movne r7, #1 + 8007354: f7fe fb2f bl 80059b6 + 8007358: 2800 cmp r0, #0 + 800735a: bf14 ite ne + 800735c: 2002 movne r0, #2 + 800735e: 2000 moveq r0, #0 + 8007360: 4307 orrs r7, r0 + point = points[index]; + 8007362: ab06 add r3, sp, #24 + 8007364: f853 1027 ldr.w r1, [r3, r7, lsl #2] + if (point) { + 8007368: b311 cbz r1, 80073b0 + uECC_vli_set(tx, point, num_words); + 800736a: 4642 mov r2, r8 + 800736c: a832 add r0, sp, #200 ; 0xc8 + 800736e: f7fe fb4c bl 8005a0a + uECC_vli_set(ty, point + num_words, num_words); + 8007372: 9b04 ldr r3, [sp, #16] + 8007374: a83a add r0, sp, #232 ; 0xe8 + 8007376: 4419 add r1, r3 + 8007378: f7fe fb47 bl 8005a0a + apply_z(tx, ty, z, curve); + 800737c: 4601 mov r1, r0 + 800737e: 462b mov r3, r5 + 8007380: 4622 mov r2, r4 + 8007382: a832 add r0, sp, #200 ; 0xc8 + 8007384: f7fe fc23 bl 8005bce + uECC_vli_modSub(tz, rx, tx, curve->p, num_words); /* Z = x2 - x1 */ + 8007388: ee18 3a10 vmov r3, s16 + 800738c: 9903 ldr r1, [sp, #12] + 800738e: aa32 add r2, sp, #200 ; 0xc8 + 8007390: a842 add r0, sp, #264 ; 0x108 + 8007392: f7ff f80f bl 80063b4 + XYcZ_add(tx, ty, rx, ry, curve); + 8007396: 9a03 ldr r2, [sp, #12] + 8007398: 9500 str r5, [sp, #0] + 800739a: 4653 mov r3, sl + 800739c: a93a add r1, sp, #232 ; 0xe8 + 800739e: a832 add r0, sp, #200 ; 0xc8 + 80073a0: f7ff f89c bl 80064dc + uECC_vli_modMult_fast(z, z, tz, curve); + 80073a4: 462b mov r3, r5 + 80073a6: aa42 add r2, sp, #264 ; 0x108 + 80073a8: 4621 mov r1, r4 + 80073aa: 4620 mov r0, r4 + 80073ac: f7fe fbfb bl 8005ba6 + for (i = num_bits - 2; i >= 0; --i) { + 80073b0: f109 39ff add.w r9, r9, #4294967295 ; 0xffffffff + 80073b4: fa0f f989 sxth.w r9, r9 + 80073b8: e792 b.n 80072e0 + diff |= (left[i] ^ right[i]); + 80073ba: 9a03 ldr r2, [sp, #12] + 80073bc: f851 0023 ldr.w r0, [r1, r3, lsl #2] + 80073c0: f852 2023 ldr.w r2, [r2, r3, lsl #2] + 80073c4: 4042 eors r2, r0 + 80073c6: 9802 ldr r0, [sp, #8] + 80073c8: 4310 orrs r0, r2 + 80073ca: 9002 str r0, [sp, #8] + for (i = num_words - 1; i >= 0; --i) { + 80073cc: 3b01 subs r3, #1 + 80073ce: e7a6 b.n 800731e + return 0; + 80073d0: 4618 mov r0, r3 + 80073d2: e7aa b.n 800732a + 80073d4: 4620 mov r0, r4 + 80073d6: e7a8 b.n 800732a + 80073d8: 9802 ldr r0, [sp, #8] + 80073da: e7a6 b.n 800732a + +080073dc : +const uint32_t MSIRangeTable[12] = {100000, 200000, 400000, 800000, 1000000, 2000000, \ + 4000000, 8000000, 16000000, 24000000, 32000000, 48000000}; +uint32_t SystemCoreClock; + +// TODO: cleanup HAL stuff to not use this +uint32_t HAL_GetTick(void) { return 53; } + 80073dc: 2035 movs r0, #53 ; 0x35 + 80073de: 4770 bx lr + +080073e0 : +uint32_t uwTickPrio = 0; /* (1UL << __NVIC_PRIO_BITS); * Invalid priority */ + +// unwanted junk from stm32l4xx_hal_rcc.c +HAL_StatusTypeDef HAL_InitTick (uint32_t TickPriority) { return 0; } + 80073e0: 2000 movs r0, #0 + 80073e2: 4770 bx lr + +080073e4 : + * or PWR_REGULATOR_VOLTAGE_SCALE1_BOOST when applicable) + */ +uint32_t HAL_PWREx_GetVoltageRange(void) +{ +#if defined(PWR_CR5_R1MODE) + if (READ_BIT(PWR->CR1, PWR_CR1_VOS) == PWR_REGULATOR_VOLTAGE_SCALE2) + 80073e4: 4b07 ldr r3, [pc, #28] ; (8007404 ) + 80073e6: 6818 ldr r0, [r3, #0] + 80073e8: f400 60c0 and.w r0, r0, #1536 ; 0x600 + 80073ec: f5b0 6f80 cmp.w r0, #1024 ; 0x400 + 80073f0: d006 beq.n 8007400 + { + return PWR_REGULATOR_VOLTAGE_SCALE2; + } + else if (READ_BIT(PWR->CR5, PWR_CR5_R1MODE) == PWR_CR5_R1MODE) + 80073f2: f8d3 0080 ldr.w r0, [r3, #128] ; 0x80 + { + /* PWR_CR5_R1MODE bit set means that Range 1 Boost is disabled */ + return PWR_REGULATOR_VOLTAGE_SCALE1; + 80073f6: f410 7080 ands.w r0, r0, #256 ; 0x100 + 80073fa: bf18 it ne + 80073fc: f44f 7000 movne.w r0, #512 ; 0x200 + return PWR_REGULATOR_VOLTAGE_SCALE1_BOOST; + } +#else + return (PWR->CR1 & PWR_CR1_VOS); +#endif +} + 8007400: 4770 bx lr + 8007402: bf00 nop + 8007404: 40007000 .word 0x40007000 + +08007408 : + uint32_t wait_loop_index; + + assert_param(IS_PWR_VOLTAGE_SCALING_RANGE(VoltageScaling)); + +#if defined(PWR_CR5_R1MODE) + if (VoltageScaling == PWR_REGULATOR_VOLTAGE_SCALE1_BOOST) + 8007408: 4b29 ldr r3, [pc, #164] ; (80074b0 ) + { + /* If current range is range 2 */ + if (READ_BIT(PWR->CR1, PWR_CR1_VOS) == PWR_REGULATOR_VOLTAGE_SCALE2) + 800740a: 681a ldr r2, [r3, #0] + if (VoltageScaling == PWR_REGULATOR_VOLTAGE_SCALE1_BOOST) + 800740c: bb30 cbnz r0, 800745c + if (READ_BIT(PWR->CR1, PWR_CR1_VOS) == PWR_REGULATOR_VOLTAGE_SCALE2) + 800740e: f402 62c0 and.w r2, r2, #1536 ; 0x600 + 8007412: f5b2 6f80 cmp.w r2, #1024 ; 0x400 + { + /* Make sure Range 1 Boost is enabled */ + CLEAR_BIT(PWR->CR5, PWR_CR5_R1MODE); + 8007416: f8d3 2080 ldr.w r2, [r3, #128] ; 0x80 + 800741a: f422 7280 bic.w r2, r2, #256 ; 0x100 + 800741e: f8c3 2080 str.w r2, [r3, #128] ; 0x80 + if (READ_BIT(PWR->CR1, PWR_CR1_VOS) == PWR_REGULATOR_VOLTAGE_SCALE2) + 8007422: d11a bne.n 800745a + + /* Set Range 1 */ + MODIFY_REG(PWR->CR1, PWR_CR1_VOS, PWR_REGULATOR_VOLTAGE_SCALE1); + 8007424: 681a ldr r2, [r3, #0] + 8007426: f422 62c0 bic.w r2, r2, #1536 ; 0x600 + 800742a: f442 7200 orr.w r2, r2, #512 ; 0x200 + 800742e: 601a str r2, [r3, #0] + + /* Wait until VOSF is cleared */ + wait_loop_index = ((PWR_FLAG_SETTING_DELAY_US * SystemCoreClock) / 1000000U) + 1; + 8007430: 4a20 ldr r2, [pc, #128] ; (80074b4 ) + 8007432: 6812 ldr r2, [r2, #0] + 8007434: 2132 movs r1, #50 ; 0x32 + 8007436: 434a muls r2, r1 + 8007438: 491f ldr r1, [pc, #124] ; (80074b8 ) + 800743a: fbb2 f2f1 udiv r2, r2, r1 + 800743e: 3201 adds r2, #1 + while ((HAL_IS_BIT_SET(PWR->SR2, PWR_SR2_VOSF)) && (wait_loop_index != 0U)) + 8007440: 6959 ldr r1, [r3, #20] + 8007442: 0549 lsls r1, r1, #21 + 8007444: d500 bpl.n 8007448 + 8007446: b922 cbnz r2, 8007452 + { + wait_loop_index--; + } + if (HAL_IS_BIT_SET(PWR->SR2, PWR_SR2_VOSF)) + 8007448: 695b ldr r3, [r3, #20] + 800744a: 0558 lsls r0, r3, #21 + 800744c: d403 bmi.n 8007456 + /* No need to wait for VOSF to be cleared for this transition */ + } + } +#endif + + return HAL_OK; + 800744e: 2000 movs r0, #0 +} + 8007450: 4770 bx lr + wait_loop_index--; + 8007452: 3a01 subs r2, #1 + 8007454: e7f4 b.n 8007440 + return HAL_TIMEOUT; + 8007456: 2003 movs r0, #3 + 8007458: 4770 bx lr + CLEAR_BIT(PWR->CR5, PWR_CR5_R1MODE); + 800745a: 4770 bx lr + else if (VoltageScaling == PWR_REGULATOR_VOLTAGE_SCALE1) + 800745c: f5b0 7f00 cmp.w r0, #512 ; 0x200 + 8007460: d11f bne.n 80074a2 + if (READ_BIT(PWR->CR1, PWR_CR1_VOS) == PWR_REGULATOR_VOLTAGE_SCALE2) + 8007462: f402 62c0 and.w r2, r2, #1536 ; 0x600 + 8007466: f5b2 6f80 cmp.w r2, #1024 ; 0x400 + SET_BIT(PWR->CR5, PWR_CR5_R1MODE); + 800746a: f8d3 2080 ldr.w r2, [r3, #128] ; 0x80 + 800746e: f442 7280 orr.w r2, r2, #256 ; 0x100 + 8007472: f8c3 2080 str.w r2, [r3, #128] ; 0x80 + if (READ_BIT(PWR->CR1, PWR_CR1_VOS) == PWR_REGULATOR_VOLTAGE_SCALE2) + 8007476: d1ea bne.n 800744e + MODIFY_REG(PWR->CR1, PWR_CR1_VOS, PWR_REGULATOR_VOLTAGE_SCALE1); + 8007478: 681a ldr r2, [r3, #0] + 800747a: f422 62c0 bic.w r2, r2, #1536 ; 0x600 + 800747e: f442 7200 orr.w r2, r2, #512 ; 0x200 + 8007482: 601a str r2, [r3, #0] + wait_loop_index = ((PWR_FLAG_SETTING_DELAY_US * SystemCoreClock) / 1000000U) + 1; + 8007484: 4a0b ldr r2, [pc, #44] ; (80074b4 ) + 8007486: 6812 ldr r2, [r2, #0] + 8007488: 2132 movs r1, #50 ; 0x32 + 800748a: 434a muls r2, r1 + 800748c: 490a ldr r1, [pc, #40] ; (80074b8 ) + 800748e: fbb2 f2f1 udiv r2, r2, r1 + 8007492: 3201 adds r2, #1 + while ((HAL_IS_BIT_SET(PWR->SR2, PWR_SR2_VOSF)) && (wait_loop_index != 0U)) + 8007494: 6959 ldr r1, [r3, #20] + 8007496: 0549 lsls r1, r1, #21 + 8007498: d5d6 bpl.n 8007448 + 800749a: 2a00 cmp r2, #0 + 800749c: d0d4 beq.n 8007448 + wait_loop_index--; + 800749e: 3a01 subs r2, #1 + 80074a0: e7f8 b.n 8007494 + MODIFY_REG(PWR->CR1, PWR_CR1_VOS, PWR_REGULATOR_VOLTAGE_SCALE2); + 80074a2: f422 62c0 bic.w r2, r2, #1536 ; 0x600 + 80074a6: f442 6280 orr.w r2, r2, #1024 ; 0x400 + 80074aa: 601a str r2, [r3, #0] + 80074ac: e7cf b.n 800744e + 80074ae: bf00 nop + 80074b0: 40007000 .word 0x40007000 + 80074b4: 2009e2ac .word 0x2009e2ac + 80074b8: 000f4240 .word 0x000f4240 + +080074bc : + +__weak void HAL_SDEx_DriveTransceiver_1_8V_Callback(FlagStatus status) +{ + // unused? +} + 80074bc: 4770 bx lr + ... + +080074c0 <__NVIC_SystemReset>: + 80074c0: f3bf 8f4f dsb sy + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 80074c4: 4905 ldr r1, [pc, #20] ; (80074dc <__NVIC_SystemReset+0x1c>) + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 80074c6: 4b06 ldr r3, [pc, #24] ; (80074e0 <__NVIC_SystemReset+0x20>) + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + 80074c8: 68ca ldr r2, [r1, #12] + 80074ca: f402 62e0 and.w r2, r2, #1792 ; 0x700 + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + 80074ce: 4313 orrs r3, r2 + 80074d0: 60cb str r3, [r1, #12] + 80074d2: f3bf 8f4f dsb sy + __NOP(); + 80074d6: bf00 nop + for(;;) /* wait until reset */ + 80074d8: e7fd b.n 80074d6 <__NVIC_SystemReset+0x16> + 80074da: bf00 nop + 80074dc: e000ed00 .word 0xe000ed00 + 80074e0: 05fa0004 .word 0x05fa0004 + +080074e4 : +{ + 80074e4: b510 push {r4, lr} + 80074e6: 3801 subs r0, #1 + 80074e8: 440a add r2, r1 + *(acc) ^= *(more); + 80074ea: f811 4b01 ldrb.w r4, [r1], #1 + 80074ee: f810 3f01 ldrb.w r3, [r0, #1]! + for(; len; len--, more++, acc++) { + 80074f2: 4291 cmp r1, r2 + *(acc) ^= *(more); + 80074f4: ea83 0304 eor.w r3, r3, r4 + 80074f8: 7003 strb r3, [r0, #0] + for(; len; len--, more++, acc++) { + 80074fa: d1f6 bne.n 80074ea + } +} + 80074fc: bd10 pop {r4, pc} + ... + +08007500 : + +// se2_write1() +// + static bool +se2_write1(uint8_t cmd, uint8_t arg) +{ + 8007500: b51f push {r0, r1, r2, r3, r4, lr} + uint8_t data[3] = { cmd, 1, arg }; + 8007502: 2301 movs r3, #1 + 8007504: f88d 300d strb.w r3, [sp, #13] + + HAL_StatusTypeDef rv = HAL_I2C_Master_Transmit(&i2c_port, I2C_ADDR, + 8007508: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + uint8_t data[3] = { cmd, 1, arg }; + 800750c: f88d 000c strb.w r0, [sp, #12] + 8007510: f88d 100e strb.w r1, [sp, #14] + HAL_StatusTypeDef rv = HAL_I2C_Master_Transmit(&i2c_port, I2C_ADDR, + 8007514: 9300 str r3, [sp, #0] + 8007516: aa03 add r2, sp, #12 + 8007518: 2303 movs r3, #3 + 800751a: 2136 movs r1, #54 ; 0x36 + 800751c: 4804 ldr r0, [pc, #16] ; (8007530 ) + 800751e: f004 fb79 bl 800bc14 + data, sizeof(data), HAL_MAX_DELAY); + + return (rv != HAL_OK); +} + 8007522: 3800 subs r0, #0 + 8007524: bf18 it ne + 8007526: 2001 movne r0, #1 + 8007528: b005 add sp, #20 + 800752a: f85d fb04 ldr.w pc, [sp], #4 + 800752e: bf00 nop + 8007530: 2009e3f0 .word 0x2009e3f0 + +08007534 : + +// se2_write2() +// + static bool +se2_write2(uint8_t cmd, uint8_t arg1, uint8_t arg2) +{ + 8007534: b51f push {r0, r1, r2, r3, r4, lr} + uint8_t data[4] = { cmd, 2, arg1, arg2 }; + 8007536: 2302 movs r3, #2 + 8007538: f88d 300d strb.w r3, [sp, #13] + + HAL_StatusTypeDef rv = HAL_I2C_Master_Transmit(&i2c_port, I2C_ADDR, + 800753c: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + uint8_t data[4] = { cmd, 2, arg1, arg2 }; + 8007540: f88d 000c strb.w r0, [sp, #12] + 8007544: f88d 100e strb.w r1, [sp, #14] + 8007548: f88d 200f strb.w r2, [sp, #15] + HAL_StatusTypeDef rv = HAL_I2C_Master_Transmit(&i2c_port, I2C_ADDR, + 800754c: 9300 str r3, [sp, #0] + 800754e: aa03 add r2, sp, #12 + 8007550: 2304 movs r3, #4 + 8007552: 2136 movs r1, #54 ; 0x36 + 8007554: 4804 ldr r0, [pc, #16] ; (8007568 ) + 8007556: f004 fb5d bl 800bc14 + data, sizeof(data), HAL_MAX_DELAY); + + return (rv != HAL_OK); +} + 800755a: 3800 subs r0, #0 + 800755c: bf18 it ne + 800755e: 2001 movne r0, #1 + 8007560: b005 add sp, #20 + 8007562: f85d fb04 ldr.w pc, [sp], #4 + 8007566: bf00 nop + 8007568: 2009e3f0 .word 0x2009e3f0 + +0800756c : + +// se2_write_n() +// + static bool +se2_write_n(uint8_t cmd, uint8_t *param1, const uint8_t *data_in, uint8_t len) +{ + 800756c: b5f0 push {r4, r5, r6, r7, lr} + 800756e: 460d mov r5, r1 + uint8_t data[2 + (param1?1:0) + len], *p = data; + 8007570: 2d00 cmp r5, #0 + 8007572: bf14 ite ne + 8007574: 2403 movne r4, #3 + 8007576: 2402 moveq r4, #2 + 8007578: 441c add r4, r3 +{ + 800757a: 4611 mov r1, r2 + uint8_t data[2 + (param1?1:0) + len], *p = data; + 800757c: f104 0207 add.w r2, r4, #7 +{ + 8007580: b083 sub sp, #12 + uint8_t data[2 + (param1?1:0) + len], *p = data; + 8007582: f402 727e and.w r2, r2, #1016 ; 0x3f8 +{ + 8007586: af02 add r7, sp, #8 + uint8_t data[2 + (param1?1:0) + len], *p = data; + 8007588: ebad 0d02 sub.w sp, sp, r2 + 800758c: ae02 add r6, sp, #8 + + *(p++) = cmd; + *(p++) = sizeof(data) - 2; + 800758e: f1a4 0202 sub.w r2, r4, #2 + *(p++) = cmd; + 8007592: f88d 0008 strb.w r0, [sp, #8] + *(p++) = sizeof(data) - 2; + 8007596: 7072 strb r2, [r6, #1] + if(param1) { + *(p++) = *param1; + 8007598: bf1b ittet ne + 800759a: 782a ldrbne r2, [r5, #0] + 800759c: 70b2 strbne r2, [r6, #2] + *(p++) = sizeof(data) - 2; + 800759e: f10d 000a addeq.w r0, sp, #10 + *(p++) = *param1; + 80075a2: f10d 000b addne.w r0, sp, #11 + } + if(len) { + 80075a6: b113 cbz r3, 80075ae + memcpy(p, data_in, len); + 80075a8: 461a mov r2, r3 + 80075aa: f006 f9ad bl 800d908 + } + + HAL_StatusTypeDef rv = HAL_I2C_Master_Transmit(&i2c_port, I2C_ADDR, + 80075ae: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 80075b2: 9300 str r3, [sp, #0] + 80075b4: 4632 mov r2, r6 + 80075b6: 4623 mov r3, r4 + 80075b8: 2136 movs r1, #54 ; 0x36 + 80075ba: 4804 ldr r0, [pc, #16] ; (80075cc ) + 80075bc: f004 fb2a bl 800bc14 + data, sizeof(data), HAL_MAX_DELAY); + + return (rv != HAL_OK); +} + 80075c0: 3800 subs r0, #0 + 80075c2: bf18 it ne + 80075c4: 2001 movne r0, #1 + 80075c6: 3704 adds r7, #4 + 80075c8: 46bd mov sp, r7 + 80075ca: bdf0 pop {r4, r5, r6, r7, pc} + 80075cc: 2009e3f0 .word 0x2009e3f0 + +080075d0 : + +// rng_for_uECC() +// + static int +rng_for_uECC(uint8_t *dest, unsigned size) +{ + 80075d0: b508 push {r3, lr} + 'dest' was filled with random data, or 0 if the random data could not be generated. + The filled-in values should be either truly random, or from a cryptographically-secure PRNG. + + typedef int (*uECC_RNG_Function)(uint8_t *dest, unsigned size); + */ + rng_buffer(dest, size); + 80075d2: f7fb f983 bl 80028dc + + return 1; +} + 80075d6: 2001 movs r0, #1 + 80075d8: bd08 pop {r3, pc} + ... + +080075dc : +{ + 80075dc: b508 push {r3, lr} + 80075de: 4602 mov r2, r0 + CALL_CHECK(se2_write_n(0x87, NULL, data, len)); + 80075e0: b2cb uxtb r3, r1 + 80075e2: 2087 movs r0, #135 ; 0x87 + 80075e4: 2100 movs r1, #0 + 80075e6: f7ff ffc1 bl 800756c + 80075ea: b118 cbz r0, 80075f4 + 80075ec: 4802 ldr r0, [pc, #8] ; (80075f8 ) + 80075ee: 21c1 movs r1, #193 ; 0xc1 + 80075f0: f006 f9a6 bl 800d940 +} + 80075f4: bd08 pop {r3, pc} + 80075f6: bf00 nop + 80075f8: 2009e394 .word 0x2009e394 + +080075fc : +{ + 80075fc: e92d 43f7 stmdb sp!, {r0, r1, r2, r4, r5, r6, r7, r8, r9, lr} + HAL_StatusTypeDef rv = HAL_I2C_Master_Receive(&i2c_port, I2C_ADDR, rx, len, HAL_MAX_DELAY); + 8007600: f8df 9044 ldr.w r9, [pc, #68] ; 8007648 +{ + 8007604: 4604 mov r4, r0 + 8007606: 460d mov r5, r1 + 8007608: f44f 7696 mov.w r6, #300 ; 0x12c + HAL_StatusTypeDef rv = HAL_I2C_Master_Receive(&i2c_port, I2C_ADDR, rx, len, HAL_MAX_DELAY); + 800760c: b287 uxth r7, r0 + 800760e: f04f 38ff mov.w r8, #4294967295 ; 0xffffffff + 8007612: f8cd 8000 str.w r8, [sp] + 8007616: 463b mov r3, r7 + 8007618: 462a mov r2, r5 + 800761a: 2136 movs r1, #54 ; 0x36 + 800761c: 4648 mov r0, r9 + 800761e: f004 fbad bl 800bd7c + if(rv == HAL_OK) { + 8007622: b938 cbnz r0, 8007634 + if(rx[0] != len-1) { + 8007624: 782b ldrb r3, [r5, #0] + 8007626: 3c01 subs r4, #1 + 8007628: 42a3 cmp r3, r4 + 800762a: d10a bne.n 8007642 + return rx[1]; + 800762c: 7868 ldrb r0, [r5, #1] +} + 800762e: b003 add sp, #12 + 8007630: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + delay_ms(1); + 8007634: 2001 movs r0, #1 + 8007636: f7fc fa25 bl 8003a84 + for(int tries=0; tries<300; tries++) { + 800763a: 3e01 subs r6, #1 + 800763c: d1e9 bne.n 8007612 + return RC_NO_ACK; + 800763e: 200f movs r0, #15 + 8007640: e7f5 b.n 800762e + return RC_WRONG_SIZE; + 8007642: 201f movs r0, #31 + 8007644: e7f3 b.n 800762e + 8007646: bf00 nop + 8007648: 2009e3f0 .word 0x2009e3f0 + +0800764c : +{ + 800764c: b507 push {r0, r1, r2, lr} + return se2_read_n(2, rx); + 800764e: 2002 movs r0, #2 + 8007650: a901 add r1, sp, #4 + 8007652: f7ff ffd3 bl 80075fc +} + 8007656: b003 add sp, #12 + 8007658: f85d fb04 ldr.w pc, [sp], #4 + +0800765c : +{ + 800765c: b507 push {r0, r1, r2, lr} + CALL_CHECK(se2_write_n(0x96, &page_num, data, 32)); + 800765e: 2320 movs r3, #32 +{ + 8007660: 460a mov r2, r1 + 8007662: f88d 0007 strb.w r0, [sp, #7] + CALL_CHECK(se2_write_n(0x96, &page_num, data, 32)); + 8007666: f10d 0107 add.w r1, sp, #7 + 800766a: 2096 movs r0, #150 ; 0x96 + 800766c: f7ff ff7e bl 800756c + 8007670: b118 cbz r0, 800767a + 8007672: 21cb movs r1, #203 ; 0xcb + CHECK_RIGHT(se2_read1() == RC_SUCCESS); + 8007674: 4805 ldr r0, [pc, #20] ; (800768c ) + 8007676: f006 f963 bl 800d940 + 800767a: f7ff ffe7 bl 800764c + 800767e: 28aa cmp r0, #170 ; 0xaa + 8007680: d001 beq.n 8007686 + 8007682: 21cd movs r1, #205 ; 0xcd + 8007684: e7f6 b.n 8007674 +} + 8007686: b003 add sp, #12 + 8007688: f85d fb04 ldr.w pc, [sp], #4 + 800768c: 2009e394 .word 0x2009e394 + +08007690 : + ASSERT(pubkey_num < 2); + 8007690: 2801 cmp r0, #1 +{ + 8007692: b508 push {r3, lr} + ASSERT(pubkey_num < 2); + 8007694: d902 bls.n 800769c + 8007696: 480a ldr r0, [pc, #40] ; (80076c0 ) + 8007698: f7f9 f9ce bl 8000a38 + CALL_CHECK(se2_write1(0xcb, (wpe <<6) | pubkey_num)); + 800769c: ea40 1181 orr.w r1, r0, r1, lsl #6 + 80076a0: b2c9 uxtb r1, r1 + 80076a2: 20cb movs r0, #203 ; 0xcb + 80076a4: f7ff ff2c bl 8007500 + 80076a8: b118 cbz r0, 80076b2 + 80076aa: 21d9 movs r1, #217 ; 0xd9 + CHECK_RIGHT(se2_read1() == RC_SUCCESS); + 80076ac: 4805 ldr r0, [pc, #20] ; (80076c4 ) + 80076ae: f006 f947 bl 800d940 + 80076b2: f7ff ffcb bl 800764c + 80076b6: 28aa cmp r0, #170 ; 0xaa + 80076b8: d001 beq.n 80076be + 80076ba: 21db movs r1, #219 ; 0xdb + 80076bc: e7f6 b.n 80076ac +} + 80076be: bd08 pop {r3, pc} + 80076c0: 0801046c .word 0x0801046c + 80076c4: 2009e394 .word 0x2009e394 + +080076c8 : +{ + 80076c8: b570 push {r4, r5, r6, lr} + 80076ca: b0dc sub sp, #368 ; 0x170 + 80076cc: 460d mov r5, r1 + 80076ce: f88d 0007 strb.w r0, [sp, #7] + rng_buffer(chal, sizeof(chal)); + 80076d2: 2120 movs r1, #32 + 80076d4: a802 add r0, sp, #8 +{ + 80076d6: 4616 mov r6, r2 + 80076d8: 461c mov r4, r3 + rng_buffer(chal, sizeof(chal)); + 80076da: f7fb f8ff bl 80028dc + se2_write_buffer(chal, sizeof(chal)); + 80076de: 2120 movs r1, #32 + 80076e0: a802 add r0, sp, #8 + 80076e2: f7ff ff7b bl 80075dc + CALL_CHECK(se2_write1(0xa5, (keynum<<5) | page_num)); + 80076e6: f89d 3007 ldrb.w r3, [sp, #7] + 80076ea: ea43 1146 orr.w r1, r3, r6, lsl #5 + 80076ee: b2c9 uxtb r1, r1 + 80076f0: 20a5 movs r0, #165 ; 0xa5 + 80076f2: f7ff ff05 bl 8007500 + 80076f6: b118 cbz r0, 8007700 + 80076f8: 21eb movs r1, #235 ; 0xeb + CHECK_RIGHT(se2_read_n(sizeof(check), check) == RC_SUCCESS); + 80076fa: 481e ldr r0, [pc, #120] ; (8007774 ) + 80076fc: f006 f920 bl 800d940 + 8007700: a912 add r1, sp, #72 ; 0x48 + 8007702: 2022 movs r0, #34 ; 0x22 + 8007704: f7ff ff7a bl 80075fc + 8007708: 28aa cmp r0, #170 ; 0xaa + 800770a: d001 beq.n 8007710 + 800770c: 21ee movs r1, #238 ; 0xee + 800770e: e7f4 b.n 80076fa + hmac_sha256_init(&ctx); + 8007710: a81b add r0, sp, #108 ; 0x6c + 8007712: f7fe f8bb bl 800588c + hmac_sha256_update(&ctx, SE2_SECRETS->romid, 8); + 8007716: 4b18 ldr r3, [pc, #96] ; (8007778 ) + 8007718: 4918 ldr r1, [pc, #96] ; (800777c ) + 800771a: f893 20b0 ldrb.w r2, [r3, #176] ; 0xb0 + 800771e: 33b0 adds r3, #176 ; 0xb0 + 8007720: 2aff cmp r2, #255 ; 0xff + 8007722: bf18 it ne + 8007724: 4619 movne r1, r3 + 8007726: a81b add r0, sp, #108 ; 0x6c + 8007728: 2208 movs r2, #8 + 800772a: 3160 adds r1, #96 ; 0x60 + 800772c: f7fe f8b4 bl 8005898 + hmac_sha256_update(&ctx, data, 32); + 8007730: 4629 mov r1, r5 + 8007732: a81b add r0, sp, #108 ; 0x6c + 8007734: 2220 movs r2, #32 + 8007736: f7fe f8af bl 8005898 + hmac_sha256_update(&ctx, chal, 32); + 800773a: a902 add r1, sp, #8 + 800773c: a81b add r0, sp, #108 ; 0x6c + 800773e: 2220 movs r2, #32 + 8007740: f7fe f8aa bl 8005898 + hmac_sha256_update(&ctx, &page_num, 1); + 8007744: f10d 0107 add.w r1, sp, #7 + 8007748: a81b add r0, sp, #108 ; 0x6c + 800774a: 2201 movs r2, #1 + 800774c: f7fe f8a4 bl 8005898 + hmac_sha256_update(&ctx, DEV_MANID, 2); + 8007750: a81b add r0, sp, #108 ; 0x6c + 8007752: 490b ldr r1, [pc, #44] ; (8007780 ) + 8007754: 2202 movs r2, #2 + 8007756: f7fe f89f bl 8005898 + hmac_sha256_final(&ctx, secret, expect); + 800775a: aa0a add r2, sp, #40 ; 0x28 + 800775c: 4621 mov r1, r4 + 800775e: a81b add r0, sp, #108 ; 0x6c + 8007760: f7fe f8b0 bl 80058c4 + return check_equal(expect, check+2, 32); + 8007764: 2220 movs r2, #32 + 8007766: f10d 014a add.w r1, sp, #74 ; 0x4a + 800776a: a80a add r0, sp, #40 ; 0x28 + 800776c: f7fb f867 bl 800283e +} + 8007770: b05c add sp, #368 ; 0x170 + 8007772: bd70 pop {r4, r5, r6, pc} + 8007774: 2009e394 .word 0x2009e394 + 8007778: 0801c000 .word 0x0801c000 + 800777c: 2009e2b4 .word 0x2009e2b4 + 8007780: 08010ac0 .word 0x08010ac0 + +08007784 : +{ + 8007784: b570 push {r4, r5, r6, lr} + 8007786: 4604 mov r4, r0 + 8007788: b08a sub sp, #40 ; 0x28 + 800778a: 460d mov r5, r1 + CALL_CHECK(se2_write1(0x69, page_num)); + 800778c: 4601 mov r1, r0 + 800778e: 2069 movs r0, #105 ; 0x69 +{ + 8007790: 4616 mov r6, r2 + CALL_CHECK(se2_write1(0x69, page_num)); + 8007792: f7ff feb5 bl 8007500 + 8007796: b120 cbz r0, 80077a2 + 8007798: f44f 7185 mov.w r1, #266 ; 0x10a + CHECK_RIGHT(se2_read_n(sizeof(rx), rx) == RC_SUCCESS); + 800779c: 481c ldr r0, [pc, #112] ; (8007810 ) + 800779e: f006 f8cf bl 800d940 + 80077a2: a901 add r1, sp, #4 + 80077a4: 2022 movs r0, #34 ; 0x22 + 80077a6: f7ff ff29 bl 80075fc + 80077aa: 28aa cmp r0, #170 ; 0xaa + 80077ac: d002 beq.n 80077b4 + 80077ae: f240 110d movw r1, #269 ; 0x10d + 80077b2: e7f3 b.n 800779c + CHECK_RIGHT(rx[0] == 33); + 80077b4: f89d 3004 ldrb.w r3, [sp, #4] + 80077b8: 2b21 cmp r3, #33 ; 0x21 + 80077ba: d002 beq.n 80077c2 + 80077bc: f240 110f movw r1, #271 ; 0x10f + 80077c0: e7ec b.n 800779c + CHECK_RIGHT(rx[1] == RC_SUCCESS); + 80077c2: f89d 3005 ldrb.w r3, [sp, #5] + 80077c6: 2baa cmp r3, #170 ; 0xaa + 80077c8: d002 beq.n 80077d0 + 80077ca: f44f 7188 mov.w r1, #272 ; 0x110 + 80077ce: e7e5 b.n 800779c + memcpy(data, rx+2, 32); + 80077d0: f10d 0306 add.w r3, sp, #6 + 80077d4: 462a mov r2, r5 + 80077d6: f10d 0126 add.w r1, sp, #38 ; 0x26 + 80077da: f853 0b04 ldr.w r0, [r3], #4 + 80077de: f842 0b04 str.w r0, [r2], #4 + 80077e2: 428b cmp r3, r1 + 80077e4: d1f9 bne.n 80077da + if(!verify) return; + 80077e6: b186 cbz r6, 800780a + CHECK_RIGHT(se2_verify_page(page_num, data, 0, SE2_SECRETS->pairing)); + 80077e8: 4b0a ldr r3, [pc, #40] ; (8007814 ) + 80077ea: 4a0b ldr r2, [pc, #44] ; (8007818 ) + 80077ec: f893 10b0 ldrb.w r1, [r3, #176] ; 0xb0 + 80077f0: 4b0a ldr r3, [pc, #40] ; (800781c ) + 80077f2: 4620 mov r0, r4 + 80077f4: 29ff cmp r1, #255 ; 0xff + 80077f6: bf18 it ne + 80077f8: 4613 movne r3, r2 + 80077fa: 2200 movs r2, #0 + 80077fc: 4629 mov r1, r5 + 80077fe: f7ff ff63 bl 80076c8 + 8007802: b910 cbnz r0, 800780a + 8007804: f44f 718b mov.w r1, #278 ; 0x116 + 8007808: e7c8 b.n 800779c +} + 800780a: b00a add sp, #40 ; 0x28 + 800780c: bd70 pop {r4, r5, r6, pc} + 800780e: bf00 nop + 8007810: 2009e394 .word 0x2009e394 + 8007814: 0801c000 .word 0x0801c000 + 8007818: 0801c0b0 .word 0x0801c0b0 + 800781c: 2009e2b4 .word 0x2009e2b4 + +08007820 : +{ + 8007820: b570 push {r4, r5, r6, lr} + 8007822: b0d6 sub sp, #344 ; 0x158 + 8007824: 461e mov r6, r3 + ASSERT((keynum == 0) || (keynum == 2)); + 8007826: f032 0302 bics.w r3, r2, #2 +{ + 800782a: 460c mov r4, r1 + 800782c: 4615 mov r5, r2 + 800782e: f88d 0007 strb.w r0, [sp, #7] + ASSERT((keynum == 0) || (keynum == 2)); + 8007832: d002 beq.n 800783a + 8007834: 4831 ldr r0, [pc, #196] ; (80078fc ) + 8007836: f7f9 f8ff bl 8000a38 + CALL_CHECK(se2_write1(0x4b, (keynum << 6) | page_num)); + 800783a: f89d 1007 ldrb.w r1, [sp, #7] + 800783e: ea41 1182 orr.w r1, r1, r2, lsl #6 + 8007842: b2c9 uxtb r1, r1 + 8007844: 204b movs r0, #75 ; 0x4b + 8007846: f7ff fe5b bl 8007500 + 800784a: b120 cbz r0, 8007856 + 800784c: f44f 71b3 mov.w r1, #358 ; 0x166 + CHECK_RIGHT(se2_read_n(sizeof(rx), rx) == RC_SUCCESS); + 8007850: 482b ldr r0, [pc, #172] ; (8007900 ) + 8007852: f006 f875 bl 800d940 + 8007856: a90a add r1, sp, #40 ; 0x28 + 8007858: 202a movs r0, #42 ; 0x2a + 800785a: f7ff fecf bl 80075fc + 800785e: 28aa cmp r0, #170 ; 0xaa + 8007860: d002 beq.n 8007868 + 8007862: f240 1169 movw r1, #361 ; 0x169 + 8007866: e7f3 b.n 8007850 + CHECK_RIGHT(rx[1] == RC_SUCCESS); + 8007868: f89d 3029 ldrb.w r3, [sp, #41] ; 0x29 + 800786c: 2baa cmp r3, #170 ; 0xaa + 800786e: d002 beq.n 8007876 + 8007870: f240 116b movw r1, #363 ; 0x16b + 8007874: e7ec b.n 8007850 + memcpy(data, rx+2+8, 32); + 8007876: f10d 0332 add.w r3, sp, #50 ; 0x32 + 800787a: 4622 mov r2, r4 + 800787c: f10d 0152 add.w r1, sp, #82 ; 0x52 + 8007880: f853 0b04 ldr.w r0, [r3], #4 + 8007884: f842 0b04 str.w r0, [r2], #4 + 8007888: 428b cmp r3, r1 + 800788a: d1f9 bne.n 8007880 + hmac_sha256_init(&ctx); + 800788c: a815 add r0, sp, #84 ; 0x54 + 800788e: f7fd fffd bl 800588c + hmac_sha256_update(&ctx, chal, 8); + 8007892: 2208 movs r2, #8 + 8007894: f10d 012a add.w r1, sp, #42 ; 0x2a + 8007898: a815 add r0, sp, #84 ; 0x54 + 800789a: f7fd fffd bl 8005898 + hmac_sha256_update(&ctx, SE2_SECRETS->romid, 8); + 800789e: 4b19 ldr r3, [pc, #100] ; (8007904 ) + 80078a0: 4919 ldr r1, [pc, #100] ; (8007908 ) + 80078a2: f893 20b0 ldrb.w r2, [r3, #176] ; 0xb0 + 80078a6: 33b0 adds r3, #176 ; 0xb0 + 80078a8: 2aff cmp r2, #255 ; 0xff + 80078aa: bf18 it ne + 80078ac: 4619 movne r1, r3 + 80078ae: 3160 adds r1, #96 ; 0x60 + 80078b0: 2208 movs r2, #8 + 80078b2: a815 add r0, sp, #84 ; 0x54 + 80078b4: f7fd fff0 bl 8005898 + hmac_sha256_update(&ctx, &page_num, 1); + 80078b8: 2201 movs r2, #1 + 80078ba: f10d 0107 add.w r1, sp, #7 + 80078be: a815 add r0, sp, #84 ; 0x54 + 80078c0: f7fd ffea bl 8005898 + hmac_sha256_update(&ctx, DEV_MANID, 2); + 80078c4: 4911 ldr r1, [pc, #68] ; (800790c ) + 80078c6: 2202 movs r2, #2 + 80078c8: a815 add r0, sp, #84 ; 0x54 + 80078ca: f7fd ffe5 bl 8005898 + hmac_sha256_final(&ctx, secret, otp); + 80078ce: aa02 add r2, sp, #8 + 80078d0: 4631 mov r1, r6 + 80078d2: a815 add r0, sp, #84 ; 0x54 + 80078d4: f7fd fff6 bl 80058c4 + xor_mixin(data, otp, 32); + 80078d8: 2220 movs r2, #32 + 80078da: a902 add r1, sp, #8 + 80078dc: 4620 mov r0, r4 + 80078de: f7ff fe01 bl 80074e4 + CHECK_RIGHT(se2_verify_page(page_num, data, keynum, secret)); + 80078e2: f89d 0007 ldrb.w r0, [sp, #7] + 80078e6: 4633 mov r3, r6 + 80078e8: 462a mov r2, r5 + 80078ea: 4621 mov r1, r4 + 80078ec: f7ff feec bl 80076c8 + 80078f0: b910 cbnz r0, 80078f8 + 80078f2: f44f 71c0 mov.w r1, #384 ; 0x180 + 80078f6: e7ab b.n 8007850 +} + 80078f8: b056 add sp, #344 ; 0x158 + 80078fa: bd70 pop {r4, r5, r6, pc} + 80078fc: 0801046c .word 0x0801046c + 8007900: 2009e394 .word 0x2009e394 + 8007904: 0801c000 .word 0x0801c000 + 8007908: 2009e2b4 .word 0x2009e2b4 + 800790c: 08010ac0 .word 0x08010ac0 + +08007910 : +{ + 8007910: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + 8007914: 460e mov r6, r1 + ASSERT((keynum == 0) || (keynum == 2)); + 8007916: f032 0102 bics.w r1, r2, #2 +{ + 800791a: b0e4 sub sp, #400 ; 0x190 + 800791c: 4604 mov r4, r0 + 800791e: 4617 mov r7, r2 + 8007920: 4698 mov r8, r3 + ASSERT((keynum == 0) || (keynum == 2)); + 8007922: d002 beq.n 800792a + 8007924: 4849 ldr r0, [pc, #292] ; (8007a4c ) + 8007926: f7f9 f887 bl 8000a38 + se2_read_encrypted(page_num, old_data, keynum, secret); + 800792a: a901 add r1, sp, #4 + 800792c: f7ff ff78 bl 8007820 + uint8_t PGDV = page_num | 0x80; + 8007930: f064 037f orn r3, r4, #127 ; 0x7f + rng_buffer(&chal_check[32], 8); + 8007934: 2108 movs r1, #8 + 8007936: a821 add r0, sp, #132 ; 0x84 + uint8_t PGDV = page_num | 0x80; + 8007938: f88d 3002 strb.w r3, [sp, #2] + rng_buffer(&chal_check[32], 8); + 800793c: f7fa ffce bl 80028dc + hmac_sha256_init(&ctx); + 8007940: a823 add r0, sp, #140 ; 0x8c + 8007942: f7fd ffa3 bl 800588c + hmac_sha256_update(&ctx, &chal_check[32], 8); + 8007946: 2208 movs r2, #8 + 8007948: a921 add r1, sp, #132 ; 0x84 + 800794a: a823 add r0, sp, #140 ; 0x8c + 800794c: f7fd ffa4 bl 8005898 + hmac_sha256_update(&ctx, SE2_SECRETS->romid, 8); + 8007950: 4b3f ldr r3, [pc, #252] ; (8007a50 ) + 8007952: 4940 ldr r1, [pc, #256] ; (8007a54 ) + 8007954: f893 20b0 ldrb.w r2, [r3, #176] ; 0xb0 + 8007958: 33b0 adds r3, #176 ; 0xb0 + 800795a: 2aff cmp r2, #255 ; 0xff + 800795c: bf18 it ne + 800795e: 4619 movne r1, r3 + 8007960: 3160 adds r1, #96 ; 0x60 + 8007962: 2208 movs r2, #8 + 8007964: a823 add r0, sp, #140 ; 0x8c + 8007966: f7fd ff97 bl 8005898 + hmac_sha256_update(&ctx, &PGDV, 1); + 800796a: 2201 movs r2, #1 + 800796c: f10d 0102 add.w r1, sp, #2 + 8007970: a823 add r0, sp, #140 ; 0x8c + 8007972: f7fd ff91 bl 8005898 + hmac_sha256_update(&ctx, DEV_MANID, 2); + 8007976: 4938 ldr r1, [pc, #224] ; (8007a58 ) + 8007978: 2202 movs r2, #2 + 800797a: a823 add r0, sp, #140 ; 0x8c + 800797c: f7fd ff8c bl 8005898 + ASSERT(ctx.num_pending == 19); + 8007980: 9b63 ldr r3, [sp, #396] ; 0x18c + 8007982: 2b13 cmp r3, #19 + 8007984: d1ce bne.n 8007924 + hmac_sha256_final(&ctx, secret, otp); + 8007986: aa09 add r2, sp, #36 ; 0x24 + 8007988: 4641 mov r1, r8 + 800798a: a823 add r0, sp, #140 ; 0x8c + 800798c: f7fd ff9a bl 80058c4 + memcpy(tmp, data, 32); + 8007990: 4635 mov r5, r6 + 8007992: aa11 add r2, sp, #68 ; 0x44 + 8007994: f106 0c20 add.w ip, r6, #32 + 8007998: 6828 ldr r0, [r5, #0] + 800799a: 6869 ldr r1, [r5, #4] + 800799c: 4613 mov r3, r2 + 800799e: c303 stmia r3!, {r0, r1} + 80079a0: 3508 adds r5, #8 + 80079a2: 4565 cmp r5, ip + 80079a4: 461a mov r2, r3 + 80079a6: d1f7 bne.n 8007998 + xor_mixin(tmp, otp, 32); + 80079a8: 2220 movs r2, #32 + 80079aa: a909 add r1, sp, #36 ; 0x24 + 80079ac: a811 add r0, sp, #68 ; 0x44 + 80079ae: f7ff fd99 bl 80074e4 + hmac_sha256_init(&ctx); + 80079b2: a823 add r0, sp, #140 ; 0x8c + 80079b4: f7fd ff6a bl 800588c + hmac_sha256_update(&ctx, SE2_SECRETS->romid, 8); + 80079b8: 4b25 ldr r3, [pc, #148] ; (8007a50 ) + 80079ba: 4926 ldr r1, [pc, #152] ; (8007a54 ) + 80079bc: f893 20b0 ldrb.w r2, [r3, #176] ; 0xb0 + 80079c0: 33b0 adds r3, #176 ; 0xb0 + 80079c2: 2aff cmp r2, #255 ; 0xff + 80079c4: bf18 it ne + 80079c6: 4619 movne r1, r3 + 80079c8: 3160 adds r1, #96 ; 0x60 + 80079ca: 2208 movs r2, #8 + 80079cc: a823 add r0, sp, #140 ; 0x8c + 80079ce: f7fd ff63 bl 8005898 + hmac_sha256_update(&ctx, old_data, 32); + 80079d2: 2220 movs r2, #32 + 80079d4: a901 add r1, sp, #4 + 80079d6: a823 add r0, sp, #140 ; 0x8c + 80079d8: f7fd ff5e bl 8005898 + hmac_sha256_update(&ctx, data, 32); + 80079dc: 2220 movs r2, #32 + 80079de: 4631 mov r1, r6 + 80079e0: a823 add r0, sp, #140 ; 0x8c + 80079e2: f7fd ff59 bl 8005898 + hmac_sha256_update(&ctx, &PGDV, 1); + 80079e6: 2201 movs r2, #1 + 80079e8: f10d 0102 add.w r1, sp, #2 + 80079ec: a823 add r0, sp, #140 ; 0x8c + 80079ee: f7fd ff53 bl 8005898 + hmac_sha256_update(&ctx, DEV_MANID, 2); + 80079f2: 4919 ldr r1, [pc, #100] ; (8007a58 ) + 80079f4: 2202 movs r2, #2 + 80079f6: a823 add r0, sp, #140 ; 0x8c + 80079f8: f7fd ff4e bl 8005898 + ASSERT(ctx.num_pending == 75); + 80079fc: 9b63 ldr r3, [sp, #396] ; 0x18c + 80079fe: 2b4b cmp r3, #75 ; 0x4b + 8007a00: d190 bne.n 8007924 + hmac_sha256_final(&ctx, secret, chal_check); + 8007a02: aa19 add r2, sp, #100 ; 0x64 + 8007a04: 4641 mov r1, r8 + 8007a06: a823 add r0, sp, #140 ; 0x8c + 8007a08: f7fd ff5c bl 80058c4 + se2_write_buffer(chal_check, sizeof(chal_check)); + 8007a0c: 2128 movs r1, #40 ; 0x28 + 8007a0e: a819 add r0, sp, #100 ; 0x64 + 8007a10: f7ff fde4 bl 80075dc + uint8_t pn = (keynum << 6) | page_num; + 8007a14: ea44 1487 orr.w r4, r4, r7, lsl #6 + CALL_CHECK(se2_write_n(0x99, &pn, tmp, 32)); + 8007a18: 2320 movs r3, #32 + 8007a1a: aa11 add r2, sp, #68 ; 0x44 + 8007a1c: f10d 0103 add.w r1, sp, #3 + 8007a20: 2099 movs r0, #153 ; 0x99 + uint8_t pn = (keynum << 6) | page_num; + 8007a22: f88d 4003 strb.w r4, [sp, #3] + CALL_CHECK(se2_write_n(0x99, &pn, tmp, 32)); + 8007a26: f7ff fda1 bl 800756c + 8007a2a: b120 cbz r0, 8007a36 + 8007a2c: f44f 71aa mov.w r1, #340 ; 0x154 + CHECK_RIGHT(se2_read1() == RC_SUCCESS); + 8007a30: 480a ldr r0, [pc, #40] ; (8007a5c ) + 8007a32: f005 ff85 bl 800d940 + 8007a36: f7ff fe09 bl 800764c + 8007a3a: 28aa cmp r0, #170 ; 0xaa + 8007a3c: d002 beq.n 8007a44 + 8007a3e: f44f 71ab mov.w r1, #342 ; 0x156 + 8007a42: e7f5 b.n 8007a30 +} + 8007a44: b064 add sp, #400 ; 0x190 + 8007a46: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + 8007a4a: bf00 nop + 8007a4c: 0801046c .word 0x0801046c + 8007a50: 0801c000 .word 0x0801c000 + 8007a54: 2009e2b4 .word 0x2009e2b4 + 8007a58: 08010ac0 .word 0x08010ac0 + 8007a5c: 2009e394 .word 0x2009e394 + +08007a60 : +{ + 8007a60: b508 push {r3, lr} + 8007a62: 4601 mov r1, r0 + CALL_CHECK(se2_write1(0xaa, page_num)); + 8007a64: 20aa movs r0, #170 ; 0xaa + 8007a66: f7ff fd4b bl 8007500 + 8007a6a: b120 cbz r0, 8007a76 + 8007a6c: 4804 ldr r0, [pc, #16] ; (8007a80 ) + 8007a6e: f240 118b movw r1, #395 ; 0x18b + 8007a72: f005 ff65 bl 800d940 +} + 8007a76: e8bd 4008 ldmia.w sp!, {r3, lr} + return se2_read1(); + 8007a7a: f7ff bde7 b.w 800764c + 8007a7e: bf00 nop + 8007a80: 2009e394 .word 0x2009e394 + +08007a84 : +{ + 8007a84: b538 push {r3, r4, r5, lr} + 8007a86: 460c mov r4, r1 + 8007a88: 4605 mov r5, r0 + if(se2_get_protection(page_num) == flags) { + 8007a8a: f7ff ffe9 bl 8007a60 + 8007a8e: 42a0 cmp r0, r4 + 8007a90: d011 beq.n 8007ab6 + CALL_CHECK(se2_write2(0xc3, page_num, flags)); + 8007a92: 4622 mov r2, r4 + 8007a94: 4629 mov r1, r5 + 8007a96: 20c3 movs r0, #195 ; 0xc3 + 8007a98: f7ff fd4c bl 8007534 + 8007a9c: b120 cbz r0, 8007aa8 + 8007a9e: f240 119b movw r1, #411 ; 0x19b + CHECK_RIGHT(se2_read1() == RC_SUCCESS); + 8007aa2: 4805 ldr r0, [pc, #20] ; (8007ab8 ) + 8007aa4: f005 ff4c bl 800d940 + 8007aa8: f7ff fdd0 bl 800764c + 8007aac: 28aa cmp r0, #170 ; 0xaa + 8007aae: d002 beq.n 8007ab6 + 8007ab0: f240 119d movw r1, #413 ; 0x19d + 8007ab4: e7f5 b.n 8007aa2 +} + 8007ab6: bd38 pop {r3, r4, r5, pc} + 8007ab8: 2009e394 .word 0x2009e394 + +08007abc : +{ + 8007abc: b500 push {lr} + if(setjmp(error_env)) { + 8007abe: 4812 ldr r0, [pc, #72] ; (8007b08 ) +{ + 8007ac0: b089 sub sp, #36 ; 0x24 + if(setjmp(error_env)) { + 8007ac2: f005 ff37 bl 800d934 + 8007ac6: b120 cbz r0, 8007ad2 + oled_show(screen_se2_issue); + 8007ac8: 4810 ldr r0, [pc, #64] ; (8007b0c ) + 8007aca: f7f9 fad3 bl 8001074 + LOCKUP_FOREVER(); + 8007ace: f7fc f8d3 bl 8003c78 + rng_delay(); + 8007ad2: f7fa ff19 bl 8002908 + if(rom_secrets->se2.pairing[0] == 0xff) { + 8007ad6: 4b0e ldr r3, [pc, #56] ; (8007b10 ) + 8007ad8: f893 30b0 ldrb.w r3, [r3, #176] ; 0xb0 + 8007adc: 2bff cmp r3, #255 ; 0xff + 8007ade: d00f beq.n 8007b00 + se2_read_page(PGN_ROM_OPTIONS, tmp, true); + 8007ae0: 2201 movs r2, #1 + 8007ae2: 4669 mov r1, sp + 8007ae4: 201c movs r0, #28 + 8007ae6: f7ff fe4d bl 8007784 + CHECK_RIGHT(check_equal(&tmp[24], rom_secrets->se2.romid, 8)); + 8007aea: 490a ldr r1, [pc, #40] ; (8007b14 ) + 8007aec: 2208 movs r2, #8 + 8007aee: a806 add r0, sp, #24 + 8007af0: f7fa fea5 bl 800283e + 8007af4: b920 cbnz r0, 8007b00 + 8007af6: 4804 ldr r0, [pc, #16] ; (8007b08 ) + 8007af8: f240 11b5 movw r1, #437 ; 0x1b5 + 8007afc: f005 ff20 bl 800d940 +} + 8007b00: b009 add sp, #36 ; 0x24 + 8007b02: f85d fb04 ldr.w pc, [sp], #4 + 8007b06: bf00 nop + 8007b08: 2009e394 .word 0x2009e394 + 8007b0c: 0800f3d7 .word 0x0800f3d7 + 8007b10: 0801c000 .word 0x0801c000 + 8007b14: 0801c110 .word 0x0801c110 + +08007b18 : +{ + 8007b18: b510 push {r4, lr} + if(setjmp(error_env)) fatal_mitm(); + 8007b1a: 4817 ldr r0, [pc, #92] ; (8007b78 ) +{ + 8007b1c: b088 sub sp, #32 + if(setjmp(error_env)) fatal_mitm(); + 8007b1e: f005 ff09 bl 800d934 + 8007b22: 4604 mov r4, r0 + 8007b24: b108 cbz r0, 8007b2a + 8007b26: f7f8 ff91 bl 8000a4c + uint8_t z32[32] = {0}; + 8007b2a: 221c movs r2, #28 + 8007b2c: 4601 mov r1, r0 + 8007b2e: 9000 str r0, [sp, #0] + 8007b30: a801 add r0, sp, #4 + 8007b32: f005 fef7 bl 800d924 + se2_write_page(PGN_PUBKEY_S+0, z32); + 8007b36: 4669 mov r1, sp + 8007b38: 201e movs r0, #30 + 8007b3a: f7ff fd8f bl 800765c + se2_write_page(PGN_PUBKEY_S+1, z32); + 8007b3e: 4669 mov r1, sp + 8007b40: 201f movs r0, #31 + 8007b42: f7ff fd8b bl 800765c + se2_write_buffer(z32, 32); + 8007b46: 2120 movs r1, #32 + 8007b48: 4668 mov r0, sp + 8007b4a: f7ff fd47 bl 80075dc + CALL_CHECK(se2_write2(0x3c, (2<<6), 0)); + 8007b4e: 4622 mov r2, r4 + 8007b50: 2180 movs r1, #128 ; 0x80 + 8007b52: 203c movs r0, #60 ; 0x3c + 8007b54: f7ff fcee bl 8007534 + 8007b58: b120 cbz r0, 8007b64 + 8007b5a: f240 11cd movw r1, #461 ; 0x1cd + CHECK_RIGHT(se2_read1() == RC_SUCCESS); + 8007b5e: 4806 ldr r0, [pc, #24] ; (8007b78 ) + 8007b60: f005 feee bl 800d940 + 8007b64: f7ff fd72 bl 800764c + 8007b68: 28aa cmp r0, #170 ; 0xaa + 8007b6a: d002 beq.n 8007b72 + 8007b6c: f44f 71e7 mov.w r1, #462 ; 0x1ce + 8007b70: e7f5 b.n 8007b5e +} + 8007b72: b008 add sp, #32 + 8007b74: bd10 pop {r4, pc} + 8007b76: bf00 nop + 8007b78: 2009e394 .word 0x2009e394 + +08007b7c : +{ + 8007b7c: b570 push {r4, r5, r6, lr} + if((setjmp(error_env))) { + 8007b7e: 485b ldr r0, [pc, #364] ; (8007cec ) +{ + 8007b80: b090 sub sp, #64 ; 0x40 + if((setjmp(error_env))) { + 8007b82: f005 fed7 bl 800d934 + 8007b86: 4604 mov r4, r0 + 8007b88: b120 cbz r0, 8007b94 + oled_show(screen_se2_issue); + 8007b8a: 4859 ldr r0, [pc, #356] ; (8007cf0 ) + 8007b8c: f7f9 fa72 bl 8001074 + LOCKUP_FOREVER(); + 8007b90: f7fc f872 bl 8003c78 + if(rom_secrets->se2.pairing[0] != 0xff) { + 8007b94: 4b57 ldr r3, [pc, #348] ; (8007cf4 ) + 8007b96: f893 10b0 ldrb.w r1, [r3, #176] ; 0xb0 + 8007b9a: 29ff cmp r1, #255 ; 0xff + 8007b9c: f040 80a0 bne.w 8007ce0 + memset(&_tbd, 0xff, sizeof(_tbd)); + 8007ba0: 4d55 ldr r5, [pc, #340] ; (8007cf8 ) + 8007ba2: 22e0 movs r2, #224 ; 0xe0 + 8007ba4: 4628 mov r0, r5 + 8007ba6: f005 febd bl 800d924 + rng_buffer(_tbd.tpin_key, 32); + 8007baa: 2120 movs r1, #32 + 8007bac: f105 0080 add.w r0, r5, #128 ; 0x80 + 8007bb0: f7fa fe94 bl 80028dc + se2_read_page(PGN_ROM_OPTIONS, tmp, false); + 8007bb4: 4622 mov r2, r4 + 8007bb6: 4669 mov r1, sp + 8007bb8: 201c movs r0, #28 + 8007bba: f7ff fde3 bl 8007784 + ASSERT(tmp[1] == 0x00); // check ANON is not set + 8007bbe: f89d 3001 ldrb.w r3, [sp, #1] + 8007bc2: b113 cbz r3, 8007bca + 8007bc4: 484d ldr r0, [pc, #308] ; (8007cfc ) + 8007bc6: f7f8 ff37 bl 8000a38 + memcpy(_tbd.romid, tmp+24, 8); + 8007bca: ab06 add r3, sp, #24 + 8007bcc: cb03 ldmia r3!, {r0, r1} + 8007bce: 6628 str r0, [r5, #96] ; 0x60 + 8007bd0: 6669 str r1, [r5, #100] ; 0x64 + rng_buffer(tmp, 32); + 8007bd2: 4668 mov r0, sp + 8007bd4: 2120 movs r1, #32 + 8007bd6: f7fa fe81 bl 80028dc + se2_write_page(PGN_SECRET_B, tmp); + 8007bda: 4669 mov r1, sp + 8007bdc: 201a movs r0, #26 + 8007bde: f7ff fd3d bl 800765c + se2_pick_keypair(0, true); + 8007be2: 2101 movs r1, #1 + 8007be4: 4620 mov r0, r4 + 8007be6: f7ff fd53 bl 8007690 + se2_read_page(PGN_PUBKEY_A, &_tbd.pubkey_A[0], false); + 8007bea: 4622 mov r2, r4 + 8007bec: f105 0120 add.w r1, r5, #32 + 8007bf0: 2010 movs r0, #16 + 8007bf2: f7ff fdc7 bl 8007784 + memset(tmp, 0, 32); + 8007bf6: 2620 movs r6, #32 + se2_read_page(PGN_PUBKEY_A+1, &_tbd.pubkey_A[32], false); + 8007bf8: 4622 mov r2, r4 + 8007bfa: f105 0140 add.w r1, r5, #64 ; 0x40 + 8007bfe: 2011 movs r0, #17 + 8007c00: f7ff fdc0 bl 8007784 + memset(tmp, 0, 32); + 8007c04: 4632 mov r2, r6 + 8007c06: 4621 mov r1, r4 + 8007c08: 4668 mov r0, sp + 8007c0a: f005 fe8b bl 800d924 + se2_write_page(PGN_PRIVKEY_B, tmp); + 8007c0e: 4669 mov r1, sp + 8007c10: 2017 movs r0, #23 + 8007c12: f7ff fd23 bl 800765c + se2_write_page(PGN_PRIVKEY_B+1, tmp); + 8007c16: 4669 mov r1, sp + 8007c18: 2018 movs r0, #24 + 8007c1a: f7ff fd1f bl 800765c + se2_write_page(PGN_PUBKEY_B, tmp); + 8007c1e: 4669 mov r1, sp + 8007c20: 2012 movs r0, #18 + 8007c22: f7ff fd1b bl 800765c + se2_write_page(PGN_PUBKEY_B+1, tmp); + 8007c26: 4669 mov r1, sp + 8007c28: 2013 movs r0, #19 + 8007c2a: f7ff fd17 bl 800765c + rng_buffer(_tbd.pairing, 32); + 8007c2e: 4631 mov r1, r6 + 8007c30: 4628 mov r0, r5 + 8007c32: f7fa fe53 bl 80028dc + } while(_tbd.pairing[0] == 0xff); + 8007c36: 782b ldrb r3, [r5, #0] + 8007c38: 2bff cmp r3, #255 ; 0xff + 8007c3a: d0f8 beq.n 8007c2e + se2_write_page(PGN_SECRET_A, _tbd.pairing); + 8007c3c: 4629 mov r1, r5 + 8007c3e: 2019 movs r0, #25 + rng_buffer(tmp, 32); + 8007c40: 466d mov r5, sp + se2_write_page(PGN_SECRET_A, _tbd.pairing); + 8007c42: f7ff fd0b bl 800765c + rng_buffer(tmp, 32); + 8007c46: 2120 movs r1, #32 + 8007c48: 4628 mov r0, r5 + 8007c4a: f7fa fe47 bl 80028dc + se2_write_page(PGN_SE2_EASY_KEY, tmp); + 8007c4e: 4629 mov r1, r5 + 8007c50: 200e movs r0, #14 + 8007c52: f7ff fd03 bl 800765c + memset(tmp, 0, 32); + 8007c56: 2220 movs r2, #32 + 8007c58: 2100 movs r1, #0 + 8007c5a: 4628 mov r0, r5 + 8007c5c: f005 fe62 bl 800d924 + for(int pn=0; pn <= PGN_LAST_TRICK; pn++) { + 8007c60: 4626 mov r6, r4 + se2_write_page(pn, tmp); + 8007c62: b2f0 uxtb r0, r6 + 8007c64: 4629 mov r1, r5 + for(int pn=0; pn <= PGN_LAST_TRICK; pn++) { + 8007c66: 3601 adds r6, #1 + se2_write_page(pn, tmp); + 8007c68: f7ff fcf8 bl 800765c + for(int pn=0; pn <= PGN_LAST_TRICK; pn++) { + 8007c6c: 2e0e cmp r6, #14 + 8007c6e: d1f8 bne.n 8007c62 + flash_save_se2_data(&_tbd); + 8007c70: 4821 ldr r0, [pc, #132] ; (8007cf8 ) + 8007c72: f7fa fb43 bl 80022fc + se2_set_protection(PGN_SECRET_A, PROT_WP); + 8007c76: 2102 movs r1, #2 + 8007c78: 2019 movs r0, #25 + 8007c7a: f7ff ff03 bl 8007a84 + se2_set_protection(PGN_SECRET_B, PROT_WP); + 8007c7e: 2102 movs r1, #2 + 8007c80: 201a movs r0, #26 + 8007c82: f7ff feff bl 8007a84 + se2_set_protection(PGN_PUBKEY_A, PROT_WP); + 8007c86: 2102 movs r1, #2 + 8007c88: 2010 movs r0, #16 + 8007c8a: f7ff fefb bl 8007a84 + se2_set_protection(PGN_PUBKEY_B, PROT_WP); + 8007c8e: 2102 movs r1, #2 + 8007c90: 2012 movs r0, #18 + 8007c92: f7ff fef7 bl 8007a84 + se2_set_protection(PGN_SE2_EASY_KEY, PROT_EPH); + 8007c96: 2110 movs r1, #16 + 8007c98: 4630 mov r0, r6 + 8007c9a: f7ff fef3 bl 8007a84 + se2_set_protection(pn, PROT_EPH); + 8007c9e: 2510 movs r5, #16 + 8007ca0: b2e0 uxtb r0, r4 + 8007ca2: 4629 mov r1, r5 + for(int pn=0; pn <= PGN_LAST_TRICK; pn++) { + 8007ca4: 3401 adds r4, #1 + se2_set_protection(pn, PROT_EPH); + 8007ca6: f7ff feed bl 8007a84 + for(int pn=0; pn <= PGN_LAST_TRICK; pn++) { + 8007caa: 2c0e cmp r4, #14 + 8007cac: d1f8 bne.n 8007ca0 + se2_set_protection(PGN_ROM_OPTIONS, PROT_APH); // not planning to change + 8007cae: 2108 movs r1, #8 + 8007cb0: 201c movs r0, #28 + 8007cb2: f7ff fee7 bl 8007a84 + se2_read_page(PGN_DEC_COUNTER, tmp, false); + 8007cb6: 2200 movs r2, #0 + 8007cb8: a908 add r1, sp, #32 + 8007cba: 201b movs r0, #27 + 8007cbc: f7ff fd62 bl 8007784 + if(tmp[2] == 0xff) { + 8007cc0: f89d 3022 ldrb.w r3, [sp, #34] ; 0x22 + 8007cc4: 2bff cmp r3, #255 ; 0xff + 8007cc6: d10d bne.n 8007ce4 + tmp[0] = val & 0x0ff; + 8007cc8: 2380 movs r3, #128 ; 0x80 + 8007cca: f88d 3020 strb.w r3, [sp, #32] + se2_write_page(PGN_DEC_COUNTER, tmp); + 8007cce: a908 add r1, sp, #32 + tmp[1] = (val >> 8) & 0x0ff; + 8007cd0: 2300 movs r3, #0 + se2_write_page(PGN_DEC_COUNTER, tmp); + 8007cd2: 201b movs r0, #27 + tmp[1] = (val >> 8) & 0x0ff; + 8007cd4: f88d 3021 strb.w r3, [sp, #33] ; 0x21 + tmp[2] = (val >> 16) & 0x01; + 8007cd8: f88d 3022 strb.w r3, [sp, #34] ; 0x22 + se2_write_page(PGN_DEC_COUNTER, tmp); + 8007cdc: f7ff fcbe bl 800765c +} + 8007ce0: b010 add sp, #64 ; 0x40 + 8007ce2: bd70 pop {r4, r5, r6, pc} + puts("ctr set?"); // not expected, but keep going + 8007ce4: 4806 ldr r0, [pc, #24] ; (8007d00 ) + 8007ce6: f7fd f9bf bl 8005068 + 8007cea: e7f9 b.n 8007ce0 + 8007cec: 2009e394 .word 0x2009e394 + 8007cf0: 0800f3d7 .word 0x0800f3d7 + 8007cf4: 0801c000 .word 0x0801c000 + 8007cf8: 2009e2b4 .word 0x2009e2b4 + 8007cfc: 0801046c .word 0x0801046c + 8007d00: 08010aa0 .word 0x08010aa0 + +08007d04 : +{ + 8007d04: b510 push {r4, lr} + 8007d06: b08a sub sp, #40 ; 0x28 + 8007d08: 9001 str r0, [sp, #4] + if(setjmp(error_env)) fatal_mitm(); + 8007d0a: 481e ldr r0, [pc, #120] ; (8007d84 ) + 8007d0c: f005 fe12 bl 800d934 + 8007d10: b108 cbz r0, 8007d16 + 8007d12: f7f8 fe9b bl 8000a4c + ASSERT(check_all_ones(rom_secrets->se2.auth_pubkey, 64)); + 8007d16: 481c ldr r0, [pc, #112] ; (8007d88 ) + 8007d18: 2140 movs r1, #64 ; 0x40 + 8007d1a: f7fa fd77 bl 800280c + 8007d1e: b910 cbnz r0, 8007d26 + 8007d20: 481a ldr r0, [pc, #104] ; (8007d8c ) + 8007d22: f7f8 fe89 bl 8000a38 + memcpy(&_tbd, &rom_secrets->se2, sizeof(_tbd)); + 8007d26: 4c1a ldr r4, [pc, #104] ; (8007d90 ) + 8007d28: 491a ldr r1, [pc, #104] ; (8007d94 ) + 8007d2a: 22e0 movs r2, #224 ; 0xe0 + 8007d2c: 4620 mov r0, r4 + 8007d2e: f005 fdeb bl 800d908 + rng_buffer(tmp, 32); + 8007d32: 2120 movs r1, #32 + 8007d34: a802 add r0, sp, #8 + 8007d36: f7fa fdd1 bl 80028dc + se2_write_page(PGN_SE2_HARD_KEY, tmp); + 8007d3a: a902 add r1, sp, #8 + 8007d3c: 200f movs r0, #15 + 8007d3e: f7ff fc8d bl 800765c + se2_write_page(PGN_PUBKEY_C, &pubkey[0]); + 8007d42: 9901 ldr r1, [sp, #4] + 8007d44: 2014 movs r0, #20 + 8007d46: f7ff fc89 bl 800765c + se2_write_page(PGN_PUBKEY_C+1, &pubkey[32]); + 8007d4a: 9b01 ldr r3, [sp, #4] + 8007d4c: 2015 movs r0, #21 + 8007d4e: f103 0120 add.w r1, r3, #32 + 8007d52: f7ff fc83 bl 800765c + memcpy(_tbd.auth_pubkey, pubkey, 64); + 8007d56: 9b01 ldr r3, [sp, #4] + 8007d58: 34a0 adds r4, #160 ; 0xa0 + 8007d5a: f103 0240 add.w r2, r3, #64 ; 0x40 + 8007d5e: f853 1b04 ldr.w r1, [r3], #4 + 8007d62: f844 1b04 str.w r1, [r4], #4 + 8007d66: 4293 cmp r3, r2 + 8007d68: d1f9 bne.n 8007d5e + flash_save_se2_data(&_tbd); + 8007d6a: 4809 ldr r0, [pc, #36] ; (8007d90 ) + 8007d6c: f7fa fac6 bl 80022fc + se2_set_protection(PGN_SE2_HARD_KEY, PROT_WP | PROT_ECH | PROT_ECW); + 8007d70: 21c2 movs r1, #194 ; 0xc2 + 8007d72: 200f movs r0, #15 + 8007d74: f7ff fe86 bl 8007a84 + se2_set_protection(PGN_PUBKEY_C, PROT_WP | PROT_RP | PROT_AUTH); + 8007d78: 2123 movs r1, #35 ; 0x23 + 8007d7a: 2014 movs r0, #20 + 8007d7c: f7ff fe82 bl 8007a84 +} + 8007d80: b00a add sp, #40 ; 0x28 + 8007d82: bd10 pop {r4, pc} + 8007d84: 2009e394 .word 0x2009e394 + 8007d88: 0801c150 .word 0x0801c150 + 8007d8c: 0801046c .word 0x0801046c + 8007d90: 2009e2b4 .word 0x2009e2b4 + 8007d94: 0801c0b0 .word 0x0801c0b0 + +08007d98 : +{ + 8007d98: b530 push {r4, r5, lr} + 8007d9a: 4614 mov r4, r2 + ASSERT(pin_len >= 0); // 12-12 typical, but empty = blank PIN + 8007d9c: 1e0a subs r2, r1, #0 +{ + 8007d9e: b0c5 sub sp, #276 ; 0x114 + 8007da0: 4605 mov r5, r0 + ASSERT(pin_len >= 0); // 12-12 typical, but empty = blank PIN + 8007da2: da02 bge.n 8007daa + 8007da4: 4812 ldr r0, [pc, #72] ; (8007df0 ) + 8007da6: f7f8 fe47 bl 8000a38 + hmac_sha256_init(&ctx); + 8007daa: a803 add r0, sp, #12 + 8007dac: 9201 str r2, [sp, #4] + 8007dae: f7fd fd6d bl 800588c + hmac_sha256_update(&ctx, (uint8_t *)pin, pin_len); + 8007db2: 9a01 ldr r2, [sp, #4] + 8007db4: 4629 mov r1, r5 + 8007db6: a803 add r0, sp, #12 + 8007db8: f7fd fd6e bl 8005898 + hmac_sha256_final(&ctx, SE2_SECRETS->tpin_key, tpin_hash); + 8007dbc: 4b0d ldr r3, [pc, #52] ; (8007df4 ) + 8007dbe: 490e ldr r1, [pc, #56] ; (8007df8 ) + 8007dc0: f893 20b0 ldrb.w r2, [r3, #176] ; 0xb0 + 8007dc4: 33b0 adds r3, #176 ; 0xb0 + 8007dc6: 2aff cmp r2, #255 ; 0xff + 8007dc8: bf18 it ne + 8007dca: 4619 movne r1, r3 + 8007dcc: a803 add r0, sp, #12 + 8007dce: 4622 mov r2, r4 + 8007dd0: 3180 adds r1, #128 ; 0x80 + 8007dd2: f7fd fd77 bl 80058c4 + sha256_single(tpin_hash, 32, tpin_hash); + 8007dd6: 4622 mov r2, r4 + 8007dd8: 4620 mov r0, r4 + 8007dda: 2120 movs r1, #32 + 8007ddc: f7fd fd36 bl 800584c + sha256_single(tpin_hash, 32, tpin_hash); + 8007de0: 4622 mov r2, r4 + 8007de2: 2120 movs r1, #32 + 8007de4: 4620 mov r0, r4 + 8007de6: f7fd fd31 bl 800584c +} + 8007dea: b045 add sp, #276 ; 0x114 + 8007dec: bd30 pop {r4, r5, pc} + 8007dee: bf00 nop + 8007df0: 0801046c .word 0x0801046c + 8007df4: 0801c000 .word 0x0801c000 + 8007df8: 2009e2b4 .word 0x2009e2b4 + +08007dfc : + +// p256_gen_keypair() +// + void +p256_gen_keypair(uint8_t privkey[32], uint8_t pubkey[64]) +{ + 8007dfc: b538 push {r3, r4, r5, lr} + 8007dfe: 4605 mov r5, r0 + uECC_set_rng(rng_for_uECC); + 8007e00: 4808 ldr r0, [pc, #32] ; (8007e24 ) +{ + 8007e02: 460c mov r4, r1 + uECC_set_rng(rng_for_uECC); + 8007e04: f7fe fedc bl 8006bc0 + + int ok = uECC_make_key(pubkey, privkey, uECC_secp256r1()); + 8007e08: f7fe fee0 bl 8006bcc + 8007e0c: 4629 mov r1, r5 + 8007e0e: 4602 mov r2, r0 + 8007e10: 4620 mov r0, r4 + 8007e12: f7fe fee3 bl 8006bdc + ASSERT(ok == 1); + 8007e16: 2801 cmp r0, #1 + 8007e18: d002 beq.n 8007e20 + 8007e1a: 4803 ldr r0, [pc, #12] ; (8007e28 ) + 8007e1c: f7f8 fe0c bl 8000a38 +} + 8007e20: bd38 pop {r3, r4, r5, pc} + 8007e22: bf00 nop + 8007e24: 080075d1 .word 0x080075d1 + 8007e28: 0801046c .word 0x0801046c + +08007e2c : + +// ps256_ecdh() +// + void +ps256_ecdh(const uint8_t pubkey[64], const uint8_t privkey[32], uint8_t result[32]) +{ + 8007e2c: b513 push {r0, r1, r4, lr} + 8007e2e: 4604 mov r4, r0 + uECC_set_rng(rng_for_uECC); + 8007e30: 4809 ldr r0, [pc, #36] ; (8007e58 ) +{ + 8007e32: e9cd 2100 strd r2, r1, [sp] + uECC_set_rng(rng_for_uECC); + 8007e36: f7fe fec3 bl 8006bc0 + + int ok = uECC_shared_secret(pubkey, privkey, result, uECC_secp256r1()); + 8007e3a: f7fe fec7 bl 8006bcc + 8007e3e: e9dd 2100 ldrd r2, r1, [sp] + 8007e42: 4603 mov r3, r0 + 8007e44: 4620 mov r0, r4 + 8007e46: f7fe ff09 bl 8006c5c + ASSERT(ok == 1); + 8007e4a: 2801 cmp r0, #1 + 8007e4c: d002 beq.n 8007e54 + 8007e4e: 4803 ldr r0, [pc, #12] ; (8007e5c ) + 8007e50: f7f8 fdf2 bl 8000a38 +} + 8007e54: b002 add sp, #8 + 8007e56: bd10 pop {r4, pc} + 8007e58: 080075d1 .word 0x080075d1 + 8007e5c: 0801046c .word 0x0801046c + +08007e60 : + +// se2_read_hard_secret() +// + static bool +se2_read_hard_secret(uint8_t hard_key[32], const uint8_t pin_digest[32]) +{ + 8007e60: b510 push {r4, lr} + 8007e62: b0e8 sub sp, #416 ; 0x1a0 + 8007e64: e9cd 0102 strd r0, r1, [sp, #8] + if(setjmp(error_env)) { + 8007e68: 4836 ldr r0, [pc, #216] ; (8007f44 ) + 8007e6a: f005 fd63 bl 800d934 + 8007e6e: 2800 cmp r0, #0 + 8007e70: d165 bne.n 8007f3e + // + SHA256_CTX ctx; + + // pick a temp key pair, share public part w/ SE2 + uint8_t tmp_privkey[32], tmp_pubkey[64]; + p256_gen_keypair(tmp_privkey, tmp_pubkey); + 8007e72: a925 add r1, sp, #148 ; 0x94 + 8007e74: a805 add r0, sp, #20 + 8007e76: f7ff ffc1 bl 8007dfc + + // - this can be mitm-ed, but we sign it next so doesn't matter + se2_write_page(PGN_PUBKEY_S, &tmp_pubkey[0]); + 8007e7a: a925 add r1, sp, #148 ; 0x94 + 8007e7c: 201e movs r0, #30 + 8007e7e: f7ff fbed bl 800765c + se2_write_page(PGN_PUBKEY_S+1, &tmp_pubkey[32]); + 8007e82: a92d add r1, sp, #180 ; 0xb4 + 8007e84: 201f movs r0, #31 + 8007e86: f7ff fbe9 bl 800765c + + // pick nonce + uint8_t chal[32+32]; + rng_buffer(chal, sizeof(chal)); + 8007e8a: 2140 movs r1, #64 ; 0x40 + 8007e8c: a835 add r0, sp, #212 ; 0xd4 + 8007e8e: f7fa fd25 bl 80028dc + se2_write_buffer(chal, sizeof(chal)); + 8007e92: 2140 movs r1, #64 ; 0x40 + 8007e94: a835 add r0, sp, #212 ; 0xd4 + 8007e96: f7ff fba1 bl 80075dc + + // md = ngu.hash.sha256s(T_pubkey + chal[0:32]) + sha256_init(&ctx); + 8007e9a: a855 add r0, sp, #340 ; 0x154 + 8007e9c: f7fd fc6e bl 800577c + sha256_update(&ctx, tmp_pubkey, 64); + 8007ea0: 2240 movs r2, #64 ; 0x40 + 8007ea2: a925 add r1, sp, #148 ; 0x94 + 8007ea4: a855 add r0, sp, #340 ; 0x154 + 8007ea6: f7fd fc77 bl 8005798 + sha256_update(&ctx, chal, 32); // only first 32 bytes + 8007eaa: 2220 movs r2, #32 + 8007eac: a935 add r1, sp, #212 ; 0xd4 + 8007eae: a855 add r0, sp, #340 ; 0x154 + 8007eb0: f7fd fc72 bl 8005798 + + uint8_t md[32]; + sha256_final(&ctx, md); + 8007eb4: a90d add r1, sp, #52 ; 0x34 + 8007eb6: a855 add r0, sp, #340 ; 0x154 + 8007eb8: f7fd fcb4 bl 8005824 + // Get that digest signed by SE1 now, and doing that requires + // the main pin, because the required slot requires auth by that key. + // - this is the critical step attackers would not be able to emulate w/o SE1 contents + // - fails here if PIN wrong + uint8_t signature[64]; + int arc = ae_sign_authed(KEYNUM_joiner_key, md, signature, KEYNUM_main_pin, pin_digest); + 8007ebc: 9b03 ldr r3, [sp, #12] + 8007ebe: 9300 str r3, [sp, #0] + 8007ec0: aa45 add r2, sp, #276 ; 0x114 + 8007ec2: 2303 movs r3, #3 + 8007ec4: a90d add r1, sp, #52 ; 0x34 + 8007ec6: 2007 movs r0, #7 + 8007ec8: f7fb f83e bl 8002f48 + CHECK_RIGHT(arc == 0); + 8007ecc: 4604 mov r4, r0 + 8007ece: b120 cbz r0, 8007eda + 8007ed0: f240 4152 movw r1, #1106 ; 0x452 + + // "Authenticate ECDSA Public Key" = 0xA8 + // cs_offset=32 ecdh_keynum=0=pubA ECDH=1 WR=0 + uint8_t param = ((32-1) << 3) | (0 << 2) | 0x2; + se2_write_n(0xA8, ¶m, signature, 64); + CHECK_RIGHT(se2_read1() == RC_SUCCESS); + 8007ed4: 481b ldr r0, [pc, #108] ; (8007f44 ) + 8007ed6: f005 fd33 bl 800d940 + uint8_t param = ((32-1) << 3) | (0 << 2) | 0x2; + 8007eda: 23fa movs r3, #250 ; 0xfa + 8007edc: f88d 3013 strb.w r3, [sp, #19] + se2_write_n(0xA8, ¶m, signature, 64); + 8007ee0: aa45 add r2, sp, #276 ; 0x114 + 8007ee2: 2340 movs r3, #64 ; 0x40 + 8007ee4: f10d 0113 add.w r1, sp, #19 + 8007ee8: 20a8 movs r0, #168 ; 0xa8 + 8007eea: f7ff fb3f bl 800756c + CHECK_RIGHT(se2_read1() == RC_SUCCESS); + 8007eee: f7ff fbad bl 800764c + 8007ef2: 28aa cmp r0, #170 ; 0xaa + 8007ef4: d002 beq.n 8007efc + 8007ef6: f44f 618b mov.w r1, #1112 ; 0x458 + 8007efa: e7eb b.n 8007ed4 + + uint8_t shared_x[32], shared_secret[32]; + ps256_ecdh(rom_secrets->se2.pubkey_A, tmp_privkey, shared_x); + 8007efc: aa15 add r2, sp, #84 ; 0x54 + 8007efe: a905 add r1, sp, #20 + 8007f00: 4811 ldr r0, [pc, #68] ; (8007f48 ) + 8007f02: f7ff ff93 bl 8007e2c + + // shared secret S will be SHA over X of shared ECDH point + chal[32:] + // s = ngu.hash.sha256s(x + chal[32:]) + sha256_init(&ctx); + 8007f06: a855 add r0, sp, #340 ; 0x154 + 8007f08: f7fd fc38 bl 800577c + sha256_update(&ctx, shared_x, 32); + 8007f0c: 2220 movs r2, #32 + 8007f0e: a915 add r1, sp, #84 ; 0x54 + 8007f10: a855 add r0, sp, #340 ; 0x154 + 8007f12: f7fd fc41 bl 8005798 + sha256_update(&ctx, &chal[32], 32); // second half + 8007f16: 2220 movs r2, #32 + 8007f18: a93d add r1, sp, #244 ; 0xf4 + 8007f1a: a855 add r0, sp, #340 ; 0x154 + 8007f1c: f7fd fc3c bl 8005798 + sha256_final(&ctx, shared_secret); + 8007f20: a91d add r1, sp, #116 ; 0x74 + 8007f22: a855 add r0, sp, #340 ; 0x154 + 8007f24: f7fd fc7e bl 8005824 + + se2_read_encrypted(PGN_SE2_HARD_KEY, hard_key, 2, shared_secret); + 8007f28: 200f movs r0, #15 + 8007f2a: 9902 ldr r1, [sp, #8] + 8007f2c: ab1d add r3, sp, #116 ; 0x74 + 8007f2e: 2202 movs r2, #2 + 8007f30: f7ff fc76 bl 8007820 + + // CONCERN: secret "S" is retained in SE2's sram. No API to clear it. + // - but you'd need to see our copy of that value to make use of it + // - and PIN checked already to get here, so you could re-do anyway + se2_clear_volatile(); + 8007f34: f7ff fdf0 bl 8007b18 + + return false; + 8007f38: 4620 mov r0, r4 +} + 8007f3a: b068 add sp, #416 ; 0x1a0 + 8007f3c: bd10 pop {r4, pc} + return true; + 8007f3e: 2001 movs r0, #1 + 8007f40: e7fb b.n 8007f3a + 8007f42: bf00 nop + 8007f44: 2009e394 .word 0x2009e394 + 8007f48: 0801c0d0 .word 0x0801c0d0 + +08007f4c : + +// se2_calc_seed_key() +// + static bool +se2_calc_seed_key(uint8_t aes_key[32], const mcu_key_t *mcu_key, const uint8_t pin_digest[32]) +{ + 8007f4c: b570 push {r4, r5, r6, lr} + 8007f4e: b0d2 sub sp, #328 ; 0x148 + 8007f50: 4614 mov r4, r2 + // Gather key parts from all over. Combine them w/ HMAC into a AES-256 key + uint8_t se1_easy_key[32], se1_hard_key[32]; + se2_read_encrypted(PGN_SE2_EASY_KEY, se1_easy_key, 0, rom_secrets->se2.pairing); + 8007f52: 4b15 ldr r3, [pc, #84] ; (8007fa8 ) + 8007f54: 2200 movs r2, #0 +{ + 8007f56: 4605 mov r5, r0 + 8007f58: 460e mov r6, r1 + se2_read_encrypted(PGN_SE2_EASY_KEY, se1_easy_key, 0, rom_secrets->se2.pairing); + 8007f5a: 200e movs r0, #14 + 8007f5c: a901 add r1, sp, #4 + 8007f5e: f7ff fc5f bl 8007820 + + if(se2_read_hard_secret(se1_hard_key, pin_digest)) return true; + 8007f62: 4621 mov r1, r4 + 8007f64: a809 add r0, sp, #36 ; 0x24 + 8007f66: f7ff ff7b bl 8007e60 + 8007f6a: 4604 mov r4, r0 + 8007f6c: b9c8 cbnz r0, 8007fa2 + + HMAC_CTX ctx; + hmac_sha256_init(&ctx); + 8007f6e: a811 add r0, sp, #68 ; 0x44 + 8007f70: f7fd fc8c bl 800588c + hmac_sha256_update(&ctx, mcu_key->value, 32); + 8007f74: 2220 movs r2, #32 + 8007f76: 4631 mov r1, r6 + 8007f78: a811 add r0, sp, #68 ; 0x44 + 8007f7a: f7fd fc8d bl 8005898 + hmac_sha256_update(&ctx, se1_hard_key, 32); + 8007f7e: 2220 movs r2, #32 + 8007f80: a909 add r1, sp, #36 ; 0x24 + 8007f82: a811 add r0, sp, #68 ; 0x44 + 8007f84: f7fd fc88 bl 8005898 + hmac_sha256_update(&ctx, se1_easy_key, 32); + 8007f88: 2220 movs r2, #32 + 8007f8a: a901 add r1, sp, #4 + 8007f8c: a811 add r0, sp, #68 ; 0x44 + 8007f8e: f7fd fc83 bl 8005898 + + // combine them all using anther MCU key via HMAC-SHA256 + hmac_sha256_final(&ctx, rom_secrets->mcu_hmac_key, aes_key); + 8007f92: a811 add r0, sp, #68 ; 0x44 + 8007f94: 4905 ldr r1, [pc, #20] ; (8007fac ) + 8007f96: 462a mov r2, r5 + 8007f98: f7fd fc94 bl 80058c4 + hmac_sha256_init(&ctx); // clear secrets + 8007f9c: a811 add r0, sp, #68 ; 0x44 + 8007f9e: f7fd fc75 bl 800588c + + return false; +} + 8007fa2: 4620 mov r0, r4 + 8007fa4: b052 add sp, #328 ; 0x148 + 8007fa6: bd70 pop {r4, r5, r6, pc} + 8007fa8: 0801c0b0 .word 0x0801c0b0 + 8007fac: 0801c090 .word 0x0801c090 + +08007fb0 : +{ + 8007fb0: b5f0 push {r4, r5, r6, r7, lr} + if(i2c_port.Instance == I2C2) { + 8007fb2: 4e1b ldr r6, [pc, #108] ; (8008020 ) + 8007fb4: 4f1b ldr r7, [pc, #108] ; (8008024 ) + 8007fb6: 6833 ldr r3, [r6, #0] + 8007fb8: 42bb cmp r3, r7 +{ + 8007fba: b089 sub sp, #36 ; 0x24 + if(i2c_port.Instance == I2C2) { + 8007fbc: d02e beq.n 800801c + __HAL_RCC_GPIOB_CLK_ENABLE(); + 8007fbe: 4b1a ldr r3, [pc, #104] ; (8008028 ) + GPIO_InitTypeDef setup = { + 8007fc0: 4d1a ldr r5, [pc, #104] ; (800802c ) + __HAL_RCC_GPIOB_CLK_ENABLE(); + 8007fc2: 6cda ldr r2, [r3, #76] ; 0x4c + 8007fc4: f042 0202 orr.w r2, r2, #2 + 8007fc8: 64da str r2, [r3, #76] ; 0x4c + 8007fca: 6cda ldr r2, [r3, #76] ; 0x4c + 8007fcc: f002 0202 and.w r2, r2, #2 + 8007fd0: 9201 str r2, [sp, #4] + 8007fd2: 9a01 ldr r2, [sp, #4] + __HAL_RCC_I2C2_CLK_ENABLE(); + 8007fd4: 6d9a ldr r2, [r3, #88] ; 0x58 + 8007fd6: f442 0280 orr.w r2, r2, #4194304 ; 0x400000 + 8007fda: 659a str r2, [r3, #88] ; 0x58 + 8007fdc: 6d9b ldr r3, [r3, #88] ; 0x58 + 8007fde: f403 0380 and.w r3, r3, #4194304 ; 0x400000 + 8007fe2: 9302 str r3, [sp, #8] + 8007fe4: 9b02 ldr r3, [sp, #8] + GPIO_InitTypeDef setup = { + 8007fe6: cd0f ldmia r5!, {r0, r1, r2, r3} + 8007fe8: ac03 add r4, sp, #12 + 8007fea: c40f stmia r4!, {r0, r1, r2, r3} + 8007fec: 682b ldr r3, [r5, #0] + HAL_GPIO_Init(GPIOB, &setup); + 8007fee: 4810 ldr r0, [pc, #64] ; (8008030 ) + GPIO_InitTypeDef setup = { + 8007ff0: 6023 str r3, [r4, #0] + HAL_GPIO_Init(GPIOB, &setup); + 8007ff2: a903 add r1, sp, #12 + 8007ff4: f7f9 f8fe bl 80011f4 + memset(&i2c_port, 0, sizeof(i2c_port)); + 8007ff8: 2244 movs r2, #68 ; 0x44 + 8007ffa: 2100 movs r1, #0 + 8007ffc: f106 0008 add.w r0, r6, #8 + 8008000: f005 fc90 bl 800d924 + i2c_port.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + 8008004: 2301 movs r3, #1 + 8008006: 60f3 str r3, [r6, #12] + HAL_StatusTypeDef rv = HAL_I2C_Init(&i2c_port); + 8008008: 4630 mov r0, r6 + i2c_port.Init.Timing = 0x00b03fb8; // 400khz "fast mode" in CubeMX @ 120Mhz (measured ok) + 800800a: 4b0a ldr r3, [pc, #40] ; (8008034 ) + i2c_port.Instance = I2C2; + 800800c: 6037 str r7, [r6, #0] + i2c_port.Init.Timing = 0x00b03fb8; // 400khz "fast mode" in CubeMX @ 120Mhz (measured ok) + 800800e: 6073 str r3, [r6, #4] + HAL_StatusTypeDef rv = HAL_I2C_Init(&i2c_port); + 8008010: f003 fdae bl 800bb70 + ASSERT(rv == HAL_OK); + 8008014: b110 cbz r0, 800801c + 8008016: 4808 ldr r0, [pc, #32] ; (8008038 ) + 8008018: f7f8 fd0e bl 8000a38 +} + 800801c: b009 add sp, #36 ; 0x24 + 800801e: bdf0 pop {r4, r5, r6, r7, pc} + 8008020: 2009e3f0 .word 0x2009e3f0 + 8008024: 40005800 .word 0x40005800 + 8008028: 40021000 .word 0x40021000 + 800802c: 08010aac .word 0x08010aac + 8008030: 48000400 .word 0x48000400 + 8008034: 00b03fb8 .word 0x00b03fb8 + 8008038: 0801046c .word 0x0801046c + +0800803c : +{ + 800803c: b5f0 push {r4, r5, r6, r7, lr} + 800803e: b089 sub sp, #36 ; 0x24 + se2_setup(); + 8008040: f7ff ffb6 bl 8007fb0 + if(setjmp(error_env)) fatal_mitm(); + 8008044: 480f ldr r0, [pc, #60] ; (8008084 ) + 8008046: f005 fc75 bl 800d934 + 800804a: 4604 mov r4, r0 + 800804c: b108 cbz r0, 8008052 + 800804e: f7f8 fcfd bl 8000a4c + uint8_t tmp[32] = {0}; + 8008052: 9000 str r0, [sp, #0] + 8008054: 4601 mov r1, r0 + 8008056: 221c movs r2, #28 + 8008058: a801 add r0, sp, #4 + 800805a: f005 fc63 bl 800d924 + se2_write_encrypted(pn, tmp, 0, SE2_SECRETS->pairing); + 800805e: 4f0a ldr r7, [pc, #40] ; (8008088 ) + 8008060: 4e0a ldr r6, [pc, #40] ; (800808c ) + 8008062: 4d0b ldr r5, [pc, #44] ; (8008090 ) + 8008064: f897 30b0 ldrb.w r3, [r7, #176] ; 0xb0 + 8008068: b2e0 uxtb r0, r4 + 800806a: 2bff cmp r3, #255 ; 0xff + 800806c: bf0c ite eq + 800806e: 4633 moveq r3, r6 + 8008070: 462b movne r3, r5 + 8008072: 2200 movs r2, #0 + 8008074: 4669 mov r1, sp + for(int pn=0; pn <= PGN_LAST_TRICK; pn++) { + 8008076: 3401 adds r4, #1 + se2_write_encrypted(pn, tmp, 0, SE2_SECRETS->pairing); + 8008078: f7ff fc4a bl 8007910 + for(int pn=0; pn <= PGN_LAST_TRICK; pn++) { + 800807c: 2c0e cmp r4, #14 + 800807e: d1f1 bne.n 8008064 +} + 8008080: b009 add sp, #36 ; 0x24 + 8008082: bdf0 pop {r4, r5, r6, r7, pc} + 8008084: 2009e394 .word 0x2009e394 + 8008088: 0801c000 .word 0x0801c000 + 800808c: 2009e2b4 .word 0x2009e2b4 + 8008090: 0801c0b0 .word 0x0801c0b0 + +08008094 : +{ + 8008094: b5f0 push {r4, r5, r6, r7, lr} + 8008096: b087 sub sp, #28 + 8008098: e9cd 0102 strd r0, r1, [sp, #8] + if(setjmp(error_env)) fatal_mitm(); + 800809c: 4816 ldr r0, [pc, #88] ; (80080f8 ) +{ + 800809e: 9201 str r2, [sp, #4] + if(setjmp(error_env)) fatal_mitm(); + 80080a0: f005 fc48 bl 800d934 + 80080a4: b108 cbz r0, 80080aa + 80080a6: f7f8 fcd1 bl 8000a4c + se2_read_encrypted(slot_num+1, &data[0], 0, SE2_SECRETS->pairing); + 80080aa: 4f14 ldr r7, [pc, #80] ; (80080fc ) + 80080ac: 9005 str r0, [sp, #20] + se2_setup(); + 80080ae: f7ff ff7f bl 8007fb0 + se2_read_encrypted(slot_num+1, &data[0], 0, SE2_SECRETS->pairing); + 80080b2: f89d 4008 ldrb.w r4, [sp, #8] + 80080b6: f897 30b0 ldrb.w r3, [r7, #176] ; 0xb0 + 80080ba: 4e11 ldr r6, [pc, #68] ; (8008100 ) + 80080bc: 4d11 ldr r5, [pc, #68] ; (8008104 ) + 80080be: 9a05 ldr r2, [sp, #20] + 80080c0: 9901 ldr r1, [sp, #4] + 80080c2: 9204 str r2, [sp, #16] + 80080c4: 1c60 adds r0, r4, #1 + 80080c6: 2bff cmp r3, #255 ; 0xff + 80080c8: bf0c ite eq + 80080ca: 4633 moveq r3, r6 + 80080cc: 462b movne r3, r5 + 80080ce: b2c0 uxtb r0, r0 + 80080d0: f7ff fba6 bl 8007820 + if(tc_flags & TC_XPRV_WALLET) { + 80080d4: 9b03 ldr r3, [sp, #12] + 80080d6: 051b lsls r3, r3, #20 + 80080d8: d50c bpl.n 80080f4 + se2_read_encrypted(slot_num+2, &data[32], 0, SE2_SECRETS->pairing); + 80080da: f897 30b0 ldrb.w r3, [r7, #176] ; 0xb0 + 80080de: 9901 ldr r1, [sp, #4] + 80080e0: 9a04 ldr r2, [sp, #16] + 80080e2: 3402 adds r4, #2 + 80080e4: 2bff cmp r3, #255 ; 0xff + 80080e6: bf0c ite eq + 80080e8: 4633 moveq r3, r6 + 80080ea: 462b movne r3, r5 + 80080ec: 3120 adds r1, #32 + 80080ee: b2e0 uxtb r0, r4 + 80080f0: f7ff fb96 bl 8007820 +} + 80080f4: b007 add sp, #28 + 80080f6: bdf0 pop {r4, r5, r6, r7, pc} + 80080f8: 2009e394 .word 0x2009e394 + 80080fc: 0801c000 .word 0x0801c000 + 8008100: 2009e2b4 .word 0x2009e2b4 + 8008104: 0801c0b0 .word 0x0801c0b0 + +08008108 : +{ + 8008108: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + 800810c: b0fe sub sp, #504 ; 0x1f8 + 800810e: e9cd 1002 strd r1, r0, [sp, #8] + 8008112: e9cd 2300 strd r2, r3, [sp] + se2_setup(); + 8008116: f7ff ff4b bl 8007fb0 + if(setjmp(error_env)) { + 800811a: 4864 ldr r0, [pc, #400] ; (80082ac ) + 800811c: f005 fc0a bl 800d934 + 8008120: 4604 mov r4, r0 + 8008122: b138 cbz r0, 8008134 + if(!safety_mode) fatal_mitm(); + 8008124: 9b01 ldr r3, [sp, #4] + 8008126: b11b cbz r3, 8008130 + return false; + 8008128: 2000 movs r0, #0 +} + 800812a: b07e add sp, #504 ; 0x1f8 + 800812c: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + if(!safety_mode) fatal_mitm(); + 8008130: f7f8 fc8c bl 8000a4c + if(!pin_len) return false; + 8008134: 9b02 ldr r3, [sp, #8] + 8008136: 2b00 cmp r3, #0 + 8008138: d0f6 beq.n 8008128 + trick_pin_hash(pin, pin_len, tpin_hash); + 800813a: 9803 ldr r0, [sp, #12] + se2_read_encrypted(pn, slots[i], 0, SE2_SECRETS->pairing); + 800813c: f8df a174 ldr.w sl, [pc, #372] ; 80082b4 + 8008140: f8df 9174 ldr.w r9, [pc, #372] ; 80082b8 + 8008144: f8df 8174 ldr.w r8, [pc, #372] ; 80082bc + trick_pin_hash(pin, pin_len, tpin_hash); + 8008148: aa06 add r2, sp, #24 + 800814a: 4619 mov r1, r3 + 800814c: f7ff fe24 bl 8007d98 + 8008150: ad0e add r5, sp, #56 ; 0x38 + 8008152: 462f mov r7, r5 + int pn = PGN_TRICK(0); + 8008154: 4626 mov r6, r4 + se2_read_encrypted(pn, slots[i], 0, SE2_SECRETS->pairing); + 8008156: f89a 30b0 ldrb.w r3, [sl, #176] ; 0xb0 + 800815a: 4639 mov r1, r7 + 800815c: 2bff cmp r3, #255 ; 0xff + 800815e: bf0c ite eq + 8008160: 464b moveq r3, r9 + 8008162: 4643 movne r3, r8 + 8008164: b2f0 uxtb r0, r6 + 8008166: 2200 movs r2, #0 + for(int i=0; ipairing); + 800816a: f7ff fb59 bl 8007820 + for(int i=0; i + se2_clear_volatile(); + 8008176: f7ff fccf bl 8007b18 + uint32_t blank = 0; + 800817a: 2700 movs r7, #0 + int found = -1; + 800817c: f04f 36ff mov.w r6, #4294967295 ; 0xffffffff + if(check_equal(here, tpin_hash, 28)) { + 8008180: f04f 091c mov.w r9, #28 + blank |= (!!check_all_zeros(here, 32)) << i; + 8008184: f04f 0820 mov.w r8, #32 + if(check_equal(here, tpin_hash, 28)) { + 8008188: 464a mov r2, r9 + 800818a: a906 add r1, sp, #24 + 800818c: 4628 mov r0, r5 + 800818e: f7fa fb56 bl 800283e + blank |= (!!check_all_zeros(here, 32)) << i; + 8008192: 4641 mov r1, r8 + if(check_equal(here, tpin_hash, 28)) { + 8008194: 2800 cmp r0, #0 + 8008196: bf18 it ne + 8008198: 4626 movne r6, r4 + blank |= (!!check_all_zeros(here, 32)) << i; + 800819a: 4628 mov r0, r5 + 800819c: f7fa fb40 bl 8002820 + 80081a0: 40a0 lsls r0, r4 + for(int i=0; i + rng_delay(); + 80081b0: f7fa fbaa bl 8002908 + memset(found_slot, 0, sizeof(trick_slot_t)); + 80081b4: 9800 ldr r0, [sp, #0] + 80081b6: 2280 movs r2, #128 ; 0x80 + 80081b8: 2100 movs r1, #0 + 80081ba: f005 fbb3 bl 800d924 + if(safety_mode) { + 80081be: 9b01 ldr r3, [sp, #4] + 80081c0: b10b cbz r3, 80081c6 + found_slot->blank_slots = blank; + 80081c2: 9b00 ldr r3, [sp, #0] + 80081c4: 65df str r7, [r3, #92] ; 0x5c + if(found >= 0) { + 80081c6: 1c72 adds r2, r6, #1 + 80081c8: d069 beq.n 800829e + found_slot->slot_num = found; + 80081ca: 9b00 ldr r3, [sp, #0] + 80081cc: 0174 lsls r4, r6, #5 + 80081ce: 601e str r6, [r3, #0] + memcpy(meta, &slots[found][28], 4); + 80081d0: ab15 add r3, sp, #84 ; 0x54 + xor_mixin(meta, &tpin_hash[28], 4); + 80081d2: 2204 movs r2, #4 + memcpy(meta, &slots[found][28], 4); + 80081d4: 591b ldr r3, [r3, r4] + 80081d6: 9305 str r3, [sp, #20] + xor_mixin(meta, &tpin_hash[28], 4); + 80081d8: a90d add r1, sp, #52 ; 0x34 + 80081da: a805 add r0, sp, #20 + 80081dc: f7ff f982 bl 80074e4 + memcpy(&found_slot->tc_flags, &meta[0], 2); + 80081e0: 9b00 ldr r3, [sp, #0] + 80081e2: f8bd 5014 ldrh.w r5, [sp, #20] + memcpy(&found_slot->tc_arg, &meta[2], 2); + 80081e6: 9a00 ldr r2, [sp, #0] + memcpy(&found_slot->tc_flags, &meta[0], 2); + 80081e8: 809d strh r5, [r3, #4] + memcpy(&found_slot->tc_arg, &meta[2], 2); + 80081ea: f8bd 3016 ldrh.w r3, [sp, #22] + 80081ee: 80d3 strh r3, [r2, #6] + if(todo & TC_WORD_WALLET) { + 80081f0: 04eb lsls r3, r5, #19 + 80081f2: d513 bpl.n 800821c + if(found+1 < NUM_TRICKS) { + 80081f4: 2e0c cmp r6, #12 + 80081f6: dc0e bgt.n 8008216 + memcpy(found_slot->xdata, &slots[found+1][0], 32); + 80081f8: f504 73fc add.w r3, r4, #504 ; 0x1f8 + 80081fc: eb0d 0403 add.w r4, sp, r3 + 8008200: f5a4 73d0 sub.w r3, r4, #416 ; 0x1a0 + 8008204: 3208 adds r2, #8 + 8008206: f5a4 74c0 sub.w r4, r4, #384 ; 0x180 + 800820a: f853 1b04 ldr.w r1, [r3], #4 + 800820e: f842 1b04 str.w r1, [r2], #4 + 8008212: 42a3 cmp r3, r4 + 8008214: d1f9 bne.n 800820a + if(!safety_mode && todo) { + 8008216: 9b01 ldr r3, [sp, #4] + 8008218: b33b cbz r3, 800826a + 800821a: e03e b.n 800829a + } else if(todo & TC_XPRV_WALLET) { + 800821c: 052f lsls r7, r5, #20 + 800821e: d521 bpl.n 8008264 + if(found+2 < NUM_TRICKS) { + 8008220: 2e0b cmp r6, #11 + 8008222: dcf8 bgt.n 8008216 + memcpy(&found_slot->xdata[0], &slots[found+1][0], 32); + 8008224: 9900 ldr r1, [sp, #0] + 8008226: f504 73fc add.w r3, r4, #504 ; 0x1f8 + 800822a: 446b add r3, sp + 800822c: f5a3 72d0 sub.w r2, r3, #416 ; 0x1a0 + 8008230: 3108 adds r1, #8 + 8008232: f5a3 73c0 sub.w r3, r3, #384 ; 0x180 + 8008236: f852 0b04 ldr.w r0, [r2], #4 + 800823a: f841 0b04 str.w r0, [r1], #4 + 800823e: 429a cmp r2, r3 + 8008240: d1f9 bne.n 8008236 + memcpy(&found_slot->xdata[32], &slots[found+2][0], 32); + 8008242: f504 73fc add.w r3, r4, #504 ; 0x1f8 + 8008246: 9a00 ldr r2, [sp, #0] + 8008248: eb0d 0403 add.w r4, sp, r3 + 800824c: f5a4 73c0 sub.w r3, r4, #384 ; 0x180 + 8008250: 3228 adds r2, #40 ; 0x28 + 8008252: f5a4 74b0 sub.w r4, r4, #352 ; 0x160 + 8008256: f853 1b04 ldr.w r1, [r3], #4 + 800825a: f842 1b04 str.w r1, [r2], #4 + 800825e: 42a3 cmp r3, r4 + 8008260: d1f9 bne.n 8008256 + 8008262: e7d8 b.n 8008216 + if(!safety_mode && todo) { + 8008264: 9b01 ldr r3, [sp, #4] + 8008266: b9c3 cbnz r3, 800829a + 8008268: b1bd cbz r5, 800829a + if(todo & TC_WIPE) { + 800826a: 0428 lsls r0, r5, #16 + 800826c: d50a bpl.n 8008284 + mcu_key_clear(NULL); + 800826e: 2000 movs r0, #0 + 8008270: f7fa f9b8 bl 80025e4 + if(todo == TC_WIPE) { + 8008274: f5b5 4f00 cmp.w r5, #32768 ; 0x8000 + 8008278: d104 bne.n 8008284 + oled_show(screen_wiped); + 800827a: 480d ldr r0, [pc, #52] ; (80082b0 ) + 800827c: f7f8 fefa bl 8001074 + LOCKUP_FOREVER(); + 8008280: f7fb fcfa bl 8003c78 + if(todo & TC_BRICK) { + 8008284: 0469 lsls r1, r5, #17 + 8008286: d403 bmi.n 8008290 + if(todo & TC_REBOOT) { + 8008288: 05aa lsls r2, r5, #22 + 800828a: d504 bpl.n 8008296 + NVIC_SystemReset(); + 800828c: f7ff f918 bl 80074c0 <__NVIC_SystemReset> + fast_brick(); + 8008290: f7fa fa6c bl 800276c + 8008294: e7f8 b.n 8008288 + if(todo & TC_FAKE_OUT) { + 8008296: 04ab lsls r3, r5, #18 + 8008298: d401 bmi.n 800829e + return true; + 800829a: 2001 movs r0, #1 + 800829c: e745 b.n 800812a + found_slot->slot_num = -1; + 800829e: 9a00 ldr r2, [sp, #0] + 80082a0: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 80082a4: 6013 str r3, [r2, #0] + rng_delay(); + 80082a6: f7fa fb2f bl 8002908 + 80082aa: e73d b.n 8008128 + 80082ac: 2009e394 .word 0x2009e394 + 80082b0: 08010174 .word 0x08010174 + 80082b4: 0801c000 .word 0x0801c000 + 80082b8: 2009e2b4 .word 0x2009e2b4 + 80082bc: 0801c0b0 .word 0x0801c0b0 + +080082c0 : +{ + 80082c0: b510 push {r4, lr} + 80082c2: b0a2 sub sp, #136 ; 0x88 + 80082c4: 4604 mov r4, r0 + bool is_trick = se2_test_trick_pin("!p", 2, &slot, true); + 80082c6: 2301 movs r3, #1 + 80082c8: 481a ldr r0, [pc, #104] ; (8008334 ) + 80082ca: aa02 add r2, sp, #8 + 80082cc: 2102 movs r1, #2 + 80082ce: f7ff ff1b bl 8008108 + if(!is_trick) return; + 80082d2: b368 cbz r0, 8008330 + if(num_fails >= slot.tc_arg) { + 80082d4: f8bd 300e ldrh.w r3, [sp, #14] + 80082d8: 42a3 cmp r3, r4 + 80082da: dc29 bgt.n 8008330 + if(slot.tc_flags & TC_WIPE) { + 80082dc: f9bd 300c ldrsh.w r3, [sp, #12] + 80082e0: f8bd 000c ldrh.w r0, [sp, #12] + 80082e4: 2b00 cmp r3, #0 + 80082e6: da17 bge.n 8008318 + if(slot.tc_flags & TC_BRICK) { + 80082e8: f410 4080 ands.w r0, r0, #16384 ; 0x4000 + 80082ec: d00d beq.n 800830a + const mcu_key_t *cur = mcu_key_get(&valid); + 80082ee: f10d 0007 add.w r0, sp, #7 + 80082f2: f7fa f957 bl 80025a4 + if(valid) { + 80082f6: f89d 3007 ldrb.w r3, [sp, #7] + 80082fa: b16b cbz r3, 8008318 + mcu_key_clear(cur); + 80082fc: f7fa f972 bl 80025e4 + oled_show(screen_wiped); + 8008300: 480d ldr r0, [pc, #52] ; (8008338 ) + 8008302: f7f8 feb7 bl 8001074 + LOCKUP_FOREVER(); + 8008306: f7fb fcb7 bl 8003c78 + mcu_key_clear(NULL); // does valid key check + 800830a: f7fa f96b bl 80025e4 + if(slot.tc_flags == TC_WIPE) { + 800830e: f8bd 300c ldrh.w r3, [sp, #12] + 8008312: f5b3 4f00 cmp.w r3, #32768 ; 0x8000 + 8008316: d0f3 beq.n 8008300 + if(slot.tc_flags & TC_BRICK) { + 8008318: f8bd 300c ldrh.w r3, [sp, #12] + 800831c: 045a lsls r2, r3, #17 + 800831e: d501 bpl.n 8008324 + fast_brick(); + 8008320: f7fa fa24 bl 800276c + if(slot.tc_flags & TC_REBOOT) { + 8008324: f8bd 300c ldrh.w r3, [sp, #12] + 8008328: 059b lsls r3, r3, #22 + 800832a: d501 bpl.n 8008330 + NVIC_SystemReset(); + 800832c: f7ff f8c8 bl 80074c0 <__NVIC_SystemReset> +} + 8008330: b022 add sp, #136 ; 0x88 + 8008332: bd10 pop {r4, pc} + 8008334: 08010aa9 .word 0x08010aa9 + 8008338: 08010174 .word 0x08010174 + +0800833c : +{ + 800833c: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + 8008340: b094 sub sp, #80 ; 0x50 + 8008342: 9001 str r0, [sp, #4] + se2_setup(); + 8008344: f7ff fe34 bl 8007fb0 + if(setjmp(error_env)) { + 8008348: 4848 ldr r0, [pc, #288] ; (800846c ) + 800834a: f005 faf3 bl 800d934 + 800834e: 4604 mov r4, r0 + 8008350: 2800 cmp r0, #0 + 8008352: f040 8088 bne.w 8008466 + if((config->slot_num < 0) || (config->slot_num >= NUM_TRICKS) ) { + 8008356: 9b01 ldr r3, [sp, #4] + 8008358: 681b ldr r3, [r3, #0] + 800835a: 2b0d cmp r3, #13 + 800835c: d804 bhi.n 8008368 + if((config->slot_num >= NUM_TRICKS-1) && (config->tc_flags & TC_WORD_WALLET) ) { + 800835e: d106 bne.n 800836e + 8008360: 9b01 ldr r3, [sp, #4] + 8008362: 889b ldrh r3, [r3, #4] + 8008364: 04d9 lsls r1, r3, #19 + 8008366: d504 bpl.n 8008372 + return EPIN_RANGE_ERR; + 8008368: f06f 0466 mvn.w r4, #102 ; 0x66 + 800836c: e01f b.n 80083ae + if((config->slot_num >= NUM_TRICKS-2) && (config->tc_flags & TC_XPRV_WALLET) ) { + 800836e: 2b0c cmp r3, #12 + 8008370: d103 bne.n 800837a + 8008372: 9b01 ldr r3, [sp, #4] + 8008374: 889b ldrh r3, [r3, #4] + 8008376: 051a lsls r2, r3, #20 + 8008378: d4f6 bmi.n 8008368 + if(config->pin_len > sizeof(config->pin)) { + 800837a: 9b01 ldr r3, [sp, #4] + 800837c: 6d99 ldr r1, [r3, #88] ; 0x58 + 800837e: 2910 cmp r1, #16 + 8008380: d8f2 bhi.n 8008368 + if(config->blank_slots) { + 8008382: 6ddd ldr r5, [r3, #92] ; 0x5c + 8008384: b31d cbz r5, 80083ce + uint8_t zeros[32] = { 0 }; + 8008386: 2100 movs r1, #0 + 8008388: 221c movs r2, #28 + 800838a: a805 add r0, sp, #20 + 800838c: 9104 str r1, [sp, #16] + 800838e: f005 fac9 bl 800d924 + se2_write_encrypted(PGN_TRICK(i), zeros, 0, SE2_SECRETS->pairing); + 8008392: f8df 80e4 ldr.w r8, [pc, #228] ; 8008478 + 8008396: 4f36 ldr r7, [pc, #216] ; (8008470 ) + 8008398: 4e36 ldr r6, [pc, #216] ; (8008474 ) + for(int i=0; iblank_slots) { + 800839c: 9a01 ldr r2, [sp, #4] + uint32_t mask = (1 << i); + 800839e: 2301 movs r3, #1 + if(mask & config->blank_slots) { + 80083a0: 6dd2 ldr r2, [r2, #92] ; 0x5c + uint32_t mask = (1 << i); + 80083a2: 40ab lsls r3, r5 + if(mask & config->blank_slots) { + 80083a4: 4213 tst r3, r2 + 80083a6: d106 bne.n 80083b6 + for(int i=0; i +} + 80083ae: 4620 mov r0, r4 + 80083b0: b014 add sp, #80 ; 0x50 + 80083b2: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + se2_write_encrypted(PGN_TRICK(i), zeros, 0, SE2_SECRETS->pairing); + 80083b6: f898 30b0 ldrb.w r3, [r8, #176] ; 0xb0 + 80083ba: 2200 movs r2, #0 + 80083bc: 2bff cmp r3, #255 ; 0xff + 80083be: bf0c ite eq + 80083c0: 463b moveq r3, r7 + 80083c2: 4633 movne r3, r6 + 80083c4: a904 add r1, sp, #16 + 80083c6: b2e8 uxtb r0, r5 + 80083c8: f7ff faa2 bl 8007910 + 80083cc: e7ec b.n 80083a8 + trick_pin_hash(config->pin, config->pin_len, tpin_digest); + 80083ce: 9b01 ldr r3, [sp, #4] + se2_write_encrypted(PGN_TRICK(config->slot_num), tpin_digest, 0, SE2_SECRETS->pairing); + 80083d0: f8df 80a4 ldr.w r8, [pc, #164] ; 8008478 + 80083d4: 4f26 ldr r7, [pc, #152] ; (8008470 ) + 80083d6: 4e27 ldr r6, [pc, #156] ; (8008474 ) + trick_pin_hash(config->pin, config->pin_len, tpin_digest); + 80083d8: f103 0048 add.w r0, r3, #72 ; 0x48 + 80083dc: aa0c add r2, sp, #48 ; 0x30 + 80083de: f7ff fcdb bl 8007d98 + memcpy(&meta[0], &config->tc_flags, 2); + 80083e2: 9b01 ldr r3, [sp, #4] + 80083e4: 889b ldrh r3, [r3, #4] + 80083e6: f8ad 300c strh.w r3, [sp, #12] + memcpy(&meta[2], &config->tc_arg, 2); + 80083ea: 9b01 ldr r3, [sp, #4] + xor_mixin(&tpin_digest[28], meta, 4); + 80083ec: 2204 movs r2, #4 + memcpy(&meta[2], &config->tc_arg, 2); + 80083ee: 88db ldrh r3, [r3, #6] + 80083f0: f8ad 300e strh.w r3, [sp, #14] + xor_mixin(&tpin_digest[28], meta, 4); + 80083f4: a903 add r1, sp, #12 + 80083f6: a813 add r0, sp, #76 ; 0x4c + 80083f8: f7ff f874 bl 80074e4 + se2_write_encrypted(PGN_TRICK(config->slot_num), tpin_digest, 0, SE2_SECRETS->pairing); + 80083fc: f898 30b0 ldrb.w r3, [r8, #176] ; 0xb0 + 8008400: 9801 ldr r0, [sp, #4] + 8008402: 2bff cmp r3, #255 ; 0xff + 8008404: bf0c ite eq + 8008406: 463b moveq r3, r7 + 8008408: 4633 movne r3, r6 + 800840a: 7800 ldrb r0, [r0, #0] + 800840c: 462a mov r2, r5 + 800840e: a90c add r1, sp, #48 ; 0x30 + 8008410: f7ff fa7e bl 8007910 + if(config->tc_flags & (TC_WORD_WALLET | TC_XPRV_WALLET)) { + 8008414: 9b01 ldr r3, [sp, #4] + 8008416: 889b ldrh r3, [r3, #4] + 8008418: f403 53c0 and.w r3, r3, #6144 ; 0x1800 + 800841c: b9a3 cbnz r3, 8008448 + if(config->tc_flags & TC_XPRV_WALLET) { + 800841e: 9b01 ldr r3, [sp, #4] + 8008420: 889b ldrh r3, [r3, #4] + 8008422: 051b lsls r3, r3, #20 + 8008424: d5c3 bpl.n 80083ae + se2_write_encrypted(PGN_TRICK(config->slot_num+2), &config->xdata[32], + 8008426: 9901 ldr r1, [sp, #4] + 0, SE2_SECRETS->pairing); + 8008428: 4b13 ldr r3, [pc, #76] ; (8008478 ) + se2_write_encrypted(PGN_TRICK(config->slot_num+2), &config->xdata[32], + 800842a: f851 0b28 ldr.w r0, [r1], #40 + 0, SE2_SECRETS->pairing); + 800842e: f893 50b0 ldrb.w r5, [r3, #176] ; 0xb0 + se2_write_encrypted(PGN_TRICK(config->slot_num+2), &config->xdata[32], + 8008432: 4a10 ldr r2, [pc, #64] ; (8008474 ) + 8008434: 4b0e ldr r3, [pc, #56] ; (8008470 ) + 8008436: 3002 adds r0, #2 + 8008438: 2dff cmp r5, #255 ; 0xff + 800843a: bf18 it ne + 800843c: 4613 movne r3, r2 + 800843e: b2c0 uxtb r0, r0 + 8008440: 2200 movs r2, #0 + 8008442: f7ff fa65 bl 8007910 + 8008446: e7b2 b.n 80083ae + se2_write_encrypted(PGN_TRICK(config->slot_num+1), &config->xdata[0], + 8008448: 9901 ldr r1, [sp, #4] + 0, SE2_SECRETS->pairing); + 800844a: f898 30b0 ldrb.w r3, [r8, #176] ; 0xb0 + se2_write_encrypted(PGN_TRICK(config->slot_num+1), &config->xdata[0], + 800844e: f851 0b08 ldr.w r0, [r1], #8 + 8008452: 3001 adds r0, #1 + 8008454: 2bff cmp r3, #255 ; 0xff + 8008456: bf0c ite eq + 8008458: 463b moveq r3, r7 + 800845a: 4633 movne r3, r6 + 800845c: 462a mov r2, r5 + 800845e: b2c0 uxtb r0, r0 + 8008460: f7ff fa56 bl 8007910 + 8008464: e7db b.n 800841e + return EPIN_SE2_FAIL; + 8008466: f06f 0472 mvn.w r4, #114 ; 0x72 + 800846a: e7a0 b.n 80083ae + 800846c: 2009e394 .word 0x2009e394 + 8008470: 2009e2b4 .word 0x2009e2b4 + 8008474: 0801c0b0 .word 0x0801c0b0 + 8008478: 0801c000 .word 0x0801c000 + +0800847c : +// + bool +se2_encrypt_secret(const uint8_t secret[], int secret_len, int offset, + uint8_t main_slot[], uint8_t *check_value, + const uint8_t pin_digest[32]) +{ + 800847c: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + 8008480: f5ad 7d10 sub.w sp, sp, #576 ; 0x240 + 8008484: 4699 mov r9, r3 + 8008486: 4682 mov sl, r0 + 8008488: 460f mov r7, r1 + 800848a: 4614 mov r4, r2 + 800848c: f8dd 8260 ldr.w r8, [sp, #608] ; 0x260 + se2_setup(); + 8008490: f7ff fd8e bl 8007fb0 + + bool is_valid; + const mcu_key_t *cur = mcu_key_get(&is_valid); + 8008494: f10d 000b add.w r0, sp, #11 + 8008498: f7fa f884 bl 80025a4 + + if(!is_valid) { + 800849c: f89d 300b ldrb.w r3, [sp, #11] + 80084a0: b953 cbnz r3, 80084b8 + if(!check_value) { + 80084a2: f1b8 0f00 cmp.w r8, #0 + 80084a6: d105 bne.n 80084b4 + // problem: we are not writing the check value but it would be changed. + // ie: change long secret before real secret--unlikely + return true; + 80084a8: 2501 movs r5, #1 + ctx.num_pending = 32; + aes_done(&ctx, check_value, 32, aes_key, nonce); + } + + return false; +} + 80084aa: 4628 mov r0, r5 + 80084ac: f50d 7d10 add.w sp, sp, #576 ; 0x240 + 80084b0: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + cur = mcu_key_pick(); + 80084b4: f7fa f8de bl 8002674 + if(se2_calc_seed_key(aes_key, cur, pin_digest)) return true; + 80084b8: 4601 mov r1, r0 + 80084ba: 9a99 ldr r2, [sp, #612] ; 0x264 + 80084bc: a807 add r0, sp, #28 + 80084be: f7ff fd45 bl 8007f4c + 80084c2: 4605 mov r5, r0 + 80084c4: 2800 cmp r0, #0 + 80084c6: d1ef bne.n 80084a8 + memcpy(nonce, rom_secrets->mcu_hmac_key, sizeof(nonce)-1); + 80084c8: 4b16 ldr r3, [pc, #88] ; (8008524 ) + 80084ca: cb0f ldmia r3, {r0, r1, r2, r3} + 80084cc: ae03 add r6, sp, #12 + 80084ce: 46b4 mov ip, r6 + 80084d0: e8ac 0007 stmia.w ip!, {r0, r1, r2} + nonce[15] = offset / AES_BLOCK_SIZE; + 80084d4: 2c00 cmp r4, #0 + memcpy(nonce, rom_secrets->mcu_hmac_key, sizeof(nonce)-1); + 80084d6: f82c 3b02 strh.w r3, [ip], #2 + nonce[15] = offset / AES_BLOCK_SIZE; + 80084da: bfb8 it lt + 80084dc: 340f addlt r4, #15 + memcpy(nonce, rom_secrets->mcu_hmac_key, sizeof(nonce)-1); + 80084de: 0c1b lsrs r3, r3, #16 + 80084e0: f88c 3000 strb.w r3, [ip] + aes_init(&ctx); + 80084e4: a80f add r0, sp, #60 ; 0x3c + nonce[15] = offset / AES_BLOCK_SIZE; + 80084e6: 1124 asrs r4, r4, #4 + 80084e8: 73f4 strb r4, [r6, #15] + aes_init(&ctx); + 80084ea: f000 f92b bl 8008744 + aes_add(&ctx, secret, secret_len); + 80084ee: 463a mov r2, r7 + 80084f0: 4651 mov r1, sl + 80084f2: a80f add r0, sp, #60 ; 0x3c + 80084f4: f000 f92c bl 8008750 + aes_done(&ctx, main_slot, secret_len, aes_key, nonce); + 80084f8: 9600 str r6, [sp, #0] + 80084fa: ab07 add r3, sp, #28 + 80084fc: 463a mov r2, r7 + 80084fe: 4649 mov r1, r9 + 8008500: a80f add r0, sp, #60 ; 0x3c + 8008502: f000 f93b bl 800877c + if(check_value) { + 8008506: f1b8 0f00 cmp.w r8, #0 + 800850a: d0ce beq.n 80084aa + aes_init(&ctx); + 800850c: a80f add r0, sp, #60 ; 0x3c + 800850e: f000 f919 bl 8008744 + ctx.num_pending = 32; + 8008512: 2220 movs r2, #32 + aes_done(&ctx, check_value, 32, aes_key, nonce); + 8008514: 9600 str r6, [sp, #0] + 8008516: ab07 add r3, sp, #28 + 8008518: 4641 mov r1, r8 + 800851a: a80f add r0, sp, #60 ; 0x3c + ctx.num_pending = 32; + 800851c: 928f str r2, [sp, #572] ; 0x23c + aes_done(&ctx, check_value, 32, aes_key, nonce); + 800851e: f000 f92d bl 800877c + 8008522: e7c2 b.n 80084aa + 8008524: 0801c090 .word 0x0801c090 + +08008528 : +// + void +se2_decrypt_secret(uint8_t secret[], int secret_len, int offset, + const uint8_t main_slot[], const uint8_t *check_value, + const uint8_t pin_digest[32], bool *is_valid) +{ + 8008528: b530 push {r4, r5, lr} + 800852a: f5ad 7d1f sub.w sp, sp, #636 ; 0x27c + 800852e: e9cd 2306 strd r2, r3, [sp, #24] + 8008532: 9005 str r0, [sp, #20] + 8008534: 9103 str r1, [sp, #12] + se2_setup(); + 8008536: f7ff fd3b bl 8007fb0 + + const mcu_key_t *cur = mcu_key_get(is_valid); + 800853a: 98a4 ldr r0, [sp, #656] ; 0x290 + 800853c: f7fa f832 bl 80025a4 + if(!*is_valid) { + 8008540: 9ba4 ldr r3, [sp, #656] ; 0x290 + const mcu_key_t *cur = mcu_key_get(is_valid); + 8008542: 9004 str r0, [sp, #16] + if(!*is_valid) { + 8008544: 781b ldrb r3, [r3, #0] + 8008546: b133 cbz r3, 8008556 + // no key set? won't be able to decrypt. + return; + } + + int line_num; + if((line_num = setjmp(error_env))) { + 8008548: 4825 ldr r0, [pc, #148] ; (80085e0 ) + 800854a: f005 f9f3 bl 800d934 + 800854e: b128 cbz r0, 800855c + // internal failures / broken i2c buses will come here + *is_valid = false; + 8008550: 9aa4 ldr r2, [sp, #656] ; 0x290 + 8008552: 2300 movs r3, #0 + 8008554: 7013 strb r3, [r2, #0] + + // decrypt the real data + aes_init(&ctx); + aes_add(&ctx, main_slot, secret_len); + aes_done(&ctx, secret, secret_len, aes_key, nonce); +} + 8008556: f50d 7d1f add.w sp, sp, #636 ; 0x27c + 800855a: bd30 pop {r4, r5, pc} + if(se2_calc_seed_key(aes_key, cur, pin_digest)) { + 800855c: 9aa3 ldr r2, [sp, #652] ; 0x28c + 800855e: 9904 ldr r1, [sp, #16] + 8008560: a80d add r0, sp, #52 ; 0x34 + 8008562: f7ff fcf3 bl 8007f4c + 8008566: 2800 cmp r0, #0 + 8008568: d1f2 bne.n 8008550 + memcpy(nonce, rom_secrets->mcu_hmac_key, sizeof(nonce)-1); + 800856a: 4b1e ldr r3, [pc, #120] ; (80085e4 ) + 800856c: cb0f ldmia r3, {r0, r1, r2, r3} + 800856e: ad09 add r5, sp, #36 ; 0x24 + 8008570: 462c mov r4, r5 + 8008572: c407 stmia r4!, {r0, r1, r2} + 8008574: f824 3b02 strh.w r3, [r4], #2 + 8008578: 0c1b lsrs r3, r3, #16 + 800857a: 7023 strb r3, [r4, #0] + nonce[15] = offset / AES_BLOCK_SIZE; + 800857c: 9b06 ldr r3, [sp, #24] + 800857e: 2b00 cmp r3, #0 + 8008580: bfb8 it lt + 8008582: 330f addlt r3, #15 + 8008584: 111b asrs r3, r3, #4 + 8008586: 73eb strb r3, [r5, #15] + if(check_value) { + 8008588: 9ba2 ldr r3, [sp, #648] ; 0x288 + 800858a: b1bb cbz r3, 80085bc + aes_init(&ctx); + 800858c: a81d add r0, sp, #116 ; 0x74 + 800858e: f000 f8d9 bl 8008744 + aes_add(&ctx, check_value, 32); + 8008592: 99a2 ldr r1, [sp, #648] ; 0x288 + 8008594: 2220 movs r2, #32 + 8008596: a81d add r0, sp, #116 ; 0x74 + 8008598: f000 f8da bl 8008750 + aes_done(&ctx, got, 32, aes_key, nonce); + 800859c: ab09 add r3, sp, #36 ; 0x24 + 800859e: 9300 str r3, [sp, #0] + 80085a0: a915 add r1, sp, #84 ; 0x54 + 80085a2: a81d add r0, sp, #116 ; 0x74 + 80085a4: ab0d add r3, sp, #52 ; 0x34 + 80085a6: 2220 movs r2, #32 + 80085a8: f000 f8e8 bl 800877c + if(!check_all_zeros(got, 32)) { + 80085ac: 2120 movs r1, #32 + 80085ae: a815 add r0, sp, #84 ; 0x54 + 80085b0: f7fa f936 bl 8002820 + 80085b4: b910 cbnz r0, 80085bc + *is_valid = false; + 80085b6: 9ba4 ldr r3, [sp, #656] ; 0x290 + 80085b8: 7018 strb r0, [r3, #0] + return; + 80085ba: e7cc b.n 8008556 + aes_init(&ctx); + 80085bc: a81d add r0, sp, #116 ; 0x74 + 80085be: f000 f8c1 bl 8008744 + aes_add(&ctx, main_slot, secret_len); + 80085c2: 9a03 ldr r2, [sp, #12] + 80085c4: 9907 ldr r1, [sp, #28] + 80085c6: a81d add r0, sp, #116 ; 0x74 + 80085c8: f000 f8c2 bl 8008750 + aes_done(&ctx, secret, secret_len, aes_key, nonce); + 80085cc: ab09 add r3, sp, #36 ; 0x24 + 80085ce: 9300 str r3, [sp, #0] + 80085d0: 9a03 ldr r2, [sp, #12] + 80085d2: 9905 ldr r1, [sp, #20] + 80085d4: ab0d add r3, sp, #52 ; 0x34 + 80085d6: a81d add r0, sp, #116 ; 0x74 + 80085d8: f000 f8d0 bl 800877c + 80085dc: e7bb b.n 8008556 + 80085de: bf00 nop + 80085e0: 2009e394 .word 0x2009e394 + 80085e4: 0801c090 .word 0x0801c090 + +080085e8 : +// +// Hash up a PIN code for login attempt: to tie it into SE2's contents. +// + void +se2_pin_hash(uint8_t digest_io[32], uint32_t purpose) +{ + 80085e8: b5f0 push {r4, r5, r6, r7, lr} + if(purpose != PIN_PURPOSE_NORMAL) { + 80085ea: 4b41 ldr r3, [pc, #260] ; (80086f0 ) +{ + 80085ec: b0d5 sub sp, #340 ; 0x154 + if(purpose != PIN_PURPOSE_NORMAL) { + 80085ee: 4299 cmp r1, r3 +{ + 80085f0: e9cd 0100 strd r0, r1, [sp] + if(purpose != PIN_PURPOSE_NORMAL) { + 80085f4: d17a bne.n 80086ec + // do nothing except for real PIN case (ie. not for prefix words) + return; + } + + se2_setup(); + 80085f6: f7ff fcdb bl 8007fb0 + if((setjmp(error_env))) { + 80085fa: 483e ldr r0, [pc, #248] ; (80086f4 ) + 80085fc: f005 f99a bl 800d934 + 8008600: 4604 mov r4, r0 + 8008602: b120 cbz r0, 800860e + oled_show(screen_se2_issue); + 8008604: 483c ldr r0, [pc, #240] ; (80086f8 ) + 8008606: f7f8 fd35 bl 8001074 + + LOCKUP_FOREVER(); + 800860a: f7fb fb35 bl 8003c78 + uint8_t rx[34]; // 2 bytes of len+status, then 32 bytes of data + uint8_t tmp[32]; + HMAC_CTX ctx; + + // HMAC(key=tpin_key, msg=given hash so far) + hmac_sha256_init(&ctx); + 800860e: a813 add r0, sp, #76 ; 0x4c + 8008610: f7fd f93c bl 800588c + hmac_sha256_update(&ctx, digest_io, 32); + 8008614: 9900 ldr r1, [sp, #0] + 8008616: 2220 movs r2, #32 + 8008618: a813 add r0, sp, #76 ; 0x4c + 800861a: f7fd f93d bl 8005898 + hmac_sha256_update(&ctx, (uint8_t *)&purpose, 4); + 800861e: 2204 movs r2, #4 + 8008620: eb0d 0102 add.w r1, sp, r2 + 8008624: a813 add r0, sp, #76 ; 0x4c + 8008626: f7fd f937 bl 8005898 + hmac_sha256_final(&ctx, SE2_SECRETS->tpin_key, tmp); + 800862a: 4b34 ldr r3, [pc, #208] ; (80086fc ) + 800862c: 4934 ldr r1, [pc, #208] ; (8008700 ) + 800862e: f893 20b0 ldrb.w r2, [r3, #176] ; 0xb0 + 8008632: 33b0 adds r3, #176 ; 0xb0 + 8008634: 2aff cmp r2, #255 ; 0xff + 8008636: bf18 it ne + 8008638: 4619 movne r1, r3 + 800863a: 3180 adds r1, #128 ; 0x80 + 800863c: aa02 add r2, sp, #8 + 800863e: a813 add r0, sp, #76 ; 0x4c + 8008640: f7fd f940 bl 80058c4 + + // NOTE: exposed as cleartext here + se2_write_buffer(tmp, 32); + 8008644: 2120 movs r1, #32 + 8008646: a802 add r0, sp, #8 + 8008648: f7fe ffc8 bl 80075dc + 800864c: 25aa movs r5, #170 ; 0xaa + se2_write_buffer(rx+2, 32); + } + + // HMAC(key=secret-B, msg=consts+easy_key+buffer+consts) + // - result put in secret-S (ram) + CALL_CHECK(se2_write2(0x3c, (2<<6) | (1<<4) | PGN_SE2_EASY_KEY, 0)); + 800864e: 269e movs r6, #158 ; 0x9e + 8008650: 273c movs r7, #60 ; 0x3c + 8008652: 4622 mov r2, r4 + 8008654: 4631 mov r1, r6 + 8008656: 4638 mov r0, r7 + 8008658: f7fe ff6c bl 8007534 + 800865c: b150 cbz r0, 8008674 + 800865e: f240 511d movw r1, #1309 ; 0x51d + CHECK_RIGHT(se2_read1() == RC_SUCCESS); + 8008662: 4824 ldr r0, [pc, #144] ; (80086f4 ) + 8008664: f005 f96c bl 800d940 + se2_write_buffer(rx+2, 32); + 8008668: 2120 movs r1, #32 + 800866a: f10d 002a add.w r0, sp, #42 ; 0x2a + 800866e: f7fe ffb5 bl 80075dc + 8008672: e7ee b.n 8008652 + CHECK_RIGHT(se2_read1() == RC_SUCCESS); + 8008674: f7fe ffea bl 800764c + 8008678: 28aa cmp r0, #170 ; 0xaa + 800867a: d002 beq.n 8008682 + 800867c: f240 511e movw r1, #1310 ; 0x51e + 8008680: e7ef b.n 8008662 + + // HMAC(key=S, msg=counter+junk), so we have something to read out + // - not 100% clear what contents of 'buffer' are here, but seems + // to be deterministic and unchanged from prev command + CALL_CHECK(se2_write1(0xa5, (2<<5) | PGN_DEC_COUNTER)); + 8008682: 215b movs r1, #91 ; 0x5b + 8008684: 20a5 movs r0, #165 ; 0xa5 + 8008686: f7fe ff3b bl 8007500 + 800868a: b110 cbz r0, 8008692 + 800868c: f240 5123 movw r1, #1315 ; 0x523 + 8008690: e7e7 b.n 8008662 + + CHECK_RIGHT(se2_read_n(sizeof(rx), rx) == RC_SUCCESS); + 8008692: a90a add r1, sp, #40 ; 0x28 + 8008694: 2022 movs r0, #34 ; 0x22 + 8008696: f7fe ffb1 bl 80075fc + 800869a: 28aa cmp r0, #170 ; 0xaa + 800869c: d002 beq.n 80086a4 + 800869e: f240 5125 movw r1, #1317 ; 0x525 + 80086a2: e7de b.n 8008662 + CHECK_RIGHT(rx[1] == RC_SUCCESS); + 80086a4: f89d 3029 ldrb.w r3, [sp, #41] ; 0x29 + 80086a8: 2baa cmp r3, #170 ; 0xaa + 80086aa: d002 beq.n 80086b2 + 80086ac: f240 5126 movw r1, #1318 ; 0x526 + 80086b0: e7d7 b.n 8008662 + for(int i=0; i + } + + // one final HMAC because we had to read cleartext from bus + hmac_sha256_init(&ctx); + 80086b6: a813 add r0, sp, #76 ; 0x4c + 80086b8: f7fd f8e8 bl 800588c + hmac_sha256_update(&ctx, rx+2, 32); + 80086bc: 2220 movs r2, #32 + 80086be: f10d 012a add.w r1, sp, #42 ; 0x2a + 80086c2: a813 add r0, sp, #76 ; 0x4c + 80086c4: f7fd f8e8 bl 8005898 + hmac_sha256_update(&ctx, digest_io, 32); + 80086c8: 9900 ldr r1, [sp, #0] + 80086ca: 2220 movs r2, #32 + 80086cc: a813 add r0, sp, #76 ; 0x4c + 80086ce: f7fd f8e3 bl 8005898 + hmac_sha256_final(&ctx, SE2_SECRETS->tpin_key, digest_io); + 80086d2: 4b0a ldr r3, [pc, #40] ; (80086fc ) + 80086d4: 490a ldr r1, [pc, #40] ; (8008700 ) + 80086d6: f893 20b0 ldrb.w r2, [r3, #176] ; 0xb0 + 80086da: 33b0 adds r3, #176 ; 0xb0 + 80086dc: 2aff cmp r2, #255 ; 0xff + 80086de: bf18 it ne + 80086e0: 4619 movne r1, r3 + 80086e2: 3180 adds r1, #128 ; 0x80 + 80086e4: 9a00 ldr r2, [sp, #0] + 80086e6: a813 add r0, sp, #76 ; 0x4c + 80086e8: f7fd f8ec bl 80058c4 +} + 80086ec: b055 add sp, #340 ; 0x154 + 80086ee: bdf0 pop {r4, r5, r6, r7, pc} + 80086f0: 334d1858 .word 0x334d1858 + 80086f4: 2009e394 .word 0x2009e394 + 80086f8: 0800f3d7 .word 0x0800f3d7 + 80086fc: 0801c000 .word 0x0801c000 + 8008700: 2009e2b4 .word 0x2009e2b4 + +08008704 : +// +// Read some random bytes, which we know cannot be MitM'ed. +// + void +se2_read_rng(uint8_t value[8]) +{ + 8008704: b500 push {lr} + 8008706: b08b sub sp, #44 ; 0x2c + 8008708: 9001 str r0, [sp, #4] + // funny business means MitM here + se2_setup(); + 800870a: f7ff fc51 bl 8007fb0 + if(setjmp(error_env)) fatal_mitm(); + 800870e: 4809 ldr r0, [pc, #36] ; (8008734 ) + 8008710: f005 f910 bl 800d934 + 8008714: b108 cbz r0, 800871a + 8008716: f7f8 f999 bl 8000a4c + + // read a field with "RPS" bytes, and verify those were read true + uint8_t tmp[32]; + se2_read_page(PGN_ROM_OPTIONS, tmp, true); + 800871a: a902 add r1, sp, #8 + 800871c: 2201 movs r2, #1 + 800871e: 201c movs r0, #28 + 8008720: f7ff f830 bl 8007784 + + memcpy(value, &tmp[4], 8); + 8008724: ab03 add r3, sp, #12 + 8008726: cb03 ldmia r3!, {r0, r1} + 8008728: 9b01 ldr r3, [sp, #4] + 800872a: 6018 str r0, [r3, #0] + 800872c: 6059 str r1, [r3, #4] +} + 800872e: b00b add sp, #44 ; 0x2c + 8008730: f85d fb04 ldr.w pc, [sp], #4 + 8008734: 2009e394 .word 0x2009e394 + +08008738 : + uint32_t rv; + + if(((uint32_t)src) & 0x3) { + memcpy(&rv, *src, 4); + } else { + rv = *(uint32_t *)(*src); + 8008738: 6803 ldr r3, [r0, #0] + 800873a: f853 2b04 ldr.w r2, [r3], #4 + } + (*src) += 4; + 800873e: 6003 str r3, [r0, #0] + + return __REV(rv); +} + 8008740: ba10 rev r0, r2 + 8008742: 4770 bx lr + +08008744 : + memset(ctx, 0, sizeof(AES_CTX)); + 8008744: f44f 7201 mov.w r2, #516 ; 0x204 + 8008748: 2100 movs r1, #0 + 800874a: f005 b8eb b.w 800d924 + ... + +08008750 : +{ + 8008750: b538 push {r3, r4, r5, lr} + 8008752: 4605 mov r5, r0 + memcpy(ctx->pending+ctx->num_pending, data_in, len); + 8008754: f8d0 0200 ldr.w r0, [r0, #512] ; 0x200 + 8008758: 4428 add r0, r5 +{ + 800875a: 4614 mov r4, r2 + memcpy(ctx->pending+ctx->num_pending, data_in, len); + 800875c: f005 f8d4 bl 800d908 + ctx->num_pending += len; + 8008760: f8d5 2200 ldr.w r2, [r5, #512] ; 0x200 + 8008764: 4422 add r2, r4 + ASSERT(ctx->num_pending < sizeof(ctx->pending)); + 8008766: f5b2 7f00 cmp.w r2, #512 ; 0x200 + ctx->num_pending += len; + 800876a: f8c5 2200 str.w r2, [r5, #512] ; 0x200 + ASSERT(ctx->num_pending < sizeof(ctx->pending)); + 800876e: d302 bcc.n 8008776 + 8008770: 4801 ldr r0, [pc, #4] ; (8008778 ) + 8008772: f7f8 f961 bl 8000a38 +} + 8008776: bd38 pop {r3, r4, r5, pc} + 8008778: 0801046c .word 0x0801046c + +0800877c : +// +// Do the decryption. +// + void +aes_done(AES_CTX *ctx, uint8_t data_out[], uint32_t len, const uint8_t key[32], const uint8_t nonce[AES_BLOCK_SIZE]) +{ + 800877c: e92d 43f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, lr} + 8008780: 4688 mov r8, r1 + 8008782: 4611 mov r1, r2 + ASSERT(len <= ctx->num_pending); + 8008784: f8d0 2200 ldr.w r2, [r0, #512] ; 0x200 +{ + 8008788: b085 sub sp, #20 + ASSERT(len <= ctx->num_pending); + 800878a: 428a cmp r2, r1 +{ + 800878c: f8dd 9030 ldr.w r9, [sp, #48] ; 0x30 + 8008790: 4606 mov r6, r0 + ASSERT(len <= ctx->num_pending); + 8008792: d202 bcs.n 800879a + 8008794: 4858 ldr r0, [pc, #352] ; (80088f8 ) + 8008796: f7f8 f94f bl 8000a38 + + // enable clock to block + __HAL_RCC_AES_CLK_ENABLE(); + 800879a: 4d58 ldr r5, [pc, #352] ; (80088fc ) + + // most changes have to be made w/ module disabled + AES->CR &= ~AES_CR_EN; + 800879c: 4c58 ldr r4, [pc, #352] ; (8008900 ) + __HAL_RCC_AES_CLK_ENABLE(); + 800879e: 6cea ldr r2, [r5, #76] ; 0x4c + 80087a0: f442 3280 orr.w r2, r2, #65536 ; 0x10000 + 80087a4: 64ea str r2, [r5, #76] ; 0x4c + 80087a6: 6cea ldr r2, [r5, #76] ; 0x4c + 80087a8: f402 3280 and.w r2, r2, #65536 ; 0x10000 + 80087ac: 9201 str r2, [sp, #4] + 80087ae: 9a01 ldr r2, [sp, #4] + AES->CR &= ~AES_CR_EN; + 80087b0: 6822 ldr r2, [r4, #0] + 80087b2: f022 0201 bic.w r2, r2, #1 + 80087b6: 6022 str r2, [r4, #0] + + // set the key size and operation mode + MODIFY_REG(AES->CR, AES_CR_KEYSIZE, CRYP_KEYSIZE_256B); + 80087b8: 6822 ldr r2, [r4, #0] + 80087ba: f442 2280 orr.w r2, r2, #262144 ; 0x40000 + 80087be: 6022 str r2, [r4, #0] + MODIFY_REG(AES->CR, AES_CR_DATATYPE|AES_CR_MODE|AES_CR_CHMOD, + 80087c0: 6827 ldr r7, [r4, #0] + 80087c2: f427 3780 bic.w r7, r7, #65536 ; 0x10000 + 80087c6: f027 077e bic.w r7, r7, #126 ; 0x7e + 80087ca: f047 0744 orr.w r7, r7, #68 ; 0x44 + 80087ce: 6027 str r7, [r4, #0] + CRYP_DATATYPE_8B | CRYP_ALGOMODE_ENCRYPT | CRYP_CHAINMODE_AES_CTR); + + // load key and IV values + const uint8_t *K = key; + AES->KEYR7 = word_pump_bytes(&K); + 80087d0: a802 add r0, sp, #8 + const uint8_t *K = key; + 80087d2: 9302 str r3, [sp, #8] + AES->KEYR7 = word_pump_bytes(&K); + 80087d4: f7ff ffb0 bl 8008738 + 80087d8: 63e0 str r0, [r4, #60] ; 0x3c + AES->KEYR6 = word_pump_bytes(&K); + 80087da: a802 add r0, sp, #8 + 80087dc: f7ff ffac bl 8008738 + 80087e0: 63a0 str r0, [r4, #56] ; 0x38 + AES->KEYR5 = word_pump_bytes(&K); + 80087e2: a802 add r0, sp, #8 + 80087e4: f7ff ffa8 bl 8008738 + 80087e8: 6360 str r0, [r4, #52] ; 0x34 + AES->KEYR4 = word_pump_bytes(&K); + 80087ea: a802 add r0, sp, #8 + 80087ec: f7ff ffa4 bl 8008738 + 80087f0: 6320 str r0, [r4, #48] ; 0x30 + AES->KEYR3 = word_pump_bytes(&K); + 80087f2: a802 add r0, sp, #8 + 80087f4: f7ff ffa0 bl 8008738 + 80087f8: 61e0 str r0, [r4, #28] + AES->KEYR2 = word_pump_bytes(&K); + 80087fa: a802 add r0, sp, #8 + 80087fc: f7ff ff9c bl 8008738 + 8008800: 61a0 str r0, [r4, #24] + AES->KEYR1 = word_pump_bytes(&K); + 8008802: a802 add r0, sp, #8 + 8008804: f7ff ff98 bl 8008738 + 8008808: 6160 str r0, [r4, #20] + AES->KEYR0 = word_pump_bytes(&K); + 800880a: a802 add r0, sp, #8 + 800880c: f7ff ff94 bl 8008738 + 8008810: 6120 str r0, [r4, #16] + + if(nonce) { + 8008812: f1b9 0f00 cmp.w r9, #0 + 8008816: d045 beq.n 80088a4 + const uint8_t *N = nonce; + AES->IVR3 = word_pump_bytes(&N); + 8008818: a803 add r0, sp, #12 + const uint8_t *N = nonce; + 800881a: f8cd 900c str.w r9, [sp, #12] + AES->IVR3 = word_pump_bytes(&N); + 800881e: f7ff ff8b bl 8008738 + 8008822: 62e0 str r0, [r4, #44] ; 0x2c + AES->IVR2 = word_pump_bytes(&N); + 8008824: a803 add r0, sp, #12 + 8008826: f7ff ff87 bl 8008738 + 800882a: 62a0 str r0, [r4, #40] ; 0x28 + AES->IVR1 = word_pump_bytes(&N); + 800882c: a803 add r0, sp, #12 + 800882e: f7ff ff83 bl 8008738 + 8008832: 6260 str r0, [r4, #36] ; 0x24 + AES->IVR0 = word_pump_bytes(&N); + 8008834: a803 add r0, sp, #12 + 8008836: f7ff ff7f bl 8008738 + 800883a: 6220 str r0, [r4, #32] + AES->IVR1 = 0; + AES->IVR0 = 0; // maybe should be byte-swapped one, but whatever + } + + // Enable the Peripheral + AES->CR |= AES_CR_EN; + 800883c: 4b30 ldr r3, [pc, #192] ; (8008900 ) + 800883e: 681a ldr r2, [r3, #0] + + ASSERT((((uint32_t)&ctx->pending) & 3) == 0); // safe because of special attr + 8008840: 07b0 lsls r0, r6, #30 + AES->CR |= AES_CR_EN; + 8008842: f042 0201 orr.w r2, r2, #1 + 8008846: 601a str r2, [r3, #0] + ASSERT((((uint32_t)&ctx->pending) & 3) == 0); // safe because of special attr + 8008848: d1a4 bne.n 8008794 + + uint32_t *p = (uint32_t *)ctx->pending; + for(int i=0; i < ctx->num_pending; i += 16) { + 800884a: f06f 070f mvn.w r7, #15 + 800884e: f8d6 0200 ldr.w r0, [r6, #512] ; 0x200 + 8008852: f106 0410 add.w r4, r6, #16 + 8008856: 1bbf subs r7, r7, r6 + 8008858: 193a adds r2, r7, r4 + 800885a: 4282 cmp r2, r0 + 800885c: db2b blt.n 80088b6 + *out = AES->DOUTR; out++; + *out = AES->DOUTR; out++; + *out = AES->DOUTR; + } + + memcpy(data_out, ctx->pending, len); + 800885e: 460a mov r2, r1 + 8008860: 4640 mov r0, r8 + 8008862: 4631 mov r1, r6 + 8008864: f005 f850 bl 800d908 + + memset(ctx, 0, sizeof(AES_CTX)); + 8008868: f44f 7201 mov.w r2, #516 ; 0x204 + 800886c: 2100 movs r1, #0 + 800886e: 4630 mov r0, r6 + 8008870: f005 f858 bl 800d924 + + // reset state of chip block, and leave clock off as well + __HAL_RCC_AES_CLK_ENABLE(); + 8008874: 6ceb ldr r3, [r5, #76] ; 0x4c + 8008876: f443 3380 orr.w r3, r3, #65536 ; 0x10000 + 800887a: 64eb str r3, [r5, #76] ; 0x4c + 800887c: 6ceb ldr r3, [r5, #76] ; 0x4c + 800887e: f403 3380 and.w r3, r3, #65536 ; 0x10000 + 8008882: 9303 str r3, [sp, #12] + 8008884: 9b03 ldr r3, [sp, #12] + __HAL_RCC_AES_FORCE_RESET(); + 8008886: 6aeb ldr r3, [r5, #44] ; 0x2c + 8008888: f443 3380 orr.w r3, r3, #65536 ; 0x10000 + 800888c: 62eb str r3, [r5, #44] ; 0x2c + __HAL_RCC_AES_RELEASE_RESET(); + 800888e: 6aeb ldr r3, [r5, #44] ; 0x2c + 8008890: f423 3380 bic.w r3, r3, #65536 ; 0x10000 + 8008894: 62eb str r3, [r5, #44] ; 0x2c + __HAL_RCC_AES_CLK_DISABLE(); + 8008896: 6ceb ldr r3, [r5, #76] ; 0x4c + 8008898: f423 3380 bic.w r3, r3, #65536 ; 0x10000 + 800889c: 64eb str r3, [r5, #76] ; 0x4c +} + 800889e: b005 add sp, #20 + 80088a0: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + AES->IVR3 = 0; + 80088a4: f8c4 902c str.w r9, [r4, #44] ; 0x2c + AES->IVR2 = 0; + 80088a8: f8c4 9028 str.w r9, [r4, #40] ; 0x28 + AES->IVR1 = 0; + 80088ac: f8c4 9024 str.w r9, [r4, #36] ; 0x24 + AES->IVR0 = 0; // maybe should be byte-swapped one, but whatever + 80088b0: f8c4 9020 str.w r9, [r4, #32] + 80088b4: e7c2 b.n 800883c + AES->DINR = *p; p++; + 80088b6: f854 2c10 ldr.w r2, [r4, #-16] + 80088ba: 609a str r2, [r3, #8] + AES->DINR = *p; p++; + 80088bc: f854 2c0c ldr.w r2, [r4, #-12] + 80088c0: 609a str r2, [r3, #8] + AES->DINR = *p; p++; + 80088c2: f854 2c08 ldr.w r2, [r4, #-8] + 80088c6: 609a str r2, [r3, #8] + AES->DINR = *p; p++; + 80088c8: f854 2c04 ldr.w r2, [r4, #-4] + 80088cc: 609a str r2, [r3, #8] + while(HAL_IS_BIT_CLR(AES->SR, AES_SR_CCF)) { + 80088ce: 685a ldr r2, [r3, #4] + 80088d0: 07d2 lsls r2, r2, #31 + 80088d2: d5fc bpl.n 80088ce + SET_BIT(AES->CR, CRYP_CCF_CLEAR); + 80088d4: 681a ldr r2, [r3, #0] + 80088d6: f042 0280 orr.w r2, r2, #128 ; 0x80 + 80088da: 601a str r2, [r3, #0] + *out = AES->DOUTR; out++; + 80088dc: 68da ldr r2, [r3, #12] + 80088de: f844 2c10 str.w r2, [r4, #-16] + *out = AES->DOUTR; out++; + 80088e2: 68da ldr r2, [r3, #12] + 80088e4: f844 2c0c str.w r2, [r4, #-12] + *out = AES->DOUTR; out++; + 80088e8: 68da ldr r2, [r3, #12] + 80088ea: f844 2c08 str.w r2, [r4, #-8] + *out = AES->DOUTR; + 80088ee: 68da ldr r2, [r3, #12] + 80088f0: f844 2c04 str.w r2, [r4, #-4] + for(int i=0; i < ctx->num_pending; i += 16) { + 80088f4: 3410 adds r4, #16 + 80088f6: e7af b.n 8008858 + 80088f8: 0801046c .word 0x0801046c + 80088fc: 40021000 .word 0x40021000 + 8008900: 50060000 .word 0x50060000 + +08008904 : + voltage range. + * @param msirange MSI range value from RCC_MSIRANGE_0 to RCC_MSIRANGE_11 + * @retval HAL status + */ +static HAL_StatusTypeDef RCC_SetFlashLatencyFromMSIRange(uint32_t msirange) +{ + 8008904: b537 push {r0, r1, r2, r4, r5, lr} + uint32_t vos; + uint32_t latency = FLASH_LATENCY_0; /* default value 0WS */ + + if(__HAL_RCC_PWR_IS_CLK_ENABLED()) + 8008906: 4d1c ldr r5, [pc, #112] ; (8008978 ) + 8008908: 6dab ldr r3, [r5, #88] ; 0x58 + 800890a: 00da lsls r2, r3, #3 +{ + 800890c: 4604 mov r4, r0 + if(__HAL_RCC_PWR_IS_CLK_ENABLED()) + 800890e: d518 bpl.n 8008942 + { + vos = HAL_PWREx_GetVoltageRange(); + 8008910: f7fe fd68 bl 80073e4 + __HAL_RCC_PWR_CLK_ENABLE(); + vos = HAL_PWREx_GetVoltageRange(); + __HAL_RCC_PWR_CLK_DISABLE(); + } + + if(vos == PWR_REGULATOR_VOLTAGE_SCALE1) + 8008914: f5b0 7f00 cmp.w r0, #512 ; 0x200 + 8008918: d123 bne.n 8008962 + { + if(msirange > RCC_MSIRANGE_8) + 800891a: 2c80 cmp r4, #128 ; 0x80 + 800891c: d928 bls.n 8008970 + latency = FLASH_LATENCY_2; /* 2WS */ + } + else + { + /* MSI 24Mhz or 32Mhz */ + latency = FLASH_LATENCY_1; /* 1WS */ + 800891e: 2ca0 cmp r4, #160 ; 0xa0 + 8008920: bf8c ite hi + 8008922: 2002 movhi r0, #2 + 8008924: 2001 movls r0, #1 + /* else MSI < 8Mhz default FLASH_LATENCY_0 0WS */ + } +#endif + } + + __HAL_FLASH_SET_LATENCY(latency); + 8008926: 4a15 ldr r2, [pc, #84] ; (800897c ) + 8008928: 6813 ldr r3, [r2, #0] + 800892a: f023 030f bic.w r3, r3, #15 + 800892e: 4303 orrs r3, r0 + 8008930: 6013 str r3, [r2, #0] + + /* Check that the new number of wait states is taken into account to access the Flash + memory by reading the FLASH_ACR register */ + if(__HAL_FLASH_GET_LATENCY() != latency) + 8008932: 6813 ldr r3, [r2, #0] + 8008934: f003 030f and.w r3, r3, #15 + { + return HAL_ERROR; + } + + return HAL_OK; +} + 8008938: 1a18 subs r0, r3, r0 + 800893a: bf18 it ne + 800893c: 2001 movne r0, #1 + 800893e: b003 add sp, #12 + 8008940: bd30 pop {r4, r5, pc} + __HAL_RCC_PWR_CLK_ENABLE(); + 8008942: 6dab ldr r3, [r5, #88] ; 0x58 + 8008944: f043 5380 orr.w r3, r3, #268435456 ; 0x10000000 + 8008948: 65ab str r3, [r5, #88] ; 0x58 + 800894a: 6dab ldr r3, [r5, #88] ; 0x58 + 800894c: f003 5380 and.w r3, r3, #268435456 ; 0x10000000 + 8008950: 9301 str r3, [sp, #4] + 8008952: 9b01 ldr r3, [sp, #4] + vos = HAL_PWREx_GetVoltageRange(); + 8008954: f7fe fd46 bl 80073e4 + __HAL_RCC_PWR_CLK_DISABLE(); + 8008958: 6dab ldr r3, [r5, #88] ; 0x58 + 800895a: f023 5380 bic.w r3, r3, #268435456 ; 0x10000000 + 800895e: 65ab str r3, [r5, #88] ; 0x58 + 8008960: e7d8 b.n 8008914 + if(msirange >= RCC_MSIRANGE_8) + 8008962: 2c7f cmp r4, #127 ; 0x7f + 8008964: d806 bhi.n 8008974 + if(msirange == RCC_MSIRANGE_7) + 8008966: f1a4 0370 sub.w r3, r4, #112 ; 0x70 + 800896a: 4258 negs r0, r3 + 800896c: 4158 adcs r0, r3 + 800896e: e7da b.n 8008926 + uint32_t latency = FLASH_LATENCY_0; /* default value 0WS */ + 8008970: 2000 movs r0, #0 + 8008972: e7d8 b.n 8008926 + latency = FLASH_LATENCY_2; /* 2WS */ + 8008974: 2002 movs r0, #2 + 8008976: e7d6 b.n 8008926 + 8008978: 40021000 .word 0x40021000 + 800897c: 40022000 .word 0x40022000 + +08008980 : +{ + 8008980: b5f8 push {r3, r4, r5, r6, r7, lr} + SET_BIT(RCC->CR, RCC_CR_MSION); + 8008982: 4c32 ldr r4, [pc, #200] ; (8008a4c ) + 8008984: 6823 ldr r3, [r4, #0] + 8008986: f043 0301 orr.w r3, r3, #1 + 800898a: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 800898c: f7fe fd26 bl 80073dc + 8008990: 4605 mov r5, r0 + while(READ_BIT(RCC->CR, RCC_CR_MSIRDY) == 0U) + 8008992: 6823 ldr r3, [r4, #0] + 8008994: 079b lsls r3, r3, #30 + 8008996: d543 bpl.n 8008a20 + MODIFY_REG(RCC->CR, RCC_CR_MSIRANGE, RCC_MSIRANGE_6); + 8008998: 6823 ldr r3, [r4, #0] + SystemCoreClock = MSI_VALUE; + 800899a: 4a2d ldr r2, [pc, #180] ; (8008a50 ) + MODIFY_REG(RCC->CR, RCC_CR_MSIRANGE, RCC_MSIRANGE_6); + 800899c: f023 03f0 bic.w r3, r3, #240 ; 0xf0 + 80089a0: f043 0360 orr.w r3, r3, #96 ; 0x60 + 80089a4: 6023 str r3, [r4, #0] + CLEAR_REG(RCC->CFGR); + 80089a6: 2300 movs r3, #0 + 80089a8: 60a3 str r3, [r4, #8] + SystemCoreClock = MSI_VALUE; + 80089aa: 4b2a ldr r3, [pc, #168] ; (8008a54 ) + 80089ac: 601a str r2, [r3, #0] + if(HAL_InitTick(uwTickPrio) != HAL_OK) + 80089ae: 4b2a ldr r3, [pc, #168] ; (8008a58 ) + 80089b0: 6818 ldr r0, [r3, #0] + 80089b2: f7fe fd15 bl 80073e0 + 80089b6: 4605 mov r5, r0 + 80089b8: 2800 cmp r0, #0 + 80089ba: d145 bne.n 8008a48 + tickstart = HAL_GetTick(); + 80089bc: f7fe fd0e bl 80073dc + if((HAL_GetTick() - tickstart) > CLOCKSWITCH_TIMEOUT_VALUE) + 80089c0: f241 3788 movw r7, #5000 ; 0x1388 + tickstart = HAL_GetTick(); + 80089c4: 4606 mov r6, r0 + while(READ_BIT(RCC->CFGR, RCC_CFGR_SWS) != RCC_CFGR_SWS_MSI) + 80089c6: 68a3 ldr r3, [r4, #8] + 80089c8: f013 0f0c tst.w r3, #12 + 80089cc: d130 bne.n 8008a30 + CLEAR_BIT(RCC->CR, RCC_CR_HSEON | RCC_CR_HSION | RCC_CR_HSIKERON| RCC_CR_HSIASFS | RCC_CR_PLLON | RCC_CR_PLLSAI1ON | RCC_CR_PLLSAI2ON); + 80089ce: 6822 ldr r2, [r4, #0] + 80089d0: 4b22 ldr r3, [pc, #136] ; (8008a5c ) + 80089d2: 4013 ands r3, r2 + 80089d4: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 80089d6: f7fe fd01 bl 80073dc + 80089da: 4606 mov r6, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLRDY | RCC_CR_PLLSAI1RDY | RCC_CR_PLLSAI2RDY) != 0U) + 80089dc: 6823 ldr r3, [r4, #0] + 80089de: f013 5328 ands.w r3, r3, #704643072 ; 0x2a000000 + 80089e2: d12b bne.n 8008a3c + CLEAR_REG(RCC->PLLCFGR); + 80089e4: 60e3 str r3, [r4, #12] + SET_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN_4 ); + 80089e6: 68e2 ldr r2, [r4, #12] + 80089e8: f442 5280 orr.w r2, r2, #4096 ; 0x1000 + 80089ec: 60e2 str r2, [r4, #12] + CLEAR_REG(RCC->PLLSAI1CFGR); + 80089ee: 6123 str r3, [r4, #16] + SET_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1N_4 ); + 80089f0: 6922 ldr r2, [r4, #16] + 80089f2: f442 5280 orr.w r2, r2, #4096 ; 0x1000 + 80089f6: 6122 str r2, [r4, #16] + CLEAR_REG(RCC->PLLSAI2CFGR); + 80089f8: 6163 str r3, [r4, #20] + SET_BIT(RCC->PLLSAI2CFGR, RCC_PLLSAI2CFGR_PLLSAI2N_4 ); + 80089fa: 6962 ldr r2, [r4, #20] + 80089fc: f442 5280 orr.w r2, r2, #4096 ; 0x1000 + 8008a00: 6162 str r2, [r4, #20] + CLEAR_BIT(RCC->CR, RCC_CR_HSEBYP); + 8008a02: 6822 ldr r2, [r4, #0] + 8008a04: f422 2280 bic.w r2, r2, #262144 ; 0x40000 + 8008a08: 6022 str r2, [r4, #0] + CLEAR_REG(RCC->CIER); + 8008a0a: 61a3 str r3, [r4, #24] + WRITE_REG(RCC->CICR, 0xFFFFFFFFU); + 8008a0c: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 8008a10: 6223 str r3, [r4, #32] + SET_BIT(RCC->CSR, RCC_CSR_RMVF); + 8008a12: f8d4 3094 ldr.w r3, [r4, #148] ; 0x94 + 8008a16: f443 0300 orr.w r3, r3, #8388608 ; 0x800000 + 8008a1a: f8c4 3094 str.w r3, [r4, #148] ; 0x94 + return HAL_OK; + 8008a1e: e005 b.n 8008a2c + if((HAL_GetTick() - tickstart) > MSI_TIMEOUT_VALUE) + 8008a20: f7fe fcdc bl 80073dc + 8008a24: 1b40 subs r0, r0, r5 + 8008a26: 2802 cmp r0, #2 + 8008a28: d9b3 bls.n 8008992 + return HAL_TIMEOUT; + 8008a2a: 2503 movs r5, #3 +} + 8008a2c: 4628 mov r0, r5 + 8008a2e: bdf8 pop {r3, r4, r5, r6, r7, pc} + if((HAL_GetTick() - tickstart) > CLOCKSWITCH_TIMEOUT_VALUE) + 8008a30: f7fe fcd4 bl 80073dc + 8008a34: 1b80 subs r0, r0, r6 + 8008a36: 42b8 cmp r0, r7 + 8008a38: d9c5 bls.n 80089c6 + 8008a3a: e7f6 b.n 8008a2a + if((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE) + 8008a3c: f7fe fcce bl 80073dc + 8008a40: 1b80 subs r0, r0, r6 + 8008a42: 2802 cmp r0, #2 + 8008a44: d9ca bls.n 80089dc + 8008a46: e7f0 b.n 8008a2a + return HAL_ERROR; + 8008a48: 2501 movs r5, #1 + 8008a4a: e7ef b.n 8008a2c + 8008a4c: 40021000 .word 0x40021000 + 8008a50: 003d0900 .word 0x003d0900 + 8008a54: 2009e2ac .word 0x2009e2ac + 8008a58: 2009e2b0 .word 0x2009e2b0 + 8008a5c: eafef4ff .word 0xeafef4ff + +08008a60 : +{ + 8008a60: b570 push {r4, r5, r6, lr} + __MCO1_CLK_ENABLE(); + 8008a62: 4c12 ldr r4, [pc, #72] ; (8008aac ) + 8008a64: 6ce3 ldr r3, [r4, #76] ; 0x4c + 8008a66: f043 0301 orr.w r3, r3, #1 + 8008a6a: 64e3 str r3, [r4, #76] ; 0x4c + 8008a6c: 6ce3 ldr r3, [r4, #76] ; 0x4c +{ + 8008a6e: b086 sub sp, #24 + __MCO1_CLK_ENABLE(); + 8008a70: f003 0301 and.w r3, r3, #1 + 8008a74: 9300 str r3, [sp, #0] + 8008a76: 9b00 ldr r3, [sp, #0] +{ + 8008a78: 4616 mov r6, r2 + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + 8008a7a: 2302 movs r3, #2 + 8008a7c: f44f 7280 mov.w r2, #256 ; 0x100 + 8008a80: e9cd 2301 strd r2, r3, [sp, #4] +{ + 8008a84: 460d mov r5, r1 + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + 8008a86: 9304 str r3, [sp, #16] + HAL_GPIO_Init(MCO1_GPIO_PORT, &GPIO_InitStruct); + 8008a88: a901 add r1, sp, #4 + GPIO_InitStruct.Pull = GPIO_NOPULL; + 8008a8a: 2300 movs r3, #0 + HAL_GPIO_Init(MCO1_GPIO_PORT, &GPIO_InitStruct); + 8008a8c: f04f 4090 mov.w r0, #1207959552 ; 0x48000000 + GPIO_InitStruct.Pull = GPIO_NOPULL; + 8008a90: 9303 str r3, [sp, #12] + GPIO_InitStruct.Alternate = GPIO_AF0_MCO; + 8008a92: 9305 str r3, [sp, #20] + HAL_GPIO_Init(MCO1_GPIO_PORT, &GPIO_InitStruct); + 8008a94: f7f8 fbae bl 80011f4 + MODIFY_REG(RCC->CFGR, (RCC_CFGR_MCOSEL | RCC_CFGR_MCOPRE), (RCC_MCOSource | RCC_MCODiv )); + 8008a98: 68a3 ldr r3, [r4, #8] + 8008a9a: f023 43fe bic.w r3, r3, #2130706432 ; 0x7f000000 + 8008a9e: ea43 0206 orr.w r2, r3, r6 + 8008aa2: 432a orrs r2, r5 + 8008aa4: 60a2 str r2, [r4, #8] +} + 8008aa6: b006 add sp, #24 + 8008aa8: bd70 pop {r4, r5, r6, pc} + 8008aaa: bf00 nop + 8008aac: 40021000 .word 0x40021000 + +08008ab0 : + sysclk_source = __HAL_RCC_GET_SYSCLK_SOURCE(); + 8008ab0: 4b22 ldr r3, [pc, #136] ; (8008b3c ) + 8008ab2: 689a ldr r2, [r3, #8] + pll_oscsource = __HAL_RCC_GET_PLL_OSCSOURCE(); + 8008ab4: 68d9 ldr r1, [r3, #12] + if((sysclk_source == RCC_CFGR_SWS_MSI) || + 8008ab6: f012 020c ands.w r2, r2, #12 + 8008aba: d005 beq.n 8008ac8 + 8008abc: 2a0c cmp r2, #12 + 8008abe: d115 bne.n 8008aec + pll_oscsource = __HAL_RCC_GET_PLL_OSCSOURCE(); + 8008ac0: f001 0103 and.w r1, r1, #3 + ((sysclk_source == RCC_CFGR_SWS_PLL) && (pll_oscsource == RCC_PLLSOURCE_MSI))) + 8008ac4: 2901 cmp r1, #1 + 8008ac6: d118 bne.n 8008afa + if(READ_BIT(RCC->CR, RCC_CR_MSIRGSEL) == 0U) + 8008ac8: 6819 ldr r1, [r3, #0] + msirange = MSIRangeTable[msirange]; + 8008aca: 481d ldr r0, [pc, #116] ; (8008b40 ) + if(READ_BIT(RCC->CR, RCC_CR_MSIRGSEL) == 0U) + 8008acc: 0709 lsls r1, r1, #28 + msirange = READ_BIT(RCC->CSR, RCC_CSR_MSISRANGE) >> RCC_CSR_MSISRANGE_Pos; + 8008ace: bf55 itete pl + 8008ad0: f8d3 1094 ldrpl.w r1, [r3, #148] ; 0x94 + msirange = READ_BIT(RCC->CR, RCC_CR_MSIRANGE) >> RCC_CR_MSIRANGE_Pos; + 8008ad4: 6819 ldrmi r1, [r3, #0] + msirange = READ_BIT(RCC->CSR, RCC_CSR_MSISRANGE) >> RCC_CSR_MSISRANGE_Pos; + 8008ad6: f3c1 2103 ubfxpl r1, r1, #8, #4 + msirange = READ_BIT(RCC->CR, RCC_CR_MSIRANGE) >> RCC_CR_MSIRANGE_Pos; + 8008ada: f3c1 1103 ubfxmi r1, r1, #4, #4 + msirange = MSIRangeTable[msirange]; + 8008ade: f850 0021 ldr.w r0, [r0, r1, lsl #2] + if(sysclk_source == RCC_CFGR_SWS_MSI) + 8008ae2: b34a cbz r2, 8008b38 + if(sysclk_source == RCC_CFGR_SWS_PLL) + 8008ae4: 2a0c cmp r2, #12 + 8008ae6: d009 beq.n 8008afc + 8008ae8: 2000 movs r0, #0 + return sysclockfreq; + 8008aea: 4770 bx lr + else if(sysclk_source == RCC_CFGR_SWS_HSI) + 8008aec: 2a04 cmp r2, #4 + 8008aee: d022 beq.n 8008b36 + else if(sysclk_source == RCC_CFGR_SWS_HSE) + 8008af0: 2a08 cmp r2, #8 + 8008af2: 4814 ldr r0, [pc, #80] ; (8008b44 ) + 8008af4: bf18 it ne + 8008af6: 2000 movne r0, #0 + 8008af8: 4770 bx lr + uint32_t msirange = 0U, sysclockfreq = 0U; + 8008afa: 2000 movs r0, #0 + pllsource = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLSRC); + 8008afc: 68da ldr r2, [r3, #12] + 8008afe: f002 0203 and.w r2, r2, #3 + switch (pllsource) + 8008b02: 2a02 cmp r2, #2 + 8008b04: d015 beq.n 8008b32 + 8008b06: 490f ldr r1, [pc, #60] ; (8008b44 ) + 8008b08: 2a03 cmp r2, #3 + 8008b0a: bf08 it eq + 8008b0c: 4608 moveq r0, r1 + pllm = (READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U ; + 8008b0e: 68d9 ldr r1, [r3, #12] + pllvco = (pllvco * (READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos)) / pllm; + 8008b10: 68da ldr r2, [r3, #12] + 8008b12: f3c2 2206 ubfx r2, r2, #8, #7 + 8008b16: 4342 muls r2, r0 + pllr = ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos) + 1U ) * 2U; + 8008b18: 68d8 ldr r0, [r3, #12] + 8008b1a: f3c0 6041 ubfx r0, r0, #25, #2 + pllm = (READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U ; + 8008b1e: f3c1 1103 ubfx r1, r1, #4, #4 + pllr = ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos) + 1U ) * 2U; + 8008b22: 3001 adds r0, #1 + pllm = (READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U ; + 8008b24: 3101 adds r1, #1 + pllr = ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos) + 1U ) * 2U; + 8008b26: 0040 lsls r0, r0, #1 + pllvco = (pllvco * (READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos)) / pllm; + 8008b28: fbb2 f2f1 udiv r2, r2, r1 + sysclockfreq = pllvco / pllr; + 8008b2c: fbb2 f0f0 udiv r0, r2, r0 + 8008b30: 4770 bx lr + pllvco = HSI_VALUE; + 8008b32: 4805 ldr r0, [pc, #20] ; (8008b48 ) + 8008b34: e7eb b.n 8008b0e + sysclockfreq = HSI_VALUE; + 8008b36: 4804 ldr r0, [pc, #16] ; (8008b48 ) +} + 8008b38: 4770 bx lr + 8008b3a: bf00 nop + 8008b3c: 40021000 .word 0x40021000 + 8008b40: 08010a70 .word 0x08010a70 + 8008b44: 007a1200 .word 0x007a1200 + 8008b48: 00f42400 .word 0x00f42400 + +08008b4c : +{ + 8008b4c: e92d 43f7 stmdb sp!, {r0, r1, r2, r4, r5, r6, r7, r8, r9, lr} + if(RCC_OscInitStruct == NULL) + 8008b50: 4605 mov r5, r0 + 8008b52: b908 cbnz r0, 8008b58 + return HAL_ERROR; + 8008b54: 2001 movs r0, #1 + 8008b56: e047 b.n 8008be8 + sysclk_source = __HAL_RCC_GET_SYSCLK_SOURCE(); + 8008b58: 4c94 ldr r4, [pc, #592] ; (8008dac ) + if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_MSI) == RCC_OSCILLATORTYPE_MSI) + 8008b5a: 6803 ldr r3, [r0, #0] + sysclk_source = __HAL_RCC_GET_SYSCLK_SOURCE(); + 8008b5c: 68a6 ldr r6, [r4, #8] + pll_config = __HAL_RCC_GET_PLL_OSCSOURCE(); + 8008b5e: 68e7 ldr r7, [r4, #12] + if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_MSI) == RCC_OSCILLATORTYPE_MSI) + 8008b60: 06db lsls r3, r3, #27 + sysclk_source = __HAL_RCC_GET_SYSCLK_SOURCE(); + 8008b62: f006 060c and.w r6, r6, #12 + pll_config = __HAL_RCC_GET_PLL_OSCSOURCE(); + 8008b66: f007 0703 and.w r7, r7, #3 + if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_MSI) == RCC_OSCILLATORTYPE_MSI) + 8008b6a: d575 bpl.n 8008c58 + if((sysclk_source == RCC_CFGR_SWS_MSI) || + 8008b6c: b11e cbz r6, 8008b76 + 8008b6e: 2e0c cmp r6, #12 + 8008b70: d154 bne.n 8008c1c + ((sysclk_source == RCC_CFGR_SWS_PLL) && (pll_config == RCC_PLLSOURCE_MSI))) + 8008b72: 2f01 cmp r7, #1 + 8008b74: d152 bne.n 8008c1c + if((READ_BIT(RCC->CR, RCC_CR_MSIRDY) != 0U) && (RCC_OscInitStruct->MSIState == RCC_MSI_OFF)) + 8008b76: 6823 ldr r3, [r4, #0] + 8008b78: 0798 lsls r0, r3, #30 + 8008b7a: d502 bpl.n 8008b82 + 8008b7c: 69ab ldr r3, [r5, #24] + 8008b7e: 2b00 cmp r3, #0 + 8008b80: d0e8 beq.n 8008b54 + if(RCC_OscInitStruct->MSIClockRange > __HAL_RCC_GET_MSI_RANGE()) + 8008b82: 6823 ldr r3, [r4, #0] + 8008b84: 6a28 ldr r0, [r5, #32] + 8008b86: 0719 lsls r1, r3, #28 + 8008b88: bf56 itet pl + 8008b8a: f8d4 3094 ldrpl.w r3, [r4, #148] ; 0x94 + 8008b8e: 6823 ldrmi r3, [r4, #0] + 8008b90: 091b lsrpl r3, r3, #4 + 8008b92: f003 03f0 and.w r3, r3, #240 ; 0xf0 + 8008b96: 4298 cmp r0, r3 + 8008b98: d929 bls.n 8008bee + if(RCC_SetFlashLatencyFromMSIRange(RCC_OscInitStruct->MSIClockRange) != HAL_OK) + 8008b9a: f7ff feb3 bl 8008904 + 8008b9e: 2800 cmp r0, #0 + 8008ba0: d1d8 bne.n 8008b54 + __HAL_RCC_MSI_RANGE_CONFIG(RCC_OscInitStruct->MSIClockRange); + 8008ba2: 6823 ldr r3, [r4, #0] + 8008ba4: f043 0308 orr.w r3, r3, #8 + 8008ba8: 6023 str r3, [r4, #0] + 8008baa: 6823 ldr r3, [r4, #0] + 8008bac: 6a2a ldr r2, [r5, #32] + 8008bae: f023 03f0 bic.w r3, r3, #240 ; 0xf0 + 8008bb2: 4313 orrs r3, r2 + 8008bb4: 6023 str r3, [r4, #0] + __HAL_RCC_MSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->MSICalibrationValue); + 8008bb6: 6863 ldr r3, [r4, #4] + 8008bb8: 69ea ldr r2, [r5, #28] + 8008bba: f423 437f bic.w r3, r3, #65280 ; 0xff00 + 8008bbe: ea43 2302 orr.w r3, r3, r2, lsl #8 + 8008bc2: 6063 str r3, [r4, #4] + SystemCoreClock = HAL_RCC_GetSysClockFreq() >> (AHBPrescTable[READ_BIT(RCC->CFGR, RCC_CFGR_HPRE) >> RCC_CFGR_HPRE_Pos] & 0x1FU); + 8008bc4: f7ff ff74 bl 8008ab0 + 8008bc8: 68a3 ldr r3, [r4, #8] + 8008bca: 4a79 ldr r2, [pc, #484] ; (8008db0 ) + 8008bcc: f3c3 1303 ubfx r3, r3, #4, #4 + 8008bd0: 5cd3 ldrb r3, [r2, r3] + 8008bd2: f003 031f and.w r3, r3, #31 + 8008bd6: 40d8 lsrs r0, r3 + 8008bd8: 4b76 ldr r3, [pc, #472] ; (8008db4 ) + 8008bda: 6018 str r0, [r3, #0] + status = HAL_InitTick(uwTickPrio); + 8008bdc: 4b76 ldr r3, [pc, #472] ; (8008db8 ) + 8008bde: 6818 ldr r0, [r3, #0] + 8008be0: f7fe fbfe bl 80073e0 + if(status != HAL_OK) + 8008be4: 2800 cmp r0, #0 + 8008be6: d037 beq.n 8008c58 +} + 8008be8: b003 add sp, #12 + 8008bea: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + __HAL_RCC_MSI_RANGE_CONFIG(RCC_OscInitStruct->MSIClockRange); + 8008bee: 6823 ldr r3, [r4, #0] + 8008bf0: f043 0308 orr.w r3, r3, #8 + 8008bf4: 6023 str r3, [r4, #0] + 8008bf6: 6823 ldr r3, [r4, #0] + 8008bf8: f023 03f0 bic.w r3, r3, #240 ; 0xf0 + 8008bfc: 4303 orrs r3, r0 + 8008bfe: 6023 str r3, [r4, #0] + __HAL_RCC_MSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->MSICalibrationValue); + 8008c00: 6863 ldr r3, [r4, #4] + 8008c02: 69ea ldr r2, [r5, #28] + 8008c04: f423 437f bic.w r3, r3, #65280 ; 0xff00 + 8008c08: ea43 2302 orr.w r3, r3, r2, lsl #8 + 8008c0c: 6063 str r3, [r4, #4] + if(sysclk_source == RCC_CFGR_SWS_MSI) + 8008c0e: 2e00 cmp r6, #0 + 8008c10: d1d8 bne.n 8008bc4 + if(RCC_SetFlashLatencyFromMSIRange(RCC_OscInitStruct->MSIClockRange) != HAL_OK) + 8008c12: f7ff fe77 bl 8008904 + 8008c16: 2800 cmp r0, #0 + 8008c18: d0d4 beq.n 8008bc4 + 8008c1a: e79b b.n 8008b54 + if(RCC_OscInitStruct->MSIState != RCC_MSI_OFF) + 8008c1c: 69ab ldr r3, [r5, #24] + 8008c1e: 2b00 cmp r3, #0 + 8008c20: d03a beq.n 8008c98 + __HAL_RCC_MSI_ENABLE(); + 8008c22: 6823 ldr r3, [r4, #0] + 8008c24: f043 0301 orr.w r3, r3, #1 + 8008c28: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 8008c2a: f7fe fbd7 bl 80073dc + 8008c2e: 4680 mov r8, r0 + while(READ_BIT(RCC->CR, RCC_CR_MSIRDY) == 0U) + 8008c30: 6823 ldr r3, [r4, #0] + 8008c32: 079a lsls r2, r3, #30 + 8008c34: d528 bpl.n 8008c88 + __HAL_RCC_MSI_RANGE_CONFIG(RCC_OscInitStruct->MSIClockRange); + 8008c36: 6823 ldr r3, [r4, #0] + 8008c38: f043 0308 orr.w r3, r3, #8 + 8008c3c: 6023 str r3, [r4, #0] + 8008c3e: 6823 ldr r3, [r4, #0] + 8008c40: 6a2a ldr r2, [r5, #32] + 8008c42: f023 03f0 bic.w r3, r3, #240 ; 0xf0 + 8008c46: 4313 orrs r3, r2 + 8008c48: 6023 str r3, [r4, #0] + __HAL_RCC_MSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->MSICalibrationValue); + 8008c4a: 6863 ldr r3, [r4, #4] + 8008c4c: 69ea ldr r2, [r5, #28] + 8008c4e: f423 437f bic.w r3, r3, #65280 ; 0xff00 + 8008c52: ea43 2302 orr.w r3, r3, r2, lsl #8 + 8008c56: 6063 str r3, [r4, #4] + if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_HSE) == RCC_OSCILLATORTYPE_HSE) + 8008c58: 682b ldr r3, [r5, #0] + 8008c5a: 07d8 lsls r0, r3, #31 + 8008c5c: d42d bmi.n 8008cba + if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_HSI) == RCC_OSCILLATORTYPE_HSI) + 8008c5e: 682b ldr r3, [r5, #0] + 8008c60: 0799 lsls r1, r3, #30 + 8008c62: d46b bmi.n 8008d3c + if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_LSI) == RCC_OSCILLATORTYPE_LSI) + 8008c64: 682b ldr r3, [r5, #0] + 8008c66: 0718 lsls r0, r3, #28 + 8008c68: f100 80a8 bmi.w 8008dbc + if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_LSE) == RCC_OSCILLATORTYPE_LSE) + 8008c6c: 682b ldr r3, [r5, #0] + 8008c6e: 0759 lsls r1, r3, #29 + 8008c70: f100 80ce bmi.w 8008e10 + if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_HSI48) == RCC_OSCILLATORTYPE_HSI48) + 8008c74: 682b ldr r3, [r5, #0] + 8008c76: 069f lsls r7, r3, #26 + 8008c78: f100 8137 bmi.w 8008eea + if(RCC_OscInitStruct->PLL.PLLState != RCC_PLL_NONE) + 8008c7c: 6aab ldr r3, [r5, #40] ; 0x28 + 8008c7e: 2b00 cmp r3, #0 + 8008c80: f040 815d bne.w 8008f3e + return HAL_OK; + 8008c84: 2000 movs r0, #0 + 8008c86: e7af b.n 8008be8 + if((HAL_GetTick() - tickstart) > MSI_TIMEOUT_VALUE) + 8008c88: f7fe fba8 bl 80073dc + 8008c8c: eba0 0008 sub.w r0, r0, r8 + 8008c90: 2802 cmp r0, #2 + 8008c92: d9cd bls.n 8008c30 + return HAL_TIMEOUT; + 8008c94: 2003 movs r0, #3 + 8008c96: e7a7 b.n 8008be8 + __HAL_RCC_MSI_DISABLE(); + 8008c98: 6823 ldr r3, [r4, #0] + 8008c9a: f023 0301 bic.w r3, r3, #1 + 8008c9e: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 8008ca0: f7fe fb9c bl 80073dc + 8008ca4: 4680 mov r8, r0 + while(READ_BIT(RCC->CR, RCC_CR_MSIRDY) != 0U) + 8008ca6: 6823 ldr r3, [r4, #0] + 8008ca8: 079b lsls r3, r3, #30 + 8008caa: d5d5 bpl.n 8008c58 + if((HAL_GetTick() - tickstart) > MSI_TIMEOUT_VALUE) + 8008cac: f7fe fb96 bl 80073dc + 8008cb0: eba0 0008 sub.w r0, r0, r8 + 8008cb4: 2802 cmp r0, #2 + 8008cb6: d9f6 bls.n 8008ca6 + 8008cb8: e7ec b.n 8008c94 + if((sysclk_source == RCC_CFGR_SWS_HSE) || + 8008cba: 2e08 cmp r6, #8 + 8008cbc: d003 beq.n 8008cc6 + 8008cbe: 2e0c cmp r6, #12 + 8008cc0: d108 bne.n 8008cd4 + ((sysclk_source == RCC_CFGR_SWS_PLL) && (pll_config == RCC_PLLSOURCE_HSE))) + 8008cc2: 2f03 cmp r7, #3 + 8008cc4: d106 bne.n 8008cd4 + if((READ_BIT(RCC->CR, RCC_CR_HSERDY) != 0U) && (RCC_OscInitStruct->HSEState == RCC_HSE_OFF)) + 8008cc6: 6823 ldr r3, [r4, #0] + 8008cc8: 039a lsls r2, r3, #14 + 8008cca: d5c8 bpl.n 8008c5e + 8008ccc: 686b ldr r3, [r5, #4] + 8008cce: 2b00 cmp r3, #0 + 8008cd0: d1c5 bne.n 8008c5e + 8008cd2: e73f b.n 8008b54 + __HAL_RCC_HSE_CONFIG(RCC_OscInitStruct->HSEState); + 8008cd4: 686b ldr r3, [r5, #4] + 8008cd6: f5b3 3f80 cmp.w r3, #65536 ; 0x10000 + 8008cda: d110 bne.n 8008cfe + 8008cdc: 6823 ldr r3, [r4, #0] + 8008cde: f443 3380 orr.w r3, r3, #65536 ; 0x10000 + 8008ce2: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 8008ce4: f7fe fb7a bl 80073dc + 8008ce8: 4680 mov r8, r0 + while(READ_BIT(RCC->CR, RCC_CR_HSERDY) == 0U) + 8008cea: 6823 ldr r3, [r4, #0] + 8008cec: 039b lsls r3, r3, #14 + 8008cee: d4b6 bmi.n 8008c5e + if((HAL_GetTick() - tickstart) > HSE_TIMEOUT_VALUE) + 8008cf0: f7fe fb74 bl 80073dc + 8008cf4: eba0 0008 sub.w r0, r0, r8 + 8008cf8: 2864 cmp r0, #100 ; 0x64 + 8008cfa: d9f6 bls.n 8008cea + 8008cfc: e7ca b.n 8008c94 + __HAL_RCC_HSE_CONFIG(RCC_OscInitStruct->HSEState); + 8008cfe: f5b3 2fa0 cmp.w r3, #327680 ; 0x50000 + 8008d02: d104 bne.n 8008d0e + 8008d04: 6823 ldr r3, [r4, #0] + 8008d06: f443 2380 orr.w r3, r3, #262144 ; 0x40000 + 8008d0a: 6023 str r3, [r4, #0] + 8008d0c: e7e6 b.n 8008cdc + 8008d0e: 6822 ldr r2, [r4, #0] + 8008d10: f422 3280 bic.w r2, r2, #65536 ; 0x10000 + 8008d14: 6022 str r2, [r4, #0] + 8008d16: 6822 ldr r2, [r4, #0] + 8008d18: f422 2280 bic.w r2, r2, #262144 ; 0x40000 + 8008d1c: 6022 str r2, [r4, #0] + if(RCC_OscInitStruct->HSEState != RCC_HSE_OFF) + 8008d1e: 2b00 cmp r3, #0 + 8008d20: d1e0 bne.n 8008ce4 + tickstart = HAL_GetTick(); + 8008d22: f7fe fb5b bl 80073dc + 8008d26: 4680 mov r8, r0 + while(READ_BIT(RCC->CR, RCC_CR_HSERDY) != 0U) + 8008d28: 6823 ldr r3, [r4, #0] + 8008d2a: 0398 lsls r0, r3, #14 + 8008d2c: d597 bpl.n 8008c5e + if((HAL_GetTick() - tickstart) > HSE_TIMEOUT_VALUE) + 8008d2e: f7fe fb55 bl 80073dc + 8008d32: eba0 0008 sub.w r0, r0, r8 + 8008d36: 2864 cmp r0, #100 ; 0x64 + 8008d38: d9f6 bls.n 8008d28 + 8008d3a: e7ab b.n 8008c94 + if((sysclk_source == RCC_CFGR_SWS_HSI) || + 8008d3c: 2e04 cmp r6, #4 + 8008d3e: d003 beq.n 8008d48 + 8008d40: 2e0c cmp r6, #12 + 8008d42: d110 bne.n 8008d66 + ((sysclk_source == RCC_CFGR_SWS_PLL) && (pll_config == RCC_PLLSOURCE_HSI))) + 8008d44: 2f02 cmp r7, #2 + 8008d46: d10e bne.n 8008d66 + if((READ_BIT(RCC->CR, RCC_CR_HSIRDY) != 0U) && (RCC_OscInitStruct->HSIState == RCC_HSI_OFF)) + 8008d48: 6823 ldr r3, [r4, #0] + 8008d4a: 0559 lsls r1, r3, #21 + 8008d4c: d503 bpl.n 8008d56 + 8008d4e: 68eb ldr r3, [r5, #12] + 8008d50: 2b00 cmp r3, #0 + 8008d52: f43f aeff beq.w 8008b54 + __HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->HSICalibrationValue); + 8008d56: 6863 ldr r3, [r4, #4] + 8008d58: 692a ldr r2, [r5, #16] + 8008d5a: f023 43fe bic.w r3, r3, #2130706432 ; 0x7f000000 + 8008d5e: ea43 6302 orr.w r3, r3, r2, lsl #24 + 8008d62: 6063 str r3, [r4, #4] + 8008d64: e77e b.n 8008c64 + if(RCC_OscInitStruct->HSIState != RCC_HSI_OFF) + 8008d66: 68eb ldr r3, [r5, #12] + 8008d68: b17b cbz r3, 8008d8a + __HAL_RCC_HSI_ENABLE(); + 8008d6a: 6823 ldr r3, [r4, #0] + 8008d6c: f443 7380 orr.w r3, r3, #256 ; 0x100 + 8008d70: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 8008d72: f7fe fb33 bl 80073dc + 8008d76: 4607 mov r7, r0 + while(READ_BIT(RCC->CR, RCC_CR_HSIRDY) == 0U) + 8008d78: 6823 ldr r3, [r4, #0] + 8008d7a: 055a lsls r2, r3, #21 + 8008d7c: d4eb bmi.n 8008d56 + if((HAL_GetTick() - tickstart) > HSI_TIMEOUT_VALUE) + 8008d7e: f7fe fb2d bl 80073dc + 8008d82: 1bc0 subs r0, r0, r7 + 8008d84: 2802 cmp r0, #2 + 8008d86: d9f7 bls.n 8008d78 + 8008d88: e784 b.n 8008c94 + __HAL_RCC_HSI_DISABLE(); + 8008d8a: 6823 ldr r3, [r4, #0] + 8008d8c: f423 7380 bic.w r3, r3, #256 ; 0x100 + 8008d90: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 8008d92: f7fe fb23 bl 80073dc + 8008d96: 4607 mov r7, r0 + while(READ_BIT(RCC->CR, RCC_CR_HSIRDY) != 0U) + 8008d98: 6823 ldr r3, [r4, #0] + 8008d9a: 055b lsls r3, r3, #21 + 8008d9c: f57f af62 bpl.w 8008c64 + if((HAL_GetTick() - tickstart) > HSI_TIMEOUT_VALUE) + 8008da0: f7fe fb1c bl 80073dc + 8008da4: 1bc0 subs r0, r0, r7 + 8008da6: 2802 cmp r0, #2 + 8008da8: d9f6 bls.n 8008d98 + 8008daa: e773 b.n 8008c94 + 8008dac: 40021000 .word 0x40021000 + 8008db0: 08010a58 .word 0x08010a58 + 8008db4: 2009e2ac .word 0x2009e2ac + 8008db8: 2009e2b0 .word 0x2009e2b0 + if(RCC_OscInitStruct->LSIState != RCC_LSI_OFF) + 8008dbc: 696b ldr r3, [r5, #20] + 8008dbe: b19b cbz r3, 8008de8 + __HAL_RCC_LSI_ENABLE(); + 8008dc0: f8d4 3094 ldr.w r3, [r4, #148] ; 0x94 + 8008dc4: f043 0301 orr.w r3, r3, #1 + 8008dc8: f8c4 3094 str.w r3, [r4, #148] ; 0x94 + tickstart = HAL_GetTick(); + 8008dcc: f7fe fb06 bl 80073dc + 8008dd0: 4607 mov r7, r0 + while(READ_BIT(RCC->CSR, RCC_CSR_LSIRDY) == 0U) + 8008dd2: f8d4 3094 ldr.w r3, [r4, #148] ; 0x94 + 8008dd6: 079a lsls r2, r3, #30 + 8008dd8: f53f af48 bmi.w 8008c6c + if((HAL_GetTick() - tickstart) > LSI_TIMEOUT_VALUE) + 8008ddc: f7fe fafe bl 80073dc + 8008de0: 1bc0 subs r0, r0, r7 + 8008de2: 2802 cmp r0, #2 + 8008de4: d9f5 bls.n 8008dd2 + 8008de6: e755 b.n 8008c94 + __HAL_RCC_LSI_DISABLE(); + 8008de8: f8d4 3094 ldr.w r3, [r4, #148] ; 0x94 + 8008dec: f023 0301 bic.w r3, r3, #1 + 8008df0: f8c4 3094 str.w r3, [r4, #148] ; 0x94 + tickstart = HAL_GetTick(); + 8008df4: f7fe faf2 bl 80073dc + 8008df8: 4607 mov r7, r0 + while(READ_BIT(RCC->CSR, RCC_CSR_LSIRDY) != 0U) + 8008dfa: f8d4 3094 ldr.w r3, [r4, #148] ; 0x94 + 8008dfe: 079b lsls r3, r3, #30 + 8008e00: f57f af34 bpl.w 8008c6c + if((HAL_GetTick() - tickstart) > LSI_TIMEOUT_VALUE) + 8008e04: f7fe faea bl 80073dc + 8008e08: 1bc0 subs r0, r0, r7 + 8008e0a: 2802 cmp r0, #2 + 8008e0c: d9f5 bls.n 8008dfa + 8008e0e: e741 b.n 8008c94 + if(HAL_IS_BIT_CLR(RCC->APB1ENR1, RCC_APB1ENR1_PWREN)) + 8008e10: 6da3 ldr r3, [r4, #88] ; 0x58 + 8008e12: 00df lsls r7, r3, #3 + 8008e14: d429 bmi.n 8008e6a + __HAL_RCC_PWR_CLK_ENABLE(); + 8008e16: 6da3 ldr r3, [r4, #88] ; 0x58 + 8008e18: f043 5380 orr.w r3, r3, #268435456 ; 0x10000000 + 8008e1c: 65a3 str r3, [r4, #88] ; 0x58 + 8008e1e: 6da3 ldr r3, [r4, #88] ; 0x58 + 8008e20: f003 5380 and.w r3, r3, #268435456 ; 0x10000000 + 8008e24: 9301 str r3, [sp, #4] + 8008e26: 9b01 ldr r3, [sp, #4] + pwrclkchanged = SET; + 8008e28: f04f 0801 mov.w r8, #1 + if(HAL_IS_BIT_CLR(PWR->CR1, PWR_CR1_DBP)) + 8008e2c: 4f9c ldr r7, [pc, #624] ; (80090a0 ) + 8008e2e: 683b ldr r3, [r7, #0] + 8008e30: 05d8 lsls r0, r3, #23 + 8008e32: d51d bpl.n 8008e70 + __HAL_RCC_LSE_CONFIG(RCC_OscInitStruct->LSEState); + 8008e34: 68ab ldr r3, [r5, #8] + 8008e36: 2b01 cmp r3, #1 + 8008e38: d12b bne.n 8008e92 + 8008e3a: f8d4 3090 ldr.w r3, [r4, #144] ; 0x90 + 8008e3e: f043 0301 orr.w r3, r3, #1 + 8008e42: f8c4 3090 str.w r3, [r4, #144] ; 0x90 + tickstart = HAL_GetTick(); + 8008e46: f7fe fac9 bl 80073dc + if((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) + 8008e4a: f241 3988 movw r9, #5000 ; 0x1388 + tickstart = HAL_GetTick(); + 8008e4e: 4607 mov r7, r0 + while(READ_BIT(RCC->BDCR, RCC_BDCR_LSERDY) == 0U) + 8008e50: f8d4 3090 ldr.w r3, [r4, #144] ; 0x90 + 8008e54: 079a lsls r2, r3, #30 + 8008e56: d542 bpl.n 8008ede + if(pwrclkchanged == SET) + 8008e58: f1b8 0f00 cmp.w r8, #0 + 8008e5c: f43f af0a beq.w 8008c74 + __HAL_RCC_PWR_CLK_DISABLE(); + 8008e60: 6da3 ldr r3, [r4, #88] ; 0x58 + 8008e62: f023 5380 bic.w r3, r3, #268435456 ; 0x10000000 + 8008e66: 65a3 str r3, [r4, #88] ; 0x58 + 8008e68: e704 b.n 8008c74 + FlagStatus pwrclkchanged = RESET; + 8008e6a: f04f 0800 mov.w r8, #0 + 8008e6e: e7dd b.n 8008e2c + SET_BIT(PWR->CR1, PWR_CR1_DBP); + 8008e70: 683b ldr r3, [r7, #0] + 8008e72: f443 7380 orr.w r3, r3, #256 ; 0x100 + 8008e76: 603b str r3, [r7, #0] + tickstart = HAL_GetTick(); + 8008e78: f7fe fab0 bl 80073dc + 8008e7c: 4681 mov r9, r0 + while(HAL_IS_BIT_CLR(PWR->CR1, PWR_CR1_DBP)) + 8008e7e: 683b ldr r3, [r7, #0] + 8008e80: 05d9 lsls r1, r3, #23 + 8008e82: d4d7 bmi.n 8008e34 + if((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE) + 8008e84: f7fe faaa bl 80073dc + 8008e88: eba0 0009 sub.w r0, r0, r9 + 8008e8c: 2802 cmp r0, #2 + 8008e8e: d9f6 bls.n 8008e7e + 8008e90: e700 b.n 8008c94 + __HAL_RCC_LSE_CONFIG(RCC_OscInitStruct->LSEState); + 8008e92: 2b05 cmp r3, #5 + 8008e94: d106 bne.n 8008ea4 + 8008e96: f8d4 3090 ldr.w r3, [r4, #144] ; 0x90 + 8008e9a: f043 0304 orr.w r3, r3, #4 + 8008e9e: f8c4 3090 str.w r3, [r4, #144] ; 0x90 + 8008ea2: e7ca b.n 8008e3a + 8008ea4: f8d4 2090 ldr.w r2, [r4, #144] ; 0x90 + 8008ea8: f022 0201 bic.w r2, r2, #1 + 8008eac: f8c4 2090 str.w r2, [r4, #144] ; 0x90 + 8008eb0: f8d4 2090 ldr.w r2, [r4, #144] ; 0x90 + 8008eb4: f022 0204 bic.w r2, r2, #4 + 8008eb8: f8c4 2090 str.w r2, [r4, #144] ; 0x90 + if(RCC_OscInitStruct->LSEState != RCC_LSE_OFF) + 8008ebc: 2b00 cmp r3, #0 + 8008ebe: d1c2 bne.n 8008e46 + tickstart = HAL_GetTick(); + 8008ec0: f7fe fa8c bl 80073dc + if((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) + 8008ec4: f241 3988 movw r9, #5000 ; 0x1388 + tickstart = HAL_GetTick(); + 8008ec8: 4607 mov r7, r0 + while(READ_BIT(RCC->BDCR, RCC_BDCR_LSERDY) != 0U) + 8008eca: f8d4 3090 ldr.w r3, [r4, #144] ; 0x90 + 8008ece: 079b lsls r3, r3, #30 + 8008ed0: d5c2 bpl.n 8008e58 + if((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) + 8008ed2: f7fe fa83 bl 80073dc + 8008ed6: 1bc0 subs r0, r0, r7 + 8008ed8: 4548 cmp r0, r9 + 8008eda: d9f6 bls.n 8008eca + 8008edc: e6da b.n 8008c94 + if((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) + 8008ede: f7fe fa7d bl 80073dc + 8008ee2: 1bc0 subs r0, r0, r7 + 8008ee4: 4548 cmp r0, r9 + 8008ee6: d9b3 bls.n 8008e50 + 8008ee8: e6d4 b.n 8008c94 + if(RCC_OscInitStruct->HSI48State != RCC_HSI48_OFF) + 8008eea: 6a6b ldr r3, [r5, #36] ; 0x24 + 8008eec: b19b cbz r3, 8008f16 + __HAL_RCC_HSI48_ENABLE(); + 8008eee: f8d4 3098 ldr.w r3, [r4, #152] ; 0x98 + 8008ef2: f043 0301 orr.w r3, r3, #1 + 8008ef6: f8c4 3098 str.w r3, [r4, #152] ; 0x98 + tickstart = HAL_GetTick(); + 8008efa: f7fe fa6f bl 80073dc + 8008efe: 4607 mov r7, r0 + while(READ_BIT(RCC->CRRCR, RCC_CRRCR_HSI48RDY) == 0U) + 8008f00: f8d4 3098 ldr.w r3, [r4, #152] ; 0x98 + 8008f04: 0798 lsls r0, r3, #30 + 8008f06: f53f aeb9 bmi.w 8008c7c + if((HAL_GetTick() - tickstart) > HSI48_TIMEOUT_VALUE) + 8008f0a: f7fe fa67 bl 80073dc + 8008f0e: 1bc0 subs r0, r0, r7 + 8008f10: 2802 cmp r0, #2 + 8008f12: d9f5 bls.n 8008f00 + 8008f14: e6be b.n 8008c94 + __HAL_RCC_HSI48_DISABLE(); + 8008f16: f8d4 3098 ldr.w r3, [r4, #152] ; 0x98 + 8008f1a: f023 0301 bic.w r3, r3, #1 + 8008f1e: f8c4 3098 str.w r3, [r4, #152] ; 0x98 + tickstart = HAL_GetTick(); + 8008f22: f7fe fa5b bl 80073dc + 8008f26: 4607 mov r7, r0 + while(READ_BIT(RCC->CRRCR, RCC_CRRCR_HSI48RDY) != 0U) + 8008f28: f8d4 3098 ldr.w r3, [r4, #152] ; 0x98 + 8008f2c: 0799 lsls r1, r3, #30 + 8008f2e: f57f aea5 bpl.w 8008c7c + if((HAL_GetTick() - tickstart) > HSI48_TIMEOUT_VALUE) + 8008f32: f7fe fa53 bl 80073dc + 8008f36: 1bc0 subs r0, r0, r7 + 8008f38: 2802 cmp r0, #2 + 8008f3a: d9f5 bls.n 8008f28 + 8008f3c: e6aa b.n 8008c94 + if(RCC_OscInitStruct->PLL.PLLState == RCC_PLL_ON) + 8008f3e: 2b02 cmp r3, #2 + 8008f40: f040 808c bne.w 800905c + pll_config = RCC->PLLCFGR; + 8008f44: 68e3 ldr r3, [r4, #12] + if((READ_BIT(pll_config, RCC_PLLCFGR_PLLSRC) != RCC_OscInitStruct->PLL.PLLSource) || + 8008f46: 6aea ldr r2, [r5, #44] ; 0x2c + 8008f48: f003 0103 and.w r1, r3, #3 + 8008f4c: 4291 cmp r1, r2 + 8008f4e: d122 bne.n 8008f96 + (READ_BIT(pll_config, RCC_PLLCFGR_PLLM) != ((RCC_OscInitStruct->PLL.PLLM - 1U) << RCC_PLLCFGR_PLLM_Pos)) || + 8008f50: 6b29 ldr r1, [r5, #48] ; 0x30 + 8008f52: f003 02f0 and.w r2, r3, #240 ; 0xf0 + 8008f56: 3901 subs r1, #1 + if((READ_BIT(pll_config, RCC_PLLCFGR_PLLSRC) != RCC_OscInitStruct->PLL.PLLSource) || + 8008f58: ebb2 1f01 cmp.w r2, r1, lsl #4 + 8008f5c: d11b bne.n 8008f96 + (READ_BIT(pll_config, RCC_PLLCFGR_PLLN) != (RCC_OscInitStruct->PLL.PLLN << RCC_PLLCFGR_PLLN_Pos)) || + 8008f5e: 6b69 ldr r1, [r5, #52] ; 0x34 + 8008f60: f403 42fe and.w r2, r3, #32512 ; 0x7f00 + (READ_BIT(pll_config, RCC_PLLCFGR_PLLM) != ((RCC_OscInitStruct->PLL.PLLM - 1U) << RCC_PLLCFGR_PLLM_Pos)) || + 8008f64: ebb2 2f01 cmp.w r2, r1, lsl #8 + 8008f68: d115 bne.n 8008f96 + (READ_BIT(pll_config, RCC_PLLCFGR_PLLPDIV) != (RCC_OscInitStruct->PLL.PLLP << RCC_PLLCFGR_PLLPDIV_Pos)) || + 8008f6a: 6ba9 ldr r1, [r5, #56] ; 0x38 + 8008f6c: f003 4278 and.w r2, r3, #4160749568 ; 0xf8000000 + (READ_BIT(pll_config, RCC_PLLCFGR_PLLN) != (RCC_OscInitStruct->PLL.PLLN << RCC_PLLCFGR_PLLN_Pos)) || + 8008f70: ebb2 6fc1 cmp.w r2, r1, lsl #27 + 8008f74: d10f bne.n 8008f96 + (READ_BIT(pll_config, RCC_PLLCFGR_PLLQ) != ((((RCC_OscInitStruct->PLL.PLLQ) >> 1U) - 1U) << RCC_PLLCFGR_PLLQ_Pos)) || + 8008f76: 6bea ldr r2, [r5, #60] ; 0x3c + 8008f78: 0852 lsrs r2, r2, #1 + 8008f7a: f403 01c0 and.w r1, r3, #6291456 ; 0x600000 + 8008f7e: 3a01 subs r2, #1 + (READ_BIT(pll_config, RCC_PLLCFGR_PLLPDIV) != (RCC_OscInitStruct->PLL.PLLP << RCC_PLLCFGR_PLLPDIV_Pos)) || + 8008f80: ebb1 5f42 cmp.w r1, r2, lsl #21 + 8008f84: d107 bne.n 8008f96 + (READ_BIT(pll_config, RCC_PLLCFGR_PLLR) != ((((RCC_OscInitStruct->PLL.PLLR) >> 1U) - 1U) << RCC_PLLCFGR_PLLR_Pos))) + 8008f86: 6c2a ldr r2, [r5, #64] ; 0x40 + 8008f88: 0852 lsrs r2, r2, #1 + 8008f8a: f003 63c0 and.w r3, r3, #100663296 ; 0x6000000 + 8008f8e: 3a01 subs r2, #1 + (READ_BIT(pll_config, RCC_PLLCFGR_PLLQ) != ((((RCC_OscInitStruct->PLL.PLLQ) >> 1U) - 1U) << RCC_PLLCFGR_PLLQ_Pos)) || + 8008f90: ebb3 6f42 cmp.w r3, r2, lsl #25 + 8008f94: d049 beq.n 800902a + if(sysclk_source != RCC_CFGR_SWS_PLL) + 8008f96: 2e0c cmp r6, #12 + 8008f98: f43f addc beq.w 8008b54 + if((READ_BIT(RCC->CR, RCC_CR_PLLSAI1ON) != 0U) + 8008f9c: 6823 ldr r3, [r4, #0] + 8008f9e: 015a lsls r2, r3, #5 + 8008fa0: f53f add8 bmi.w 8008b54 + || (READ_BIT(RCC->CR, RCC_CR_PLLSAI2ON) != 0U) + 8008fa4: 6823 ldr r3, [r4, #0] + 8008fa6: 00db lsls r3, r3, #3 + 8008fa8: f53f add4 bmi.w 8008b54 + __HAL_RCC_PLL_DISABLE(); + 8008fac: 6823 ldr r3, [r4, #0] + 8008fae: f023 7380 bic.w r3, r3, #16777216 ; 0x1000000 + 8008fb2: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 8008fb4: f7fe fa12 bl 80073dc + 8008fb8: 4606 mov r6, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLRDY) != 0U) + 8008fba: 6823 ldr r3, [r4, #0] + 8008fbc: 019f lsls r7, r3, #6 + 8008fbe: d42e bmi.n 800901e + __HAL_RCC_PLL_CONFIG(RCC_OscInitStruct->PLL.PLLSource, + 8008fc0: 68e2 ldr r2, [r4, #12] + 8008fc2: 4b38 ldr r3, [pc, #224] ; (80090a4 ) + 8008fc4: 4013 ands r3, r2 + 8008fc6: 6aea ldr r2, [r5, #44] ; 0x2c + 8008fc8: 4313 orrs r3, r2 + 8008fca: 6b6a ldr r2, [r5, #52] ; 0x34 + 8008fcc: ea43 2302 orr.w r3, r3, r2, lsl #8 + 8008fd0: 6baa ldr r2, [r5, #56] ; 0x38 + 8008fd2: ea43 63c2 orr.w r3, r3, r2, lsl #27 + 8008fd6: 6b2a ldr r2, [r5, #48] ; 0x30 + 8008fd8: 3a01 subs r2, #1 + 8008fda: ea43 1302 orr.w r3, r3, r2, lsl #4 + 8008fde: 6bea ldr r2, [r5, #60] ; 0x3c + 8008fe0: 0852 lsrs r2, r2, #1 + 8008fe2: 3a01 subs r2, #1 + 8008fe4: ea43 5342 orr.w r3, r3, r2, lsl #21 + 8008fe8: 6c2a ldr r2, [r5, #64] ; 0x40 + 8008fea: 0852 lsrs r2, r2, #1 + 8008fec: 3a01 subs r2, #1 + 8008fee: ea43 6342 orr.w r3, r3, r2, lsl #25 + 8008ff2: 60e3 str r3, [r4, #12] + __HAL_RCC_PLL_ENABLE(); + 8008ff4: 6823 ldr r3, [r4, #0] + 8008ff6: f043 7380 orr.w r3, r3, #16777216 ; 0x1000000 + 8008ffa: 6023 str r3, [r4, #0] + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL_SYSCLK); + 8008ffc: 68e3 ldr r3, [r4, #12] + 8008ffe: f043 7380 orr.w r3, r3, #16777216 ; 0x1000000 + 8009002: 60e3 str r3, [r4, #12] + tickstart = HAL_GetTick(); + 8009004: f7fe f9ea bl 80073dc + 8009008: 4605 mov r5, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLRDY) == 0U) + 800900a: 6823 ldr r3, [r4, #0] + 800900c: 0198 lsls r0, r3, #6 + 800900e: f53f ae39 bmi.w 8008c84 + if((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE) + 8009012: f7fe f9e3 bl 80073dc + 8009016: 1b40 subs r0, r0, r5 + 8009018: 2802 cmp r0, #2 + 800901a: d9f6 bls.n 800900a + 800901c: e63a b.n 8008c94 + if((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE) + 800901e: f7fe f9dd bl 80073dc + 8009022: 1b80 subs r0, r0, r6 + 8009024: 2802 cmp r0, #2 + 8009026: d9c8 bls.n 8008fba + 8009028: e634 b.n 8008c94 + if(READ_BIT(RCC->CR, RCC_CR_PLLRDY) == 0U) + 800902a: 6823 ldr r3, [r4, #0] + 800902c: 0199 lsls r1, r3, #6 + 800902e: f53f ae29 bmi.w 8008c84 + __HAL_RCC_PLL_ENABLE(); + 8009032: 6823 ldr r3, [r4, #0] + 8009034: f043 7380 orr.w r3, r3, #16777216 ; 0x1000000 + 8009038: 6023 str r3, [r4, #0] + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL_SYSCLK); + 800903a: 68e3 ldr r3, [r4, #12] + 800903c: f043 7380 orr.w r3, r3, #16777216 ; 0x1000000 + 8009040: 60e3 str r3, [r4, #12] + tickstart = HAL_GetTick(); + 8009042: f7fe f9cb bl 80073dc + 8009046: 4605 mov r5, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLRDY) == 0U) + 8009048: 6823 ldr r3, [r4, #0] + 800904a: 019a lsls r2, r3, #6 + 800904c: f53f ae1a bmi.w 8008c84 + if((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE) + 8009050: f7fe f9c4 bl 80073dc + 8009054: 1b40 subs r0, r0, r5 + 8009056: 2802 cmp r0, #2 + 8009058: d9f6 bls.n 8009048 + 800905a: e61b b.n 8008c94 + if(sysclk_source != RCC_CFGR_SWS_PLL) + 800905c: 2e0c cmp r6, #12 + 800905e: f43f ad79 beq.w 8008b54 + __HAL_RCC_PLL_DISABLE(); + 8009062: 6823 ldr r3, [r4, #0] + 8009064: f023 7380 bic.w r3, r3, #16777216 ; 0x1000000 + 8009068: 6023 str r3, [r4, #0] + if(READ_BIT(RCC->CR, (RCC_CR_PLLSAI1RDY | RCC_CR_PLLSAI2RDY)) == 0U) + 800906a: 6823 ldr r3, [r4, #0] + 800906c: f013 5f20 tst.w r3, #671088640 ; 0x28000000 + MODIFY_REG(RCC->PLLCFGR, RCC_PLLCFGR_PLLSRC, RCC_PLLSOURCE_NONE); + 8009070: bf02 ittt eq + 8009072: 68e3 ldreq r3, [r4, #12] + 8009074: f023 0303 biceq.w r3, r3, #3 + 8009078: 60e3 streq r3, [r4, #12] + __HAL_RCC_PLLCLKOUT_DISABLE(RCC_PLL_SYSCLK | RCC_PLL_48M1CLK | RCC_PLL_SAI3CLK); + 800907a: 68e3 ldr r3, [r4, #12] + 800907c: f023 7388 bic.w r3, r3, #17825792 ; 0x1100000 + 8009080: f423 3380 bic.w r3, r3, #65536 ; 0x10000 + 8009084: 60e3 str r3, [r4, #12] + tickstart = HAL_GetTick(); + 8009086: f7fe f9a9 bl 80073dc + 800908a: 4605 mov r5, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLRDY) != 0U) + 800908c: 6823 ldr r3, [r4, #0] + 800908e: 019b lsls r3, r3, #6 + 8009090: f57f adf8 bpl.w 8008c84 + if((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE) + 8009094: f7fe f9a2 bl 80073dc + 8009098: 1b40 subs r0, r0, r5 + 800909a: 2802 cmp r0, #2 + 800909c: d9f6 bls.n 800908c + 800909e: e5f9 b.n 8008c94 + 80090a0: 40007000 .word 0x40007000 + 80090a4: 019d800c .word 0x019d800c + +080090a8 : +{ + 80090a8: e92d 43f8 stmdb sp!, {r3, r4, r5, r6, r7, r8, r9, lr} + 80090ac: 460e mov r6, r1 + if(RCC_ClkInitStruct == NULL) + 80090ae: 4605 mov r5, r0 + 80090b0: b910 cbnz r0, 80090b8 + return HAL_ERROR; + 80090b2: 2001 movs r0, #1 +} + 80090b4: e8bd 83f8 ldmia.w sp!, {r3, r4, r5, r6, r7, r8, r9, pc} + if(FLatency > __HAL_FLASH_GET_LATENCY()) + 80090b8: 4a6f ldr r2, [pc, #444] ; (8009278 ) + 80090ba: 6813 ldr r3, [r2, #0] + 80090bc: f003 030f and.w r3, r3, #15 + 80090c0: 428b cmp r3, r1 + 80090c2: d335 bcc.n 8009130 + if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_SYSCLK) == RCC_CLOCKTYPE_SYSCLK) + 80090c4: 6829 ldr r1, [r5, #0] + 80090c6: f011 0701 ands.w r7, r1, #1 + 80090ca: d13c bne.n 8009146 + if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_HCLK) == RCC_CLOCKTYPE_HCLK) + 80090cc: 682a ldr r2, [r5, #0] + 80090ce: 0791 lsls r1, r2, #30 + 80090d0: f140 80b7 bpl.w 8009242 + MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_ClkInitStruct->AHBCLKDivider); + 80090d4: 4969 ldr r1, [pc, #420] ; (800927c ) + 80090d6: 68a8 ldr r0, [r5, #8] + 80090d8: 688b ldr r3, [r1, #8] + 80090da: f023 03f0 bic.w r3, r3, #240 ; 0xf0 + 80090de: 4303 orrs r3, r0 + MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_SYSCLK_DIV1); + 80090e0: 608b str r3, [r1, #8] + if(FLatency < __HAL_FLASH_GET_LATENCY()) + 80090e2: 4965 ldr r1, [pc, #404] ; (8009278 ) + 80090e4: 680b ldr r3, [r1, #0] + 80090e6: f003 030f and.w r3, r3, #15 + 80090ea: 42b3 cmp r3, r6 + 80090ec: f200 80b1 bhi.w 8009252 + if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK1) == RCC_CLOCKTYPE_PCLK1) + 80090f0: f012 0f04 tst.w r2, #4 + 80090f4: 4c61 ldr r4, [pc, #388] ; (800927c ) + 80090f6: f040 80b8 bne.w 800926a + if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK2) == RCC_CLOCKTYPE_PCLK2) + 80090fa: 0713 lsls r3, r2, #28 + 80090fc: d506 bpl.n 800910c + MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE2, ((RCC_ClkInitStruct->APB2CLKDivider) << 3U)); + 80090fe: 68a3 ldr r3, [r4, #8] + 8009100: 692a ldr r2, [r5, #16] + 8009102: f423 5360 bic.w r3, r3, #14336 ; 0x3800 + 8009106: ea43 03c2 orr.w r3, r3, r2, lsl #3 + 800910a: 60a3 str r3, [r4, #8] + SystemCoreClock = HAL_RCC_GetSysClockFreq() >> (AHBPrescTable[READ_BIT(RCC->CFGR, RCC_CFGR_HPRE) >> RCC_CFGR_HPRE_Pos] & 0x1FU); + 800910c: f7ff fcd0 bl 8008ab0 + 8009110: 68a3 ldr r3, [r4, #8] + 8009112: 4a5b ldr r2, [pc, #364] ; (8009280 ) + 8009114: f3c3 1303 ubfx r3, r3, #4, #4 + 8009118: 5cd3 ldrb r3, [r2, r3] + 800911a: f003 031f and.w r3, r3, #31 + 800911e: 40d8 lsrs r0, r3 + 8009120: 4b58 ldr r3, [pc, #352] ; (8009284 ) + 8009122: 6018 str r0, [r3, #0] + status = HAL_InitTick(uwTickPrio); + 8009124: 4b58 ldr r3, [pc, #352] ; (8009288 ) + 8009126: 6818 ldr r0, [r3, #0] +} + 8009128: e8bd 43f8 ldmia.w sp!, {r3, r4, r5, r6, r7, r8, r9, lr} + status = HAL_InitTick(uwTickPrio); + 800912c: f7fe b958 b.w 80073e0 + __HAL_FLASH_SET_LATENCY(FLatency); + 8009130: 6813 ldr r3, [r2, #0] + 8009132: f023 030f bic.w r3, r3, #15 + 8009136: 430b orrs r3, r1 + 8009138: 6013 str r3, [r2, #0] + if(__HAL_FLASH_GET_LATENCY() != FLatency) + 800913a: 6813 ldr r3, [r2, #0] + 800913c: f003 030f and.w r3, r3, #15 + 8009140: 428b cmp r3, r1 + 8009142: d1b6 bne.n 80090b2 + 8009144: e7be b.n 80090c4 + if(RCC_ClkInitStruct->SYSCLKSource == RCC_SYSCLKSOURCE_PLLCLK) + 8009146: 686b ldr r3, [r5, #4] + 8009148: 4c4c ldr r4, [pc, #304] ; (800927c ) + 800914a: 2b03 cmp r3, #3 + 800914c: d163 bne.n 8009216 + if(READ_BIT(RCC->CR, RCC_CR_PLLRDY) == 0U) + 800914e: 6823 ldr r3, [r4, #0] + 8009150: 019b lsls r3, r3, #6 + 8009152: d5ae bpl.n 80090b2 +static uint32_t RCC_GetSysClockFreqFromPLLSource(void) +{ + uint32_t msirange = 0U; + uint32_t pllvco, pllsource, pllr, pllm, sysclockfreq; /* no init needed */ + + if(__HAL_RCC_GET_PLL_OSCSOURCE() == RCC_PLLSOURCE_MSI) + 8009154: 68e3 ldr r3, [r4, #12] + 8009156: f003 0303 and.w r3, r3, #3 + 800915a: 2b01 cmp r3, #1 + 800915c: d145 bne.n 80091ea + { + /* Get MSI range source */ + if(READ_BIT(RCC->CR, RCC_CR_MSIRGSEL) == 0U) + 800915e: 6823 ldr r3, [r4, #0] + else + { /* MSIRANGE from RCC_CR applies */ + msirange = READ_BIT(RCC->CR, RCC_CR_MSIRANGE) >> RCC_CR_MSIRANGE_Pos; + } + /*MSI frequency range in HZ*/ + msirange = MSIRangeTable[msirange]; + 8009160: 4a4a ldr r2, [pc, #296] ; (800928c ) + if(READ_BIT(RCC->CR, RCC_CR_MSIRGSEL) == 0U) + 8009162: 071f lsls r7, r3, #28 + msirange = READ_BIT(RCC->CSR, RCC_CSR_MSISRANGE) >> RCC_CSR_MSISRANGE_Pos; + 8009164: bf55 itete pl + 8009166: f8d4 3094 ldrpl.w r3, [r4, #148] ; 0x94 + msirange = READ_BIT(RCC->CR, RCC_CR_MSIRANGE) >> RCC_CR_MSIRANGE_Pos; + 800916a: 6823 ldrmi r3, [r4, #0] + msirange = READ_BIT(RCC->CSR, RCC_CSR_MSISRANGE) >> RCC_CSR_MSISRANGE_Pos; + 800916c: f3c3 2303 ubfxpl r3, r3, #8, #4 + msirange = READ_BIT(RCC->CR, RCC_CR_MSIRANGE) >> RCC_CR_MSIRANGE_Pos; + 8009170: f3c3 1303 ubfxmi r3, r3, #4, #4 + msirange = MSIRangeTable[msirange]; + 8009174: f852 2023 ldr.w r2, [r2, r3, lsl #2] + } + + /* PLL_VCO = (HSE_VALUE or HSI_VALUE or MSI_VALUE) * PLLN / PLLM + SYSCLK = PLL_VCO / PLLR + */ + pllsource = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLSRC); + 8009178: 68e3 ldr r3, [r4, #12] + 800917a: f003 0303 and.w r3, r3, #3 + + switch (pllsource) + 800917e: 2b02 cmp r3, #2 + 8009180: d035 beq.n 80091ee + 8009182: 4843 ldr r0, [pc, #268] ; (8009290 ) + 8009184: 2b03 cmp r3, #3 + 8009186: bf08 it eq + 8009188: 4602 moveq r2, r0 + case RCC_PLLSOURCE_MSI: /* MSI used as PLL clock source */ + default: + pllvco = msirange; + break; + } + pllm = (READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U ; + 800918a: 68e0 ldr r0, [r4, #12] + pllvco = (pllvco * (READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos)) / pllm; + 800918c: 68e3 ldr r3, [r4, #12] + 800918e: f3c3 2306 ubfx r3, r3, #8, #7 + 8009192: 4353 muls r3, r2 + pllr = ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos) + 1U ) * 2U; + 8009194: 68e2 ldr r2, [r4, #12] + 8009196: f3c2 6241 ubfx r2, r2, #25, #2 + pllm = (READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U ; + 800919a: f3c0 1003 ubfx r0, r0, #4, #4 + pllr = ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos) + 1U ) * 2U; + 800919e: 3201 adds r2, #1 + 80091a0: 0052 lsls r2, r2, #1 + pllm = (READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U ; + 80091a2: 3001 adds r0, #1 + pllvco = (pllvco * (READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos)) / pllm; + 80091a4: fbb3 f3f0 udiv r3, r3, r0 + sysclockfreq = pllvco / pllr; + 80091a8: fbb3 f3f2 udiv r3, r3, r2 + if(RCC_GetSysClockFreqFromPLLSource() > 80000000U) + 80091ac: 4a39 ldr r2, [pc, #228] ; (8009294 ) + 80091ae: 4293 cmp r3, r2 + 80091b0: d81f bhi.n 80091f2 + uint32_t hpre = RCC_SYSCLK_DIV1; + 80091b2: 2700 movs r7, #0 + MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_ClkInitStruct->SYSCLKSource); + 80091b4: 68a3 ldr r3, [r4, #8] + 80091b6: 686a ldr r2, [r5, #4] + 80091b8: f023 0303 bic.w r3, r3, #3 + 80091bc: 4313 orrs r3, r2 + 80091be: 60a3 str r3, [r4, #8] + tickstart = HAL_GetTick(); + 80091c0: f7fe f90c bl 80073dc + if((HAL_GetTick() - tickstart) > CLOCKSWITCH_TIMEOUT_VALUE) + 80091c4: f241 3988 movw r9, #5000 ; 0x1388 + tickstart = HAL_GetTick(); + 80091c8: 4680 mov r8, r0 + while(__HAL_RCC_GET_SYSCLK_SOURCE() != (RCC_ClkInitStruct->SYSCLKSource << RCC_CFGR_SWS_Pos)) + 80091ca: 68a3 ldr r3, [r4, #8] + 80091cc: 686a ldr r2, [r5, #4] + 80091ce: f003 030c and.w r3, r3, #12 + 80091d2: ebb3 0f82 cmp.w r3, r2, lsl #2 + 80091d6: f43f af79 beq.w 80090cc + if((HAL_GetTick() - tickstart) > CLOCKSWITCH_TIMEOUT_VALUE) + 80091da: f7fe f8ff bl 80073dc + 80091de: eba0 0008 sub.w r0, r0, r8 + 80091e2: 4548 cmp r0, r9 + 80091e4: d9f1 bls.n 80091ca + return HAL_TIMEOUT; + 80091e6: 2003 movs r0, #3 + 80091e8: e764 b.n 80090b4 + uint32_t msirange = 0U; + 80091ea: 2200 movs r2, #0 + 80091ec: e7c4 b.n 8009178 + pllvco = HSI_VALUE; + 80091ee: 4a2a ldr r2, [pc, #168] ; (8009298 ) + 80091f0: e7cb b.n 800918a + if(READ_BIT(RCC->CFGR, RCC_CFGR_HPRE) == RCC_SYSCLK_DIV1) + 80091f2: 68a3 ldr r3, [r4, #8] + 80091f4: f013 0ff0 tst.w r3, #240 ; 0xf0 + 80091f8: d107 bne.n 800920a + MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_SYSCLK_DIV2); + 80091fa: 68a3 ldr r3, [r4, #8] + 80091fc: f023 03f0 bic.w r3, r3, #240 ; 0xf0 + 8009200: f043 0380 orr.w r3, r3, #128 ; 0x80 + 8009204: 60a3 str r3, [r4, #8] + hpre = RCC_SYSCLK_DIV2; + 8009206: 2780 movs r7, #128 ; 0x80 + 8009208: e7d4 b.n 80091b4 + else if((((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_HCLK) == RCC_CLOCKTYPE_HCLK) && (RCC_ClkInitStruct->AHBCLKDivider == RCC_SYSCLK_DIV1)) + 800920a: 0788 lsls r0, r1, #30 + 800920c: d5d1 bpl.n 80091b2 + 800920e: 68ab ldr r3, [r5, #8] + 8009210: 2b00 cmp r3, #0 + 8009212: d1ce bne.n 80091b2 + 8009214: e7f1 b.n 80091fa + if(RCC_ClkInitStruct->SYSCLKSource == RCC_SYSCLKSOURCE_HSE) + 8009216: 2b02 cmp r3, #2 + 8009218: d10a bne.n 8009230 + if(READ_BIT(RCC->CR, RCC_CR_HSERDY) == 0U) + 800921a: 6823 ldr r3, [r4, #0] + 800921c: f413 3f00 tst.w r3, #131072 ; 0x20000 + if(READ_BIT(RCC->CR, RCC_CR_HSIRDY) == 0U) + 8009220: f43f af47 beq.w 80090b2 + if(HAL_RCC_GetSysClockFreq() > 80000000U) + 8009224: f7ff fc44 bl 8008ab0 + 8009228: 4b1a ldr r3, [pc, #104] ; (8009294 ) + 800922a: 4298 cmp r0, r3 + 800922c: d9c1 bls.n 80091b2 + 800922e: e7e4 b.n 80091fa + else if(RCC_ClkInitStruct->SYSCLKSource == RCC_SYSCLKSOURCE_MSI) + 8009230: b91b cbnz r3, 800923a + if(READ_BIT(RCC->CR, RCC_CR_MSIRDY) == 0U) + 8009232: 6823 ldr r3, [r4, #0] + 8009234: f013 0f02 tst.w r3, #2 + 8009238: e7f2 b.n 8009220 + if(READ_BIT(RCC->CR, RCC_CR_HSIRDY) == 0U) + 800923a: 6823 ldr r3, [r4, #0] + 800923c: f413 6f80 tst.w r3, #1024 ; 0x400 + 8009240: e7ee b.n 8009220 + if(hpre == RCC_SYSCLK_DIV2) + 8009242: 2f80 cmp r7, #128 ; 0x80 + 8009244: f47f af4d bne.w 80090e2 + MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_SYSCLK_DIV1); + 8009248: 490c ldr r1, [pc, #48] ; (800927c ) + 800924a: 688b ldr r3, [r1, #8] + 800924c: f023 03f0 bic.w r3, r3, #240 ; 0xf0 + 8009250: e746 b.n 80090e0 + __HAL_FLASH_SET_LATENCY(FLatency); + 8009252: 680b ldr r3, [r1, #0] + 8009254: f023 030f bic.w r3, r3, #15 + 8009258: 4333 orrs r3, r6 + 800925a: 600b str r3, [r1, #0] + if(__HAL_FLASH_GET_LATENCY() != FLatency) + 800925c: 680b ldr r3, [r1, #0] + 800925e: f003 030f and.w r3, r3, #15 + 8009262: 42b3 cmp r3, r6 + 8009264: f47f af25 bne.w 80090b2 + 8009268: e742 b.n 80090f0 + MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, RCC_ClkInitStruct->APB1CLKDivider); + 800926a: 68a3 ldr r3, [r4, #8] + 800926c: 68e9 ldr r1, [r5, #12] + 800926e: f423 63e0 bic.w r3, r3, #1792 ; 0x700 + 8009272: 430b orrs r3, r1 + 8009274: 60a3 str r3, [r4, #8] + 8009276: e740 b.n 80090fa + 8009278: 40022000 .word 0x40022000 + 800927c: 40021000 .word 0x40021000 + 8009280: 08010a58 .word 0x08010a58 + 8009284: 2009e2ac .word 0x2009e2ac + 8009288: 2009e2b0 .word 0x2009e2b0 + 800928c: 08010a70 .word 0x08010a70 + 8009290: 007a1200 .word 0x007a1200 + 8009294: 04c4b400 .word 0x04c4b400 + 8009298: 00f42400 .word 0x00f42400 + +0800929c : +} + 800929c: 4b01 ldr r3, [pc, #4] ; (80092a4 ) + 800929e: 6818 ldr r0, [r3, #0] + 80092a0: 4770 bx lr + 80092a2: bf00 nop + 80092a4: 2009e2ac .word 0x2009e2ac + +080092a8 : + return (HAL_RCC_GetHCLKFreq() >> (APBPrescTable[READ_BIT(RCC->CFGR, RCC_CFGR_PPRE1) >> RCC_CFGR_PPRE1_Pos] & 0x1FU)); + 80092a8: 4b05 ldr r3, [pc, #20] ; (80092c0 ) + 80092aa: 4a06 ldr r2, [pc, #24] ; (80092c4 ) + 80092ac: 689b ldr r3, [r3, #8] + 80092ae: f3c3 2302 ubfx r3, r3, #8, #3 + 80092b2: 5cd3 ldrb r3, [r2, r3] + 80092b4: 4a04 ldr r2, [pc, #16] ; (80092c8 ) + 80092b6: 6810 ldr r0, [r2, #0] + 80092b8: f003 031f and.w r3, r3, #31 +} + 80092bc: 40d8 lsrs r0, r3 + 80092be: 4770 bx lr + 80092c0: 40021000 .word 0x40021000 + 80092c4: 08010a68 .word 0x08010a68 + 80092c8: 2009e2ac .word 0x2009e2ac + +080092cc : + return (HAL_RCC_GetHCLKFreq()>> (APBPrescTable[READ_BIT(RCC->CFGR, RCC_CFGR_PPRE2) >> RCC_CFGR_PPRE2_Pos] & 0x1FU)); + 80092cc: 4b05 ldr r3, [pc, #20] ; (80092e4 ) + 80092ce: 4a06 ldr r2, [pc, #24] ; (80092e8 ) + 80092d0: 689b ldr r3, [r3, #8] + 80092d2: f3c3 23c2 ubfx r3, r3, #11, #3 + 80092d6: 5cd3 ldrb r3, [r2, r3] + 80092d8: 4a04 ldr r2, [pc, #16] ; (80092ec ) + 80092da: 6810 ldr r0, [r2, #0] + 80092dc: f003 031f and.w r3, r3, #31 +} + 80092e0: 40d8 lsrs r0, r3 + 80092e2: 4770 bx lr + 80092e4: 40021000 .word 0x40021000 + 80092e8: 08010a68 .word 0x08010a68 + 80092ec: 2009e2ac .word 0x2009e2ac + +080092f0 : + RCC_OscInitStruct->OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_MSI | \ + 80092f0: 233f movs r3, #63 ; 0x3f + 80092f2: 6003 str r3, [r0, #0] + if(READ_BIT(RCC->CR, RCC_CR_HSEBYP) == RCC_CR_HSEBYP) + 80092f4: 4b2e ldr r3, [pc, #184] ; (80093b0 ) + 80092f6: 681a ldr r2, [r3, #0] + 80092f8: 0351 lsls r1, r2, #13 + 80092fa: d54a bpl.n 8009392 + RCC_OscInitStruct->HSEState = RCC_HSE_BYPASS; + 80092fc: f44f 22a0 mov.w r2, #327680 ; 0x50000 + RCC_OscInitStruct->HSEState = RCC_HSE_OFF; + 8009300: 6042 str r2, [r0, #4] + if(READ_BIT(RCC->CR, RCC_CR_MSION) == RCC_CR_MSION) + 8009302: 681a ldr r2, [r3, #0] + 8009304: f002 0201 and.w r2, r2, #1 + 8009308: 6182 str r2, [r0, #24] + RCC_OscInitStruct->MSICalibrationValue = READ_BIT(RCC->ICSCR, RCC_ICSCR_MSITRIM) >> RCC_ICSCR_MSITRIM_Pos; + 800930a: 685a ldr r2, [r3, #4] + 800930c: f3c2 2207 ubfx r2, r2, #8, #8 + 8009310: 61c2 str r2, [r0, #28] + RCC_OscInitStruct->MSIClockRange = READ_BIT(RCC->CR, RCC_CR_MSIRANGE); + 8009312: 681a ldr r2, [r3, #0] + 8009314: f002 02f0 and.w r2, r2, #240 ; 0xf0 + 8009318: 6202 str r2, [r0, #32] + if(READ_BIT(RCC->CR, RCC_CR_HSION) == RCC_CR_HSION) + 800931a: 681a ldr r2, [r3, #0] + RCC_OscInitStruct->HSIState = RCC_HSI_ON; + 800931c: f402 7280 and.w r2, r2, #256 ; 0x100 + 8009320: 60c2 str r2, [r0, #12] + RCC_OscInitStruct->HSICalibrationValue = READ_BIT(RCC->ICSCR, RCC_ICSCR_HSITRIM) >> RCC_ICSCR_HSITRIM_Pos; + 8009322: 685a ldr r2, [r3, #4] + 8009324: f3c2 6206 ubfx r2, r2, #24, #7 + 8009328: 6102 str r2, [r0, #16] + if(READ_BIT(RCC->BDCR, RCC_BDCR_LSEBYP) == RCC_BDCR_LSEBYP) + 800932a: f8d3 2090 ldr.w r2, [r3, #144] ; 0x90 + 800932e: 0752 lsls r2, r2, #29 + 8009330: d536 bpl.n 80093a0 + RCC_OscInitStruct->LSEState = RCC_LSE_BYPASS; + 8009332: 2205 movs r2, #5 + RCC_OscInitStruct->LSEState = RCC_LSE_OFF; + 8009334: 6082 str r2, [r0, #8] + if(READ_BIT(RCC->CSR, RCC_CSR_LSION) == RCC_CSR_LSION) + 8009336: f8d3 2094 ldr.w r2, [r3, #148] ; 0x94 + 800933a: f002 0201 and.w r2, r2, #1 + 800933e: 6142 str r2, [r0, #20] + if(READ_BIT(RCC->CRRCR, RCC_CRRCR_HSI48ON) == RCC_CRRCR_HSI48ON) + 8009340: f8d3 2098 ldr.w r2, [r3, #152] ; 0x98 + 8009344: f002 0201 and.w r2, r2, #1 + 8009348: 6242 str r2, [r0, #36] ; 0x24 + if(READ_BIT(RCC->CR, RCC_CR_PLLON) == RCC_CR_PLLON) + 800934a: 681a ldr r2, [r3, #0] + RCC_OscInitStruct->PLL.PLLState = RCC_PLL_OFF; + 800934c: f012 7f80 tst.w r2, #16777216 ; 0x1000000 + 8009350: bf14 ite ne + 8009352: 2202 movne r2, #2 + 8009354: 2201 moveq r2, #1 + 8009356: 6282 str r2, [r0, #40] ; 0x28 + RCC_OscInitStruct->PLL.PLLSource = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLSRC); + 8009358: 68da ldr r2, [r3, #12] + 800935a: f002 0203 and.w r2, r2, #3 + 800935e: 62c2 str r2, [r0, #44] ; 0x2c + RCC_OscInitStruct->PLL.PLLM = (READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U; + 8009360: 68da ldr r2, [r3, #12] + 8009362: f3c2 1203 ubfx r2, r2, #4, #4 + 8009366: 3201 adds r2, #1 + 8009368: 6302 str r2, [r0, #48] ; 0x30 + RCC_OscInitStruct->PLL.PLLN = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos; + 800936a: 68da ldr r2, [r3, #12] + 800936c: f3c2 2206 ubfx r2, r2, #8, #7 + 8009370: 6342 str r2, [r0, #52] ; 0x34 + RCC_OscInitStruct->PLL.PLLQ = (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLQ) >> RCC_PLLCFGR_PLLQ_Pos) + 1U) << 1U); + 8009372: 68da ldr r2, [r3, #12] + 8009374: f3c2 5241 ubfx r2, r2, #21, #2 + 8009378: 3201 adds r2, #1 + 800937a: 0052 lsls r2, r2, #1 + 800937c: 63c2 str r2, [r0, #60] ; 0x3c + RCC_OscInitStruct->PLL.PLLR = (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos) + 1U) << 1U); + 800937e: 68da ldr r2, [r3, #12] + 8009380: f3c2 6241 ubfx r2, r2, #25, #2 + 8009384: 3201 adds r2, #1 + 8009386: 0052 lsls r2, r2, #1 + 8009388: 6402 str r2, [r0, #64] ; 0x40 + RCC_OscInitStruct->PLL.PLLP = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLPDIV) >> RCC_PLLCFGR_PLLPDIV_Pos; + 800938a: 68db ldr r3, [r3, #12] + 800938c: 0edb lsrs r3, r3, #27 + 800938e: 6383 str r3, [r0, #56] ; 0x38 +} + 8009390: 4770 bx lr + else if(READ_BIT(RCC->CR, RCC_CR_HSEON) == RCC_CR_HSEON) + 8009392: 681a ldr r2, [r3, #0] + 8009394: f412 3280 ands.w r2, r2, #65536 ; 0x10000 + RCC_OscInitStruct->HSEState = RCC_HSE_ON; + 8009398: bf18 it ne + 800939a: f44f 3280 movne.w r2, #65536 ; 0x10000 + 800939e: e7af b.n 8009300 + else if(READ_BIT(RCC->BDCR, RCC_BDCR_LSEON) == RCC_BDCR_LSEON) + 80093a0: f8d3 2090 ldr.w r2, [r3, #144] ; 0x90 + 80093a4: f012 0201 ands.w r2, r2, #1 + RCC_OscInitStruct->LSEState = RCC_LSE_ON; + 80093a8: bf18 it ne + 80093aa: 2201 movne r2, #1 + 80093ac: e7c2 b.n 8009334 + 80093ae: bf00 nop + 80093b0: 40021000 .word 0x40021000 + +080093b4 : + RCC_ClkInitStruct->ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; + 80093b4: 230f movs r3, #15 + 80093b6: 6003 str r3, [r0, #0] + RCC_ClkInitStruct->SYSCLKSource = READ_BIT(RCC->CFGR, RCC_CFGR_SW); + 80093b8: 4b0b ldr r3, [pc, #44] ; (80093e8 ) + 80093ba: 689a ldr r2, [r3, #8] + 80093bc: f002 0203 and.w r2, r2, #3 + 80093c0: 6042 str r2, [r0, #4] + RCC_ClkInitStruct->AHBCLKDivider = READ_BIT(RCC->CFGR, RCC_CFGR_HPRE); + 80093c2: 689a ldr r2, [r3, #8] + 80093c4: f002 02f0 and.w r2, r2, #240 ; 0xf0 + 80093c8: 6082 str r2, [r0, #8] + RCC_ClkInitStruct->APB1CLKDivider = READ_BIT(RCC->CFGR, RCC_CFGR_PPRE1); + 80093ca: 689a ldr r2, [r3, #8] + 80093cc: f402 62e0 and.w r2, r2, #1792 ; 0x700 + 80093d0: 60c2 str r2, [r0, #12] + RCC_ClkInitStruct->APB2CLKDivider = (READ_BIT(RCC->CFGR, RCC_CFGR_PPRE2) >> 3U); + 80093d2: 689b ldr r3, [r3, #8] + 80093d4: 08db lsrs r3, r3, #3 + 80093d6: f403 63e0 and.w r3, r3, #1792 ; 0x700 + 80093da: 6103 str r3, [r0, #16] + *pFLatency = __HAL_FLASH_GET_LATENCY(); + 80093dc: 4b03 ldr r3, [pc, #12] ; (80093ec ) + 80093de: 681b ldr r3, [r3, #0] + 80093e0: f003 030f and.w r3, r3, #15 + 80093e4: 600b str r3, [r1, #0] +} + 80093e6: 4770 bx lr + 80093e8: 40021000 .word 0x40021000 + 80093ec: 40022000 .word 0x40022000 + +080093f0 : + SET_BIT(RCC->CR, RCC_CR_CSSON) ; + 80093f0: 4a02 ldr r2, [pc, #8] ; (80093fc ) + 80093f2: 6813 ldr r3, [r2, #0] + 80093f4: f443 2300 orr.w r3, r3, #524288 ; 0x80000 + 80093f8: 6013 str r3, [r2, #0] +} + 80093fa: 4770 bx lr + 80093fc: 40021000 .word 0x40021000 + +08009400 : +} + 8009400: 4770 bx lr + ... + +08009404 : +{ + 8009404: b510 push {r4, lr} + if(__HAL_RCC_GET_IT(RCC_IT_CSS)) + 8009406: 4c05 ldr r4, [pc, #20] ; (800941c ) + 8009408: 69e3 ldr r3, [r4, #28] + 800940a: 05db lsls r3, r3, #23 + 800940c: d504 bpl.n 8009418 + HAL_RCC_CSSCallback(); + 800940e: f7ff fff7 bl 8009400 + __HAL_RCC_CLEAR_IT(RCC_IT_CSS); + 8009412: f44f 7380 mov.w r3, #256 ; 0x100 + 8009416: 6223 str r3, [r4, #32] +} + 8009418: bd10 pop {r4, pc} + 800941a: bf00 nop + 800941c: 40021000 .word 0x40021000 + +08009420 : +#if defined(RCC_PLLP_SUPPORT) + uint32_t pllp = 0U; +#endif /* RCC_PLLP_SUPPORT */ + + /* Handle SAIs */ + if(PeriphClk == RCC_PERIPHCLK_SAI1) + 8009420: f5b0 6f00 cmp.w r0, #2048 ; 0x800 + 8009424: 4a3d ldr r2, [pc, #244] ; (800951c ) + 8009426: d108 bne.n 800943a + { + srcclk = __HAL_RCC_GET_SAI1_SOURCE(); + 8009428: f8d2 309c ldr.w r3, [r2, #156] ; 0x9c + 800942c: f003 03e0 and.w r3, r3, #224 ; 0xe0 + if(srcclk == RCC_SAI1CLKSOURCE_PIN) + 8009430: 2b60 cmp r3, #96 ; 0x60 + 8009432: d12d bne.n 8009490 + { + frequency = EXTERNAL_SAI1_CLOCK_VALUE; + 8009434: f64b 3080 movw r0, #48000 ; 0xbb80 + 8009438: 4770 bx lr + /* Else, PLL clock output to check below */ + } +#if defined(SAI2) + else + { + if(PeriphClk == RCC_PERIPHCLK_SAI2) + 800943a: f5b0 5f80 cmp.w r0, #4096 ; 0x1000 + 800943e: d12a bne.n 8009496 + { + srcclk = __HAL_RCC_GET_SAI2_SOURCE(); + 8009440: f8d2 309c ldr.w r3, [r2, #156] ; 0x9c + 8009444: f403 63e0 and.w r3, r3, #1792 ; 0x700 + if(srcclk == RCC_SAI2CLKSOURCE_PIN) + 8009448: f5b3 7f40 cmp.w r3, #768 ; 0x300 + 800944c: d0f2 beq.n 8009434 + if(frequency == 0U) + { + pllvco = InputFrequency; + +#if defined(SAI2) + if((srcclk == RCC_SAI1CLKSOURCE_PLL) || (srcclk == RCC_SAI2CLKSOURCE_PLL)) + 800944e: f5b3 7f00 cmp.w r3, #512 ; 0x200 + 8009452: d15c bne.n 800950e + { + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLLRDY) && (__HAL_RCC_GET_PLLCLKOUT_CONFIG(RCC_PLL_SAI3CLK) != 0U)) + 8009454: 6810 ldr r0, [r2, #0] + 8009456: f010 7000 ands.w r0, r0, #33554432 ; 0x2000000 + 800945a: d05d beq.n 8009518 + 800945c: 68d0 ldr r0, [r2, #12] + 800945e: f410 3080 ands.w r0, r0, #65536 ; 0x10000 + 8009462: d059 beq.n 8009518 + { + /* f(PLL Source) / PLLM */ + pllvco = (pllvco / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009464: 68d0 ldr r0, [r2, #12] + 8009466: f3c0 1003 ubfx r0, r0, #4, #4 + 800946a: 3001 adds r0, #1 + 800946c: fbb1 f0f0 udiv r0, r1, r0 + /* f(PLLSAI3CLK) = f(VCO input) * PLLN / PLLP */ + plln = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos; + 8009470: 68d1 ldr r1, [r2, #12] +#if defined(RCC_PLLP_DIV_2_31_SUPPORT) + pllp = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLPDIV) >> RCC_PLLCFGR_PLLPDIV_Pos; + 8009472: 68d3 ldr r3, [r2, #12] +#endif + if(pllp == 0U) + 8009474: 0edb lsrs r3, r3, #27 + plln = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos; + 8009476: f3c1 2106 ubfx r1, r1, #8, #7 + if(pllp == 0U) + 800947a: d105 bne.n 8009488 + { + if(READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLP) != 0U) + 800947c: 68d3 ldr r3, [r2, #12] + { + pllp = 17U; + } + else + { + pllp = 7U; + 800947e: f413 3f00 tst.w r3, #131072 ; 0x20000 + 8009482: bf14 ite ne + 8009484: 2311 movne r3, #17 + 8009486: 2307 moveq r3, #7 + } + } + frequency = (pllvco * plln) / pllp; + 8009488: 4348 muls r0, r1 + 800948a: fbb0 f0f3 udiv r0, r0, r3 + 800948e: 4770 bx lr + if((srcclk == RCC_SAI1CLKSOURCE_PLL) || (srcclk == RCC_SAI2CLKSOURCE_PLL)) + 8009490: 2b40 cmp r3, #64 ; 0x40 + 8009492: d0df beq.n 8009454 + else if(srcclk == 0U) /* RCC_SAI1CLKSOURCE_PLLSAI1 || RCC_SAI2CLKSOURCE_PLLSAI1 */ + 8009494: b9ab cbnz r3, 80094c2 + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLLSAI1RDY) && (__HAL_RCC_GET_PLLSAI1CLKOUT_CONFIG(RCC_PLLSAI1_SAI1CLK) != 0U)) + 8009496: 6810 ldr r0, [r2, #0] + 8009498: f010 6000 ands.w r0, r0, #134217728 ; 0x8000000 + 800949c: d03c beq.n 8009518 + 800949e: 6910 ldr r0, [r2, #16] + 80094a0: f410 3080 ands.w r0, r0, #65536 ; 0x10000 + 80094a4: d038 beq.n 8009518 + pllvco = (pllvco / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 80094a6: 6913 ldr r3, [r2, #16] + plln = READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1N) >> RCC_PLLSAI1CFGR_PLLSAI1N_Pos; + 80094a8: 6910 ldr r0, [r2, #16] + pllvco = (pllvco / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 80094aa: f3c3 1303 ubfx r3, r3, #4, #4 + 80094ae: 3301 adds r3, #1 + 80094b0: fbb1 f1f3 udiv r1, r1, r3 + pllp = READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1PDIV) >> RCC_PLLSAI1CFGR_PLLSAI1PDIV_Pos; + 80094b4: 6913 ldr r3, [r2, #16] + if(pllp == 0U) + 80094b6: 0edb lsrs r3, r3, #27 + plln = READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1N) >> RCC_PLLSAI1CFGR_PLLSAI1N_Pos; + 80094b8: f3c0 2006 ubfx r0, r0, #8, #7 + if(pllp == 0U) + 80094bc: d1e4 bne.n 8009488 + if(READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1P) != 0U) + 80094be: 6913 ldr r3, [r2, #16] + 80094c0: e7dd b.n 800947e + else if((srcclk == RCC_SAI1CLKSOURCE_HSI) || (srcclk == RCC_SAI2CLKSOURCE_HSI)) + 80094c2: 2b80 cmp r3, #128 ; 0x80 + 80094c4: d106 bne.n 80094d4 + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSIRDY)) + 80094c6: 6810 ldr r0, [r2, #0] + frequency = HSI_VALUE; + 80094c8: 4b15 ldr r3, [pc, #84] ; (8009520 ) + 80094ca: f410 6080 ands.w r0, r0, #1024 ; 0x400 + 80094ce: bf18 it ne + 80094d0: 4618 movne r0, r3 + 80094d2: 4770 bx lr + else if((srcclk == RCC_SAI1CLKSOURCE_PLLSAI2) || (srcclk == RCC_SAI2CLKSOURCE_PLLSAI2)) + 80094d4: 2b20 cmp r3, #32 + 80094d6: d002 beq.n 80094de + 80094d8: f5b3 7f80 cmp.w r3, #256 ; 0x100 + 80094dc: d115 bne.n 800950a + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLLSAI2RDY) && (__HAL_RCC_GET_PLLSAI2CLKOUT_CONFIG(RCC_PLLSAI2_SAI2CLK) != 0U)) + 80094de: 6810 ldr r0, [r2, #0] + 80094e0: f010 5000 ands.w r0, r0, #536870912 ; 0x20000000 + 80094e4: d018 beq.n 8009518 + 80094e6: 6950 ldr r0, [r2, #20] + 80094e8: f410 3080 ands.w r0, r0, #65536 ; 0x10000 + 80094ec: d014 beq.n 8009518 + pllvco = (pllvco / ((READ_BIT(RCC->PLLSAI2CFGR, RCC_PLLSAI2CFGR_PLLSAI2M) >> RCC_PLLSAI2CFGR_PLLSAI2M_Pos) + 1U)); + 80094ee: 6953 ldr r3, [r2, #20] + 80094f0: f3c3 1303 ubfx r3, r3, #4, #4 + 80094f4: 3301 adds r3, #1 + 80094f6: fbb1 f0f3 udiv r0, r1, r3 + plln = READ_BIT(RCC->PLLSAI2CFGR, RCC_PLLSAI2CFGR_PLLSAI2N) >> RCC_PLLSAI2CFGR_PLLSAI2N_Pos; + 80094fa: 6951 ldr r1, [r2, #20] + pllp = READ_BIT(RCC->PLLSAI2CFGR, RCC_PLLSAI2CFGR_PLLSAI2PDIV) >> RCC_PLLSAI2CFGR_PLLSAI2PDIV_Pos; + 80094fc: 6953 ldr r3, [r2, #20] + if(pllp == 0U) + 80094fe: 0edb lsrs r3, r3, #27 + plln = READ_BIT(RCC->PLLSAI2CFGR, RCC_PLLSAI2CFGR_PLLSAI2N) >> RCC_PLLSAI2CFGR_PLLSAI2N_Pos; + 8009500: f3c1 2106 ubfx r1, r1, #8, #7 + if(pllp == 0U) + 8009504: d1c0 bne.n 8009488 + if(READ_BIT(RCC->PLLSAI2CFGR, RCC_PLLSAI2CFGR_PLLSAI2P) != 0U) + 8009506: 6953 ldr r3, [r2, #20] + 8009508: e7b9 b.n 800947e + 800950a: 2000 movs r0, #0 + /* No clock source, frequency default init at 0 */ + } + } + + + return frequency; + 800950c: 4770 bx lr + else if(srcclk == 0U) /* RCC_SAI1CLKSOURCE_PLLSAI1 || RCC_SAI2CLKSOURCE_PLLSAI1 */ + 800950e: 2b00 cmp r3, #0 + 8009510: d0c1 beq.n 8009496 + else if((srcclk == RCC_SAI1CLKSOURCE_HSI) || (srcclk == RCC_SAI2CLKSOURCE_HSI)) + 8009512: f5b3 6f80 cmp.w r3, #1024 ; 0x400 + 8009516: e7d5 b.n 80094c4 +} + 8009518: 4770 bx lr + 800951a: bf00 nop + 800951c: 40021000 .word 0x40021000 + 8009520: 00f42400 .word 0x00f42400 + +08009524 : +{ + 8009524: b5f8 push {r3, r4, r5, r6, r7, lr} + if(__HAL_RCC_GET_PLL_OSCSOURCE() != RCC_PLLSOURCE_NONE) + 8009526: 4c3c ldr r4, [pc, #240] ; (8009618 ) + if((__HAL_RCC_GET_PLL_OSCSOURCE() != PllSai1->PLLSAI1Source) + 8009528: 6803 ldr r3, [r0, #0] + if(__HAL_RCC_GET_PLL_OSCSOURCE() != RCC_PLLSOURCE_NONE) + 800952a: 68e2 ldr r2, [r4, #12] +{ + 800952c: 4605 mov r5, r0 + if(__HAL_RCC_GET_PLL_OSCSOURCE() != RCC_PLLSOURCE_NONE) + 800952e: 0790 lsls r0, r2, #30 +{ + 8009530: 460f mov r7, r1 + if(__HAL_RCC_GET_PLL_OSCSOURCE() != RCC_PLLSOURCE_NONE) + 8009532: d023 beq.n 800957c + if((__HAL_RCC_GET_PLL_OSCSOURCE() != PllSai1->PLLSAI1Source) + 8009534: 68e2 ldr r2, [r4, #12] + 8009536: f002 0203 and.w r2, r2, #3 + 800953a: 429a cmp r2, r3 + 800953c: d16a bne.n 8009614 + || + 800953e: 2a00 cmp r2, #0 + 8009540: d068 beq.n 8009614 + __HAL_RCC_PLLSAI1_DISABLE(); + 8009542: 6823 ldr r3, [r4, #0] + 8009544: f023 6380 bic.w r3, r3, #67108864 ; 0x4000000 + 8009548: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 800954a: f7fd ff47 bl 80073dc + 800954e: 4606 mov r6, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI1RDY) != 0U) + 8009550: 6823 ldr r3, [r4, #0] + 8009552: 011a lsls r2, r3, #4 + 8009554: d42d bmi.n 80095b2 + MODIFY_REG(RCC->PLLSAI1CFGR, + 8009556: 68ab ldr r3, [r5, #8] + 8009558: 021e lsls r6, r3, #8 + 800955a: 686b ldr r3, [r5, #4] + 800955c: 3b01 subs r3, #1 + 800955e: 0118 lsls r0, r3, #4 + if(Divider == DIVIDER_P_UPDATE) + 8009560: b377 cbz r7, 80095c0 + else if(Divider == DIVIDER_Q_UPDATE) + 8009562: 2f01 cmp r7, #1 + 8009564: d145 bne.n 80095f2 + MODIFY_REG(RCC->PLLSAI1CFGR, + 8009566: 692b ldr r3, [r5, #16] + 8009568: 6927 ldr r7, [r4, #16] + 800956a: 085b lsrs r3, r3, #1 + 800956c: 1e59 subs r1, r3, #1 + 800956e: 4b2b ldr r3, [pc, #172] ; (800961c ) + 8009570: 403b ands r3, r7 + 8009572: 4333 orrs r3, r6 + 8009574: 4303 orrs r3, r0 + 8009576: ea43 5341 orr.w r3, r3, r1, lsl #21 + 800957a: e029 b.n 80095d0 + switch(PllSai1->PLLSAI1Source) + 800957c: 2b02 cmp r3, #2 + 800957e: d00d beq.n 800959c + 8009580: 2b03 cmp r3, #3 + 8009582: d00f beq.n 80095a4 + 8009584: 2b01 cmp r3, #1 + 8009586: d145 bne.n 8009614 + if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_MSIRDY)) + 8009588: 6822 ldr r2, [r4, #0] + 800958a: f012 0f02 tst.w r2, #2 + if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_HSEBYP)) + 800958e: d041 beq.n 8009614 + MODIFY_REG(RCC->PLLCFGR, RCC_PLLCFGR_PLLSRC, PllSai1->PLLSAI1Source); + 8009590: 68e0 ldr r0, [r4, #12] + 8009592: f020 0003 bic.w r0, r0, #3 + 8009596: 4318 orrs r0, r3 + 8009598: 60e0 str r0, [r4, #12] + if(status == HAL_OK) + 800959a: e7d2 b.n 8009542 + if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_HSIRDY)) + 800959c: 6822 ldr r2, [r4, #0] + 800959e: f412 6f80 tst.w r2, #1024 ; 0x400 + 80095a2: e7f4 b.n 800958e + if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_HSERDY)) + 80095a4: 6822 ldr r2, [r4, #0] + 80095a6: 0391 lsls r1, r2, #14 + 80095a8: d4f2 bmi.n 8009590 + if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_HSEBYP)) + 80095aa: 6822 ldr r2, [r4, #0] + 80095ac: f412 2f80 tst.w r2, #262144 ; 0x40000 + 80095b0: e7ed b.n 800958e + if((HAL_GetTick() - tickstart) > PLLSAI1_TIMEOUT_VALUE) + 80095b2: f7fd ff13 bl 80073dc + 80095b6: 1b80 subs r0, r0, r6 + 80095b8: 2802 cmp r0, #2 + 80095ba: d9c9 bls.n 8009550 + status = HAL_TIMEOUT; + 80095bc: 2003 movs r0, #3 +} + 80095be: bdf8 pop {r3, r4, r5, r6, r7, pc} + MODIFY_REG(RCC->PLLSAI1CFGR, + 80095c0: 68e9 ldr r1, [r5, #12] + 80095c2: 6922 ldr r2, [r4, #16] + 80095c4: ea46 63c1 orr.w r3, r6, r1, lsl #27 + 80095c8: 4915 ldr r1, [pc, #84] ; (8009620 ) + 80095ca: 4011 ands r1, r2 + 80095cc: 430b orrs r3, r1 + 80095ce: 4303 orrs r3, r0 + MODIFY_REG(RCC->PLLSAI1CFGR, + 80095d0: 6123 str r3, [r4, #16] + __HAL_RCC_PLLSAI1_ENABLE(); + 80095d2: 6823 ldr r3, [r4, #0] + 80095d4: f043 6380 orr.w r3, r3, #67108864 ; 0x4000000 + 80095d8: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 80095da: f7fd feff bl 80073dc + 80095de: 4606 mov r6, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI1RDY) == 0U) + 80095e0: 6823 ldr r3, [r4, #0] + 80095e2: 011b lsls r3, r3, #4 + 80095e4: d510 bpl.n 8009608 + __HAL_RCC_PLLSAI1CLKOUT_ENABLE(PllSai1->PLLSAI1ClockOut); + 80095e6: 6923 ldr r3, [r4, #16] + 80095e8: 69aa ldr r2, [r5, #24] + 80095ea: 4313 orrs r3, r2 + 80095ec: 6123 str r3, [r4, #16] + 80095ee: 2000 movs r0, #0 + return status; + 80095f0: e7e5 b.n 80095be + MODIFY_REG(RCC->PLLSAI1CFGR, + 80095f2: 696b ldr r3, [r5, #20] + 80095f4: 6921 ldr r1, [r4, #16] + 80095f6: 085b lsrs r3, r3, #1 + 80095f8: 1e5a subs r2, r3, #1 + 80095fa: 4b0a ldr r3, [pc, #40] ; (8009624 ) + 80095fc: 400b ands r3, r1 + 80095fe: 4333 orrs r3, r6 + 8009600: 4303 orrs r3, r0 + 8009602: ea43 6342 orr.w r3, r3, r2, lsl #25 + 8009606: e7e3 b.n 80095d0 + if((HAL_GetTick() - tickstart) > PLLSAI1_TIMEOUT_VALUE) + 8009608: f7fd fee8 bl 80073dc + 800960c: 1b80 subs r0, r0, r6 + 800960e: 2802 cmp r0, #2 + 8009610: d9e6 bls.n 80095e0 + 8009612: e7d3 b.n 80095bc + status = HAL_ERROR; + 8009614: 2001 movs r0, #1 + 8009616: e7d2 b.n 80095be + 8009618: 40021000 .word 0x40021000 + 800961c: ff9f800f .word 0xff9f800f + 8009620: 07ff800f .word 0x07ff800f + 8009624: f9ff800f .word 0xf9ff800f + +08009628 : +static HAL_StatusTypeDef RCCEx_PLLSAI2_Config(RCC_PLLSAI2InitTypeDef *PllSai2, uint32_t Divider) + 8009628: b570 push {r4, r5, r6, lr} + if(__HAL_RCC_GET_PLL_OSCSOURCE() != RCC_PLLSOURCE_NONE) + 800962a: 4c2f ldr r4, [pc, #188] ; (80096e8 ) + if((__HAL_RCC_GET_PLL_OSCSOURCE() != PllSai2->PLLSAI2Source) + 800962c: 6803 ldr r3, [r0, #0] + if(__HAL_RCC_GET_PLL_OSCSOURCE() != RCC_PLLSOURCE_NONE) + 800962e: 68e2 ldr r2, [r4, #12] +static HAL_StatusTypeDef RCCEx_PLLSAI2_Config(RCC_PLLSAI2InitTypeDef *PllSai2, uint32_t Divider) + 8009630: 4605 mov r5, r0 + if(__HAL_RCC_GET_PLL_OSCSOURCE() != RCC_PLLSOURCE_NONE) + 8009632: 0790 lsls r0, r2, #30 + 8009634: d026 beq.n 8009684 + if((__HAL_RCC_GET_PLL_OSCSOURCE() != PllSai2->PLLSAI2Source) + 8009636: 68e2 ldr r2, [r4, #12] + 8009638: f002 0203 and.w r2, r2, #3 + 800963c: 429a cmp r2, r3 + 800963e: d151 bne.n 80096e4 + || + 8009640: 2a00 cmp r2, #0 + 8009642: d04f beq.n 80096e4 + __HAL_RCC_PLLSAI2_DISABLE(); + 8009644: 6823 ldr r3, [r4, #0] + 8009646: f023 5380 bic.w r3, r3, #268435456 ; 0x10000000 + 800964a: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 800964c: f7fd fec6 bl 80073dc + 8009650: 4606 mov r6, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI2RDY) != 0U) + 8009652: 6823 ldr r3, [r4, #0] + 8009654: 009a lsls r2, r3, #2 + 8009656: d430 bmi.n 80096ba + MODIFY_REG(RCC->PLLSAI2CFGR, + 8009658: e9d5 2302 ldrd r2, r3, [r5, #8] + 800965c: 06db lsls r3, r3, #27 + 800965e: 6961 ldr r1, [r4, #20] + 8009660: ea43 2302 orr.w r3, r3, r2, lsl #8 + 8009664: 4a21 ldr r2, [pc, #132] ; (80096ec ) + 8009666: 400a ands r2, r1 + 8009668: 4313 orrs r3, r2 + 800966a: 686a ldr r2, [r5, #4] + 800966c: 3a01 subs r2, #1 + 800966e: ea43 1302 orr.w r3, r3, r2, lsl #4 + 8009672: 6163 str r3, [r4, #20] + __HAL_RCC_PLLSAI2_ENABLE(); + 8009674: 6823 ldr r3, [r4, #0] + 8009676: f043 5380 orr.w r3, r3, #268435456 ; 0x10000000 + 800967a: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 800967c: f7fd feae bl 80073dc + 8009680: 4606 mov r6, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI2RDY) == 0U) + 8009682: e026 b.n 80096d2 + switch(PllSai2->PLLSAI2Source) + 8009684: 2b02 cmp r3, #2 + 8009686: d00d beq.n 80096a4 + 8009688: 2b03 cmp r3, #3 + 800968a: d00f beq.n 80096ac + 800968c: 2b01 cmp r3, #1 + 800968e: d129 bne.n 80096e4 + if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_MSIRDY)) + 8009690: 6822 ldr r2, [r4, #0] + 8009692: f012 0f02 tst.w r2, #2 + if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_HSEBYP)) + 8009696: d025 beq.n 80096e4 + MODIFY_REG(RCC->PLLCFGR, RCC_PLLCFGR_PLLSRC, PllSai2->PLLSAI2Source); + 8009698: 68e0 ldr r0, [r4, #12] + 800969a: f020 0003 bic.w r0, r0, #3 + 800969e: 4318 orrs r0, r3 + 80096a0: 60e0 str r0, [r4, #12] + if(status == HAL_OK) + 80096a2: e7cf b.n 8009644 + if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_HSIRDY)) + 80096a4: 6822 ldr r2, [r4, #0] + 80096a6: f412 6f80 tst.w r2, #1024 ; 0x400 + 80096aa: e7f4 b.n 8009696 + if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_HSERDY)) + 80096ac: 6822 ldr r2, [r4, #0] + 80096ae: 0391 lsls r1, r2, #14 + 80096b0: d4f2 bmi.n 8009698 + if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_HSEBYP)) + 80096b2: 6822 ldr r2, [r4, #0] + 80096b4: f412 2f80 tst.w r2, #262144 ; 0x40000 + 80096b8: e7ed b.n 8009696 + if((HAL_GetTick() - tickstart) > PLLSAI2_TIMEOUT_VALUE) + 80096ba: f7fd fe8f bl 80073dc + 80096be: 1b80 subs r0, r0, r6 + 80096c0: 2802 cmp r0, #2 + 80096c2: d9c6 bls.n 8009652 + status = HAL_TIMEOUT; + 80096c4: 2003 movs r0, #3 +} + 80096c6: bd70 pop {r4, r5, r6, pc} + if((HAL_GetTick() - tickstart) > PLLSAI2_TIMEOUT_VALUE) + 80096c8: f7fd fe88 bl 80073dc + 80096cc: 1b80 subs r0, r0, r6 + 80096ce: 2802 cmp r0, #2 + 80096d0: d8f8 bhi.n 80096c4 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI2RDY) == 0U) + 80096d2: 6823 ldr r3, [r4, #0] + 80096d4: 009b lsls r3, r3, #2 + 80096d6: d5f7 bpl.n 80096c8 + __HAL_RCC_PLLSAI2CLKOUT_ENABLE(PllSai2->PLLSAI2ClockOut); + 80096d8: 6963 ldr r3, [r4, #20] + 80096da: 69aa ldr r2, [r5, #24] + 80096dc: 4313 orrs r3, r2 + 80096de: 6163 str r3, [r4, #20] + 80096e0: 2000 movs r0, #0 + return status; + 80096e2: e7f0 b.n 80096c6 + status = HAL_ERROR; + 80096e4: 2001 movs r0, #1 + 80096e6: e7ee b.n 80096c6 + 80096e8: 40021000 .word 0x40021000 + 80096ec: 07ff800f .word 0x07ff800f + +080096f0 : +{ + 80096f0: e92d 47f3 stmdb sp!, {r0, r1, r4, r5, r6, r7, r8, r9, sl, lr} + if((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAI1) == RCC_PERIPHCLK_SAI1)) + 80096f4: 6806 ldr r6, [r0, #0] + 80096f6: f416 6600 ands.w r6, r6, #2048 ; 0x800 +{ + 80096fa: 4604 mov r4, r0 + if((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAI1) == RCC_PERIPHCLK_SAI1)) + 80096fc: d007 beq.n 800970e + switch(PeriphClkInit->Sai1ClockSelection) + 80096fe: 6ec1 ldr r1, [r0, #108] ; 0x6c + 8009700: 2940 cmp r1, #64 ; 0x40 + 8009702: d022 beq.n 800974a + 8009704: d812 bhi.n 800972c + 8009706: b331 cbz r1, 8009756 + 8009708: 2920 cmp r1, #32 + 800970a: d02b beq.n 8009764 + 800970c: 2601 movs r6, #1 + if((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAI2) == RCC_PERIPHCLK_SAI2)) + 800970e: 6823 ldr r3, [r4, #0] + 8009710: 04db lsls r3, r3, #19 + 8009712: d509 bpl.n 8009728 + switch(PeriphClkInit->Sai2ClockSelection) + 8009714: 6f21 ldr r1, [r4, #112] ; 0x70 + 8009716: f5b1 7f00 cmp.w r1, #512 ; 0x200 + 800971a: d02f beq.n 800977c + 800971c: d826 bhi.n 800976c + 800971e: b399 cbz r1, 8009788 + 8009720: f5b1 7f80 cmp.w r1, #256 ; 0x100 + 8009724: d073 beq.n 800980e + 8009726: 2601 movs r6, #1 + 8009728: 4635 mov r5, r6 + 800972a: e03c b.n 80097a6 + switch(PeriphClkInit->Sai1ClockSelection) + 800972c: 2960 cmp r1, #96 ; 0x60 + 800972e: d001 beq.n 8009734 + 8009730: 2980 cmp r1, #128 ; 0x80 + 8009732: d1eb bne.n 800970c + __HAL_RCC_SAI1_CONFIG(PeriphClkInit->Sai1ClockSelection); + 8009734: 4a3b ldr r2, [pc, #236] ; (8009824 ) + 8009736: 6ee1 ldr r1, [r4, #108] ; 0x6c + 8009738: f8d2 309c ldr.w r3, [r2, #156] ; 0x9c + 800973c: f023 03e0 bic.w r3, r3, #224 ; 0xe0 + 8009740: 430b orrs r3, r1 + 8009742: f8c2 309c str.w r3, [r2, #156] ; 0x9c + 8009746: 2600 movs r6, #0 + 8009748: e7e1 b.n 800970e + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL_SAI3CLK); + 800974a: 4a36 ldr r2, [pc, #216] ; (8009824 ) + 800974c: 68d3 ldr r3, [r2, #12] + 800974e: f443 3380 orr.w r3, r3, #65536 ; 0x10000 + 8009752: 60d3 str r3, [r2, #12] + if(ret == HAL_OK) + 8009754: e7ee b.n 8009734 + ret = RCCEx_PLLSAI1_Config(&(PeriphClkInit->PLLSAI1), DIVIDER_P_UPDATE); + 8009756: 3004 adds r0, #4 + 8009758: f7ff fee4 bl 8009524 + ret = RCCEx_PLLSAI2_Config(&(PeriphClkInit->PLLSAI2), DIVIDER_P_UPDATE); + 800975c: 4606 mov r6, r0 + if(ret == HAL_OK) + 800975e: 2800 cmp r0, #0 + 8009760: d1d5 bne.n 800970e + 8009762: e7e7 b.n 8009734 + ret = RCCEx_PLLSAI2_Config(&(PeriphClkInit->PLLSAI2), DIVIDER_P_UPDATE); + 8009764: 3020 adds r0, #32 + 8009766: f7ff ff5f bl 8009628 + 800976a: e7f7 b.n 800975c + switch(PeriphClkInit->Sai2ClockSelection) + 800976c: f5b1 7f40 cmp.w r1, #768 ; 0x300 + 8009770: d002 beq.n 8009778 + 8009772: f5b1 6f80 cmp.w r1, #1024 ; 0x400 + 8009776: d1d6 bne.n 8009726 + 8009778: 4635 mov r5, r6 + 800977a: e009 b.n 8009790 + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL_SAI3CLK); + 800977c: 4a29 ldr r2, [pc, #164] ; (8009824 ) + 800977e: 68d3 ldr r3, [r2, #12] + 8009780: f443 3380 orr.w r3, r3, #65536 ; 0x10000 + 8009784: 60d3 str r3, [r2, #12] + break; + 8009786: e7f7 b.n 8009778 + ret = RCCEx_PLLSAI1_Config(&(PeriphClkInit->PLLSAI1), DIVIDER_P_UPDATE); + 8009788: 1d20 adds r0, r4, #4 + 800978a: f7ff fecb bl 8009524 + ret = RCCEx_PLLSAI2_Config(&(PeriphClkInit->PLLSAI2), DIVIDER_P_UPDATE); + 800978e: 4605 mov r5, r0 + if(ret == HAL_OK) + 8009790: 2d00 cmp r5, #0 + 8009792: d141 bne.n 8009818 + __HAL_RCC_SAI2_CONFIG(PeriphClkInit->Sai2ClockSelection); + 8009794: 4a23 ldr r2, [pc, #140] ; (8009824 ) + 8009796: 6f21 ldr r1, [r4, #112] ; 0x70 + 8009798: f8d2 309c ldr.w r3, [r2, #156] ; 0x9c + 800979c: f423 63e0 bic.w r3, r3, #1792 ; 0x700 + 80097a0: 430b orrs r3, r1 + 80097a2: f8c2 309c str.w r3, [r2, #156] ; 0x9c + if((PeriphClkInit->PeriphClockSelection & RCC_PERIPHCLK_RTC) == RCC_PERIPHCLK_RTC) + 80097a6: 6823 ldr r3, [r4, #0] + 80097a8: 039f lsls r7, r3, #14 + 80097aa: f140 817d bpl.w 8009aa8 + if(__HAL_RCC_PWR_IS_CLK_DISABLED() != 0U) + 80097ae: 4f1d ldr r7, [pc, #116] ; (8009824 ) + 80097b0: 6dbb ldr r3, [r7, #88] ; 0x58 + 80097b2: 00d8 lsls r0, r3, #3 + 80097b4: d432 bmi.n 800981c + __HAL_RCC_PWR_CLK_ENABLE(); + 80097b6: 6dbb ldr r3, [r7, #88] ; 0x58 + 80097b8: f043 5380 orr.w r3, r3, #268435456 ; 0x10000000 + 80097bc: 65bb str r3, [r7, #88] ; 0x58 + 80097be: 6dbb ldr r3, [r7, #88] ; 0x58 + 80097c0: f003 5380 and.w r3, r3, #268435456 ; 0x10000000 + 80097c4: 9301 str r3, [sp, #4] + 80097c6: 9b01 ldr r3, [sp, #4] + pwrclkchanged = SET; + 80097c8: f04f 0801 mov.w r8, #1 + SET_BIT(PWR->CR1, PWR_CR1_DBP); + 80097cc: f8df 9058 ldr.w r9, [pc, #88] ; 8009828 + 80097d0: f8d9 3000 ldr.w r3, [r9] + 80097d4: f443 7380 orr.w r3, r3, #256 ; 0x100 + 80097d8: f8c9 3000 str.w r3, [r9] + tickstart = HAL_GetTick(); + 80097dc: f7fd fdfe bl 80073dc + 80097e0: 4682 mov sl, r0 + while(READ_BIT(PWR->CR1, PWR_CR1_DBP) == 0U) + 80097e2: f8d9 3000 ldr.w r3, [r9] + 80097e6: 05d9 lsls r1, r3, #23 + 80097e8: d520 bpl.n 800982c + if(ret == HAL_OK) + 80097ea: bb35 cbnz r5, 800983a + tmpregister = READ_BIT(RCC->BDCR, RCC_BDCR_RTCSEL); + 80097ec: f8d7 3090 ldr.w r3, [r7, #144] ; 0x90 + if((tmpregister != RCC_RTCCLKSOURCE_NONE) && (tmpregister != PeriphClkInit->RTCClockSelection)) + 80097f0: f413 7340 ands.w r3, r3, #768 ; 0x300 + 80097f4: f040 812e bne.w 8009a54 + __HAL_RCC_RTC_CONFIG(PeriphClkInit->RTCClockSelection); + 80097f8: f8d7 3090 ldr.w r3, [r7, #144] ; 0x90 + 80097fc: f8d4 2090 ldr.w r2, [r4, #144] ; 0x90 + 8009800: f423 7340 bic.w r3, r3, #768 ; 0x300 + 8009804: 4313 orrs r3, r2 + 8009806: f8c7 3090 str.w r3, [r7, #144] ; 0x90 + 800980a: 4635 mov r5, r6 + 800980c: e015 b.n 800983a + ret = RCCEx_PLLSAI2_Config(&(PeriphClkInit->PLLSAI2), DIVIDER_P_UPDATE); + 800980e: f104 0020 add.w r0, r4, #32 + 8009812: f7ff ff09 bl 8009628 + 8009816: e7ba b.n 800978e + 8009818: 462e mov r6, r5 + 800981a: e7c4 b.n 80097a6 + FlagStatus pwrclkchanged = RESET; + 800981c: f04f 0800 mov.w r8, #0 + 8009820: e7d4 b.n 80097cc + 8009822: bf00 nop + 8009824: 40021000 .word 0x40021000 + 8009828: 40007000 .word 0x40007000 + if((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE) + 800982c: f7fd fdd6 bl 80073dc + 8009830: eba0 000a sub.w r0, r0, sl + 8009834: 2802 cmp r0, #2 + 8009836: d9d4 bls.n 80097e2 + ret = HAL_TIMEOUT; + 8009838: 2503 movs r5, #3 + if(pwrclkchanged == SET) + 800983a: f1b8 0f00 cmp.w r8, #0 + 800983e: d003 beq.n 8009848 + __HAL_RCC_PWR_CLK_DISABLE(); + 8009840: 6dbb ldr r3, [r7, #88] ; 0x58 + 8009842: f023 5380 bic.w r3, r3, #268435456 ; 0x10000000 + 8009846: 65bb str r3, [r7, #88] ; 0x58 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_USART1) == RCC_PERIPHCLK_USART1) + 8009848: 6823 ldr r3, [r4, #0] + 800984a: 07d8 lsls r0, r3, #31 + 800984c: d508 bpl.n 8009860 + __HAL_RCC_USART1_CONFIG(PeriphClkInit->Usart1ClockSelection); + 800984e: 49b2 ldr r1, [pc, #712] ; (8009b18 ) + 8009850: 6be0 ldr r0, [r4, #60] ; 0x3c + 8009852: f8d1 2088 ldr.w r2, [r1, #136] ; 0x88 + 8009856: f022 0203 bic.w r2, r2, #3 + 800985a: 4302 orrs r2, r0 + 800985c: f8c1 2088 str.w r2, [r1, #136] ; 0x88 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_USART2) == RCC_PERIPHCLK_USART2) + 8009860: 0799 lsls r1, r3, #30 + 8009862: d508 bpl.n 8009876 + __HAL_RCC_USART2_CONFIG(PeriphClkInit->Usart2ClockSelection); + 8009864: 49ac ldr r1, [pc, #688] ; (8009b18 ) + 8009866: 6c20 ldr r0, [r4, #64] ; 0x40 + 8009868: f8d1 2088 ldr.w r2, [r1, #136] ; 0x88 + 800986c: f022 020c bic.w r2, r2, #12 + 8009870: 4302 orrs r2, r0 + 8009872: f8c1 2088 str.w r2, [r1, #136] ; 0x88 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_USART3) == RCC_PERIPHCLK_USART3) + 8009876: 075a lsls r2, r3, #29 + 8009878: d508 bpl.n 800988c + __HAL_RCC_USART3_CONFIG(PeriphClkInit->Usart3ClockSelection); + 800987a: 49a7 ldr r1, [pc, #668] ; (8009b18 ) + 800987c: 6c60 ldr r0, [r4, #68] ; 0x44 + 800987e: f8d1 2088 ldr.w r2, [r1, #136] ; 0x88 + 8009882: f022 0230 bic.w r2, r2, #48 ; 0x30 + 8009886: 4302 orrs r2, r0 + 8009888: f8c1 2088 str.w r2, [r1, #136] ; 0x88 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_UART4) == RCC_PERIPHCLK_UART4) + 800988c: 071f lsls r7, r3, #28 + 800988e: d508 bpl.n 80098a2 + __HAL_RCC_UART4_CONFIG(PeriphClkInit->Uart4ClockSelection); + 8009890: 49a1 ldr r1, [pc, #644] ; (8009b18 ) + 8009892: 6ca0 ldr r0, [r4, #72] ; 0x48 + 8009894: f8d1 2088 ldr.w r2, [r1, #136] ; 0x88 + 8009898: f022 02c0 bic.w r2, r2, #192 ; 0xc0 + 800989c: 4302 orrs r2, r0 + 800989e: f8c1 2088 str.w r2, [r1, #136] ; 0x88 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_UART5) == RCC_PERIPHCLK_UART5) + 80098a2: 06de lsls r6, r3, #27 + 80098a4: d508 bpl.n 80098b8 + __HAL_RCC_UART5_CONFIG(PeriphClkInit->Uart5ClockSelection); + 80098a6: 499c ldr r1, [pc, #624] ; (8009b18 ) + 80098a8: 6ce0 ldr r0, [r4, #76] ; 0x4c + 80098aa: f8d1 2088 ldr.w r2, [r1, #136] ; 0x88 + 80098ae: f422 7240 bic.w r2, r2, #768 ; 0x300 + 80098b2: 4302 orrs r2, r0 + 80098b4: f8c1 2088 str.w r2, [r1, #136] ; 0x88 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_LPUART1) == RCC_PERIPHCLK_LPUART1) + 80098b8: 0698 lsls r0, r3, #26 + 80098ba: d508 bpl.n 80098ce + __HAL_RCC_LPUART1_CONFIG(PeriphClkInit->Lpuart1ClockSelection); + 80098bc: 4996 ldr r1, [pc, #600] ; (8009b18 ) + 80098be: 6d20 ldr r0, [r4, #80] ; 0x50 + 80098c0: f8d1 2088 ldr.w r2, [r1, #136] ; 0x88 + 80098c4: f422 6240 bic.w r2, r2, #3072 ; 0xc00 + 80098c8: 4302 orrs r2, r0 + 80098ca: f8c1 2088 str.w r2, [r1, #136] ; 0x88 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_LPTIM1) == (RCC_PERIPHCLK_LPTIM1)) + 80098ce: 0599 lsls r1, r3, #22 + 80098d0: d508 bpl.n 80098e4 + __HAL_RCC_LPTIM1_CONFIG(PeriphClkInit->Lptim1ClockSelection); + 80098d2: 4991 ldr r1, [pc, #580] ; (8009b18 ) + 80098d4: 6e60 ldr r0, [r4, #100] ; 0x64 + 80098d6: f8d1 2088 ldr.w r2, [r1, #136] ; 0x88 + 80098da: f422 2240 bic.w r2, r2, #786432 ; 0xc0000 + 80098de: 4302 orrs r2, r0 + 80098e0: f8c1 2088 str.w r2, [r1, #136] ; 0x88 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_LPTIM2) == (RCC_PERIPHCLK_LPTIM2)) + 80098e4: 055a lsls r2, r3, #21 + 80098e6: d508 bpl.n 80098fa + __HAL_RCC_LPTIM2_CONFIG(PeriphClkInit->Lptim2ClockSelection); + 80098e8: 498b ldr r1, [pc, #556] ; (8009b18 ) + 80098ea: 6ea0 ldr r0, [r4, #104] ; 0x68 + 80098ec: f8d1 2088 ldr.w r2, [r1, #136] ; 0x88 + 80098f0: f422 1240 bic.w r2, r2, #3145728 ; 0x300000 + 80098f4: 4302 orrs r2, r0 + 80098f6: f8c1 2088 str.w r2, [r1, #136] ; 0x88 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2C1) == RCC_PERIPHCLK_I2C1) + 80098fa: 065f lsls r7, r3, #25 + 80098fc: d508 bpl.n 8009910 + __HAL_RCC_I2C1_CONFIG(PeriphClkInit->I2c1ClockSelection); + 80098fe: 4986 ldr r1, [pc, #536] ; (8009b18 ) + 8009900: 6d60 ldr r0, [r4, #84] ; 0x54 + 8009902: f8d1 2088 ldr.w r2, [r1, #136] ; 0x88 + 8009906: f422 5240 bic.w r2, r2, #12288 ; 0x3000 + 800990a: 4302 orrs r2, r0 + 800990c: f8c1 2088 str.w r2, [r1, #136] ; 0x88 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2C2) == RCC_PERIPHCLK_I2C2) + 8009910: 061e lsls r6, r3, #24 + 8009912: d508 bpl.n 8009926 + __HAL_RCC_I2C2_CONFIG(PeriphClkInit->I2c2ClockSelection); + 8009914: 4980 ldr r1, [pc, #512] ; (8009b18 ) + 8009916: 6da0 ldr r0, [r4, #88] ; 0x58 + 8009918: f8d1 2088 ldr.w r2, [r1, #136] ; 0x88 + 800991c: f422 4240 bic.w r2, r2, #49152 ; 0xc000 + 8009920: 4302 orrs r2, r0 + 8009922: f8c1 2088 str.w r2, [r1, #136] ; 0x88 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2C3) == RCC_PERIPHCLK_I2C3) + 8009926: 05d8 lsls r0, r3, #23 + 8009928: d508 bpl.n 800993c + __HAL_RCC_I2C3_CONFIG(PeriphClkInit->I2c3ClockSelection); + 800992a: 497b ldr r1, [pc, #492] ; (8009b18 ) + 800992c: 6de0 ldr r0, [r4, #92] ; 0x5c + 800992e: f8d1 2088 ldr.w r2, [r1, #136] ; 0x88 + 8009932: f422 3240 bic.w r2, r2, #196608 ; 0x30000 + 8009936: 4302 orrs r2, r0 + 8009938: f8c1 2088 str.w r2, [r1, #136] ; 0x88 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2C4) == RCC_PERIPHCLK_I2C4) + 800993c: 02d9 lsls r1, r3, #11 + 800993e: d508 bpl.n 8009952 + __HAL_RCC_I2C4_CONFIG(PeriphClkInit->I2c4ClockSelection); + 8009940: 4975 ldr r1, [pc, #468] ; (8009b18 ) + 8009942: 6e20 ldr r0, [r4, #96] ; 0x60 + 8009944: f8d1 209c ldr.w r2, [r1, #156] ; 0x9c + 8009948: f022 0203 bic.w r2, r2, #3 + 800994c: 4302 orrs r2, r0 + 800994e: f8c1 209c str.w r2, [r1, #156] ; 0x9c + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_USB) == (RCC_PERIPHCLK_USB)) + 8009952: 049a lsls r2, r3, #18 + 8009954: d510 bpl.n 8009978 + __HAL_RCC_USB_CONFIG(PeriphClkInit->UsbClockSelection); + 8009956: 4a70 ldr r2, [pc, #448] ; (8009b18 ) + 8009958: 6f61 ldr r1, [r4, #116] ; 0x74 + 800995a: f8d2 3088 ldr.w r3, [r2, #136] ; 0x88 + 800995e: f023 6340 bic.w r3, r3, #201326592 ; 0xc000000 + 8009962: 430b orrs r3, r1 + if(PeriphClkInit->UsbClockSelection == RCC_USBCLKSOURCE_PLL) + 8009964: f1b1 6f00 cmp.w r1, #134217728 ; 0x8000000 + __HAL_RCC_USB_CONFIG(PeriphClkInit->UsbClockSelection); + 8009968: f8c2 3088 str.w r3, [r2, #136] ; 0x88 + if(PeriphClkInit->UsbClockSelection == RCC_USBCLKSOURCE_PLL) + 800996c: f040 809e bne.w 8009aac + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL_48M1CLK); + 8009970: 68d3 ldr r3, [r2, #12] + 8009972: f443 1380 orr.w r3, r3, #1048576 ; 0x100000 + 8009976: 60d3 str r3, [r2, #12] + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SDMMC1) == (RCC_PERIPHCLK_SDMMC1)) + 8009978: 6823 ldr r3, [r4, #0] + 800997a: 031b lsls r3, r3, #12 + 800997c: d50f bpl.n 800999e + __HAL_RCC_SDMMC1_CONFIG(PeriphClkInit->Sdmmc1ClockSelection); + 800997e: 6fa1 ldr r1, [r4, #120] ; 0x78 + 8009980: 4b65 ldr r3, [pc, #404] ; (8009b18 ) + 8009982: f5b1 4f80 cmp.w r1, #16384 ; 0x4000 + 8009986: f8d3 209c ldr.w r2, [r3, #156] ; 0x9c + 800998a: f040 809b bne.w 8009ac4 + 800998e: f442 4280 orr.w r2, r2, #16384 ; 0x4000 + 8009992: f8c3 209c str.w r2, [r3, #156] ; 0x9c + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL_SAI3CLK); + 8009996: 68da ldr r2, [r3, #12] + 8009998: f442 3280 orr.w r2, r2, #65536 ; 0x10000 + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL_48M1CLK); + 800999c: 60da str r2, [r3, #12] + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_RNG) == (RCC_PERIPHCLK_RNG)) + 800999e: 6823 ldr r3, [r4, #0] + 80099a0: 035f lsls r7, r3, #13 + 80099a2: d510 bpl.n 80099c6 + __HAL_RCC_RNG_CONFIG(PeriphClkInit->RngClockSelection); + 80099a4: 4a5c ldr r2, [pc, #368] ; (8009b18 ) + 80099a6: 6fe1 ldr r1, [r4, #124] ; 0x7c + 80099a8: f8d2 3088 ldr.w r3, [r2, #136] ; 0x88 + 80099ac: f023 6340 bic.w r3, r3, #201326592 ; 0xc000000 + 80099b0: 430b orrs r3, r1 + if(PeriphClkInit->RngClockSelection == RCC_RNGCLKSOURCE_PLL) + 80099b2: f1b1 6f00 cmp.w r1, #134217728 ; 0x8000000 + __HAL_RCC_RNG_CONFIG(PeriphClkInit->RngClockSelection); + 80099b6: f8c2 3088 str.w r3, [r2, #136] ; 0x88 + if(PeriphClkInit->RngClockSelection == RCC_RNGCLKSOURCE_PLL) + 80099ba: f040 80a1 bne.w 8009b00 + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL_48M1CLK); + 80099be: 68d3 ldr r3, [r2, #12] + 80099c0: f443 1380 orr.w r3, r3, #1048576 ; 0x100000 + 80099c4: 60d3 str r3, [r2, #12] + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_ADC) == RCC_PERIPHCLK_ADC) + 80099c6: 6823 ldr r3, [r4, #0] + 80099c8: 045e lsls r6, r3, #17 + 80099ca: d513 bpl.n 80099f4 + __HAL_RCC_ADC_CONFIG(PeriphClkInit->AdcClockSelection); + 80099cc: 4952 ldr r1, [pc, #328] ; (8009b18 ) + 80099ce: f8d4 2080 ldr.w r2, [r4, #128] ; 0x80 + 80099d2: f8d1 3088 ldr.w r3, [r1, #136] ; 0x88 + 80099d6: f023 5340 bic.w r3, r3, #805306368 ; 0x30000000 + 80099da: 4313 orrs r3, r2 + if(PeriphClkInit->AdcClockSelection == RCC_ADCCLKSOURCE_PLLSAI1) + 80099dc: f1b2 5f80 cmp.w r2, #268435456 ; 0x10000000 + __HAL_RCC_ADC_CONFIG(PeriphClkInit->AdcClockSelection); + 80099e0: f8c1 3088 str.w r3, [r1, #136] ; 0x88 + if(PeriphClkInit->AdcClockSelection == RCC_ADCCLKSOURCE_PLLSAI1) + 80099e4: d106 bne.n 80099f4 + ret = RCCEx_PLLSAI1_Config(&(PeriphClkInit->PLLSAI1), DIVIDER_R_UPDATE); + 80099e6: 2102 movs r1, #2 + 80099e8: 1d20 adds r0, r4, #4 + 80099ea: f7ff fd9b bl 8009524 + if(ret != HAL_OK) + 80099ee: 2800 cmp r0, #0 + 80099f0: bf18 it ne + 80099f2: 4605 movne r5, r0 + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_DFSDM1) == RCC_PERIPHCLK_DFSDM1) + 80099f4: 6822 ldr r2, [r4, #0] + 80099f6: 03d0 lsls r0, r2, #15 + 80099f8: d509 bpl.n 8009a0e + __HAL_RCC_DFSDM1_CONFIG(PeriphClkInit->Dfsdm1ClockSelection); + 80099fa: 4947 ldr r1, [pc, #284] ; (8009b18 ) + 80099fc: f8d4 0084 ldr.w r0, [r4, #132] ; 0x84 + 8009a00: f8d1 309c ldr.w r3, [r1, #156] ; 0x9c + 8009a04: f023 0304 bic.w r3, r3, #4 + 8009a08: 4303 orrs r3, r0 + 8009a0a: f8c1 309c str.w r3, [r1, #156] ; 0x9c + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_DFSDM1AUDIO) == RCC_PERIPHCLK_DFSDM1AUDIO) + 8009a0e: 0291 lsls r1, r2, #10 + 8009a10: d509 bpl.n 8009a26 + __HAL_RCC_DFSDM1AUDIO_CONFIG(PeriphClkInit->Dfsdm1AudioClockSelection); + 8009a12: 4941 ldr r1, [pc, #260] ; (8009b18 ) + 8009a14: f8d4 0088 ldr.w r0, [r4, #136] ; 0x88 + 8009a18: f8d1 309c ldr.w r3, [r1, #156] ; 0x9c + 8009a1c: f023 0318 bic.w r3, r3, #24 + 8009a20: 4303 orrs r3, r0 + 8009a22: f8c1 309c str.w r3, [r1, #156] ; 0x9c + if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_OSPI) == RCC_PERIPHCLK_OSPI) + 8009a26: 01d3 lsls r3, r2, #7 + 8009a28: d510 bpl.n 8009a4c + __HAL_RCC_OSPI_CONFIG(PeriphClkInit->OspiClockSelection); + 8009a2a: 4a3b ldr r2, [pc, #236] ; (8009b18 ) + 8009a2c: f8d4 108c ldr.w r1, [r4, #140] ; 0x8c + 8009a30: f8d2 309c ldr.w r3, [r2, #156] ; 0x9c + 8009a34: f423 1340 bic.w r3, r3, #3145728 ; 0x300000 + 8009a38: 430b orrs r3, r1 + 8009a3a: f8c2 309c str.w r3, [r2, #156] ; 0x9c + if(PeriphClkInit->OspiClockSelection == RCC_OSPICLKSOURCE_PLL) + 8009a3e: f5b1 1f00 cmp.w r1, #2097152 ; 0x200000 + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL_48M1CLK); + 8009a42: bf02 ittt eq + 8009a44: 68d3 ldreq r3, [r2, #12] + 8009a46: f443 1380 orreq.w r3, r3, #1048576 ; 0x100000 + 8009a4a: 60d3 streq r3, [r2, #12] +} + 8009a4c: 4628 mov r0, r5 + 8009a4e: b002 add sp, #8 + 8009a50: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + if((tmpregister != RCC_RTCCLKSOURCE_NONE) && (tmpregister != PeriphClkInit->RTCClockSelection)) + 8009a54: f8d4 2090 ldr.w r2, [r4, #144] ; 0x90 + 8009a58: 429a cmp r2, r3 + 8009a5a: f43f aecd beq.w 80097f8 + tmpregister = READ_BIT(RCC->BDCR, ~(RCC_BDCR_RTCSEL)); + 8009a5e: f8d7 2090 ldr.w r2, [r7, #144] ; 0x90 + __HAL_RCC_BACKUPRESET_FORCE(); + 8009a62: f8d7 3090 ldr.w r3, [r7, #144] ; 0x90 + 8009a66: f443 3380 orr.w r3, r3, #65536 ; 0x10000 + 8009a6a: f8c7 3090 str.w r3, [r7, #144] ; 0x90 + __HAL_RCC_BACKUPRESET_RELEASE(); + 8009a6e: f8d7 3090 ldr.w r3, [r7, #144] ; 0x90 + tmpregister = READ_BIT(RCC->BDCR, ~(RCC_BDCR_RTCSEL)); + 8009a72: f422 7140 bic.w r1, r2, #768 ; 0x300 + __HAL_RCC_BACKUPRESET_RELEASE(); + 8009a76: f423 3380 bic.w r3, r3, #65536 ; 0x10000 + if (HAL_IS_BIT_SET(tmpregister, RCC_BDCR_LSEON)) + 8009a7a: 07d2 lsls r2, r2, #31 + __HAL_RCC_BACKUPRESET_RELEASE(); + 8009a7c: f8c7 3090 str.w r3, [r7, #144] ; 0x90 + RCC->BDCR = tmpregister; + 8009a80: f8c7 1090 str.w r1, [r7, #144] ; 0x90 + if (HAL_IS_BIT_SET(tmpregister, RCC_BDCR_LSEON)) + 8009a84: f57f aeb8 bpl.w 80097f8 + tickstart = HAL_GetTick(); + 8009a88: f7fd fca8 bl 80073dc + if((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) + 8009a8c: f241 3988 movw r9, #5000 ; 0x1388 + tickstart = HAL_GetTick(); + 8009a90: 4605 mov r5, r0 + while(READ_BIT(RCC->BDCR, RCC_BDCR_LSERDY) == 0U) + 8009a92: f8d7 3090 ldr.w r3, [r7, #144] ; 0x90 + 8009a96: 079b lsls r3, r3, #30 + 8009a98: f53f aeae bmi.w 80097f8 + if((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) + 8009a9c: f7fd fc9e bl 80073dc + 8009aa0: 1b40 subs r0, r0, r5 + 8009aa2: 4548 cmp r0, r9 + 8009aa4: d9f5 bls.n 8009a92 + 8009aa6: e6c7 b.n 8009838 + 8009aa8: 4635 mov r5, r6 + 8009aaa: e6cd b.n 8009848 + if(PeriphClkInit->UsbClockSelection == RCC_USBCLKSOURCE_PLLSAI1) + 8009aac: f1b1 6f80 cmp.w r1, #67108864 ; 0x4000000 + 8009ab0: f47f af62 bne.w 8009978 + ret = RCCEx_PLLSAI1_Config(&(PeriphClkInit->PLLSAI1), DIVIDER_Q_UPDATE); + 8009ab4: 2101 movs r1, #1 + 8009ab6: 1d20 adds r0, r4, #4 + 8009ab8: f7ff fd34 bl 8009524 + if(ret != HAL_OK) + 8009abc: 2800 cmp r0, #0 + 8009abe: bf18 it ne + 8009ac0: 4605 movne r5, r0 + 8009ac2: e759 b.n 8009978 + __HAL_RCC_SDMMC1_CONFIG(PeriphClkInit->Sdmmc1ClockSelection); + 8009ac4: f422 4280 bic.w r2, r2, #16384 ; 0x4000 + 8009ac8: f8c3 209c str.w r2, [r3, #156] ; 0x9c + 8009acc: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 8009ad0: f022 6240 bic.w r2, r2, #201326592 ; 0xc000000 + 8009ad4: 430a orrs r2, r1 + if(PeriphClkInit->Sdmmc1ClockSelection == RCC_SDMMC1CLKSOURCE_PLL) /* PLL "Q" ? */ + 8009ad6: f1b1 6f00 cmp.w r1, #134217728 ; 0x8000000 + __HAL_RCC_SDMMC1_CONFIG(PeriphClkInit->Sdmmc1ClockSelection); + 8009ada: f8c3 2088 str.w r2, [r3, #136] ; 0x88 + if(PeriphClkInit->Sdmmc1ClockSelection == RCC_SDMMC1CLKSOURCE_PLL) /* PLL "Q" ? */ + 8009ade: d103 bne.n 8009ae8 + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL_48M1CLK); + 8009ae0: 68da ldr r2, [r3, #12] + 8009ae2: f442 1280 orr.w r2, r2, #1048576 ; 0x100000 + 8009ae6: e759 b.n 800999c + else if(PeriphClkInit->Sdmmc1ClockSelection == RCC_SDMMC1CLKSOURCE_PLLSAI1) + 8009ae8: f1b1 6f80 cmp.w r1, #67108864 ; 0x4000000 + 8009aec: f47f af57 bne.w 800999e + ret = RCCEx_PLLSAI1_Config(&(PeriphClkInit->PLLSAI1), DIVIDER_Q_UPDATE); + 8009af0: 2101 movs r1, #1 + 8009af2: 1d20 adds r0, r4, #4 + 8009af4: f7ff fd16 bl 8009524 + if(ret != HAL_OK) + 8009af8: 2800 cmp r0, #0 + 8009afa: bf18 it ne + 8009afc: 4605 movne r5, r0 + 8009afe: e74e b.n 800999e + else if(PeriphClkInit->RngClockSelection == RCC_RNGCLKSOURCE_PLLSAI1) + 8009b00: f1b1 6f80 cmp.w r1, #67108864 ; 0x4000000 + 8009b04: f47f af5f bne.w 80099c6 + ret = RCCEx_PLLSAI1_Config(&(PeriphClkInit->PLLSAI1), DIVIDER_Q_UPDATE); + 8009b08: 2101 movs r1, #1 + 8009b0a: 1d20 adds r0, r4, #4 + 8009b0c: f7ff fd0a bl 8009524 + if(ret != HAL_OK) + 8009b10: 2800 cmp r0, #0 + 8009b12: bf18 it ne + 8009b14: 4605 movne r5, r0 + 8009b16: e756 b.n 80099c6 + 8009b18: 40021000 .word 0x40021000 + +08009b1c : + PeriphClkInit->PeriphClockSelection = RCC_PERIPHCLK_USART1 | RCC_PERIPHCLK_USART2 | RCC_PERIPHCLK_USART3 | RCC_PERIPHCLK_UART4 | RCC_PERIPHCLK_UART5 | \ + 8009b1c: 4b5b ldr r3, [pc, #364] ; (8009c8c ) + 8009b1e: 6003 str r3, [r0, #0] + PeriphClkInit->PLLSAI1.PLLSAI1Source = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLSRC) >> RCC_PLLCFGR_PLLSRC_Pos; + 8009b20: 4b5b ldr r3, [pc, #364] ; (8009c90 ) + 8009b22: 68d9 ldr r1, [r3, #12] + 8009b24: f001 0103 and.w r1, r1, #3 + 8009b28: 6041 str r1, [r0, #4] + PeriphClkInit->PLLSAI1.PLLSAI1M = (READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U; + 8009b2a: 691a ldr r2, [r3, #16] + 8009b2c: f3c2 1203 ubfx r2, r2, #4, #4 + 8009b30: 3201 adds r2, #1 + 8009b32: 6082 str r2, [r0, #8] + PeriphClkInit->PLLSAI1.PLLSAI1N = READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1N) >> RCC_PLLSAI1CFGR_PLLSAI1N_Pos; + 8009b34: 691a ldr r2, [r3, #16] + 8009b36: f3c2 2206 ubfx r2, r2, #8, #7 + 8009b3a: 60c2 str r2, [r0, #12] + PeriphClkInit->PLLSAI1.PLLSAI1P = ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1P) >> RCC_PLLSAI1CFGR_PLLSAI1P_Pos) << 4U) + 7U; + 8009b3c: 691a ldr r2, [r3, #16] + 8009b3e: 0b52 lsrs r2, r2, #13 + 8009b40: f002 0210 and.w r2, r2, #16 + 8009b44: 3207 adds r2, #7 + 8009b46: 6102 str r2, [r0, #16] + PeriphClkInit->PLLSAI1.PLLSAI1Q = ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1Q) >> RCC_PLLSAI1CFGR_PLLSAI1Q_Pos) + 1U) * 2U; + 8009b48: 691a ldr r2, [r3, #16] + 8009b4a: f3c2 5241 ubfx r2, r2, #21, #2 + 8009b4e: 3201 adds r2, #1 + 8009b50: 0052 lsls r2, r2, #1 + 8009b52: 6142 str r2, [r0, #20] + PeriphClkInit->PLLSAI1.PLLSAI1R = ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1R) >> RCC_PLLSAI1CFGR_PLLSAI1R_Pos) + 1U) * 2U; + 8009b54: 691a ldr r2, [r3, #16] + PeriphClkInit->PLLSAI2.PLLSAI2Source = PeriphClkInit->PLLSAI1.PLLSAI1Source; + 8009b56: 6201 str r1, [r0, #32] + PeriphClkInit->PLLSAI1.PLLSAI1R = ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1R) >> RCC_PLLSAI1CFGR_PLLSAI1R_Pos) + 1U) * 2U; + 8009b58: f3c2 6241 ubfx r2, r2, #25, #2 + 8009b5c: 3201 adds r2, #1 + 8009b5e: 0052 lsls r2, r2, #1 + 8009b60: 6182 str r2, [r0, #24] + PeriphClkInit->PLLSAI2.PLLSAI2M = (READ_BIT(RCC->PLLSAI2CFGR, RCC_PLLSAI2CFGR_PLLSAI2M) >> RCC_PLLSAI2CFGR_PLLSAI2M_Pos) + 1U; + 8009b62: 695a ldr r2, [r3, #20] + 8009b64: f3c2 1203 ubfx r2, r2, #4, #4 + 8009b68: 3201 adds r2, #1 + 8009b6a: 6242 str r2, [r0, #36] ; 0x24 + PeriphClkInit->PLLSAI2.PLLSAI2N = READ_BIT(RCC->PLLSAI2CFGR, RCC_PLLSAI2CFGR_PLLSAI2N) >> RCC_PLLSAI2CFGR_PLLSAI2N_Pos; + 8009b6c: 695a ldr r2, [r3, #20] + 8009b6e: f3c2 2206 ubfx r2, r2, #8, #7 + 8009b72: 6282 str r2, [r0, #40] ; 0x28 + PeriphClkInit->PLLSAI2.PLLSAI2P = ((READ_BIT(RCC->PLLSAI2CFGR, RCC_PLLSAI2CFGR_PLLSAI2P) >> RCC_PLLSAI2CFGR_PLLSAI2P_Pos) << 4U) + 7U; + 8009b74: 695a ldr r2, [r3, #20] + 8009b76: 0b52 lsrs r2, r2, #13 + 8009b78: f002 0210 and.w r2, r2, #16 + 8009b7c: 3207 adds r2, #7 + 8009b7e: 62c2 str r2, [r0, #44] ; 0x2c + PeriphClkInit->PLLSAI2.PLLSAI2Q = ((READ_BIT(RCC->PLLSAI2CFGR, RCC_PLLSAI2CFGR_PLLSAI2Q) >> RCC_PLLSAI2CFGR_PLLSAI2Q_Pos) + 1U) * 2U; + 8009b80: 695a ldr r2, [r3, #20] + 8009b82: f3c2 5241 ubfx r2, r2, #21, #2 + 8009b86: 3201 adds r2, #1 + 8009b88: 0052 lsls r2, r2, #1 + 8009b8a: 6302 str r2, [r0, #48] ; 0x30 + PeriphClkInit->PLLSAI2.PLLSAI2R = ((READ_BIT(RCC->PLLSAI2CFGR, RCC_PLLSAI2CFGR_PLLSAI2R)>> RCC_PLLSAI2CFGR_PLLSAI2R_Pos) + 1U) * 2U; + 8009b8c: 695a ldr r2, [r3, #20] + 8009b8e: f3c2 6241 ubfx r2, r2, #25, #2 + 8009b92: 3201 adds r2, #1 + 8009b94: 0052 lsls r2, r2, #1 + 8009b96: 6342 str r2, [r0, #52] ; 0x34 + PeriphClkInit->Usart1ClockSelection = __HAL_RCC_GET_USART1_SOURCE(); + 8009b98: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 8009b9c: f002 0203 and.w r2, r2, #3 + 8009ba0: 63c2 str r2, [r0, #60] ; 0x3c + PeriphClkInit->Usart2ClockSelection = __HAL_RCC_GET_USART2_SOURCE(); + 8009ba2: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 8009ba6: f002 020c and.w r2, r2, #12 + 8009baa: 6402 str r2, [r0, #64] ; 0x40 + PeriphClkInit->Usart3ClockSelection = __HAL_RCC_GET_USART3_SOURCE(); + 8009bac: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 8009bb0: f002 0230 and.w r2, r2, #48 ; 0x30 + 8009bb4: 6442 str r2, [r0, #68] ; 0x44 + PeriphClkInit->Uart4ClockSelection = __HAL_RCC_GET_UART4_SOURCE(); + 8009bb6: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 8009bba: f002 02c0 and.w r2, r2, #192 ; 0xc0 + 8009bbe: 6482 str r2, [r0, #72] ; 0x48 + PeriphClkInit->Uart5ClockSelection = __HAL_RCC_GET_UART5_SOURCE(); + 8009bc0: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 8009bc4: f402 7240 and.w r2, r2, #768 ; 0x300 + 8009bc8: 64c2 str r2, [r0, #76] ; 0x4c + PeriphClkInit->Lpuart1ClockSelection = __HAL_RCC_GET_LPUART1_SOURCE(); + 8009bca: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 8009bce: f402 6240 and.w r2, r2, #3072 ; 0xc00 + 8009bd2: 6502 str r2, [r0, #80] ; 0x50 + PeriphClkInit->I2c1ClockSelection = __HAL_RCC_GET_I2C1_SOURCE(); + 8009bd4: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 8009bd8: f402 5240 and.w r2, r2, #12288 ; 0x3000 + 8009bdc: 6542 str r2, [r0, #84] ; 0x54 + PeriphClkInit->I2c2ClockSelection = __HAL_RCC_GET_I2C2_SOURCE(); + 8009bde: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 8009be2: f402 4240 and.w r2, r2, #49152 ; 0xc000 + 8009be6: 6582 str r2, [r0, #88] ; 0x58 + PeriphClkInit->I2c3ClockSelection = __HAL_RCC_GET_I2C3_SOURCE(); + 8009be8: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 8009bec: f402 3240 and.w r2, r2, #196608 ; 0x30000 + 8009bf0: 65c2 str r2, [r0, #92] ; 0x5c + PeriphClkInit->I2c4ClockSelection = __HAL_RCC_GET_I2C4_SOURCE(); + 8009bf2: f8d3 209c ldr.w r2, [r3, #156] ; 0x9c + 8009bf6: f002 0203 and.w r2, r2, #3 + 8009bfa: 6602 str r2, [r0, #96] ; 0x60 + PeriphClkInit->Lptim1ClockSelection = __HAL_RCC_GET_LPTIM1_SOURCE(); + 8009bfc: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 8009c00: f402 2240 and.w r2, r2, #786432 ; 0xc0000 + 8009c04: 6642 str r2, [r0, #100] ; 0x64 + PeriphClkInit->Lptim2ClockSelection = __HAL_RCC_GET_LPTIM2_SOURCE(); + 8009c06: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 8009c0a: f402 1240 and.w r2, r2, #3145728 ; 0x300000 + 8009c0e: 6682 str r2, [r0, #104] ; 0x68 + PeriphClkInit->Sai1ClockSelection = __HAL_RCC_GET_SAI1_SOURCE(); + 8009c10: f8d3 209c ldr.w r2, [r3, #156] ; 0x9c + 8009c14: f002 02e0 and.w r2, r2, #224 ; 0xe0 + 8009c18: 66c2 str r2, [r0, #108] ; 0x6c + PeriphClkInit->Sai2ClockSelection = __HAL_RCC_GET_SAI2_SOURCE(); + 8009c1a: f8d3 209c ldr.w r2, [r3, #156] ; 0x9c + 8009c1e: f402 62e0 and.w r2, r2, #1792 ; 0x700 + 8009c22: 6702 str r2, [r0, #112] ; 0x70 + PeriphClkInit->RTCClockSelection = __HAL_RCC_GET_RTC_SOURCE(); + 8009c24: f8d3 2090 ldr.w r2, [r3, #144] ; 0x90 + 8009c28: f402 7240 and.w r2, r2, #768 ; 0x300 + 8009c2c: f8c0 2090 str.w r2, [r0, #144] ; 0x90 + PeriphClkInit->UsbClockSelection = __HAL_RCC_GET_USB_SOURCE(); + 8009c30: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 8009c34: f002 6240 and.w r2, r2, #201326592 ; 0xc000000 + 8009c38: 6742 str r2, [r0, #116] ; 0x74 + PeriphClkInit->Sdmmc1ClockSelection = __HAL_RCC_GET_SDMMC1_SOURCE(); + 8009c3a: f8d3 209c ldr.w r2, [r3, #156] ; 0x9c + 8009c3e: 0452 lsls r2, r2, #17 + 8009c40: bf56 itet pl + 8009c42: f8d3 2088 ldrpl.w r2, [r3, #136] ; 0x88 + 8009c46: f44f 4280 movmi.w r2, #16384 ; 0x4000 + 8009c4a: f002 6240 andpl.w r2, r2, #201326592 ; 0xc000000 + 8009c4e: 6782 str r2, [r0, #120] ; 0x78 + PeriphClkInit->RngClockSelection = __HAL_RCC_GET_RNG_SOURCE(); + 8009c50: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 8009c54: f002 6240 and.w r2, r2, #201326592 ; 0xc000000 + 8009c58: 67c2 str r2, [r0, #124] ; 0x7c + PeriphClkInit->AdcClockSelection = __HAL_RCC_GET_ADC_SOURCE(); + 8009c5a: f8d3 2088 ldr.w r2, [r3, #136] ; 0x88 + 8009c5e: f002 5240 and.w r2, r2, #805306368 ; 0x30000000 + 8009c62: f8c0 2080 str.w r2, [r0, #128] ; 0x80 + PeriphClkInit->Dfsdm1ClockSelection = __HAL_RCC_GET_DFSDM1_SOURCE(); + 8009c66: f8d3 209c ldr.w r2, [r3, #156] ; 0x9c + 8009c6a: f002 0204 and.w r2, r2, #4 + 8009c6e: f8c0 2084 str.w r2, [r0, #132] ; 0x84 + PeriphClkInit->Dfsdm1AudioClockSelection = __HAL_RCC_GET_DFSDM1AUDIO_SOURCE(); + 8009c72: f8d3 209c ldr.w r2, [r3, #156] ; 0x9c + 8009c76: f002 0218 and.w r2, r2, #24 + 8009c7a: f8c0 2088 str.w r2, [r0, #136] ; 0x88 + PeriphClkInit->OspiClockSelection = __HAL_RCC_GET_OSPI_SOURCE(); + 8009c7e: f8d3 309c ldr.w r3, [r3, #156] ; 0x9c + 8009c82: f403 1340 and.w r3, r3, #3145728 ; 0x300000 + 8009c86: f8c0 308c str.w r3, [r0, #140] ; 0x8c +} + 8009c8a: 4770 bx lr + 8009c8c: 013f7fff .word 0x013f7fff + 8009c90: 40021000 .word 0x40021000 + +08009c94 : + if(PeriphClk == RCC_PERIPHCLK_RTC) + 8009c94: f5b0 3f00 cmp.w r0, #131072 ; 0x20000 +{ + 8009c98: b4f0 push {r4, r5, r6, r7} + 8009c9a: 4d9a ldr r5, [pc, #616] ; (8009f04 ) + if(PeriphClk == RCC_PERIPHCLK_RTC) + 8009c9c: d11c bne.n 8009cd8 + srcclk = __HAL_RCC_GET_RTC_SOURCE(); + 8009c9e: f8d5 3090 ldr.w r3, [r5, #144] ; 0x90 + 8009ca2: f403 7340 and.w r3, r3, #768 ; 0x300 + switch(srcclk) + 8009ca6: f5b3 7f00 cmp.w r3, #512 ; 0x200 + 8009caa: f000 8085 beq.w 8009db8 + 8009cae: f5b3 7f40 cmp.w r3, #768 ; 0x300 + 8009cb2: d00a beq.n 8009cca + 8009cb4: f5b3 7f80 cmp.w r3, #256 ; 0x100 + 8009cb8: d154 bne.n 8009d64 + if(HAL_IS_BIT_SET(RCC->BDCR, RCC_BDCR_LSERDY)) + 8009cba: f8d5 0090 ldr.w r0, [r5, #144] ; 0x90 + frequency = LSE_VALUE; + 8009cbe: f010 0002 ands.w r0, r0, #2 + 8009cc2: bf18 it ne + 8009cc4: f44f 4000 movne.w r0, #32768 ; 0x8000 + 8009cc8: e11a b.n 8009f00 + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSERDY)) + 8009cca: 6828 ldr r0, [r5, #0] + frequency = HSE_VALUE / 32U; + 8009ccc: 4b8e ldr r3, [pc, #568] ; (8009f08 ) + 8009cce: f410 3000 ands.w r0, r0, #131072 ; 0x20000 + frequency = HSI_VALUE; + 8009cd2: bf18 it ne + 8009cd4: 4618 movne r0, r3 + 8009cd6: e113 b.n 8009f00 + pll_oscsource = __HAL_RCC_GET_PLL_OSCSOURCE(); + 8009cd8: 68eb ldr r3, [r5, #12] + 8009cda: f003 0303 and.w r3, r3, #3 + switch(pll_oscsource) + 8009cde: 2b02 cmp r3, #2 + 8009ce0: d02f beq.n 8009d42 + 8009ce2: 2b03 cmp r3, #3 + 8009ce4: d034 beq.n 8009d50 + 8009ce6: 2b01 cmp r3, #1 + 8009ce8: d137 bne.n 8009d5a + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_MSIRDY)) + 8009cea: 6829 ldr r1, [r5, #0] + 8009cec: f011 0102 ands.w r1, r1, #2 + 8009cf0: d00c beq.n 8009d0c + pllvco = MSIRangeTable[(__HAL_RCC_GET_MSI_RANGE() >> 4U)]; + 8009cf2: 682b ldr r3, [r5, #0] + 8009cf4: 4a85 ldr r2, [pc, #532] ; (8009f0c ) + 8009cf6: 0719 lsls r1, r3, #28 + 8009cf8: bf4b itete mi + 8009cfa: 682b ldrmi r3, [r5, #0] + 8009cfc: f8d5 3094 ldrpl.w r3, [r5, #148] ; 0x94 + 8009d00: f3c3 1303 ubfxmi r3, r3, #4, #4 + 8009d04: f3c3 2303 ubfxpl r3, r3, #8, #4 + 8009d08: f852 1023 ldr.w r1, [r2, r3, lsl #2] + switch(PeriphClk) + 8009d0c: f5b0 6f80 cmp.w r0, #1024 ; 0x400 + 8009d10: f000 8226 beq.w 800a160 + 8009d14: d858 bhi.n 8009dc8 + 8009d16: 2820 cmp r0, #32 + 8009d18: f000 81be beq.w 800a098 + 8009d1c: d824 bhi.n 8009d68 + 8009d1e: 2808 cmp r0, #8 + 8009d20: d81d bhi.n 8009d5e + 8009d22: 2800 cmp r0, #0 + 8009d24: f000 80ec beq.w 8009f00 + 8009d28: 3801 subs r0, #1 + 8009d2a: 2807 cmp r0, #7 + 8009d2c: d81a bhi.n 8009d64 + 8009d2e: e8df f010 tbh [pc, r0, lsl #1] + 8009d32: 0164 .short 0x0164 + 8009d34: 00190177 .word 0x00190177 + 8009d38: 00190189 .word 0x00190189 + 8009d3c: 00190019 .word 0x00190019 + 8009d40: 0196 .short 0x0196 + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSIRDY)) + 8009d42: 6829 ldr r1, [r5, #0] + pllvco = HSI_VALUE; + 8009d44: 4b72 ldr r3, [pc, #456] ; (8009f10 ) + 8009d46: f411 6180 ands.w r1, r1, #1024 ; 0x400 + pllvco = HSE_VALUE; + 8009d4a: bf18 it ne + 8009d4c: 4619 movne r1, r3 + 8009d4e: e7dd b.n 8009d0c + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSERDY)) + 8009d50: 6829 ldr r1, [r5, #0] + pllvco = HSE_VALUE; + 8009d52: 4b70 ldr r3, [pc, #448] ; (8009f14 ) + 8009d54: f411 3100 ands.w r1, r1, #131072 ; 0x20000 + 8009d58: e7f7 b.n 8009d4a + switch(pll_oscsource) + 8009d5a: 2100 movs r1, #0 + 8009d5c: e7d6 b.n 8009d0c + switch(PeriphClk) + 8009d5e: 2810 cmp r0, #16 + 8009d60: f000 818a beq.w 800a078 + 8009d64: 2000 movs r0, #0 + 8009d66: e0cb b.n 8009f00 + 8009d68: f5b0 7f80 cmp.w r0, #256 ; 0x100 + 8009d6c: f000 81ea beq.w 800a144 + 8009d70: d80f bhi.n 8009d92 + 8009d72: 2840 cmp r0, #64 ; 0x40 + 8009d74: f000 81d5 beq.w 800a122 + 8009d78: 2880 cmp r0, #128 ; 0x80 + 8009d7a: d1f3 bne.n 8009d64 + srcclk = __HAL_RCC_GET_I2C2_SOURCE(); + 8009d7c: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 8009d80: f403 4340 and.w r3, r3, #49152 ; 0xc000 + switch(srcclk) + 8009d84: f5b3 4f80 cmp.w r3, #16384 ; 0x4000 + 8009d88: f000 8157 beq.w 800a03a + 8009d8c: f5b3 4f00 cmp.w r3, #32768 ; 0x8000 + 8009d90: e1d0 b.n 800a134 + switch(PeriphClk) + 8009d92: f5b0 7f00 cmp.w r0, #512 ; 0x200 + 8009d96: d1e5 bne.n 8009d64 + srcclk = __HAL_RCC_GET_LPTIM1_SOURCE(); + 8009d98: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 8009d9c: f403 2340 and.w r3, r3, #786432 ; 0xc0000 + switch(srcclk) + 8009da0: f5b3 2f00 cmp.w r3, #524288 ; 0x80000 + 8009da4: f000 8137 beq.w 800a016 + 8009da8: f200 81d7 bhi.w 800a15a + 8009dac: 2b00 cmp r3, #0 + 8009dae: f000 81c6 beq.w 800a13e + 8009db2: f5b3 2f80 cmp.w r3, #262144 ; 0x40000 + 8009db6: d1d5 bne.n 8009d64 + if(HAL_IS_BIT_SET(RCC->CSR, RCC_CSR_LSIRDY)) + 8009db8: f8d5 0094 ldr.w r0, [r5, #148] ; 0x94 + frequency = LSI_VALUE; + 8009dbc: f010 0002 ands.w r0, r0, #2 + 8009dc0: bf18 it ne + 8009dc2: f44f 40fa movne.w r0, #32000 ; 0x7d00 + 8009dc6: e09b b.n 8009f00 + switch(PeriphClk) + 8009dc8: f5b0 2f80 cmp.w r0, #262144 ; 0x40000 + 8009dcc: d040 beq.n 8009e50 + 8009dce: d819 bhi.n 8009e04 + 8009dd0: f5b0 5f00 cmp.w r0, #8192 ; 0x2000 + 8009dd4: d03c beq.n 8009e50 + 8009dd6: d808 bhi.n 8009dea + 8009dd8: f5b0 6f00 cmp.w r0, #2048 ; 0x800 + 8009ddc: d002 beq.n 8009de4 + 8009dde: f5b0 5f80 cmp.w r0, #4096 ; 0x1000 + 8009de2: d1bf bne.n 8009d64 +} + 8009de4: bcf0 pop {r4, r5, r6, r7} + frequency = RCCEx_GetSAIxPeriphCLKFreq(RCC_PERIPHCLK_SAI1, pllvco); + 8009de6: f7ff bb1b b.w 8009420 + switch(PeriphClk) + 8009dea: f5b0 4f80 cmp.w r0, #16384 ; 0x4000 + 8009dee: f000 8163 beq.w 800a0b8 + 8009df2: f5b0 3f80 cmp.w r0, #65536 ; 0x10000 + 8009df6: d1b5 bne.n 8009d64 + srcclk = __HAL_RCC_GET_DFSDM1_SOURCE(); + 8009df8: f8d5 309c ldr.w r3, [r5, #156] ; 0x9c + if(srcclk == RCC_DFSDM1CLKSOURCE_PCLK2) + 8009dfc: 075a lsls r2, r3, #29 + 8009dfe: f100 811c bmi.w 800a03a + 8009e02: e105 b.n 800a010 + switch(PeriphClk) + 8009e04: f5b0 1f00 cmp.w r0, #2097152 ; 0x200000 + 8009e08: f000 817c beq.w 800a104 + 8009e0c: d80f bhi.n 8009e2e + 8009e0e: f5b0 2f00 cmp.w r0, #524288 ; 0x80000 + 8009e12: f000 8081 beq.w 8009f18 + 8009e16: f5b0 1f80 cmp.w r0, #1048576 ; 0x100000 + 8009e1a: d1a3 bne.n 8009d64 + srcclk = __HAL_RCC_GET_I2C4_SOURCE(); + 8009e1c: f8d5 309c ldr.w r3, [r5, #156] ; 0x9c + 8009e20: f003 0303 and.w r3, r3, #3 + switch(srcclk) + 8009e24: 2b01 cmp r3, #1 + 8009e26: f000 8108 beq.w 800a03a + 8009e2a: 2b02 cmp r3, #2 + 8009e2c: e182 b.n 800a134 + switch(PeriphClk) + 8009e2e: f1b0 7f80 cmp.w r0, #16777216 ; 0x1000000 + 8009e32: d197 bne.n 8009d64 + srcclk = __HAL_RCC_GET_OSPI_SOURCE(); + 8009e34: f8d5 309c ldr.w r3, [r5, #156] ; 0x9c + 8009e38: f403 1340 and.w r3, r3, #3145728 ; 0x300000 + switch(srcclk) + 8009e3c: f5b3 1f80 cmp.w r3, #1048576 ; 0x100000 + 8009e40: d033 beq.n 8009eaa + 8009e42: f5b3 1f00 cmp.w r3, #2097152 ; 0x200000 + 8009e46: f000 819c beq.w 800a182 + 8009e4a: 2b00 cmp r3, #0 + 8009e4c: d18a bne.n 8009d64 + 8009e4e: e0f4 b.n 800a03a + srcclk = READ_BIT(RCC->CCIPR, RCC_CCIPR_CLK48SEL); + 8009e50: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 8009e54: f003 6340 and.w r3, r3, #201326592 ; 0xc000000 + switch(srcclk) + 8009e58: f1b3 6f00 cmp.w r3, #134217728 ; 0x8000000 + 8009e5c: d037 beq.n 8009ece + 8009e5e: d820 bhi.n 8009ea2 + 8009e60: 2b00 cmp r3, #0 + 8009e62: f000 80c4 beq.w 8009fee + 8009e66: f1b3 6f80 cmp.w r3, #67108864 ; 0x4000000 + 8009e6a: f47f af7b bne.w 8009d64 + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLLSAI1RDY)) + 8009e6e: 6828 ldr r0, [r5, #0] + 8009e70: f010 6000 ands.w r0, r0, #134217728 ; 0x8000000 + 8009e74: d044 beq.n 8009f00 + if(HAL_IS_BIT_SET(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1QEN)) + 8009e76: 6928 ldr r0, [r5, #16] + 8009e78: f410 1080 ands.w r0, r0, #1048576 ; 0x100000 + 8009e7c: d040 beq.n 8009f00 + plln = READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1N) >> RCC_PLLSAI1CFGR_PLLSAI1N_Pos; + 8009e7e: 692f ldr r7, [r5, #16] + 8009e80: f3c7 2706 ubfx r7, r7, #8, #7 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 8009e84: 4379 muls r1, r7 + 8009e86: 692f ldr r7, [r5, #16] + frequency = (pllvco / (((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1Q) >> RCC_PLLSAI1CFGR_PLLSAI1Q_Pos) + 1U) << 1U)); + 8009e88: 6928 ldr r0, [r5, #16] + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 8009e8a: f3c7 1703 ubfx r7, r7, #4, #4 + 8009e8e: 3701 adds r7, #1 + 8009e90: fbb1 f1f7 udiv r1, r1, r7 + frequency = (pllvco / (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLQ) >> RCC_PLLCFGR_PLLQ_Pos) + 1U) << 1U)); + 8009e94: f3c0 5041 ubfx r0, r0, #21, #2 + 8009e98: 3001 adds r0, #1 + 8009e9a: 0040 lsls r0, r0, #1 + 8009e9c: fbb1 f0f0 udiv r0, r1, r0 + 8009ea0: e02e b.n 8009f00 + 8009ea2: f1b3 6f40 cmp.w r3, #201326592 ; 0xc000000 + 8009ea6: f47f af5d bne.w 8009d64 + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_MSIRDY)) + 8009eaa: 6828 ldr r0, [r5, #0] + 8009eac: f010 0002 ands.w r0, r0, #2 + 8009eb0: d026 beq.n 8009f00 + frequency = MSIRangeTable[(__HAL_RCC_GET_MSI_RANGE() >> 4U)]; + 8009eb2: 682b ldr r3, [r5, #0] + 8009eb4: 4a15 ldr r2, [pc, #84] ; (8009f0c ) + 8009eb6: 071b lsls r3, r3, #28 + 8009eb8: bf4b itete mi + 8009eba: 682b ldrmi r3, [r5, #0] + 8009ebc: f8d5 3094 ldrpl.w r3, [r5, #148] ; 0x94 + 8009ec0: f3c3 1303 ubfxmi r3, r3, #4, #4 + 8009ec4: f3c3 2303 ubfxpl r3, r3, #8, #4 + 8009ec8: f852 0023 ldr.w r0, [r2, r3, lsl #2] + 8009ecc: e018 b.n 8009f00 + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLLRDY)) + 8009ece: 6828 ldr r0, [r5, #0] + 8009ed0: f010 7000 ands.w r0, r0, #33554432 ; 0x2000000 + 8009ed4: d014 beq.n 8009f00 + if(HAL_IS_BIT_SET(RCC->PLLCFGR, RCC_PLLCFGR_PLLQEN)) + 8009ed6: 68e8 ldr r0, [r5, #12] + 8009ed8: f410 1080 ands.w r0, r0, #1048576 ; 0x100000 + 8009edc: d010 beq.n 8009f00 + plln = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos; + 8009ede: 68e8 ldr r0, [r5, #12] + 8009ee0: f3c0 2006 ubfx r0, r0, #8, #7 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009ee4: 4348 muls r0, r1 + 8009ee6: 68e9 ldr r1, [r5, #12] + frequency = (pllvco / (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLQ) >> RCC_PLLCFGR_PLLQ_Pos) + 1U) << 1U)); + 8009ee8: 68ed ldr r5, [r5, #12] + 8009eea: f3c5 5541 ubfx r5, r5, #21, #2 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009eee: f3c1 1103 ubfx r1, r1, #4, #4 + frequency = (pllvco / (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLQ) >> RCC_PLLCFGR_PLLQ_Pos) + 1U) << 1U)); + 8009ef2: 3501 adds r5, #1 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009ef4: 3101 adds r1, #1 + frequency = (pllvco / (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLQ) >> RCC_PLLCFGR_PLLQ_Pos) + 1U) << 1U)); + 8009ef6: 006d lsls r5, r5, #1 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009ef8: fbb0 f0f1 udiv r0, r0, r1 + frequency = (pllvco / (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLQ) >> RCC_PLLCFGR_PLLQ_Pos) + 1U) << 1U)); + 8009efc: fbb0 f0f5 udiv r0, r0, r5 +} + 8009f00: bcf0 pop {r4, r5, r6, r7} + 8009f02: 4770 bx lr + 8009f04: 40021000 .word 0x40021000 + 8009f08: 0003d090 .word 0x0003d090 + 8009f0c: 08010a70 .word 0x08010a70 + 8009f10: 00f42400 .word 0x00f42400 + 8009f14: 007a1200 .word 0x007a1200 + if(HAL_IS_BIT_SET(RCC->CCIPR2, RCC_CCIPR2_SDMMCSEL)) /* PLL "P" ? */ + 8009f18: f8d5 009c ldr.w r0, [r5, #156] ; 0x9c + 8009f1c: f410 4080 ands.w r0, r0, #16384 ; 0x4000 + 8009f20: d01f beq.n 8009f62 + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLLRDY)) + 8009f22: 6828 ldr r0, [r5, #0] + 8009f24: f010 7000 ands.w r0, r0, #33554432 ; 0x2000000 + 8009f28: d0ea beq.n 8009f00 + if(HAL_IS_BIT_SET(RCC->PLLCFGR, RCC_PLLCFGR_PLLPEN)) + 8009f2a: 68e8 ldr r0, [r5, #12] + 8009f2c: f410 3080 ands.w r0, r0, #65536 ; 0x10000 + 8009f30: d0e6 beq.n 8009f00 + plln = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos; + 8009f32: 68ee ldr r6, [r5, #12] + 8009f34: f3c6 2606 ubfx r6, r6, #8, #7 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009f38: fb01 f006 mul.w r0, r1, r6 + 8009f3c: 68ee ldr r6, [r5, #12] + pllp = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLPDIV) >> RCC_PLLCFGR_PLLPDIV_Pos; + 8009f3e: 68eb ldr r3, [r5, #12] + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009f40: f3c6 1603 ubfx r6, r6, #4, #4 + if(pllp == 0U) + 8009f44: 0edb lsrs r3, r3, #27 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009f46: f106 0601 add.w r6, r6, #1 + 8009f4a: fbb0 f0f6 udiv r0, r0, r6 + if(pllp == 0U) + 8009f4e: d105 bne.n 8009f5c + if(READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLP) != 0U) + 8009f50: 68eb ldr r3, [r5, #12] + pllp = 7U; + 8009f52: f413 3f00 tst.w r3, #131072 ; 0x20000 + 8009f56: bf14 ite ne + 8009f58: 2311 movne r3, #17 + 8009f5a: 2307 moveq r3, #7 + frequency = (pllvco / pllp); + 8009f5c: fbb0 f0f3 udiv r0, r0, r3 + 8009f60: e7ce b.n 8009f00 + srcclk = READ_BIT(RCC->CCIPR, RCC_CCIPR_CLK48SEL); + 8009f62: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 8009f66: f003 6340 and.w r3, r3, #201326592 ; 0xc000000 + switch(srcclk) + 8009f6a: f1b3 6f00 cmp.w r3, #134217728 ; 0x8000000 + 8009f6e: d024 beq.n 8009fba + 8009f70: d81e bhi.n 8009fb0 + 8009f72: 2b00 cmp r3, #0 + 8009f74: d03b beq.n 8009fee + 8009f76: f1b3 6f80 cmp.w r3, #67108864 ; 0x4000000 + 8009f7a: d1c1 bne.n 8009f00 + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLLSAI1RDY)) + 8009f7c: 6828 ldr r0, [r5, #0] + 8009f7e: f010 6000 ands.w r0, r0, #134217728 ; 0x8000000 + 8009f82: d0bd beq.n 8009f00 + if(HAL_IS_BIT_SET(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1QEN)) + 8009f84: 6928 ldr r0, [r5, #16] + 8009f86: f410 1080 ands.w r0, r0, #1048576 ; 0x100000 + 8009f8a: d0b9 beq.n 8009f00 + plln = READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1N) >> RCC_PLLSAI1CFGR_PLLSAI1N_Pos; + 8009f8c: 692a ldr r2, [r5, #16] + 8009f8e: f3c2 2206 ubfx r2, r2, #8, #7 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 8009f92: 434a muls r2, r1 + 8009f94: 6929 ldr r1, [r5, #16] + frequency = (pllvco / (((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1Q) >> RCC_PLLSAI1CFGR_PLLSAI1Q_Pos) + 1U) << 1U)); + 8009f96: 6928 ldr r0, [r5, #16] + 8009f98: f3c0 5041 ubfx r0, r0, #21, #2 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 8009f9c: f3c1 1103 ubfx r1, r1, #4, #4 + frequency = (pllvco / (((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1Q) >> RCC_PLLSAI1CFGR_PLLSAI1Q_Pos) + 1U) << 1U)); + 8009fa0: 3001 adds r0, #1 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 8009fa2: 3101 adds r1, #1 + frequency = (pllvco / (((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1Q) >> RCC_PLLSAI1CFGR_PLLSAI1Q_Pos) + 1U) << 1U)); + 8009fa4: 0040 lsls r0, r0, #1 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 8009fa6: fbb2 f2f1 udiv r2, r2, r1 + frequency = (pllvco / (((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1Q) >> RCC_PLLSAI1CFGR_PLLSAI1Q_Pos) + 1U) << 1U)); + 8009faa: fbb2 f0f0 udiv r0, r2, r0 + 8009fae: e7a7 b.n 8009f00 + 8009fb0: f1b3 6f40 cmp.w r3, #201326592 ; 0xc000000 + 8009fb4: f43f af79 beq.w 8009eaa + 8009fb8: e7a2 b.n 8009f00 + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLLRDY)) + 8009fba: 6828 ldr r0, [r5, #0] + 8009fbc: f010 7000 ands.w r0, r0, #33554432 ; 0x2000000 + 8009fc0: d09e beq.n 8009f00 + if(HAL_IS_BIT_SET(RCC->PLLCFGR, RCC_PLLCFGR_PLLQEN)) + 8009fc2: 68e8 ldr r0, [r5, #12] + 8009fc4: f410 1080 ands.w r0, r0, #1048576 ; 0x100000 + 8009fc8: d09a beq.n 8009f00 + plln = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos; + 8009fca: 68ec ldr r4, [r5, #12] + 8009fcc: f3c4 2406 ubfx r4, r4, #8, #7 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009fd0: 434c muls r4, r1 + 8009fd2: 68e9 ldr r1, [r5, #12] + frequency = (pllvco / (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLQ) >> RCC_PLLCFGR_PLLQ_Pos) + 1U) << 1U)); + 8009fd4: 68e8 ldr r0, [r5, #12] + 8009fd6: f3c0 5041 ubfx r0, r0, #21, #2 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009fda: f3c1 1103 ubfx r1, r1, #4, #4 + frequency = (pllvco / (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLQ) >> RCC_PLLCFGR_PLLQ_Pos) + 1U) << 1U)); + 8009fde: 3001 adds r0, #1 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009fe0: 3101 adds r1, #1 + frequency = (pllvco / (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLQ) >> RCC_PLLCFGR_PLLQ_Pos) + 1U) << 1U)); + 8009fe2: 0040 lsls r0, r0, #1 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 8009fe4: fbb4 f4f1 udiv r4, r4, r1 + frequency = (pllvco / (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLQ) >> RCC_PLLCFGR_PLLQ_Pos) + 1U) << 1U)); + 8009fe8: fbb4 f0f0 udiv r0, r4, r0 + 8009fec: e788 b.n 8009f00 + if(HAL_IS_BIT_SET(RCC->CRRCR, RCC_CRRCR_HSI48RDY)) /* HSI48 ? */ + 8009fee: f8d5 0098 ldr.w r0, [r5, #152] ; 0x98 + frequency = HSI48_VALUE; + 8009ff2: 4b6f ldr r3, [pc, #444] ; (800a1b0 ) + 8009ff4: f010 0002 ands.w r0, r0, #2 + 8009ff8: e66b b.n 8009cd2 + srcclk = __HAL_RCC_GET_USART1_SOURCE(); + 8009ffa: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 8009ffe: f003 0303 and.w r3, r3, #3 + switch(srcclk) + 800a002: 2b02 cmp r3, #2 + 800a004: d007 beq.n 800a016 + 800a006: 2b03 cmp r3, #3 + 800a008: f43f ae57 beq.w 8009cba + 800a00c: 2b01 cmp r3, #1 + 800a00e: d014 beq.n 800a03a +} + 800a010: bcf0 pop {r4, r5, r6, r7} + frequency = HAL_RCC_GetPCLK2Freq(); + 800a012: f7ff b95b b.w 80092cc + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSIRDY)) + 800a016: 6828 ldr r0, [r5, #0] + frequency = HSI_VALUE; + 800a018: 4b66 ldr r3, [pc, #408] ; (800a1b4 ) + 800a01a: f410 6080 ands.w r0, r0, #1024 ; 0x400 + 800a01e: e658 b.n 8009cd2 + srcclk = __HAL_RCC_GET_USART2_SOURCE(); + 800a020: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 800a024: f003 030c and.w r3, r3, #12 + switch(srcclk) + 800a028: 2b08 cmp r3, #8 + 800a02a: d0f4 beq.n 800a016 + 800a02c: d808 bhi.n 800a040 + 800a02e: 2b00 cmp r3, #0 + 800a030: f000 8085 beq.w 800a13e + 800a034: 2b04 cmp r3, #4 + 800a036: f47f ae95 bne.w 8009d64 +} + 800a03a: bcf0 pop {r4, r5, r6, r7} + frequency = HAL_RCC_GetSysClockFreq(); + 800a03c: f7fe bd38 b.w 8008ab0 + 800a040: 2b0c cmp r3, #12 + 800a042: e639 b.n 8009cb8 + srcclk = __HAL_RCC_GET_USART3_SOURCE(); + 800a044: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 800a048: f003 0330 and.w r3, r3, #48 ; 0x30 + switch(srcclk) + 800a04c: 2b20 cmp r3, #32 + 800a04e: d0e2 beq.n 800a016 + 800a050: d803 bhi.n 800a05a + 800a052: 2b00 cmp r3, #0 + 800a054: d073 beq.n 800a13e + 800a056: 2b10 cmp r3, #16 + 800a058: e7ed b.n 800a036 + 800a05a: 2b30 cmp r3, #48 ; 0x30 + 800a05c: e62c b.n 8009cb8 + srcclk = __HAL_RCC_GET_UART4_SOURCE(); + 800a05e: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 800a062: f003 03c0 and.w r3, r3, #192 ; 0xc0 + switch(srcclk) + 800a066: 2b80 cmp r3, #128 ; 0x80 + 800a068: d0d5 beq.n 800a016 + 800a06a: d803 bhi.n 800a074 + 800a06c: 2b00 cmp r3, #0 + 800a06e: d066 beq.n 800a13e + 800a070: 2b40 cmp r3, #64 ; 0x40 + 800a072: e7e0 b.n 800a036 + 800a074: 2bc0 cmp r3, #192 ; 0xc0 + 800a076: e61f b.n 8009cb8 + srcclk = __HAL_RCC_GET_UART5_SOURCE(); + 800a078: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 800a07c: f403 7340 and.w r3, r3, #768 ; 0x300 + switch(srcclk) + 800a080: f5b3 7f00 cmp.w r3, #512 ; 0x200 + 800a084: d0c7 beq.n 800a016 + 800a086: d804 bhi.n 800a092 + 800a088: 2b00 cmp r3, #0 + 800a08a: d058 beq.n 800a13e + 800a08c: f5b3 7f80 cmp.w r3, #256 ; 0x100 + 800a090: e7d1 b.n 800a036 + 800a092: f5b3 7f40 cmp.w r3, #768 ; 0x300 + 800a096: e60f b.n 8009cb8 + srcclk = __HAL_RCC_GET_LPUART1_SOURCE(); + 800a098: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 800a09c: f403 6340 and.w r3, r3, #3072 ; 0xc00 + switch(srcclk) + 800a0a0: f5b3 6f00 cmp.w r3, #2048 ; 0x800 + 800a0a4: d0b7 beq.n 800a016 + 800a0a6: d804 bhi.n 800a0b2 + 800a0a8: 2b00 cmp r3, #0 + 800a0aa: d048 beq.n 800a13e + 800a0ac: f5b3 6f80 cmp.w r3, #1024 ; 0x400 + 800a0b0: e7c1 b.n 800a036 + 800a0b2: f5b3 6f40 cmp.w r3, #3072 ; 0xc00 + 800a0b6: e5ff b.n 8009cb8 + srcclk = __HAL_RCC_GET_ADC_SOURCE(); + 800a0b8: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 800a0bc: f003 5340 and.w r3, r3, #805306368 ; 0x30000000 + switch(srcclk) + 800a0c0: f1b3 5f80 cmp.w r3, #268435456 ; 0x10000000 + 800a0c4: d002 beq.n 800a0cc + 800a0c6: f1b3 5f40 cmp.w r3, #805306368 ; 0x30000000 + 800a0ca: e7b4 b.n 800a036 + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLLSAI1RDY) && (__HAL_RCC_GET_PLLSAI1CLKOUT_CONFIG(RCC_PLLSAI1_ADC1CLK) != 0U)) + 800a0cc: 6828 ldr r0, [r5, #0] + 800a0ce: f010 6000 ands.w r0, r0, #134217728 ; 0x8000000 + 800a0d2: f43f af15 beq.w 8009f00 + 800a0d6: 6928 ldr r0, [r5, #16] + 800a0d8: f010 7080 ands.w r0, r0, #16777216 ; 0x1000000 + 800a0dc: f43f af10 beq.w 8009f00 + plln = READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1N) >> RCC_PLLSAI1CFGR_PLLSAI1N_Pos; + 800a0e0: 692b ldr r3, [r5, #16] + 800a0e2: f3c3 2306 ubfx r3, r3, #8, #7 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 800a0e6: 434b muls r3, r1 + 800a0e8: 6929 ldr r1, [r5, #16] + frequency = (pllvco / (((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1R) >> RCC_PLLSAI1CFGR_PLLSAI1R_Pos) + 1U) << 1U)); + 800a0ea: 6928 ldr r0, [r5, #16] + 800a0ec: f3c0 6041 ubfx r0, r0, #25, #2 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 800a0f0: f3c1 1103 ubfx r1, r1, #4, #4 + frequency = (pllvco / (((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1R) >> RCC_PLLSAI1CFGR_PLLSAI1R_Pos) + 1U) << 1U)); + 800a0f4: 3001 adds r0, #1 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 800a0f6: 3101 adds r1, #1 + frequency = (pllvco / (((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1R) >> RCC_PLLSAI1CFGR_PLLSAI1R_Pos) + 1U) << 1U)); + 800a0f8: 0040 lsls r0, r0, #1 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1M) >> RCC_PLLSAI1CFGR_PLLSAI1M_Pos) + 1U)); + 800a0fa: fbb3 f3f1 udiv r3, r3, r1 + frequency = (pllvco / (((READ_BIT(RCC->PLLSAI1CFGR, RCC_PLLSAI1CFGR_PLLSAI1R) >> RCC_PLLSAI1CFGR_PLLSAI1R_Pos) + 1U) << 1U)); + 800a0fe: fbb3 f0f0 udiv r0, r3, r0 + 800a102: e6fd b.n 8009f00 + srcclk = __HAL_RCC_GET_DFSDM1AUDIO_SOURCE(); + 800a104: f8d5 309c ldr.w r3, [r5, #156] ; 0x9c + 800a108: f003 0318 and.w r3, r3, #24 + switch(srcclk) + 800a10c: 2b08 cmp r3, #8 + 800a10e: d082 beq.n 800a016 + 800a110: 2b10 cmp r3, #16 + 800a112: f43f aeca beq.w 8009eaa + 800a116: 2b00 cmp r3, #0 + 800a118: f47f ae24 bne.w 8009d64 + frequency = RCCEx_GetSAIxPeriphCLKFreq(RCC_PERIPHCLK_SAI1, pllvco); + 800a11c: f44f 6000 mov.w r0, #2048 ; 0x800 + 800a120: e660 b.n 8009de4 + srcclk = __HAL_RCC_GET_I2C1_SOURCE(); + 800a122: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 800a126: f403 5340 and.w r3, r3, #12288 ; 0x3000 + switch(srcclk) + 800a12a: f5b3 5f80 cmp.w r3, #4096 ; 0x1000 + 800a12e: d084 beq.n 800a03a + 800a130: f5b3 5f00 cmp.w r3, #8192 ; 0x2000 + 800a134: f43f af6f beq.w 800a016 + 800a138: 2b00 cmp r3, #0 + 800a13a: f47f ae13 bne.w 8009d64 +} + 800a13e: bcf0 pop {r4, r5, r6, r7} + frequency = HAL_RCC_GetPCLK1Freq(); + 800a140: f7ff b8b2 b.w 80092a8 + srcclk = __HAL_RCC_GET_I2C3_SOURCE(); + 800a144: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 800a148: f403 3340 and.w r3, r3, #196608 ; 0x30000 + switch(srcclk) + 800a14c: f5b3 3f80 cmp.w r3, #65536 ; 0x10000 + 800a150: f43f af73 beq.w 800a03a + 800a154: f5b3 3f00 cmp.w r3, #131072 ; 0x20000 + 800a158: e7ec b.n 800a134 + 800a15a: f5b3 2f40 cmp.w r3, #786432 ; 0xc0000 + 800a15e: e5ab b.n 8009cb8 + srcclk = __HAL_RCC_GET_LPTIM2_SOURCE(); + 800a160: f8d5 3088 ldr.w r3, [r5, #136] ; 0x88 + 800a164: f403 1340 and.w r3, r3, #3145728 ; 0x300000 + switch(srcclk) + 800a168: f5b3 1f00 cmp.w r3, #2097152 ; 0x200000 + 800a16c: f43f af53 beq.w 800a016 + 800a170: d804 bhi.n 800a17c + 800a172: 2b00 cmp r3, #0 + 800a174: d0e3 beq.n 800a13e + 800a176: f5b3 1f80 cmp.w r3, #1048576 ; 0x100000 + 800a17a: e61c b.n 8009db6 + 800a17c: f5b3 1f40 cmp.w r3, #3145728 ; 0x300000 + 800a180: e59a b.n 8009cb8 + if(HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLLRDY)) + 800a182: 6828 ldr r0, [r5, #0] + 800a184: f010 7000 ands.w r0, r0, #33554432 ; 0x2000000 + 800a188: f43f aeba beq.w 8009f00 + if(HAL_IS_BIT_SET(RCC->PLLCFGR, RCC_PLLCFGR_PLLQEN)) + 800a18c: 68e8 ldr r0, [r5, #12] + 800a18e: f410 1080 ands.w r0, r0, #1048576 ; 0x100000 + 800a192: f43f aeb5 beq.w 8009f00 + plln = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos; + 800a196: 68e8 ldr r0, [r5, #12] + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 800a198: 68eb ldr r3, [r5, #12] + plln = READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos; + 800a19a: f3c0 2006 ubfx r0, r0, #8, #7 + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 800a19e: f3c3 1303 ubfx r3, r3, #4, #4 + 800a1a2: 4341 muls r1, r0 + 800a1a4: 3301 adds r3, #1 + frequency = (pllvco / (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLQ) >> RCC_PLLCFGR_PLLQ_Pos) + 1U) << 1U)); + 800a1a6: 68e8 ldr r0, [r5, #12] + pllvco = ((pllvco * plln) / ((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U)); + 800a1a8: fbb1 f1f3 udiv r1, r1, r3 + 800a1ac: e672 b.n 8009e94 + 800a1ae: bf00 nop + 800a1b0: 02dc6c00 .word 0x02dc6c00 + 800a1b4: 00f42400 .word 0x00f42400 + +0800a1b8 : +{ + 800a1b8: b570 push {r4, r5, r6, lr} + __HAL_RCC_PLLSAI1_DISABLE(); + 800a1ba: 4c20 ldr r4, [pc, #128] ; (800a23c ) + 800a1bc: 6823 ldr r3, [r4, #0] + 800a1be: f023 6380 bic.w r3, r3, #67108864 ; 0x4000000 + 800a1c2: 6023 str r3, [r4, #0] +{ + 800a1c4: 4605 mov r5, r0 + tickstart = HAL_GetTick(); + 800a1c6: f7fd f909 bl 80073dc + 800a1ca: 4606 mov r6, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI1RDY) != 0U) + 800a1cc: 6823 ldr r3, [r4, #0] + 800a1ce: 011a lsls r2, r3, #4 + 800a1d0: d423 bmi.n 800a21a + __HAL_RCC_PLLSAI1_CONFIG(PLLSAI1Init->PLLSAI1M, PLLSAI1Init->PLLSAI1N, PLLSAI1Init->PLLSAI1P, PLLSAI1Init->PLLSAI1Q, PLLSAI1Init->PLLSAI1R); + 800a1d2: e9d5 2302 ldrd r2, r3, [r5, #8] + 800a1d6: 06db lsls r3, r3, #27 + 800a1d8: 6921 ldr r1, [r4, #16] + 800a1da: ea43 2302 orr.w r3, r3, r2, lsl #8 + 800a1de: 4a18 ldr r2, [pc, #96] ; (800a240 ) + 800a1e0: 400a ands r2, r1 + 800a1e2: 4313 orrs r3, r2 + 800a1e4: 686a ldr r2, [r5, #4] + 800a1e6: 3a01 subs r2, #1 + 800a1e8: ea43 1302 orr.w r3, r3, r2, lsl #4 + 800a1ec: 692a ldr r2, [r5, #16] + 800a1ee: 0852 lsrs r2, r2, #1 + 800a1f0: 3a01 subs r2, #1 + 800a1f2: ea43 5342 orr.w r3, r3, r2, lsl #21 + 800a1f6: 696a ldr r2, [r5, #20] + 800a1f8: 0852 lsrs r2, r2, #1 + 800a1fa: 3a01 subs r2, #1 + 800a1fc: ea43 6342 orr.w r3, r3, r2, lsl #25 + 800a200: 6123 str r3, [r4, #16] + __HAL_RCC_PLLSAI1CLKOUT_ENABLE(PLLSAI1Init->PLLSAI1ClockOut); + 800a202: 6923 ldr r3, [r4, #16] + 800a204: 69aa ldr r2, [r5, #24] + 800a206: 4313 orrs r3, r2 + 800a208: 6123 str r3, [r4, #16] + __HAL_RCC_PLLSAI1_ENABLE(); + 800a20a: 6823 ldr r3, [r4, #0] + 800a20c: f043 6380 orr.w r3, r3, #67108864 ; 0x4000000 + 800a210: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 800a212: f7fd f8e3 bl 80073dc + 800a216: 4605 mov r5, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI1RDY) == 0U) + 800a218: e00b b.n 800a232 + if((HAL_GetTick() - tickstart) > PLLSAI1_TIMEOUT_VALUE) + 800a21a: f7fd f8df bl 80073dc + 800a21e: 1b80 subs r0, r0, r6 + 800a220: 2802 cmp r0, #2 + 800a222: d9d3 bls.n 800a1cc + status = HAL_TIMEOUT; + 800a224: 2003 movs r0, #3 +} + 800a226: bd70 pop {r4, r5, r6, pc} + if((HAL_GetTick() - tickstart) > PLLSAI1_TIMEOUT_VALUE) + 800a228: f7fd f8d8 bl 80073dc + 800a22c: 1b40 subs r0, r0, r5 + 800a22e: 2802 cmp r0, #2 + 800a230: d8f8 bhi.n 800a224 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI1RDY) == 0U) + 800a232: 6823 ldr r3, [r4, #0] + 800a234: 011b lsls r3, r3, #4 + 800a236: d5f7 bpl.n 800a228 + 800a238: 2000 movs r0, #0 + return status; + 800a23a: e7f4 b.n 800a226 + 800a23c: 40021000 .word 0x40021000 + 800a240: 019d800f .word 0x019d800f + +0800a244 : +{ + 800a244: b538 push {r3, r4, r5, lr} + __HAL_RCC_PLLSAI1_DISABLE(); + 800a246: 4c11 ldr r4, [pc, #68] ; (800a28c ) + 800a248: 6823 ldr r3, [r4, #0] + 800a24a: f023 6380 bic.w r3, r3, #67108864 ; 0x4000000 + 800a24e: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 800a250: f7fd f8c4 bl 80073dc + 800a254: 4605 mov r5, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI1RDY) != 0U) + 800a256: 6823 ldr r3, [r4, #0] + 800a258: f013 6300 ands.w r3, r3, #134217728 ; 0x8000000 + 800a25c: d10f bne.n 800a27e + HAL_StatusTypeDef status = HAL_OK; + 800a25e: 4618 mov r0, r3 + __HAL_RCC_PLLSAI1CLKOUT_DISABLE(RCC_PLLSAI1CFGR_PLLSAI1PEN|RCC_PLLSAI1CFGR_PLLSAI1QEN|RCC_PLLSAI1CFGR_PLLSAI1REN); + 800a260: 6923 ldr r3, [r4, #16] + 800a262: f023 7388 bic.w r3, r3, #17825792 ; 0x1100000 + 800a266: f423 3380 bic.w r3, r3, #65536 ; 0x10000 + 800a26a: 6123 str r3, [r4, #16] + if(READ_BIT(RCC->CR, (RCC_CR_PLLRDY | RCC_CR_PLLSAI2RDY)) == 0U) + 800a26c: 6823 ldr r3, [r4, #0] + 800a26e: f013 5f08 tst.w r3, #570425344 ; 0x22000000 + MODIFY_REG(RCC->PLLCFGR, RCC_PLLCFGR_PLLSRC, RCC_PLLSOURCE_NONE); + 800a272: bf02 ittt eq + 800a274: 68e3 ldreq r3, [r4, #12] + 800a276: f023 0303 biceq.w r3, r3, #3 + 800a27a: 60e3 streq r3, [r4, #12] +} + 800a27c: bd38 pop {r3, r4, r5, pc} + if((HAL_GetTick() - tickstart) > PLLSAI1_TIMEOUT_VALUE) + 800a27e: f7fd f8ad bl 80073dc + 800a282: 1b40 subs r0, r0, r5 + 800a284: 2802 cmp r0, #2 + 800a286: d9e6 bls.n 800a256 + status = HAL_TIMEOUT; + 800a288: 2003 movs r0, #3 + 800a28a: e7e9 b.n 800a260 + 800a28c: 40021000 .word 0x40021000 + +0800a290 : +{ + 800a290: b570 push {r4, r5, r6, lr} + __HAL_RCC_PLLSAI2_DISABLE(); + 800a292: 4c20 ldr r4, [pc, #128] ; (800a314 ) + 800a294: 6823 ldr r3, [r4, #0] + 800a296: f023 5380 bic.w r3, r3, #268435456 ; 0x10000000 + 800a29a: 6023 str r3, [r4, #0] +{ + 800a29c: 4605 mov r5, r0 + tickstart = HAL_GetTick(); + 800a29e: f7fd f89d bl 80073dc + 800a2a2: 4606 mov r6, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI2RDY) != 0U) + 800a2a4: 6823 ldr r3, [r4, #0] + 800a2a6: 009a lsls r2, r3, #2 + 800a2a8: d423 bmi.n 800a2f2 + __HAL_RCC_PLLSAI2_CONFIG(PLLSAI2Init->PLLSAI2M, PLLSAI2Init->PLLSAI2N, PLLSAI2Init->PLLSAI2P, PLLSAI2Init->PLLSAI2Q, PLLSAI2Init->PLLSAI2R); + 800a2aa: e9d5 2302 ldrd r2, r3, [r5, #8] + 800a2ae: 06db lsls r3, r3, #27 + 800a2b0: 6961 ldr r1, [r4, #20] + 800a2b2: ea43 2302 orr.w r3, r3, r2, lsl #8 + 800a2b6: 4a18 ldr r2, [pc, #96] ; (800a318 ) + 800a2b8: 400a ands r2, r1 + 800a2ba: 4313 orrs r3, r2 + 800a2bc: 686a ldr r2, [r5, #4] + 800a2be: 3a01 subs r2, #1 + 800a2c0: ea43 1302 orr.w r3, r3, r2, lsl #4 + 800a2c4: 692a ldr r2, [r5, #16] + 800a2c6: 0852 lsrs r2, r2, #1 + 800a2c8: 3a01 subs r2, #1 + 800a2ca: ea43 5342 orr.w r3, r3, r2, lsl #21 + 800a2ce: 696a ldr r2, [r5, #20] + 800a2d0: 0852 lsrs r2, r2, #1 + 800a2d2: 3a01 subs r2, #1 + 800a2d4: ea43 6342 orr.w r3, r3, r2, lsl #25 + 800a2d8: 6163 str r3, [r4, #20] + __HAL_RCC_PLLSAI2CLKOUT_ENABLE(PLLSAI2Init->PLLSAI2ClockOut); + 800a2da: 6963 ldr r3, [r4, #20] + 800a2dc: 69aa ldr r2, [r5, #24] + 800a2de: 4313 orrs r3, r2 + 800a2e0: 6163 str r3, [r4, #20] + __HAL_RCC_PLLSAI2_ENABLE(); + 800a2e2: 6823 ldr r3, [r4, #0] + 800a2e4: f043 5380 orr.w r3, r3, #268435456 ; 0x10000000 + 800a2e8: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 800a2ea: f7fd f877 bl 80073dc + 800a2ee: 4605 mov r5, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI2RDY) == 0U) + 800a2f0: e00b b.n 800a30a + if((HAL_GetTick() - tickstart) > PLLSAI2_TIMEOUT_VALUE) + 800a2f2: f7fd f873 bl 80073dc + 800a2f6: 1b80 subs r0, r0, r6 + 800a2f8: 2802 cmp r0, #2 + 800a2fa: d9d3 bls.n 800a2a4 + status = HAL_TIMEOUT; + 800a2fc: 2003 movs r0, #3 +} + 800a2fe: bd70 pop {r4, r5, r6, pc} + if((HAL_GetTick() - tickstart) > PLLSAI2_TIMEOUT_VALUE) + 800a300: f7fd f86c bl 80073dc + 800a304: 1b40 subs r0, r0, r5 + 800a306: 2802 cmp r0, #2 + 800a308: d8f8 bhi.n 800a2fc + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI2RDY) == 0U) + 800a30a: 6823 ldr r3, [r4, #0] + 800a30c: 009b lsls r3, r3, #2 + 800a30e: d5f7 bpl.n 800a300 + 800a310: 2000 movs r0, #0 + return status; + 800a312: e7f4 b.n 800a2fe + 800a314: 40021000 .word 0x40021000 + 800a318: 019d800f .word 0x019d800f + +0800a31c : +{ + 800a31c: b538 push {r3, r4, r5, lr} + __HAL_RCC_PLLSAI2_DISABLE(); + 800a31e: 4c11 ldr r4, [pc, #68] ; (800a364 ) + 800a320: 6823 ldr r3, [r4, #0] + 800a322: f023 5380 bic.w r3, r3, #268435456 ; 0x10000000 + 800a326: 6023 str r3, [r4, #0] + tickstart = HAL_GetTick(); + 800a328: f7fd f858 bl 80073dc + 800a32c: 4605 mov r5, r0 + while(READ_BIT(RCC->CR, RCC_CR_PLLSAI2RDY) != 0U) + 800a32e: 6823 ldr r3, [r4, #0] + 800a330: f013 5300 ands.w r3, r3, #536870912 ; 0x20000000 + 800a334: d10f bne.n 800a356 + HAL_StatusTypeDef status = HAL_OK; + 800a336: 4618 mov r0, r3 + __HAL_RCC_PLLSAI2CLKOUT_DISABLE(RCC_PLLSAI2CFGR_PLLSAI2PEN|RCC_PLLSAI2CFGR_PLLSAI2QEN|RCC_PLLSAI2CFGR_PLLSAI2REN); + 800a338: 6963 ldr r3, [r4, #20] + 800a33a: f023 7388 bic.w r3, r3, #17825792 ; 0x1100000 + 800a33e: f423 3380 bic.w r3, r3, #65536 ; 0x10000 + 800a342: 6163 str r3, [r4, #20] + if(READ_BIT(RCC->CR, (RCC_CR_PLLRDY | RCC_CR_PLLSAI1RDY)) == 0U) + 800a344: 6823 ldr r3, [r4, #0] + 800a346: f013 6f20 tst.w r3, #167772160 ; 0xa000000 + MODIFY_REG(RCC->PLLCFGR, RCC_PLLCFGR_PLLSRC, RCC_PLLSOURCE_NONE); + 800a34a: bf02 ittt eq + 800a34c: 68e3 ldreq r3, [r4, #12] + 800a34e: f023 0303 biceq.w r3, r3, #3 + 800a352: 60e3 streq r3, [r4, #12] +} + 800a354: bd38 pop {r3, r4, r5, pc} + if((HAL_GetTick() - tickstart) > PLLSAI2_TIMEOUT_VALUE) + 800a356: f7fd f841 bl 80073dc + 800a35a: 1b40 subs r0, r0, r5 + 800a35c: 2802 cmp r0, #2 + 800a35e: d9e6 bls.n 800a32e + status = HAL_TIMEOUT; + 800a360: 2003 movs r0, #3 + 800a362: e7e9 b.n 800a338 + 800a364: 40021000 .word 0x40021000 + +0800a368 : + __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(WakeUpClk); + 800a368: 4a03 ldr r2, [pc, #12] ; (800a378 ) + 800a36a: 6893 ldr r3, [r2, #8] + 800a36c: f423 4300 bic.w r3, r3, #32768 ; 0x8000 + 800a370: 4318 orrs r0, r3 + 800a372: 6090 str r0, [r2, #8] +} + 800a374: 4770 bx lr + 800a376: bf00 nop + 800a378: 40021000 .word 0x40021000 + +0800a37c : + __HAL_RCC_MSI_STANDBY_RANGE_CONFIG(MSIRange); + 800a37c: 4a04 ldr r2, [pc, #16] ; (800a390 ) + 800a37e: f8d2 3094 ldr.w r3, [r2, #148] ; 0x94 + 800a382: f423 6370 bic.w r3, r3, #3840 ; 0xf00 + 800a386: ea43 1000 orr.w r0, r3, r0, lsl #4 + 800a38a: f8c2 0094 str.w r0, [r2, #148] ; 0x94 +} + 800a38e: 4770 bx lr + 800a390: 40021000 .word 0x40021000 + +0800a394 : + SET_BIT(RCC->BDCR, RCC_BDCR_LSECSSON); + 800a394: 4a03 ldr r2, [pc, #12] ; (800a3a4 ) + 800a396: f8d2 3090 ldr.w r3, [r2, #144] ; 0x90 + 800a39a: f043 0320 orr.w r3, r3, #32 + 800a39e: f8c2 3090 str.w r3, [r2, #144] ; 0x90 +} + 800a3a2: 4770 bx lr + 800a3a4: 40021000 .word 0x40021000 + +0800a3a8 : + CLEAR_BIT(RCC->BDCR, RCC_BDCR_LSECSSON) ; + 800a3a8: 4b05 ldr r3, [pc, #20] ; (800a3c0 ) + 800a3aa: f8d3 2090 ldr.w r2, [r3, #144] ; 0x90 + 800a3ae: f022 0220 bic.w r2, r2, #32 + 800a3b2: f8c3 2090 str.w r2, [r3, #144] ; 0x90 + __HAL_RCC_DISABLE_IT(RCC_IT_LSECSS); + 800a3b6: 699a ldr r2, [r3, #24] + 800a3b8: f422 7200 bic.w r2, r2, #512 ; 0x200 + 800a3bc: 619a str r2, [r3, #24] +} + 800a3be: 4770 bx lr + 800a3c0: 40021000 .word 0x40021000 + +0800a3c4 : + SET_BIT(RCC->BDCR, RCC_BDCR_LSECSSON) ; + 800a3c4: 4b0a ldr r3, [pc, #40] ; (800a3f0 ) + 800a3c6: f8d3 2090 ldr.w r2, [r3, #144] ; 0x90 + 800a3ca: f042 0220 orr.w r2, r2, #32 + 800a3ce: f8c3 2090 str.w r2, [r3, #144] ; 0x90 + __HAL_RCC_ENABLE_IT(RCC_IT_LSECSS); + 800a3d2: 699a ldr r2, [r3, #24] + 800a3d4: f442 7200 orr.w r2, r2, #512 ; 0x200 + 800a3d8: 619a str r2, [r3, #24] + __HAL_RCC_LSECSS_EXTI_ENABLE_IT(); + 800a3da: f5a3 3386 sub.w r3, r3, #68608 ; 0x10c00 + 800a3de: 681a ldr r2, [r3, #0] + 800a3e0: f442 2200 orr.w r2, r2, #524288 ; 0x80000 + 800a3e4: 601a str r2, [r3, #0] + __HAL_RCC_LSECSS_EXTI_ENABLE_RISING_EDGE(); + 800a3e6: 689a ldr r2, [r3, #8] + 800a3e8: f442 2200 orr.w r2, r2, #524288 ; 0x80000 + 800a3ec: 609a str r2, [r3, #8] +} + 800a3ee: 4770 bx lr + 800a3f0: 40021000 .word 0x40021000 + +0800a3f4 : +} + 800a3f4: 4770 bx lr + ... + +0800a3f8 : +{ + 800a3f8: b510 push {r4, lr} + if(__HAL_RCC_GET_IT(RCC_IT_LSECSS)) + 800a3fa: 4c05 ldr r4, [pc, #20] ; (800a410 ) + 800a3fc: 69e3 ldr r3, [r4, #28] + 800a3fe: 059b lsls r3, r3, #22 + 800a400: d504 bpl.n 800a40c + HAL_RCCEx_LSECSS_Callback(); + 800a402: f7ff fff7 bl 800a3f4 + __HAL_RCC_CLEAR_IT(RCC_IT_LSECSS); + 800a406: f44f 7300 mov.w r3, #512 ; 0x200 + 800a40a: 6223 str r3, [r4, #32] +} + 800a40c: bd10 pop {r4, pc} + 800a40e: bf00 nop + 800a410: 40021000 .word 0x40021000 + +0800a414 : + SET_BIT(RCC->CR, RCC_CR_MSIPLLEN) ; + 800a414: 4a02 ldr r2, [pc, #8] ; (800a420 ) + 800a416: 6813 ldr r3, [r2, #0] + 800a418: f043 0304 orr.w r3, r3, #4 + 800a41c: 6013 str r3, [r2, #0] +} + 800a41e: 4770 bx lr + 800a420: 40021000 .word 0x40021000 + +0800a424 : + CLEAR_BIT(RCC->CR, RCC_CR_MSIPLLEN) ; + 800a424: 4a02 ldr r2, [pc, #8] ; (800a430 ) + 800a426: 6813 ldr r3, [r2, #0] + 800a428: f023 0304 bic.w r3, r3, #4 + 800a42c: 6013 str r3, [r2, #0] +} + 800a42e: 4770 bx lr + 800a430: 40021000 .word 0x40021000 + +0800a434 : + MODIFY_REG(RCC->DLYCFGR, RCC_DLYCFGR_OCTOSPI1_DLY|RCC_DLYCFGR_OCTOSPI2_DLY, (Delay1 | (Delay2 << RCC_DLYCFGR_OCTOSPI2_DLY_Pos))) ; + 800a434: 4a05 ldr r2, [pc, #20] ; (800a44c ) + 800a436: f8d2 30a4 ldr.w r3, [r2, #164] ; 0xa4 + 800a43a: f023 03ff bic.w r3, r3, #255 ; 0xff + 800a43e: 4318 orrs r0, r3 + 800a440: ea40 1101 orr.w r1, r0, r1, lsl #4 + 800a444: f8c2 10a4 str.w r1, [r2, #164] ; 0xa4 +} + 800a448: 4770 bx lr + 800a44a: bf00 nop + 800a44c: 40021000 .word 0x40021000 + +0800a450 : + __HAL_RCC_CRS_FORCE_RESET(); + 800a450: 4b10 ldr r3, [pc, #64] ; (800a494 ) + 800a452: 6b9a ldr r2, [r3, #56] ; 0x38 + 800a454: f042 7280 orr.w r2, r2, #16777216 ; 0x1000000 + 800a458: 639a str r2, [r3, #56] ; 0x38 + __HAL_RCC_CRS_RELEASE_RESET(); + 800a45a: 6b9a ldr r2, [r3, #56] ; 0x38 + 800a45c: f022 7280 bic.w r2, r2, #16777216 ; 0x1000000 + 800a460: 639a str r2, [r3, #56] ; 0x38 + value = (pInit->Prescaler | pInit->Source | pInit->Polarity); + 800a462: e9d0 3200 ldrd r3, r2, [r0] + 800a466: 4313 orrs r3, r2 + 800a468: 6882 ldr r2, [r0, #8] + 800a46a: 4313 orrs r3, r2 + value |= pInit->ReloadValue; + 800a46c: 68c2 ldr r2, [r0, #12] + 800a46e: 4313 orrs r3, r2 + value |= (pInit->ErrorLimitValue << CRS_CFGR_FELIM_Pos); + 800a470: 6902 ldr r2, [r0, #16] + 800a472: ea43 4302 orr.w r3, r3, r2, lsl #16 + WRITE_REG(CRS->CFGR, value); + 800a476: 4a08 ldr r2, [pc, #32] ; (800a498 ) + 800a478: 6053 str r3, [r2, #4] + MODIFY_REG(CRS->CR, CRS_CR_TRIM, (pInit->HSI48CalibrationValue << CRS_CR_TRIM_Pos)); + 800a47a: 6813 ldr r3, [r2, #0] + 800a47c: 6941 ldr r1, [r0, #20] + 800a47e: f423 537c bic.w r3, r3, #16128 ; 0x3f00 + 800a482: ea43 2301 orr.w r3, r3, r1, lsl #8 + 800a486: 6013 str r3, [r2, #0] + SET_BIT(CRS->CR, CRS_CR_AUTOTRIMEN | CRS_CR_CEN); + 800a488: 6813 ldr r3, [r2, #0] + 800a48a: f043 0360 orr.w r3, r3, #96 ; 0x60 + 800a48e: 6013 str r3, [r2, #0] +} + 800a490: 4770 bx lr + 800a492: bf00 nop + 800a494: 40021000 .word 0x40021000 + 800a498: 40006000 .word 0x40006000 + +0800a49c : + SET_BIT(CRS->CR, CRS_CR_SWSYNC); + 800a49c: 4a02 ldr r2, [pc, #8] ; (800a4a8 ) + 800a49e: 6813 ldr r3, [r2, #0] + 800a4a0: f043 0380 orr.w r3, r3, #128 ; 0x80 + 800a4a4: 6013 str r3, [r2, #0] +} + 800a4a6: 4770 bx lr + 800a4a8: 40006000 .word 0x40006000 + +0800a4ac : + pSynchroInfo->ReloadValue = (READ_BIT(CRS->CFGR, CRS_CFGR_RELOAD)); + 800a4ac: 4b07 ldr r3, [pc, #28] ; (800a4cc ) + 800a4ae: 685a ldr r2, [r3, #4] + 800a4b0: b292 uxth r2, r2 + 800a4b2: 6002 str r2, [r0, #0] + pSynchroInfo->HSI48CalibrationValue = (READ_BIT(CRS->CR, CRS_CR_TRIM) >> CRS_CR_TRIM_Pos); + 800a4b4: 681a ldr r2, [r3, #0] + 800a4b6: f3c2 2205 ubfx r2, r2, #8, #6 + 800a4ba: 6042 str r2, [r0, #4] + pSynchroInfo->FreqErrorCapture = (READ_BIT(CRS->ISR, CRS_ISR_FECAP) >> CRS_ISR_FECAP_Pos); + 800a4bc: 689a ldr r2, [r3, #8] + 800a4be: 0c12 lsrs r2, r2, #16 + 800a4c0: 6082 str r2, [r0, #8] + pSynchroInfo->FreqErrorDirection = (READ_BIT(CRS->ISR, CRS_ISR_FEDIR)); + 800a4c2: 689b ldr r3, [r3, #8] + 800a4c4: f403 4300 and.w r3, r3, #32768 ; 0x8000 + 800a4c8: 60c3 str r3, [r0, #12] +} + 800a4ca: 4770 bx lr + 800a4cc: 40006000 .word 0x40006000 + +0800a4d0 : +{ + 800a4d0: b5f8 push {r3, r4, r5, r6, r7, lr} + 800a4d2: 4605 mov r5, r0 + tickstart = HAL_GetTick(); + 800a4d4: f7fc ff82 bl 80073dc + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_SYNCOK)) + 800a4d8: 4c1e ldr r4, [pc, #120] ; (800a554 ) + tickstart = HAL_GetTick(); + 800a4da: 4606 mov r6, r0 + __HAL_RCC_CRS_CLEAR_FLAG(RCC_CRS_FLAG_SYNCOK); + 800a4dc: 2701 movs r7, #1 + if(Timeout != HAL_MAX_DELAY) + 800a4de: 1c68 adds r0, r5, #1 + 800a4e0: d12f bne.n 800a542 + crsstatus = RCC_CRS_TIMEOUT; + 800a4e2: 2000 movs r0, #0 + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_SYNCOK)) + 800a4e4: 68a2 ldr r2, [r4, #8] + 800a4e6: 07d1 lsls r1, r2, #31 + __HAL_RCC_CRS_CLEAR_FLAG(RCC_CRS_FLAG_SYNCOK); + 800a4e8: bf48 it mi + 800a4ea: 60e7 strmi r7, [r4, #12] + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_SYNCWARN)) + 800a4ec: 68a2 ldr r2, [r4, #8] + crsstatus |= RCC_CRS_SYNCOK; + 800a4ee: bf48 it mi + 800a4f0: f040 0002 orrmi.w r0, r0, #2 + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_SYNCWARN)) + 800a4f4: 0792 lsls r2, r2, #30 + __HAL_RCC_CRS_CLEAR_FLAG(RCC_CRS_FLAG_SYNCWARN); + 800a4f6: bf44 itt mi + 800a4f8: 2202 movmi r2, #2 + 800a4fa: 60e2 strmi r2, [r4, #12] + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_TRIMOVF)) + 800a4fc: 68a2 ldr r2, [r4, #8] + crsstatus |= RCC_CRS_SYNCWARN; + 800a4fe: bf48 it mi + 800a500: f040 0004 orrmi.w r0, r0, #4 + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_TRIMOVF)) + 800a504: 0553 lsls r3, r2, #21 + __HAL_RCC_CRS_CLEAR_FLAG(RCC_CRS_FLAG_TRIMOVF); + 800a506: bf44 itt mi + 800a508: 2204 movmi r2, #4 + 800a50a: 60e2 strmi r2, [r4, #12] + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_SYNCERR)) + 800a50c: 68a2 ldr r2, [r4, #8] + crsstatus |= RCC_CRS_TRIMOVF; + 800a50e: bf48 it mi + 800a510: f040 0020 orrmi.w r0, r0, #32 + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_SYNCERR)) + 800a514: 05d1 lsls r1, r2, #23 + __HAL_RCC_CRS_CLEAR_FLAG(RCC_CRS_FLAG_SYNCERR); + 800a516: bf44 itt mi + 800a518: 2204 movmi r2, #4 + 800a51a: 60e2 strmi r2, [r4, #12] + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_SYNCMISS)) + 800a51c: 68a2 ldr r2, [r4, #8] + crsstatus |= RCC_CRS_SYNCERR; + 800a51e: bf48 it mi + 800a520: f040 0008 orrmi.w r0, r0, #8 + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_SYNCMISS)) + 800a524: 0592 lsls r2, r2, #22 + __HAL_RCC_CRS_CLEAR_FLAG(RCC_CRS_FLAG_SYNCMISS); + 800a526: bf44 itt mi + 800a528: 2204 movmi r2, #4 + 800a52a: 60e2 strmi r2, [r4, #12] + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_ESYNC)) + 800a52c: 68a2 ldr r2, [r4, #8] + crsstatus |= RCC_CRS_SYNCMISS; + 800a52e: bf48 it mi + 800a530: f040 0010 orrmi.w r0, r0, #16 + if(__HAL_RCC_CRS_GET_FLAG(RCC_CRS_FLAG_ESYNC)) + 800a534: 0713 lsls r3, r2, #28 + __HAL_RCC_CRS_CLEAR_FLAG(RCC_CRS_FLAG_ESYNC); + 800a536: bf44 itt mi + 800a538: 2208 movmi r2, #8 + 800a53a: 60e2 strmi r2, [r4, #12] + } while(RCC_CRS_NONE == crsstatus); + 800a53c: 2800 cmp r0, #0 + 800a53e: d0ce beq.n 800a4de +} + 800a540: bdf8 pop {r3, r4, r5, r6, r7, pc} + if(((HAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U)) + 800a542: f7fc ff4b bl 80073dc + 800a546: 1b80 subs r0, r0, r6 + 800a548: 42a8 cmp r0, r5 + 800a54a: d801 bhi.n 800a550 + 800a54c: 2d00 cmp r5, #0 + 800a54e: d1c8 bne.n 800a4e2 + crsstatus = RCC_CRS_TIMEOUT; + 800a550: 2001 movs r0, #1 + 800a552: e7c7 b.n 800a4e4 + 800a554: 40006000 .word 0x40006000 + +0800a558 : + 800a558: 4770 bx lr + +0800a55a : + 800a55a: 4770 bx lr + +0800a55c : + 800a55c: 4770 bx lr + +0800a55e : +} + 800a55e: 4770 bx lr + +0800a560 : + uint32_t itflags = READ_REG(CRS->ISR); + 800a560: 491b ldr r1, [pc, #108] ; (800a5d0 ) +{ + 800a562: b508 push {r3, lr} + uint32_t itflags = READ_REG(CRS->ISR); + 800a564: 688b ldr r3, [r1, #8] + uint32_t itsources = READ_REG(CRS->CR); + 800a566: 680a ldr r2, [r1, #0] + if(((itflags & RCC_CRS_FLAG_SYNCOK) != 0U) && ((itsources & RCC_CRS_IT_SYNCOK) != 0U)) + 800a568: 07d8 lsls r0, r3, #31 + 800a56a: d506 bpl.n 800a57a + 800a56c: 07d0 lsls r0, r2, #31 + 800a56e: d504 bpl.n 800a57a + WRITE_REG(CRS->ICR, CRS_ICR_SYNCOKC); + 800a570: 2301 movs r3, #1 + 800a572: 60cb str r3, [r1, #12] + HAL_RCCEx_CRS_SyncOkCallback(); + 800a574: f7ff fff0 bl 800a558 +} + 800a578: bd08 pop {r3, pc} + else if(((itflags & RCC_CRS_FLAG_SYNCWARN) != 0U) && ((itsources & RCC_CRS_IT_SYNCWARN) != 0U)) + 800a57a: 0798 lsls r0, r3, #30 + 800a57c: d507 bpl.n 800a58e + 800a57e: 0791 lsls r1, r2, #30 + 800a580: d505 bpl.n 800a58e + WRITE_REG(CRS->ICR, CRS_ICR_SYNCWARNC); + 800a582: 4b13 ldr r3, [pc, #76] ; (800a5d0 ) + 800a584: 2202 movs r2, #2 + 800a586: 60da str r2, [r3, #12] + HAL_RCCEx_CRS_SyncWarnCallback(); + 800a588: f7ff ffe7 bl 800a55a + 800a58c: e7f4 b.n 800a578 + else if(((itflags & RCC_CRS_FLAG_ESYNC) != 0U) && ((itsources & RCC_CRS_IT_ESYNC) != 0U)) + 800a58e: 0718 lsls r0, r3, #28 + 800a590: d507 bpl.n 800a5a2 + 800a592: 0711 lsls r1, r2, #28 + 800a594: d505 bpl.n 800a5a2 + WRITE_REG(CRS->ICR, CRS_ICR_ESYNCC); + 800a596: 4b0e ldr r3, [pc, #56] ; (800a5d0 ) + 800a598: 2208 movs r2, #8 + 800a59a: 60da str r2, [r3, #12] + HAL_RCCEx_CRS_ExpectedSyncCallback(); + 800a59c: f7ff ffde bl 800a55c + 800a5a0: e7ea b.n 800a578 + if(((itflags & RCC_CRS_FLAG_ERR) != 0U) && ((itsources & RCC_CRS_IT_ERR) != 0U)) + 800a5a2: 0758 lsls r0, r3, #29 + 800a5a4: d5e8 bpl.n 800a578 + 800a5a6: 0751 lsls r1, r2, #29 + 800a5a8: d5e6 bpl.n 800a578 + crserror |= RCC_CRS_SYNCERR; + 800a5aa: f413 7080 ands.w r0, r3, #256 ; 0x100 + 800a5ae: bf18 it ne + 800a5b0: 2008 movne r0, #8 + if((itflags & RCC_CRS_FLAG_SYNCMISS) != 0U) + 800a5b2: 059a lsls r2, r3, #22 + crserror |= RCC_CRS_SYNCMISS; + 800a5b4: bf48 it mi + 800a5b6: f040 0010 orrmi.w r0, r0, #16 + if((itflags & RCC_CRS_FLAG_TRIMOVF) != 0U) + 800a5ba: 055b lsls r3, r3, #21 + WRITE_REG(CRS->ICR, CRS_ICR_ERRC); + 800a5bc: 4b04 ldr r3, [pc, #16] ; (800a5d0 ) + 800a5be: f04f 0204 mov.w r2, #4 + crserror |= RCC_CRS_TRIMOVF; + 800a5c2: bf48 it mi + 800a5c4: f040 0020 orrmi.w r0, r0, #32 + WRITE_REG(CRS->ICR, CRS_ICR_ERRC); + 800a5c8: 60da str r2, [r3, #12] + HAL_RCCEx_CRS_ErrorCallback(crserror); + 800a5ca: f7ff ffc8 bl 800a55e +} + 800a5ce: e7d3 b.n 800a578 + 800a5d0: 40006000 .word 0x40006000 + +0800a5d4 : + * processing is suspended when possible and the Peripheral feeding point reached at + * suspension time is stored in the handle for resumption later on. + * @retval HAL status + */ +static HAL_StatusTypeDef HASH_WriteData(HASH_HandleTypeDef *hhash, uint8_t *pInBuffer, uint32_t Size) +{ + 800a5d4: b573 push {r0, r1, r4, r5, r6, lr} + __IO uint32_t inputaddr = (uint32_t) pInBuffer; + + for(buffercounter = 0U; buffercounter < Size; buffercounter+=4U) + { + /* Write input data 4 bytes at a time */ + HASH->DIN = *(uint32_t*)inputaddr; + 800a5d6: 4d1e ldr r5, [pc, #120] ; (800a650 ) + __IO uint32_t inputaddr = (uint32_t) pInBuffer; + 800a5d8: 9101 str r1, [sp, #4] +{ + 800a5da: 4604 mov r4, r0 + for(buffercounter = 0U; buffercounter < Size; buffercounter+=4U) + 800a5dc: 2100 movs r1, #0 + 800a5de: 4291 cmp r1, r2 + 800a5e0: d221 bcs.n 800a626 + HASH->DIN = *(uint32_t*)inputaddr; + 800a5e2: 9b01 ldr r3, [sp, #4] + 800a5e4: 681b ldr r3, [r3, #0] + 800a5e6: 606b str r3, [r5, #4] + inputaddr+=4U; + 800a5e8: 9b01 ldr r3, [sp, #4] + + /* If the suspension flag has been raised and if the processing is not about + to end, suspend processing */ + if ((hhash->SuspendRequest == HAL_HASH_SUSPEND) && ((buffercounter+4U) < Size)) + 800a5ea: f894 0036 ldrb.w r0, [r4, #54] ; 0x36 + inputaddr+=4U; + 800a5ee: 3304 adds r3, #4 + if ((hhash->SuspendRequest == HAL_HASH_SUSPEND) && ((buffercounter+4U) < Size)) + 800a5f0: 2801 cmp r0, #1 + inputaddr+=4U; + 800a5f2: 9301 str r3, [sp, #4] + if ((hhash->SuspendRequest == HAL_HASH_SUSPEND) && ((buffercounter+4U) < Size)) + 800a5f4: f101 0304 add.w r3, r1, #4 + 800a5f8: d127 bne.n 800a64a + 800a5fa: 4293 cmp r3, r2 + 800a5fc: d225 bcs.n 800a64a + { + /* Wait for DINIS = 1, which occurs when 16 32-bit locations are free + in the input buffer */ + if (__HAL_HASH_GET_FLAG(HASH_FLAG_DINIS)) + 800a5fe: 6a6e ldr r6, [r5, #36] ; 0x24 + 800a600: 07f6 lsls r6, r6, #31 + 800a602: d522 bpl.n 800a64a + /* Reset SuspendRequest */ + hhash->SuspendRequest = HAL_HASH_SUSPEND_NONE; + + /* Depending whether the key or the input data were fed to the Peripheral, the feeding point + reached at suspension time is not saved in the same handle fields */ + if ((hhash->Phase == HAL_HASH_PHASE_PROCESS) || (hhash->Phase == HAL_HASH_PHASE_HMAC_STEP_2)) + 800a604: f894 302d ldrb.w r3, [r4, #45] ; 0x2d + hhash->SuspendRequest = HAL_HASH_SUSPEND_NONE; + 800a608: 2500 movs r5, #0 + if ((hhash->Phase == HAL_HASH_PHASE_PROCESS) || (hhash->Phase == HAL_HASH_PHASE_HMAC_STEP_2)) + 800a60a: 2b02 cmp r3, #2 + hhash->SuspendRequest = HAL_HASH_SUSPEND_NONE; + 800a60c: f884 5036 strb.w r5, [r4, #54] ; 0x36 + if ((hhash->Phase == HAL_HASH_PHASE_PROCESS) || (hhash->Phase == HAL_HASH_PHASE_HMAC_STEP_2)) + 800a610: d001 beq.n 800a616 + 800a612: 2b04 cmp r3, #4 + 800a614: d109 bne.n 800a62a + { + /* Save current reading and writing locations of Input and Output buffers */ + hhash->pHashInBuffPtr = (uint8_t *)inputaddr; + /* Save the number of bytes that remain to be processed at this point */ + hhash->HashInCount = Size - (buffercounter + 4U); + 800a616: 3a04 subs r2, #4 + hhash->pHashInBuffPtr = (uint8_t *)inputaddr; + 800a618: 9b01 ldr r3, [sp, #4] + 800a61a: 60e3 str r3, [r4, #12] + hhash->HashInCount = Size - (buffercounter + 4U); + 800a61c: 1a52 subs r2, r2, r1 + 800a61e: 6222 str r2, [r4, #32] + __HAL_UNLOCK(hhash); + return HAL_ERROR; + } + + /* Set the HASH state to Suspended and exit to stop entering data */ + hhash->State = HAL_HASH_STATE_SUSPENDED; + 800a620: 2308 movs r3, #8 + 800a622: f884 3035 strb.w r3, [r4, #53] ; 0x35 + } /* if (__HAL_HASH_GET_FLAG(HASH_FLAG_DINIS)) */ + } /* if ((hhash->SuspendRequest == HAL_HASH_SUSPEND) && ((buffercounter+4) < Size)) */ + } /* for(buffercounter = 0; buffercounter < Size; buffercounter+=4) */ + + /* At this point, all the data have been entered to the Peripheral: exit */ + return HAL_OK; + 800a626: 2000 movs r0, #0 + 800a628: e00d b.n 800a646 + else if ((hhash->Phase == HAL_HASH_PHASE_HMAC_STEP_1) || (hhash->Phase == HAL_HASH_PHASE_HMAC_STEP_3)) + 800a62a: 2b03 cmp r3, #3 + 800a62c: d001 beq.n 800a632 + 800a62e: 2b05 cmp r3, #5 + 800a630: d105 bne.n 800a63e + hhash->HashKeyCount = Size - (buffercounter + 4U); + 800a632: 3a04 subs r2, #4 + hhash->pHashKeyBuffPtr = (uint8_t *)inputaddr; + 800a634: 9b01 ldr r3, [sp, #4] + 800a636: 6163 str r3, [r4, #20] + hhash->HashKeyCount = Size - (buffercounter + 4U); + 800a638: 1a52 subs r2, r2, r1 + 800a63a: 62a2 str r2, [r4, #40] ; 0x28 + 800a63c: e7f0 b.n 800a620 + hhash->State = HAL_HASH_STATE_READY; + 800a63e: f884 0035 strb.w r0, [r4, #53] ; 0x35 + __HAL_UNLOCK(hhash); + 800a642: f884 5034 strb.w r5, [r4, #52] ; 0x34 +} + 800a646: b002 add sp, #8 + 800a648: bd70 pop {r4, r5, r6, pc} + 800a64a: 4619 mov r1, r3 + 800a64c: e7c7 b.n 800a5de + 800a64e: bf00 nop + 800a650: 50060400 .word 0x50060400 + +0800a654 : + */ +static void HASH_GetDigest(uint8_t *pMsgDigest, uint8_t Size) +{ + uint32_t msgdigest = (uint32_t)pMsgDigest; + + switch(Size) + 800a654: 291c cmp r1, #28 + 800a656: d027 beq.n 800a6a8 + 800a658: d804 bhi.n 800a664 + 800a65a: 2910 cmp r1, #16 + 800a65c: d005 beq.n 800a66a + 800a65e: 2914 cmp r1, #20 + 800a660: d011 beq.n 800a686 + 800a662: 4770 bx lr + 800a664: 2920 cmp r1, #32 + 800a666: d037 beq.n 800a6d8 + 800a668: 4770 bx lr + { + /* Read the message digest */ + case 16: /* MD5 */ + *(uint32_t*)(msgdigest) = __REV(HASH->HR[0]); + 800a66a: 4b29 ldr r3, [pc, #164] ; (800a710 ) + 800a66c: 68da ldr r2, [r3, #12] + \return Reversed value + */ +__STATIC_FORCEINLINE uint32_t __REV(uint32_t value) +{ +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) + return __builtin_bswap32(value); + 800a66e: ba12 rev r2, r2 + 800a670: 6002 str r2, [r0, #0] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[1]); + 800a672: 691a ldr r2, [r3, #16] + 800a674: ba12 rev r2, r2 + 800a676: 6042 str r2, [r0, #4] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[2]); + 800a678: 695a ldr r2, [r3, #20] + 800a67a: ba12 rev r2, r2 + 800a67c: 6082 str r2, [r0, #8] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[3]); + 800a67e: 699b ldr r3, [r3, #24] + 800a680: ba1b rev r3, r3 + 800a682: 60c3 str r3, [r0, #12] + break; + 800a684: 4770 bx lr + case 20: /* SHA1 */ + *(uint32_t*)(msgdigest) = __REV(HASH->HR[0]); + 800a686: 4b22 ldr r3, [pc, #136] ; (800a710 ) + 800a688: 68da ldr r2, [r3, #12] + 800a68a: ba12 rev r2, r2 + 800a68c: 6002 str r2, [r0, #0] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[1]); + 800a68e: 691a ldr r2, [r3, #16] + 800a690: ba12 rev r2, r2 + 800a692: 6042 str r2, [r0, #4] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[2]); + 800a694: 695a ldr r2, [r3, #20] + 800a696: ba12 rev r2, r2 + 800a698: 6082 str r2, [r0, #8] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[3]); + 800a69a: 699a ldr r2, [r3, #24] + 800a69c: ba12 rev r2, r2 + 800a69e: 60c2 str r2, [r0, #12] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[4]); + 800a6a0: 69db ldr r3, [r3, #28] + 800a6a2: ba1b rev r3, r3 + 800a6a4: 6103 str r3, [r0, #16] + break; + 800a6a6: 4770 bx lr + case 28: /* SHA224 */ + *(uint32_t*)(msgdigest) = __REV(HASH->HR[0]); + 800a6a8: 4b19 ldr r3, [pc, #100] ; (800a710 ) + 800a6aa: 68da ldr r2, [r3, #12] + 800a6ac: ba12 rev r2, r2 + 800a6ae: 6002 str r2, [r0, #0] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[1]); + 800a6b0: 691a ldr r2, [r3, #16] + 800a6b2: ba12 rev r2, r2 + 800a6b4: 6042 str r2, [r0, #4] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[2]); + 800a6b6: 695a ldr r2, [r3, #20] + 800a6b8: ba12 rev r2, r2 + 800a6ba: 6082 str r2, [r0, #8] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[3]); + 800a6bc: 699a ldr r2, [r3, #24] + 800a6be: ba12 rev r2, r2 + 800a6c0: 60c2 str r2, [r0, #12] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[4]); + 800a6c2: 69db ldr r3, [r3, #28] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH_DIGEST->HR[5]); + 800a6c4: 4a13 ldr r2, [pc, #76] ; (800a714 ) + 800a6c6: ba1b rev r3, r3 + *(uint32_t*)(msgdigest) = __REV(HASH->HR[4]); + 800a6c8: 6103 str r3, [r0, #16] + *(uint32_t*)(msgdigest) = __REV(HASH_DIGEST->HR[5]); + 800a6ca: 6a53 ldr r3, [r2, #36] ; 0x24 + 800a6cc: ba1b rev r3, r3 + 800a6ce: 6143 str r3, [r0, #20] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH_DIGEST->HR[6]); + 800a6d0: 6a93 ldr r3, [r2, #40] ; 0x28 + 800a6d2: ba1b rev r3, r3 + 800a6d4: 6183 str r3, [r0, #24] + break; + 800a6d6: 4770 bx lr + case 32: /* SHA256 */ + *(uint32_t*)(msgdigest) = __REV(HASH->HR[0]); + 800a6d8: 4b0d ldr r3, [pc, #52] ; (800a710 ) + 800a6da: 68da ldr r2, [r3, #12] + 800a6dc: ba12 rev r2, r2 + 800a6de: 6002 str r2, [r0, #0] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[1]); + 800a6e0: 691a ldr r2, [r3, #16] + 800a6e2: ba12 rev r2, r2 + 800a6e4: 6042 str r2, [r0, #4] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[2]); + 800a6e6: 695a ldr r2, [r3, #20] + 800a6e8: ba12 rev r2, r2 + 800a6ea: 6082 str r2, [r0, #8] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[3]); + 800a6ec: 699a ldr r2, [r3, #24] + 800a6ee: ba12 rev r2, r2 + 800a6f0: 60c2 str r2, [r0, #12] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH->HR[4]); + 800a6f2: 69db ldr r3, [r3, #28] + 800a6f4: ba1b rev r3, r3 + 800a6f6: 6103 str r3, [r0, #16] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH_DIGEST->HR[5]); + 800a6f8: 4b06 ldr r3, [pc, #24] ; (800a714 ) + 800a6fa: 6a5a ldr r2, [r3, #36] ; 0x24 + 800a6fc: ba12 rev r2, r2 + 800a6fe: 6142 str r2, [r0, #20] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH_DIGEST->HR[6]); + 800a700: 6a9a ldr r2, [r3, #40] ; 0x28 + 800a702: ba12 rev r2, r2 + 800a704: 6182 str r2, [r0, #24] + msgdigest+=4U; + *(uint32_t*)(msgdigest) = __REV(HASH_DIGEST->HR[7]); + 800a706: 6adb ldr r3, [r3, #44] ; 0x2c + 800a708: ba1b rev r3, r3 + 800a70a: 61c3 str r3, [r0, #28] + break; + default: + break; + } +} + 800a70c: 4770 bx lr + 800a70e: bf00 nop + 800a710: 50060400 .word 0x50060400 + 800a714: 50060700 .word 0x50060700 + +0800a718 : + * @param Status the Flag status (SET or RESET). + * @param Timeout Timeout duration. + * @retval HAL status + */ +static HAL_StatusTypeDef HASH_WaitOnFlagUntilTimeout(HASH_HandleTypeDef *hhash, uint32_t Flag, FlagStatus Status, uint32_t Timeout) +{ + 800a718: e92d 43f8 stmdb sp!, {r3, r4, r5, r6, r7, r8, r9, lr} + 800a71c: 4604 mov r4, r0 + 800a71e: 460e mov r6, r1 + 800a720: 4691 mov r9, r2 + 800a722: 461d mov r5, r3 + uint32_t tickstart = HAL_GetTick(); + 800a724: f7fc fe5a bl 80073dc + 800a728: f8df 805c ldr.w r8, [pc, #92] ; 800a788 + 800a72c: 4607 mov r7, r0 + + /* Wait until flag is set */ + if(Status == RESET) + 800a72e: f1b9 0f00 cmp.w r9, #0 + 800a732: d021 beq.n 800a778 + } + } + } + else + { + while(__HAL_HASH_GET_FLAG(Flag) != RESET) + 800a734: f8d8 3024 ldr.w r3, [r8, #36] ; 0x24 + 800a738: ea36 0303 bics.w r3, r6, r3 + 800a73c: d121 bne.n 800a782 + { + /* Check for the Timeout */ + if(Timeout != HAL_MAX_DELAY) + 800a73e: 1c6b adds r3, r5, #1 + 800a740: d0f8 beq.n 800a734 + { + if(((HAL_GetTick()-tickstart) > Timeout) || (Timeout == 0U)) + 800a742: f7fc fe4b bl 80073dc + 800a746: 1bc0 subs r0, r0, r7 + 800a748: 42a8 cmp r0, r5 + 800a74a: d80a bhi.n 800a762 + 800a74c: 2d00 cmp r5, #0 + 800a74e: d1f1 bne.n 800a734 + 800a750: e007 b.n 800a762 + if(Timeout != HAL_MAX_DELAY) + 800a752: 1c6a adds r2, r5, #1 + 800a754: d010 beq.n 800a778 + if(((HAL_GetTick()-tickstart) > Timeout) || (Timeout == 0U)) + 800a756: f7fc fe41 bl 80073dc + 800a75a: 1bc0 subs r0, r0, r7 + 800a75c: 42a8 cmp r0, r5 + 800a75e: d800 bhi.n 800a762 + 800a760: b955 cbnz r5, 800a778 + { + /* Set State to Ready to be able to restart later on */ + hhash->State = HAL_HASH_STATE_READY; + 800a762: 2301 movs r3, #1 + 800a764: f884 3035 strb.w r3, [r4, #53] ; 0x35 + /* Store time out issue in handle status */ + hhash->Status = HAL_TIMEOUT; + + /* Process Unlocked */ + __HAL_UNLOCK(hhash); + 800a768: 2200 movs r2, #0 + hhash->Status = HAL_TIMEOUT; + 800a76a: 2303 movs r3, #3 + 800a76c: f884 302c strb.w r3, [r4, #44] ; 0x2c + __HAL_UNLOCK(hhash); + 800a770: f884 2034 strb.w r2, [r4, #52] ; 0x34 + + return HAL_TIMEOUT; + 800a774: 4618 mov r0, r3 + 800a776: e005 b.n 800a784 + while(__HAL_HASH_GET_FLAG(Flag) == RESET) + 800a778: f8d8 3024 ldr.w r3, [r8, #36] ; 0x24 + 800a77c: ea36 0303 bics.w r3, r6, r3 + 800a780: d1e7 bne.n 800a752 + } + } + } + } + return HAL_OK; + 800a782: 2000 movs r0, #0 +} + 800a784: e8bd 83f8 ldmia.w sp!, {r3, r4, r5, r6, r7, r8, r9, pc} + 800a788: 50060400 .word 0x50060400 + +0800a78c : +} + 800a78c: 4770 bx lr + ... + +0800a790 : +{ + 800a790: b538 push {r3, r4, r5, lr} + if(hhash == NULL) + 800a792: 4604 mov r4, r0 + 800a794: b328 cbz r0, 800a7e2 + if(hhash->State == HAL_HASH_STATE_RESET) + 800a796: f890 3035 ldrb.w r3, [r0, #53] ; 0x35 + 800a79a: f003 02ff and.w r2, r3, #255 ; 0xff + 800a79e: b91b cbnz r3, 800a7a8 + hhash->Lock = HAL_UNLOCKED; + 800a7a0: f880 2034 strb.w r2, [r0, #52] ; 0x34 + HAL_HASH_MspInit(hhash); + 800a7a4: f7ff fff2 bl 800a78c + hhash->HashInCount = 0; + 800a7a8: 2000 movs r0, #0 + MODIFY_REG(HASH->CR, HASH_CR_DATATYPE, hhash->Init.DataType); + 800a7aa: 4a0f ldr r2, [pc, #60] ; (800a7e8 ) + hhash->HashBuffSize = 0; + 800a7ac: 61e0 str r0, [r4, #28] + hhash->State = HAL_HASH_STATE_BUSY; + 800a7ae: 2302 movs r3, #2 + hhash->Phase = HAL_HASH_PHASE_READY; + 800a7b0: 2101 movs r1, #1 + hhash->State = HAL_HASH_STATE_BUSY; + 800a7b2: f884 3035 strb.w r3, [r4, #53] ; 0x35 + hhash->Phase = HAL_HASH_PHASE_READY; + 800a7b6: f884 102d strb.w r1, [r4, #45] ; 0x2d + hhash->HashInCount = 0; + 800a7ba: 6220 str r0, [r4, #32] + hhash->SuspendRequest = HAL_HASH_SUSPEND_NONE; + 800a7bc: 86e0 strh r0, [r4, #54] ; 0x36 + hhash->HashITCounter = 0; + 800a7be: 6260 str r0, [r4, #36] ; 0x24 + hhash->NbWordsAlreadyPushed = 0; + 800a7c0: 63a0 str r0, [r4, #56] ; 0x38 + MODIFY_REG(HASH->CR, HASH_CR_DATATYPE, hhash->Init.DataType); + 800a7c2: 6813 ldr r3, [r2, #0] + 800a7c4: 6825 ldr r5, [r4, #0] + 800a7c6: f023 0330 bic.w r3, r3, #48 ; 0x30 + 800a7ca: 432b orrs r3, r5 + 800a7cc: 6013 str r3, [r2, #0] +__HAL_HASH_RESET_MDMAT(); + 800a7ce: 6813 ldr r3, [r2, #0] + 800a7d0: f423 5300 bic.w r3, r3, #8192 ; 0x2000 + 800a7d4: 6013 str r3, [r2, #0] + hhash->State = HAL_HASH_STATE_READY; + 800a7d6: f884 1035 strb.w r1, [r4, #53] ; 0x35 + hhash->Status = HAL_OK; + 800a7da: f884 002c strb.w r0, [r4, #44] ; 0x2c + hhash->ErrorCode = HAL_HASH_ERROR_NONE; + 800a7de: 63e0 str r0, [r4, #60] ; 0x3c +} + 800a7e0: bd38 pop {r3, r4, r5, pc} + return HAL_ERROR; + 800a7e2: 2001 movs r0, #1 + 800a7e4: e7fc b.n 800a7e0 + 800a7e6: bf00 nop + 800a7e8: 50060400 .word 0x50060400 + +0800a7ec : + 800a7ec: 4770 bx lr + +0800a7ee : + 800a7ee: 4770 bx lr + +0800a7f0 : + 800a7f0: 4770 bx lr + +0800a7f2 : + 800a7f2: 4770 bx lr + +0800a7f4 : +{ + 800a7f4: b570 push {r4, r5, r6, lr} + * suspension time is stored in the handle for resumption later on. + * @retval HAL status + */ +static HAL_StatusTypeDef HASH_IT(HASH_HandleTypeDef *hhash) +{ + if (hhash->State == HAL_HASH_STATE_BUSY) + 800a7f6: f890 3035 ldrb.w r3, [r0, #53] ; 0x35 + 800a7fa: 2b02 cmp r3, #2 +{ + 800a7fc: 4604 mov r4, r0 + if (hhash->State == HAL_HASH_STATE_BUSY) + 800a7fe: b2da uxtb r2, r3 + 800a800: f040 80e7 bne.w 800a9d2 + { + /* ITCounter must not be equal to 0 at this point. Report an error if this is the case. */ + if(hhash->HashITCounter == 0U) + 800a804: 6a43 ldr r3, [r0, #36] ; 0x24 + 800a806: 4d74 ldr r5, [pc, #464] ; (800a9d8 ) + 800a808: b94b cbnz r3, 800a81e + { + /* Disable Interrupts */ + __HAL_HASH_DISABLE_IT(HASH_IT_DINI|HASH_IT_DCI); + 800a80a: 6a2b ldr r3, [r5, #32] + 800a80c: f023 0303 bic.w r3, r3, #3 + 800a810: 622b str r3, [r5, #32] + /* HASH state set back to Ready to prevent any issue in user code + present in HAL_HASH_ErrorCallback() */ + hhash->State = HAL_HASH_STATE_READY; + 800a812: 2301 movs r3, #1 + 800a814: f880 3035 strb.w r3, [r0, #53] ; 0x35 + hhash->Status = HASH_IT(hhash); + 800a818: f884 302c strb.w r3, [r4, #44] ; 0x2c + if (hhash->Status != HAL_OK) + 800a81c: e099 b.n 800a952 + return HAL_ERROR; + } + else if (hhash->HashITCounter == 1U) + 800a81e: 6a43 ldr r3, [r0, #36] ; 0x24 + 800a820: 2b01 cmp r3, #1 + } + else + { + /* Cruise speed reached, HashITCounter remains equal to 3 until the end of + the HASH processing or the end of the current step for HMAC processing. */ + hhash->HashITCounter = 3U; + 800a822: bf16 itet ne + 800a824: 2303 movne r3, #3 + hhash->HashITCounter = 2U; + 800a826: 6242 streq r2, [r0, #36] ; 0x24 + hhash->HashITCounter = 3U; + 800a828: 6243 strne r3, [r0, #36] ; 0x24 + } + + /* If digest is ready */ + if (__HAL_HASH_GET_FLAG(HASH_FLAG_DCIS)) + 800a82a: 6a6b ldr r3, [r5, #36] ; 0x24 + 800a82c: f013 0302 ands.w r3, r3, #2 + 800a830: d022 beq.n 800a878 + { + /* Read the digest */ + HASH_GetDigest(hhash->pHashOutBuffPtr, HASH_DIGEST_LENGTH()); + 800a832: 682a ldr r2, [r5, #0] + 800a834: 4b69 ldr r3, [pc, #420] ; (800a9dc ) + 800a836: 6900 ldr r0, [r0, #16] + 800a838: 421a tst r2, r3 + 800a83a: d019 beq.n 800a870 + 800a83c: 682a ldr r2, [r5, #0] + 800a83e: 401a ands r2, r3 + 800a840: f5b2 2f80 cmp.w r2, #262144 ; 0x40000 + 800a844: d016 beq.n 800a874 + 800a846: 682a ldr r2, [r5, #0] + 800a848: 4393 bics r3, r2 + 800a84a: bf0c ite eq + 800a84c: 2120 moveq r1, #32 + 800a84e: 2110 movne r1, #16 + 800a850: f7ff ff00 bl 800a654 + + /* Disable Interrupts */ + __HAL_HASH_DISABLE_IT(HASH_IT_DINI|HASH_IT_DCI); + 800a854: 6a2b ldr r3, [r5, #32] + 800a856: f023 0303 bic.w r3, r3, #3 + 800a85a: 622b str r3, [r5, #32] + /* Change the HASH state */ + hhash->State = HAL_HASH_STATE_READY; + 800a85c: 2301 movs r3, #1 + 800a85e: f884 3035 strb.w r3, [r4, #53] ; 0x35 + /* Reset HASH state machine */ + hhash->Phase = HAL_HASH_PHASE_READY; + 800a862: f884 302d strb.w r3, [r4, #45] ; 0x2d + /* Call digest computation complete call back */ +#if (USE_HAL_HASH_REGISTER_CALLBACKS == 1) + hhash->DgstCpltCallback(hhash); +#else + HAL_HASH_DgstCpltCallback(hhash); + 800a866: 4620 mov r0, r4 + 800a868: f7ff ffc2 bl 800a7f0 + hhash->Status = HAL_OK; + 800a86c: 2300 movs r3, #0 + 800a86e: e015 b.n 800a89c + HASH_GetDigest(hhash->pHashOutBuffPtr, HASH_DIGEST_LENGTH()); + 800a870: 2114 movs r1, #20 + 800a872: e7ed b.n 800a850 + 800a874: 211c movs r1, #28 + 800a876: e7eb b.n 800a850 + + return HAL_OK; + } + + /* If Peripheral ready to accept new data */ + if (__HAL_HASH_GET_FLAG(HASH_FLAG_DINIS)) + 800a878: 6a6a ldr r2, [r5, #36] ; 0x24 + 800a87a: 07d2 lsls r2, r2, #31 + 800a87c: d5f6 bpl.n 800a86c + { + + /* If the suspension flag has been raised and if the processing is not about + to end, suspend processing */ + if ( (hhash->HashInCount != 0U) && (hhash->SuspendRequest == HAL_HASH_SUSPEND)) + 800a87e: 6a02 ldr r2, [r0, #32] + 800a880: b17a cbz r2, 800a8a2 + 800a882: f890 2036 ldrb.w r2, [r0, #54] ; 0x36 + 800a886: 2a01 cmp r2, #1 + 800a888: d10b bne.n 800a8a2 + { + /* Disable Interrupts */ + __HAL_HASH_DISABLE_IT(HASH_IT_DINI|HASH_IT_DCI); + 800a88a: 6a2a ldr r2, [r5, #32] + 800a88c: f022 0203 bic.w r2, r2, #3 + 800a890: 622a str r2, [r5, #32] + + /* Reset SuspendRequest */ + hhash->SuspendRequest = HAL_HASH_SUSPEND_NONE; + + /* Change the HASH state */ + hhash->State = HAL_HASH_STATE_SUSPENDED; + 800a892: 2208 movs r2, #8 + hhash->SuspendRequest = HAL_HASH_SUSPEND_NONE; + 800a894: f880 3036 strb.w r3, [r0, #54] ; 0x36 + hhash->State = HAL_HASH_STATE_SUSPENDED; + 800a898: f880 2035 strb.w r2, [r0, #53] ; 0x35 + hhash->Status = HAL_OK; + 800a89c: f884 302c strb.w r3, [r4, #44] ; 0x2c +} + 800a8a0: e076 b.n 800a990 + uint32_t buffercounter; + uint32_t inputcounter; + uint32_t ret = HASH_DIGEST_CALCULATION_NOT_STARTED; + + /* If there are more than 64 bytes remaining to be entered */ + if(hhash->HashInCount > 64U) + 800a8a2: 6a21 ldr r1, [r4, #32] + { + inputaddr = (uint32_t)hhash->pHashInBuffPtr; + 800a8a4: 68e3 ldr r3, [r4, #12] + if(hhash->HashInCount > 64U) + 800a8a6: 2940 cmp r1, #64 ; 0x40 + inputaddr = (uint32_t)hhash->pHashInBuffPtr; + 800a8a8: 461a mov r2, r3 + if(hhash->HashInCount > 64U) + 800a8aa: d91c bls.n 800a8e6 + 800a8ac: f103 0140 add.w r1, r3, #64 ; 0x40 + /* Write the Input block in the Data IN register + (16 32-bit words, or 64 bytes are entered) */ + for(buffercounter = 0U; buffercounter < 64U; buffercounter+=4U) + { + HASH->DIN = *(uint32_t*)inputaddr; + 800a8b0: f853 0b04 ldr.w r0, [r3], #4 + 800a8b4: 6068 str r0, [r5, #4] + for(buffercounter = 0U; buffercounter < 64U; buffercounter+=4U) + 800a8b6: 4299 cmp r1, r3 + 800a8b8: d1fa bne.n 800a8b0 + inputaddr+=4U; + } + /* If this is the start of input data entering, an additional word + must be entered to start up the HASH processing */ + if(hhash->HashITCounter == 2U) + 800a8ba: 6a63 ldr r3, [r4, #36] ; 0x24 + 800a8bc: 2b02 cmp r3, #2 + 800a8be: d10d bne.n 800a8dc + { + HASH->DIN = *(uint32_t*)inputaddr; + 800a8c0: 680b ldr r3, [r1, #0] + 800a8c2: 606b str r3, [r5, #4] + if(hhash->HashInCount >= 68U) + 800a8c4: 6a23 ldr r3, [r4, #32] + 800a8c6: 2b43 cmp r3, #67 ; 0x43 + 800a8c8: d905 bls.n 800a8d6 + { + /* There are still data waiting to be entered in the Peripheral. + Decrement buffer counter and set pointer to the proper + memory location for the next data entering round. */ + hhash->HashInCount -= 68U; + 800a8ca: 6a23 ldr r3, [r4, #32] + 800a8cc: 3b44 subs r3, #68 ; 0x44 + 800a8ce: 6223 str r3, [r4, #32] + hhash->pHashInBuffPtr+= 68U; + 800a8d0: 3244 adds r2, #68 ; 0x44 + { + /* 64 bytes have been entered and there are still some remaining: + Decrement buffer counter and set pointer to the proper + memory location for the next data entering round.*/ + hhash->HashInCount -= 64U; + hhash->pHashInBuffPtr+= 64U; + 800a8d2: 60e2 str r2, [r4, #12] + /* Reset buffer counter */ + hhash->HashInCount = 0; + } + + /* Return whether or digest calculation has started */ + return ret; + 800a8d4: e7ca b.n 800a86c + hhash->HashInCount = 0U; + 800a8d6: 2300 movs r3, #0 + 800a8d8: 6223 str r3, [r4, #32] + return ret; + 800a8da: e7c7 b.n 800a86c + hhash->HashInCount -= 64U; + 800a8dc: 6a23 ldr r3, [r4, #32] + 800a8de: 3b40 subs r3, #64 ; 0x40 + 800a8e0: 6223 str r3, [r4, #32] + hhash->pHashInBuffPtr+= 64U; + 800a8e2: 3240 adds r2, #64 ; 0x40 + 800a8e4: e7f5 b.n 800a8d2 + inputcounter = hhash->HashInCount; + 800a8e6: 6a22 ldr r2, [r4, #32] + __HAL_HASH_DISABLE_IT(HASH_IT_DINI); + 800a8e8: 6a29 ldr r1, [r5, #32] + for(buffercounter = 0U; buffercounter < ((inputcounter+3U)/4U); buffercounter++) + 800a8ea: 3203 adds r2, #3 + __HAL_HASH_DISABLE_IT(HASH_IT_DINI); + 800a8ec: f021 0101 bic.w r1, r1, #1 + 800a8f0: f022 0203 bic.w r2, r2, #3 + 800a8f4: 6229 str r1, [r5, #32] + for(buffercounter = 0U; buffercounter < ((inputcounter+3U)/4U); buffercounter++) + 800a8f6: 441a add r2, r3 + 800a8f8: 4293 cmp r3, r2 + 800a8fa: d10b bne.n 800a914 + if (hhash->Accumulation == 1U) + 800a8fc: 6c23 ldr r3, [r4, #64] ; 0x40 + 800a8fe: 2b01 cmp r3, #1 + 800a900: d10c bne.n 800a91c + hhash->Accumulation = 0U; + 800a902: 2500 movs r5, #0 + 800a904: 6425 str r5, [r4, #64] ; 0x40 + HAL_HASH_InCpltCallback(hhash); + 800a906: 4620 mov r0, r4 + hhash->State = HAL_HASH_STATE_READY; + 800a908: f884 3035 strb.w r3, [r4, #53] ; 0x35 + HAL_HASH_InCpltCallback(hhash); + 800a90c: f7ff ff6f bl 800a7ee + hhash->HashInCount = 0; + 800a910: 6225 str r5, [r4, #32] + return ret; + 800a912: e7ab b.n 800a86c + HASH->DIN = *(uint32_t*)inputaddr; + 800a914: f853 1b04 ldr.w r1, [r3], #4 + 800a918: 6069 str r1, [r5, #4] + for(buffercounter = 0U; buffercounter < ((inputcounter+3U)/4U); buffercounter++) + 800a91a: e7ed b.n 800a8f8 + __HAL_HASH_START_DIGEST(); + 800a91c: 68ab ldr r3, [r5, #8] + 800a91e: f443 7380 orr.w r3, r3, #256 ; 0x100 + 800a922: 60ab str r3, [r5, #8] + hhash->HashInCount = 0; + 800a924: 2300 movs r3, #0 + 800a926: 6223 str r3, [r4, #32] + HAL_HASH_InCpltCallback(hhash); + 800a928: 4620 mov r0, r4 + 800a92a: f7ff ff60 bl 800a7ee + if (hhash->Phase == HAL_HASH_PHASE_HMAC_STEP_1) + 800a92e: f894 602d ldrb.w r6, [r4, #45] ; 0x2d + 800a932: 2e03 cmp r6, #3 + 800a934: d12d bne.n 800a992 + if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_BUSY, SET, HASH_TIMEOUTVALUE) != HAL_OK) + 800a936: f44f 737a mov.w r3, #1000 ; 0x3e8 + 800a93a: 2201 movs r2, #1 + 800a93c: 2108 movs r1, #8 + 800a93e: 4620 mov r0, r4 + 800a940: f7ff feea bl 800a718 + 800a944: b168 cbz r0, 800a962 + __HAL_HASH_DISABLE_IT(HASH_IT_DINI|HASH_IT_DCI); + 800a946: 6a2b ldr r3, [r5, #32] + 800a948: f023 0303 bic.w r3, r3, #3 + 800a94c: 622b str r3, [r5, #32] + hhash->Status = HASH_IT(hhash); + 800a94e: f884 602c strb.w r6, [r4, #44] ; 0x2c + hhash->ErrorCode |= HAL_HASH_ERROR_IT; + 800a952: 6be3 ldr r3, [r4, #60] ; 0x3c + 800a954: f043 0301 orr.w r3, r3, #1 + 800a958: 63e3 str r3, [r4, #60] ; 0x3c + HAL_HASH_ErrorCallback(hhash); + 800a95a: 4620 mov r0, r4 + 800a95c: f7ff ff49 bl 800a7f2 + 800a960: e784 b.n 800a86c + hhash->Phase = HAL_HASH_PHASE_HMAC_STEP_2; /* Move phase from Step 1 to Step 2 */ + 800a962: 2304 movs r3, #4 + 800a964: f884 302d strb.w r3, [r4, #45] ; 0x2d + __HAL_HASH_SET_NBVALIDBITS(hhash->HashBuffSize); /* Set NBLW for the input message */ + 800a968: 68ab ldr r3, [r5, #8] + 800a96a: 69e2 ldr r2, [r4, #28] + 800a96c: f023 031f bic.w r3, r3, #31 + 800a970: f002 0103 and.w r1, r2, #3 + 800a974: ea43 03c1 orr.w r3, r3, r1, lsl #3 + 800a978: 60ab str r3, [r5, #8] + hhash->pHashInBuffPtr = hhash->pHashMsgBuffPtr; /* Set the input data address */ + 800a97a: 69a3 ldr r3, [r4, #24] + hhash->HashInCount = hhash->HashBuffSize; /* Set the input data size (in bytes) */ + 800a97c: 6222 str r2, [r4, #32] + hhash->pHashInBuffPtr = hhash->Init.pKey; /* Set the key address */ + 800a97e: 60e3 str r3, [r4, #12] + hhash->HashITCounter = 1; /* Set ITCounter to 1 to indicate the start of a new phase */ + 800a980: 2301 movs r3, #1 + 800a982: 6263 str r3, [r4, #36] ; 0x24 + __HAL_HASH_ENABLE_IT(HASH_IT_DINI); /* Enable IT (was disabled in HASH_Write_Block_Data) */ + 800a984: 6a2b ldr r3, [r5, #32] + 800a986: f043 0301 orr.w r3, r3, #1 + 800a98a: 622b str r3, [r5, #32] + hhash->Status = HASH_IT(hhash); + 800a98c: f884 002c strb.w r0, [r4, #44] ; 0x2c +} + 800a990: bd70 pop {r4, r5, r6, pc} + else if (hhash->Phase == HAL_HASH_PHASE_HMAC_STEP_2) + 800a992: 2e04 cmp r6, #4 + 800a994: f47f af6a bne.w 800a86c + if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_BUSY, SET, HASH_TIMEOUTVALUE) != HAL_OK) + 800a998: f44f 737a mov.w r3, #1000 ; 0x3e8 + 800a99c: 2201 movs r2, #1 + 800a99e: 2108 movs r1, #8 + 800a9a0: 4620 mov r0, r4 + 800a9a2: f7ff feb9 bl 800a718 + 800a9a6: b128 cbz r0, 800a9b4 + __HAL_HASH_DISABLE_IT(HASH_IT_DINI|HASH_IT_DCI); + 800a9a8: 6a2b ldr r3, [r5, #32] + 800a9aa: f023 0303 bic.w r3, r3, #3 + 800a9ae: 622b str r3, [r5, #32] + hhash->Status = HASH_IT(hhash); + 800a9b0: 2303 movs r3, #3 + 800a9b2: e731 b.n 800a818 + hhash->Phase = HAL_HASH_PHASE_HMAC_STEP_3; /* Move phase from Step 2 to Step 3 */ + 800a9b4: 2305 movs r3, #5 + 800a9b6: f884 302d strb.w r3, [r4, #45] ; 0x2d + __HAL_HASH_SET_NBVALIDBITS(hhash->Init.KeySize); /* Set NBLW for the key */ + 800a9ba: 68ab ldr r3, [r5, #8] + 800a9bc: 6862 ldr r2, [r4, #4] + 800a9be: f023 031f bic.w r3, r3, #31 + 800a9c2: f002 0103 and.w r1, r2, #3 + 800a9c6: ea43 03c1 orr.w r3, r3, r1, lsl #3 + 800a9ca: 60ab str r3, [r5, #8] + hhash->pHashInBuffPtr = hhash->Init.pKey; /* Set the key address */ + 800a9cc: 68a3 ldr r3, [r4, #8] + hhash->HashInCount = hhash->Init.KeySize; /* Set the key size (in bytes) */ + 800a9ce: 6222 str r2, [r4, #32] + hhash->pHashInBuffPtr = hhash->Init.pKey; /* Set the key address */ + 800a9d0: e7d5 b.n 800a97e + hhash->Status = HASH_IT(hhash); + 800a9d2: 2302 movs r3, #2 + 800a9d4: e720 b.n 800a818 + 800a9d6: bf00 nop + 800a9d8: 50060400 .word 0x50060400 + 800a9dc: 00040080 .word 0x00040080 + +0800a9e0 : + return hhash->State; + 800a9e0: f890 0035 ldrb.w r0, [r0, #53] ; 0x35 +} + 800a9e4: 4770 bx lr + +0800a9e6 : +} + 800a9e6: f890 002c ldrb.w r0, [r0, #44] ; 0x2c + 800a9ea: 4770 bx lr + +0800a9ec : + *(uint32_t*)(mem_ptr) = READ_BIT(HASH->IMR,HASH_IT_DINI|HASH_IT_DCI); + 800a9ec: 4b0e ldr r3, [pc, #56] ; (800aa28 ) + 800a9ee: 6a1a ldr r2, [r3, #32] + 800a9f0: f002 0203 and.w r2, r2, #3 + 800a9f4: 600a str r2, [r1, #0] + *(uint32_t*)(mem_ptr) = READ_BIT(HASH->STR,HASH_STR_NBLW); + 800a9f6: 689a ldr r2, [r3, #8] + 800a9f8: f002 021f and.w r2, r2, #31 + 800a9fc: 604a str r2, [r1, #4] + *(uint32_t*)(mem_ptr) = READ_BIT(HASH->CR,HASH_CR_DMAE|HASH_CR_DATATYPE|HASH_CR_MODE|HASH_CR_ALGO|HASH_CR_LKEY|HASH_CR_MDMAT); + 800a9fe: 681b ldr r3, [r3, #0] + for (i = HASH_NUMBER_OF_CSR_REGISTERS; i >0U; i--) + 800aa00: 4a0a ldr r2, [pc, #40] ; (800aa2c ) + *(uint32_t*)(mem_ptr) = READ_BIT(HASH->CR,HASH_CR_DMAE|HASH_CR_DATATYPE|HASH_CR_MODE|HASH_CR_ALGO|HASH_CR_LKEY|HASH_CR_MDMAT); + 800aa02: f023 437f bic.w r3, r3, #4278190080 ; 0xff000000 + 800aa06: f423 037a bic.w r3, r3, #16384000 ; 0xfa0000 + 800aa0a: f423 435f bic.w r3, r3, #57088 ; 0xdf00 + 800aa0e: f023 0307 bic.w r3, r3, #7 + 800aa12: 608b str r3, [r1, #8] + uint32_t csr_ptr = (uint32_t)HASH->CSR; + 800aa14: 4b06 ldr r3, [pc, #24] ; (800aa30 ) + mem_ptr+=4U; + 800aa16: 310c adds r1, #12 + *(uint32_t*)(mem_ptr) = *(uint32_t*)(csr_ptr); + 800aa18: f853 0b04 ldr.w r0, [r3], #4 + 800aa1c: f841 0b04 str.w r0, [r1], #4 + for (i = HASH_NUMBER_OF_CSR_REGISTERS; i >0U; i--) + 800aa20: 4293 cmp r3, r2 + 800aa22: d1f9 bne.n 800aa18 +} + 800aa24: 4770 bx lr + 800aa26: bf00 nop + 800aa28: 50060400 .word 0x50060400 + 800aa2c: 500605d0 .word 0x500605d0 + 800aa30: 500604f8 .word 0x500604f8 + +0800aa34 : + WRITE_REG(HASH->IMR, (*(uint32_t*)(mem_ptr))); + 800aa34: 4b0a ldr r3, [pc, #40] ; (800aa60 ) + 800aa36: 680a ldr r2, [r1, #0] + 800aa38: 621a str r2, [r3, #32] + WRITE_REG(HASH->STR, (*(uint32_t*)(mem_ptr))); + 800aa3a: 684a ldr r2, [r1, #4] + 800aa3c: 609a str r2, [r3, #8] + WRITE_REG(HASH->CR, (*(uint32_t*)(mem_ptr))); + 800aa3e: 688a ldr r2, [r1, #8] + 800aa40: 601a str r2, [r3, #0] + __HAL_HASH_INIT(); + 800aa42: 681a ldr r2, [r3, #0] + 800aa44: f042 0204 orr.w r2, r2, #4 + 800aa48: 601a str r2, [r3, #0] + for (i = HASH_NUMBER_OF_CSR_REGISTERS; i >0U; i--) + 800aa4a: 4a06 ldr r2, [pc, #24] ; (800aa64 ) + mem_ptr+=4U; + 800aa4c: 310c adds r1, #12 + uint32_t csr_ptr = (uint32_t)HASH->CSR; + 800aa4e: 33f8 adds r3, #248 ; 0xf8 + WRITE_REG((*(uint32_t*)(csr_ptr)), (*(uint32_t*)(mem_ptr))); + 800aa50: f851 0b04 ldr.w r0, [r1], #4 + 800aa54: f843 0b04 str.w r0, [r3], #4 + for (i = HASH_NUMBER_OF_CSR_REGISTERS; i >0U; i--) + 800aa58: 4293 cmp r3, r2 + 800aa5a: d1f9 bne.n 800aa50 +} + 800aa5c: 4770 bx lr + 800aa5e: bf00 nop + 800aa60: 50060400 .word 0x50060400 + 800aa64: 500605d0 .word 0x500605d0 + +0800aa68 : + hhash->SuspendRequest = HAL_HASH_SUSPEND; + 800aa68: 2301 movs r3, #1 + 800aa6a: f880 3036 strb.w r3, [r0, #54] ; 0x36 +} + 800aa6e: 4770 bx lr + +0800aa70 : + return hhash->ErrorCode; + 800aa70: 6bc0 ldr r0, [r0, #60] ; 0x3c +} + 800aa72: 4770 bx lr + +0800aa74 : + * @param Timeout Timeout value. + * @param Algorithm HASH algorithm. + * @retval HAL status + */ +HAL_StatusTypeDef HASH_Start(HASH_HandleTypeDef *hhash, uint8_t *pInBuffer, uint32_t Size, uint8_t* pOutBuffer, uint32_t Timeout, uint32_t Algorithm) +{ + 800aa74: b5f8 push {r3, r4, r5, r6, r7, lr} + 800aa76: 461e mov r6, r3 + uint8_t *pInBuffer_tmp; /* input data address, input parameter of HASH_WriteData() */ + uint32_t Size_tmp; /* input data size (in bytes), input parameter of HASH_WriteData() */ + HAL_HASH_StateTypeDef State_tmp = hhash->State; + 800aa78: f890 3035 ldrb.w r3, [r0, #53] ; 0x35 + + + /* Initiate HASH processing in case of start or resumption */ +if((State_tmp == HAL_HASH_STATE_READY) || (State_tmp == HAL_HASH_STATE_SUSPENDED)) + 800aa7c: 2b01 cmp r3, #1 +{ + 800aa7e: 4604 mov r4, r0 + HAL_HASH_StateTypeDef State_tmp = hhash->State; + 800aa80: b2d8 uxtb r0, r3 +if((State_tmp == HAL_HASH_STATE_READY) || (State_tmp == HAL_HASH_STATE_SUSPENDED)) + 800aa82: d001 beq.n 800aa88 + 800aa84: 2808 cmp r0, #8 + 800aa86: d17a bne.n 800ab7e + { + /* Check input parameters */ + if ((pInBuffer == NULL) || (pOutBuffer == NULL)) + 800aa88: b101 cbz r1, 800aa8c + 800aa8a: b926 cbnz r6, 800aa96 + { + hhash->State = HAL_HASH_STATE_READY; + 800aa8c: 2501 movs r5, #1 + 800aa8e: f884 5035 strb.w r5, [r4, #53] ; 0x35 + } + else + { + return HAL_BUSY; + } +} + 800aa92: 4628 mov r0, r5 + 800aa94: bdf8 pop {r3, r4, r5, r6, r7, pc} + __HAL_LOCK(hhash); + 800aa96: f894 3034 ldrb.w r3, [r4, #52] ; 0x34 + 800aa9a: 2b01 cmp r3, #1 + 800aa9c: d06f beq.n 800ab7e + if(hhash->Phase == HAL_HASH_PHASE_READY) + 800aa9e: f894 302d ldrb.w r3, [r4, #45] ; 0x2d + __HAL_LOCK(hhash); + 800aaa2: 2501 movs r5, #1 + if(hhash->Phase == HAL_HASH_PHASE_READY) + 800aaa4: 42ab cmp r3, r5 + __HAL_LOCK(hhash); + 800aaa6: f884 5034 strb.w r5, [r4, #52] ; 0x34 + if(hhash->Phase == HAL_HASH_PHASE_READY) + 800aaaa: d148 bne.n 800ab3e + MODIFY_REG(HASH->CR, HASH_CR_LKEY|HASH_CR_ALGO|HASH_CR_MODE|HASH_CR_INIT, Algorithm | HASH_CR_INIT); + 800aaac: 4f36 ldr r7, [pc, #216] ; (800ab88 ) + 800aaae: 9b07 ldr r3, [sp, #28] + hhash->State = HAL_HASH_STATE_BUSY; + 800aab0: f04f 0c02 mov.w ip, #2 + 800aab4: f884 c035 strb.w ip, [r4, #53] ; 0x35 + MODIFY_REG(HASH->CR, HASH_CR_LKEY|HASH_CR_ALGO|HASH_CR_MODE|HASH_CR_INIT, Algorithm | HASH_CR_INIT); + 800aab8: 683d ldr r5, [r7, #0] + 800aaba: f425 25a0 bic.w r5, r5, #327680 ; 0x50000 + 800aabe: f025 05c4 bic.w r5, r5, #196 ; 0xc4 + 800aac2: 431d orrs r5, r3 + 800aac4: f045 0504 orr.w r5, r5, #4 + 800aac8: 603d str r5, [r7, #0] + __HAL_HASH_SET_NBVALIDBITS(Size); + 800aaca: 68b8 ldr r0, [r7, #8] + 800aacc: f002 0303 and.w r3, r2, #3 + 800aad0: f020 001f bic.w r0, r0, #31 + 800aad4: ea40 03c3 orr.w r3, r0, r3, lsl #3 + 800aad8: 60bb str r3, [r7, #8] + hhash->Phase = HAL_HASH_PHASE_PROCESS; + 800aada: f884 c02d strb.w ip, [r4, #45] ; 0x2d + hhash->Status = HASH_WriteData(hhash, pInBuffer_tmp, Size_tmp); + 800aade: 4620 mov r0, r4 + 800aae0: f7ff fd78 bl 800a5d4 + 800aae4: 4605 mov r5, r0 + 800aae6: f884 002c strb.w r0, [r4, #44] ; 0x2c + if (hhash->Status != HAL_OK) + 800aaea: 2800 cmp r0, #0 + 800aaec: d1d1 bne.n 800aa92 + if (hhash->State != HAL_HASH_STATE_SUSPENDED) + 800aaee: f894 3035 ldrb.w r3, [r4, #53] ; 0x35 + 800aaf2: 2b08 cmp r3, #8 + 800aaf4: d03b beq.n 800ab6e + __HAL_HASH_START_DIGEST(); + 800aaf6: 4f24 ldr r7, [pc, #144] ; (800ab88 ) + 800aaf8: 68bb ldr r3, [r7, #8] + 800aafa: f443 7380 orr.w r3, r3, #256 ; 0x100 + 800aafe: 60bb str r3, [r7, #8] + if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_DCIS, RESET, Timeout) != HAL_OK) + 800ab00: 4602 mov r2, r0 + 800ab02: 9b06 ldr r3, [sp, #24] + 800ab04: 2102 movs r1, #2 + 800ab06: 4620 mov r0, r4 + 800ab08: f7ff fe06 bl 800a718 + 800ab0c: 2800 cmp r0, #0 + 800ab0e: d138 bne.n 800ab82 + HASH_GetDigest(pOutBuffer, HASH_DIGEST_LENGTH()); + 800ab10: 683a ldr r2, [r7, #0] + 800ab12: 4b1e ldr r3, [pc, #120] ; (800ab8c ) + 800ab14: 421a tst r2, r3 + 800ab16: d02e beq.n 800ab76 + 800ab18: 683a ldr r2, [r7, #0] + 800ab1a: 401a ands r2, r3 + 800ab1c: f5b2 2f80 cmp.w r2, #262144 ; 0x40000 + 800ab20: d02b beq.n 800ab7a + 800ab22: 683a ldr r2, [r7, #0] + 800ab24: 4393 bics r3, r2 + 800ab26: bf0c ite eq + 800ab28: 2120 moveq r1, #32 + 800ab2a: 2110 movne r1, #16 + 800ab2c: 4630 mov r0, r6 + 800ab2e: f7ff fd91 bl 800a654 + hhash->State = HAL_HASH_STATE_READY; + 800ab32: 2301 movs r3, #1 + 800ab34: f884 3035 strb.w r3, [r4, #53] ; 0x35 + hhash->Phase = HAL_HASH_PHASE_READY; + 800ab38: f884 302d strb.w r3, [r4, #45] ; 0x2d + 800ab3c: e017 b.n 800ab6e + else if (hhash->Phase == HAL_HASH_PHASE_PROCESS) + 800ab3e: 2b02 cmp r3, #2 + 800ab40: d113 bne.n 800ab6a + if (hhash->State == HAL_HASH_STATE_SUSPENDED) + 800ab42: f894 3035 ldrb.w r3, [r4, #53] ; 0x35 + 800ab46: 2b08 cmp r3, #8 + __HAL_HASH_SET_NBVALIDBITS(Size); + 800ab48: bf15 itete ne + 800ab4a: 4d0f ldrne r5, [pc, #60] ; (800ab88 ) + Size_tmp = hhash->HashInCount; + 800ab4c: 6a22 ldreq r2, [r4, #32] + __HAL_HASH_SET_NBVALIDBITS(Size); + 800ab4e: 68a8 ldrne r0, [r5, #8] + pInBuffer_tmp = hhash->pHashInBuffPtr; + 800ab50: 68e1 ldreq r1, [r4, #12] + __HAL_HASH_SET_NBVALIDBITS(Size); + 800ab52: bf1f itttt ne + 800ab54: f002 0303 andne.w r3, r2, #3 + 800ab58: f020 001f bicne.w r0, r0, #31 + 800ab5c: ea40 03c3 orrne.w r3, r0, r3, lsl #3 + 800ab60: 60ab strne r3, [r5, #8] + hhash->State = HAL_HASH_STATE_BUSY; + 800ab62: 2302 movs r3, #2 + 800ab64: f884 3035 strb.w r3, [r4, #53] ; 0x35 + 800ab68: e7b9 b.n 800aade + hhash->State = HAL_HASH_STATE_READY; + 800ab6a: f884 5035 strb.w r5, [r4, #53] ; 0x35 + __HAL_UNLOCK(hhash); + 800ab6e: 2300 movs r3, #0 + 800ab70: f884 3034 strb.w r3, [r4, #52] ; 0x34 + return HAL_OK; + 800ab74: e78d b.n 800aa92 + HASH_GetDigest(pOutBuffer, HASH_DIGEST_LENGTH()); + 800ab76: 2114 movs r1, #20 + 800ab78: e7d8 b.n 800ab2c + 800ab7a: 211c movs r1, #28 + 800ab7c: e7d6 b.n 800ab2c + return HAL_BUSY; + 800ab7e: 2502 movs r5, #2 + 800ab80: e787 b.n 800aa92 + return HAL_TIMEOUT; + 800ab82: 2503 movs r5, #3 + 800ab84: e785 b.n 800aa92 + 800ab86: bf00 nop + 800ab88: 50060400 .word 0x50060400 + 800ab8c: 00040080 .word 0x00040080 + +0800ab90 : +{ + 800ab90: b513 push {r0, r1, r4, lr} + return HASH_Start(hhash, pInBuffer, Size, pOutBuffer, Timeout, HASH_ALGOSELECTION_MD5); + 800ab92: 2480 movs r4, #128 ; 0x80 + 800ab94: 9401 str r4, [sp, #4] + 800ab96: 9c04 ldr r4, [sp, #16] + 800ab98: 9400 str r4, [sp, #0] + 800ab9a: f7ff ff6b bl 800aa74 +} + 800ab9e: b002 add sp, #8 + 800aba0: bd10 pop {r4, pc} + +0800aba2 : + 800aba2: f7ff bff5 b.w 800ab90 + +0800aba6 : +{ + 800aba6: b513 push {r0, r1, r4, lr} + return HASH_Start(hhash, pInBuffer, Size, pOutBuffer, Timeout, HASH_ALGOSELECTION_SHA1); + 800aba8: 2400 movs r4, #0 + 800abaa: 9401 str r4, [sp, #4] + 800abac: 9c04 ldr r4, [sp, #16] + 800abae: 9400 str r4, [sp, #0] + 800abb0: f7ff ff60 bl 800aa74 +} + 800abb4: b002 add sp, #8 + 800abb6: bd10 pop {r4, pc} + +0800abb8 : + 800abb8: f7ff bff5 b.w 800aba6 + +0800abbc : + * @param Size length of the input buffer in bytes, must be a multiple of 4. + * @param Algorithm HASH algorithm. + * @retval HAL status + */ +HAL_StatusTypeDef HASH_Accumulate(HASH_HandleTypeDef *hhash, uint8_t *pInBuffer, uint32_t Size, uint32_t Algorithm) +{ + 800abbc: b570 push {r4, r5, r6, lr} + uint8_t *pInBuffer_tmp; /* input data address, input parameter of HASH_WriteData() */ + uint32_t Size_tmp; /* input data size (in bytes), input parameter of HASH_WriteData() */ + HAL_HASH_StateTypeDef State_tmp = hhash->State; + 800abbe: f890 5035 ldrb.w r5, [r0, #53] ; 0x35 +{ + 800abc2: 4604 mov r4, r0 + + /* Make sure the input buffer size (in bytes) is a multiple of 4 */ + if ((Size % 4U) != 0U) + 800abc4: 0790 lsls r0, r2, #30 + HAL_HASH_StateTypeDef State_tmp = hhash->State; + 800abc6: b2ed uxtb r5, r5 + if ((Size % 4U) != 0U) + 800abc8: d13e bne.n 800ac48 + { + return HAL_ERROR; + } + + /* Initiate HASH processing in case of start or resumption */ +if((State_tmp == HAL_HASH_STATE_READY) || (State_tmp == HAL_HASH_STATE_SUSPENDED)) + 800abca: 2d01 cmp r5, #1 + 800abcc: d001 beq.n 800abd2 + 800abce: 2d08 cmp r5, #8 + 800abd0: d13c bne.n 800ac4c + { + /* Check input parameters */ + if ((pInBuffer == NULL) || (Size == 0U)) + 800abd2: b101 cbz r1, 800abd6 + 800abd4: b91a cbnz r2, 800abde + { + hhash->State = HAL_HASH_STATE_READY; + 800abd6: 2001 movs r0, #1 + 800abd8: f884 0035 strb.w r0, [r4, #53] ; 0x35 + { + return HAL_BUSY; + } + + +} + 800abdc: bd70 pop {r4, r5, r6, pc} + __HAL_LOCK(hhash); + 800abde: f894 0034 ldrb.w r0, [r4, #52] ; 0x34 + 800abe2: 2801 cmp r0, #1 + 800abe4: d032 beq.n 800ac4c + 800abe6: 2001 movs r0, #1 + 800abe8: f884 0034 strb.w r0, [r4, #52] ; 0x34 + if (hhash->State == HAL_HASH_STATE_SUSPENDED) + 800abec: f894 0035 ldrb.w r0, [r4, #53] ; 0x35 + 800abf0: 2808 cmp r0, #8 + 800abf2: f04f 0002 mov.w r0, #2 + hhash->State = HAL_HASH_STATE_BUSY; + 800abf6: f884 0035 strb.w r0, [r4, #53] ; 0x35 + if (hhash->State == HAL_HASH_STATE_SUSPENDED) + 800abfa: d113 bne.n 800ac24 + pInBuffer_tmp = hhash->pHashInBuffPtr; /* pInBuffer_tmp is set to the input data address */ + 800abfc: 68e1 ldr r1, [r4, #12] + Size_tmp = hhash->HashInCount; /* Size_tmp contains the input data size in bytes */ + 800abfe: 6a22 ldr r2, [r4, #32] + hhash->Status = HASH_WriteData(hhash, pInBuffer_tmp, Size_tmp); + 800ac00: 4620 mov r0, r4 + 800ac02: f7ff fce7 bl 800a5d4 + 800ac06: f884 002c strb.w r0, [r4, #44] ; 0x2c + if (hhash->Status != HAL_OK) + 800ac0a: 2800 cmp r0, #0 + 800ac0c: d1e6 bne.n 800abdc + if (hhash->State != HAL_HASH_STATE_SUSPENDED) + 800ac0e: f894 3035 ldrb.w r3, [r4, #53] ; 0x35 + 800ac12: 2b08 cmp r3, #8 + hhash->State = HAL_HASH_STATE_READY; + 800ac14: bf1c itt ne + 800ac16: 2301 movne r3, #1 + 800ac18: f884 3035 strbne.w r3, [r4, #53] ; 0x35 + __HAL_UNLOCK(hhash); + 800ac1c: 2300 movs r3, #0 + 800ac1e: f884 3034 strb.w r3, [r4, #52] ; 0x34 + return HAL_OK; + 800ac22: e7db b.n 800abdc + if(hhash->Phase == HAL_HASH_PHASE_READY) + 800ac24: f894 002d ldrb.w r0, [r4, #45] ; 0x2d + 800ac28: 2801 cmp r0, #1 + 800ac2a: d109 bne.n 800ac40 + MODIFY_REG(HASH->CR, HASH_CR_LKEY|HASH_CR_ALGO|HASH_CR_MODE|HASH_CR_INIT, Algorithm | HASH_CR_INIT); + 800ac2c: 4e08 ldr r6, [pc, #32] ; (800ac50 ) + 800ac2e: 6830 ldr r0, [r6, #0] + 800ac30: f420 20a0 bic.w r0, r0, #327680 ; 0x50000 + 800ac34: f020 00c4 bic.w r0, r0, #196 ; 0xc4 + 800ac38: 4318 orrs r0, r3 + 800ac3a: f040 0004 orr.w r0, r0, #4 + 800ac3e: 6030 str r0, [r6, #0] + hhash->Phase = HAL_HASH_PHASE_PROCESS; + 800ac40: 2302 movs r3, #2 + 800ac42: f884 302d strb.w r3, [r4, #45] ; 0x2d + 800ac46: e7db b.n 800ac00 + return HAL_ERROR; + 800ac48: 2001 movs r0, #1 + 800ac4a: e7c7 b.n 800abdc + return HAL_BUSY; + 800ac4c: 2002 movs r0, #2 + 800ac4e: e7c5 b.n 800abdc + 800ac50: 50060400 .word 0x50060400 + +0800ac54 : + return HASH_Accumulate(hhash, pInBuffer, Size,HASH_ALGOSELECTION_MD5); + 800ac54: 2380 movs r3, #128 ; 0x80 + 800ac56: f7ff bfb1 b.w 800abbc + +0800ac5a : + return HASH_Accumulate(hhash, pInBuffer, Size,HASH_ALGOSELECTION_SHA1); + 800ac5a: 2300 movs r3, #0 + 800ac5c: f7ff bfae b.w 800abbc + +0800ac60 : + * @param Size length of the input buffer in bytes, must be a multiple of 4. + * @param Algorithm HASH algorithm. + * @retval HAL status + */ +HAL_StatusTypeDef HASH_Accumulate_IT(HASH_HandleTypeDef *hhash, uint8_t *pInBuffer, uint32_t Size, uint32_t Algorithm) +{ + 800ac60: b567 push {r0, r1, r2, r5, r6, lr} + HAL_HASH_StateTypeDef State_tmp = hhash->State; + 800ac62: f890 5035 ldrb.w r5, [r0, #53] ; 0x35 + __IO uint32_t inputaddr = (uint32_t) pInBuffer; + 800ac66: 9101 str r1, [sp, #4] + uint32_t SizeVar = Size; + + /* Make sure the input buffer size (in bytes) is a multiple of 4 */ + if ((Size % 4U) != 0U) + 800ac68: 0796 lsls r6, r2, #30 + HAL_HASH_StateTypeDef State_tmp = hhash->State; + 800ac6a: b2ed uxtb r5, r5 + if ((Size % 4U) != 0U) + 800ac6c: d154 bne.n 800ad18 + { + return HAL_ERROR; + } + + /* Initiate HASH processing in case of start or resumption */ + if((State_tmp == HAL_HASH_STATE_READY) || (State_tmp == HAL_HASH_STATE_SUSPENDED)) + 800ac6e: 2d01 cmp r5, #1 + 800ac70: d001 beq.n 800ac76 + 800ac72: 2d08 cmp r5, #8 + 800ac74: d152 bne.n 800ad1c + { + /* Check input parameters */ + if ((pInBuffer == NULL) || (Size == 0U)) + 800ac76: b101 cbz r1, 800ac7a + 800ac78: b92a cbnz r2, 800ac86 + { + hhash->State = HAL_HASH_STATE_READY; + 800ac7a: 2301 movs r3, #1 + 800ac7c: f880 3035 strb.w r3, [r0, #53] ; 0x35 + else + { + return HAL_BUSY; + } + +} + 800ac80: 4618 mov r0, r3 + 800ac82: b003 add sp, #12 + 800ac84: bd60 pop {r5, r6, pc} + __HAL_LOCK(hhash); + 800ac86: f890 1034 ldrb.w r1, [r0, #52] ; 0x34 + 800ac8a: 2901 cmp r1, #1 + 800ac8c: d046 beq.n 800ad1c + 800ac8e: 2101 movs r1, #1 + 800ac90: f880 1034 strb.w r1, [r0, #52] ; 0x34 + if (hhash->State == HAL_HASH_STATE_SUSPENDED) + 800ac94: f890 1035 ldrb.w r1, [r0, #53] ; 0x35 + 800ac98: 4d21 ldr r5, [pc, #132] ; (800ad20 ) + 800ac9a: 2908 cmp r1, #8 + 800ac9c: f04f 0102 mov.w r1, #2 + hhash->State = HAL_HASH_STATE_BUSY; + 800aca0: f880 1035 strb.w r1, [r0, #53] ; 0x35 + if (hhash->State == HAL_HASH_STATE_SUSPENDED) + 800aca4: d109 bne.n 800acba + hhash->Accumulation = 1U; + 800aca6: 2301 movs r3, #1 + 800aca8: 6403 str r3, [r0, #64] ; 0x40 + __HAL_UNLOCK(hhash); + 800acaa: 2300 movs r3, #0 + 800acac: f880 3034 strb.w r3, [r0, #52] ; 0x34 + __HAL_HASH_ENABLE_IT(HASH_IT_DINI); + 800acb0: 6a2a ldr r2, [r5, #32] + 800acb2: f042 0201 orr.w r2, r2, #1 + 800acb6: 622a str r2, [r5, #32] + return HAL_OK; + 800acb8: e7e2 b.n 800ac80 + if(hhash->Phase == HAL_HASH_PHASE_READY) + 800acba: f890 602d ldrb.w r6, [r0, #45] ; 0x2d + 800acbe: 2e01 cmp r6, #1 + 800acc0: d11b bne.n 800acfa + MODIFY_REG(HASH->CR, HASH_CR_LKEY|HASH_CR_ALGO|HASH_CR_MODE|HASH_CR_INIT, Algorithm | HASH_CR_INIT); + 800acc2: 6829 ldr r1, [r5, #0] + 800acc4: f421 21a0 bic.w r1, r1, #327680 ; 0x50000 + 800acc8: f021 01c4 bic.w r1, r1, #196 ; 0xc4 + 800accc: 4319 orrs r1, r3 + 800acce: f041 0104 orr.w r1, r1, #4 + 800acd2: 6029 str r1, [r5, #0] + hhash->HashITCounter = 1; + 800acd4: 6246 str r6, [r0, #36] ; 0x24 + hhash->Phase = HAL_HASH_PHASE_PROCESS; + 800acd6: 2302 movs r3, #2 + 800acd8: f880 302d strb.w r3, [r0, #45] ; 0x2d + while((!(__HAL_HASH_GET_FLAG(HASH_FLAG_DINIS))) && (SizeVar > 0U)) + 800acdc: 6a6b ldr r3, [r5, #36] ; 0x24 + 800acde: 07d9 lsls r1, r3, #31 + 800ace0: d400 bmi.n 800ace4 + 800ace2: b96a cbnz r2, 800ad00 + if ((!(__HAL_HASH_GET_FLAG(HASH_FLAG_DINIS))) || (SizeVar == 0U)) + 800ace4: 6a6b ldr r3, [r5, #36] ; 0x24 + 800ace6: 07db lsls r3, r3, #31 + 800ace8: d500 bpl.n 800acec + 800acea: b98a cbnz r2, 800ad10 + hhash->State = HAL_HASH_STATE_READY; + 800acec: 2301 movs r3, #1 + 800acee: f880 3035 strb.w r3, [r0, #53] ; 0x35 + __HAL_UNLOCK(hhash); + 800acf2: 2300 movs r3, #0 + 800acf4: f880 3034 strb.w r3, [r0, #52] ; 0x34 + return HAL_OK; + 800acf8: e7c2 b.n 800ac80 + hhash->HashITCounter = 3; /* 'cruise-speed' reached during a previous buffer processing */ + 800acfa: 2303 movs r3, #3 + 800acfc: 6243 str r3, [r0, #36] ; 0x24 + 800acfe: e7ea b.n 800acd6 + HASH->DIN = *(uint32_t*)inputaddr; + 800ad00: 9b01 ldr r3, [sp, #4] + 800ad02: 681b ldr r3, [r3, #0] + 800ad04: 606b str r3, [r5, #4] + inputaddr+=4U; + 800ad06: 9b01 ldr r3, [sp, #4] + 800ad08: 3304 adds r3, #4 + 800ad0a: 9301 str r3, [sp, #4] + SizeVar-=4U; + 800ad0c: 3a04 subs r2, #4 + 800ad0e: e7e5 b.n 800acdc + hhash->HashInCount = SizeVar; /* Counter used to keep track of number of data + 800ad10: 6202 str r2, [r0, #32] + hhash->pHashInBuffPtr = (uint8_t *)inputaddr; /* Points at data which will be fed to the Peripheral at + 800ad12: 9b01 ldr r3, [sp, #4] + 800ad14: 60c3 str r3, [r0, #12] + 800ad16: e7c6 b.n 800aca6 + return HAL_ERROR; + 800ad18: 2301 movs r3, #1 + 800ad1a: e7b1 b.n 800ac80 + return HAL_BUSY; + 800ad1c: 2302 movs r3, #2 + 800ad1e: e7af b.n 800ac80 + 800ad20: 50060400 .word 0x50060400 + +0800ad24 : + return HASH_Accumulate_IT(hhash, pInBuffer, Size,HASH_ALGOSELECTION_MD5); + 800ad24: 2380 movs r3, #128 ; 0x80 + 800ad26: f7ff bf9b b.w 800ac60 + +0800ad2a : + return HASH_Accumulate_IT(hhash, pInBuffer, Size,HASH_ALGOSELECTION_SHA1); + 800ad2a: 2300 movs r3, #0 + 800ad2c: f7ff bf98 b.w 800ac60 + +0800ad30 : + * @param pOutBuffer pointer to the computed digest. + * @param Algorithm HASH algorithm. + * @retval HAL status + */ +HAL_StatusTypeDef HASH_Start_IT(HASH_HandleTypeDef *hhash, uint8_t *pInBuffer, uint32_t Size, uint8_t* pOutBuffer, uint32_t Algorithm) +{ + 800ad30: b573 push {r0, r1, r4, r5, r6, lr} + HAL_HASH_StateTypeDef State_tmp = hhash->State; + 800ad32: f890 4035 ldrb.w r4, [r0, #53] ; 0x35 + __IO uint32_t inputaddr = (uint32_t) pInBuffer; + 800ad36: 9101 str r1, [sp, #4] + uint32_t polling_step = 0U; + uint32_t initialization_skipped = 0U; + uint32_t SizeVar = Size; + + /* If State is ready or suspended, start or resume IT-based HASH processing */ +if((State_tmp == HAL_HASH_STATE_READY) || (State_tmp == HAL_HASH_STATE_SUSPENDED)) + 800ad38: 2c01 cmp r4, #1 + HAL_HASH_StateTypeDef State_tmp = hhash->State; + 800ad3a: b2e5 uxtb r5, r4 +if((State_tmp == HAL_HASH_STATE_READY) || (State_tmp == HAL_HASH_STATE_SUSPENDED)) + 800ad3c: d001 beq.n 800ad42 + 800ad3e: 2d08 cmp r5, #8 + 800ad40: d17f bne.n 800ae42 + { + /* Check input parameters */ + if ((pInBuffer == NULL) || (Size == 0U) || (pOutBuffer == NULL)) + 800ad42: b109 cbz r1, 800ad48 + 800ad44: b102 cbz r2, 800ad48 + 800ad46: b92b cbnz r3, 800ad54 + { + hhash->State = HAL_HASH_STATE_READY; + 800ad48: 2201 movs r2, #1 + 800ad4a: f880 2035 strb.w r2, [r0, #53] ; 0x35 + else + { + return HAL_BUSY; + } + +} + 800ad4e: 4610 mov r0, r2 + 800ad50: b002 add sp, #8 + 800ad52: bd70 pop {r4, r5, r6, pc} + __HAL_LOCK(hhash); + 800ad54: f890 4034 ldrb.w r4, [r0, #52] ; 0x34 + 800ad58: 2c01 cmp r4, #1 + 800ad5a: f04f 0402 mov.w r4, #2 + 800ad5e: d072 beq.n 800ae46 + hhash->State = HAL_HASH_STATE_BUSY; + 800ad60: f880 4035 strb.w r4, [r0, #53] ; 0x35 + if(hhash->Phase == HAL_HASH_PHASE_READY) + 800ad64: f890 402d ldrb.w r4, [r0, #45] ; 0x2d + __HAL_LOCK(hhash); + 800ad68: 2601 movs r6, #1 + if(hhash->Phase == HAL_HASH_PHASE_READY) + 800ad6a: 42b4 cmp r4, r6 + __HAL_LOCK(hhash); + 800ad6c: f880 6034 strb.w r6, [r0, #52] ; 0x34 + hhash->HashITCounter = 1; + 800ad70: 4c36 ldr r4, [pc, #216] ; (800ae4c ) + 800ad72: 6246 str r6, [r0, #36] ; 0x24 + if(hhash->Phase == HAL_HASH_PHASE_READY) + 800ad74: d115 bne.n 800ada2 + MODIFY_REG(HASH->CR, HASH_CR_LKEY|HASH_CR_ALGO|HASH_CR_MODE|HASH_CR_INIT, Algorithm | HASH_CR_INIT); + 800ad76: 6825 ldr r5, [r4, #0] + 800ad78: 9e06 ldr r6, [sp, #24] + 800ad7a: f425 25a0 bic.w r5, r5, #327680 ; 0x50000 + 800ad7e: f025 05c4 bic.w r5, r5, #196 ; 0xc4 + 800ad82: 4335 orrs r5, r6 + 800ad84: f045 0504 orr.w r5, r5, #4 + 800ad88: 6025 str r5, [r4, #0] + __HAL_HASH_SET_NBVALIDBITS(SizeVar); + 800ad8a: 68a6 ldr r6, [r4, #8] + 800ad8c: f002 0503 and.w r5, r2, #3 + 800ad90: f026 061f bic.w r6, r6, #31 + 800ad94: ea46 05c5 orr.w r5, r6, r5, lsl #3 + 800ad98: 60a5 str r5, [r4, #8] + hhash->pHashOutBuffPtr = pOutBuffer; /* Points at the computed digest */ + 800ad9a: e9c0 1303 strd r1, r3, [r0, #12] + hhash->HashInCount = SizeVar; /* Counter used to keep track of number of data + 800ad9e: 6202 str r2, [r0, #32] + uint32_t initialization_skipped = 0U; + 800ada0: 2600 movs r6, #0 + hhash->Phase = HAL_HASH_PHASE_PROCESS; + 800ada2: 2102 movs r1, #2 + 800ada4: f880 102d strb.w r1, [r0, #45] ; 0x2d + uint32_t polling_step = 0U; + 800ada8: 2100 movs r1, #0 + while((!(__HAL_HASH_GET_FLAG(HASH_FLAG_DINIS))) && (SizeVar > 3U)) + 800adaa: 6a65 ldr r5, [r4, #36] ; 0x24 + 800adac: 07ed lsls r5, r5, #31 + 800adae: d401 bmi.n 800adb4 + 800adb0: 2a03 cmp r2, #3 + 800adb2: d80d bhi.n 800add0 + if (polling_step == 1U) + 800adb4: b349 cbz r1, 800ae0a + if (SizeVar == 0U) + 800adb6: b9a2 cbnz r2, 800ade2 + hhash->pHashOutBuffPtr = pOutBuffer; /* Points at the computed digest */ + 800adb8: 6103 str r3, [r0, #16] + __HAL_HASH_START_DIGEST(); + 800adba: 68a3 ldr r3, [r4, #8] + 800adbc: f443 7380 orr.w r3, r3, #256 ; 0x100 + 800adc0: 60a3 str r3, [r4, #8] + __HAL_UNLOCK(hhash); + 800adc2: f880 2034 strb.w r2, [r0, #52] ; 0x34 + __HAL_HASH_ENABLE_IT(HASH_IT_DCI); + 800adc6: 6a23 ldr r3, [r4, #32] + 800adc8: f043 0302 orr.w r3, r3, #2 + __HAL_HASH_ENABLE_IT(HASH_IT_DINI|HASH_IT_DCI); + 800adcc: 6223 str r3, [r4, #32] + return HAL_OK; + 800adce: e7be b.n 800ad4e + HASH->DIN = *(uint32_t*)inputaddr; + 800add0: 9901 ldr r1, [sp, #4] + 800add2: 6809 ldr r1, [r1, #0] + 800add4: 6061 str r1, [r4, #4] + inputaddr+=4U; + 800add6: 9901 ldr r1, [sp, #4] + 800add8: 3104 adds r1, #4 + 800adda: 9101 str r1, [sp, #4] + SizeVar-=4U; + 800addc: 3a04 subs r2, #4 + polling_step = 1U; /* note that some words are entered before enabling the interrupt */ + 800adde: 2101 movs r1, #1 + 800ade0: e7e3 b.n 800adaa + else if (__HAL_HASH_GET_FLAG(HASH_FLAG_DINIS)) + 800ade2: 6a61 ldr r1, [r4, #36] ; 0x24 + __HAL_HASH_SET_NBVALIDBITS(SizeVar); /* Update the configuration of the number of valid bits in last word of the message */ + 800ade4: f002 0503 and.w r5, r2, #3 + else if (__HAL_HASH_GET_FLAG(HASH_FLAG_DINIS)) + 800ade8: f011 0101 ands.w r1, r1, #1 + __HAL_HASH_SET_NBVALIDBITS(SizeVar); /* Update the configuration of the number of valid bits in last word of the message */ + 800adec: ea4f 05c5 mov.w r5, r5, lsl #3 + else if (__HAL_HASH_GET_FLAG(HASH_FLAG_DINIS)) + 800adf0: d012 beq.n 800ae18 + hhash->HashInCount = SizeVar; + 800adf2: 6202 str r2, [r0, #32] + hhash->pHashInBuffPtr = (uint8_t *)inputaddr; + 800adf4: 9a01 ldr r2, [sp, #4] + 800adf6: 60c2 str r2, [r0, #12] + __HAL_HASH_SET_NBVALIDBITS(SizeVar); /* Update the configuration of the number of valid bits in last word of the message */ + 800adf8: 68a2 ldr r2, [r4, #8] + 800adfa: f022 021f bic.w r2, r2, #31 + 800adfe: 432a orrs r2, r5 + 800ae00: 60a2 str r2, [r4, #8] + hhash->pHashOutBuffPtr = pOutBuffer; /* Points at the computed digest */ + 800ae02: 6103 str r3, [r0, #16] + if (initialization_skipped == 1U) + 800ae04: b10e cbz r6, 800ae0a + hhash->HashITCounter = 3; /* 'cruise-speed' reached during a previous buffer processing */ + 800ae06: 2303 movs r3, #3 + 800ae08: 6243 str r3, [r0, #36] ; 0x24 + __HAL_UNLOCK(hhash); + 800ae0a: 2200 movs r2, #0 + 800ae0c: f880 2034 strb.w r2, [r0, #52] ; 0x34 + __HAL_HASH_ENABLE_IT(HASH_IT_DINI|HASH_IT_DCI); + 800ae10: 6a23 ldr r3, [r4, #32] + 800ae12: f043 0303 orr.w r3, r3, #3 + 800ae16: e7d9 b.n 800adcc + __HAL_HASH_SET_NBVALIDBITS(SizeVar); + 800ae18: 68a2 ldr r2, [r4, #8] + 800ae1a: f022 021f bic.w r2, r2, #31 + 800ae1e: 432a orrs r2, r5 + 800ae20: 60a2 str r2, [r4, #8] + HASH->DIN = *(uint32_t*)inputaddr; + 800ae22: 9a01 ldr r2, [sp, #4] + 800ae24: 6812 ldr r2, [r2, #0] + 800ae26: 6062 str r2, [r4, #4] + hhash->pHashOutBuffPtr = pOutBuffer; /* Points at the computed digest */ + 800ae28: 6103 str r3, [r0, #16] + __HAL_HASH_START_DIGEST(); + 800ae2a: 68a3 ldr r3, [r4, #8] + 800ae2c: f443 7380 orr.w r3, r3, #256 ; 0x100 + 800ae30: 60a3 str r3, [r4, #8] + __HAL_UNLOCK(hhash); + 800ae32: f880 1034 strb.w r1, [r0, #52] ; 0x34 + __HAL_HASH_ENABLE_IT(HASH_IT_DCI); + 800ae36: 6a23 ldr r3, [r4, #32] + 800ae38: f043 0302 orr.w r3, r3, #2 + 800ae3c: 6223 str r3, [r4, #32] + return HAL_OK; + 800ae3e: 460a mov r2, r1 + 800ae40: e785 b.n 800ad4e + return HAL_BUSY; + 800ae42: 2202 movs r2, #2 + 800ae44: e783 b.n 800ad4e + 800ae46: 4622 mov r2, r4 + 800ae48: e781 b.n 800ad4e + 800ae4a: bf00 nop + 800ae4c: 50060400 .word 0x50060400 + +0800ae50 : +{ + 800ae50: b513 push {r0, r1, r4, lr} + return HASH_Start_IT(hhash, pInBuffer, Size, pOutBuffer,HASH_ALGOSELECTION_MD5); + 800ae52: 2480 movs r4, #128 ; 0x80 + 800ae54: 9400 str r4, [sp, #0] + 800ae56: f7ff ff6b bl 800ad30 +} + 800ae5a: b002 add sp, #8 + 800ae5c: bd10 pop {r4, pc} + +0800ae5e : + 800ae5e: f7ff bff7 b.w 800ae50 + +0800ae62 : +{ + 800ae62: b513 push {r0, r1, r4, lr} + return HASH_Start_IT(hhash, pInBuffer, Size, pOutBuffer,HASH_ALGOSELECTION_SHA1); + 800ae64: 2400 movs r4, #0 + 800ae66: 9400 str r4, [sp, #0] + 800ae68: f7ff ff62 bl 800ad30 +} + 800ae6c: b002 add sp, #8 + 800ae6e: bd10 pop {r4, pc} + +0800ae70 : + 800ae70: f7ff bff7 b.w 800ae62 + +0800ae74 : + * @param pOutBuffer pointer to the computed digest. + * @param Timeout Timeout value. + * @retval HAL status + */ +HAL_StatusTypeDef HASH_Finish(HASH_HandleTypeDef *hhash, uint8_t* pOutBuffer, uint32_t Timeout) +{ + 800ae74: b570 push {r4, r5, r6, lr} + 800ae76: 4613 mov r3, r2 + + if(hhash->State == HAL_HASH_STATE_READY) + 800ae78: f890 2035 ldrb.w r2, [r0, #53] ; 0x35 + 800ae7c: 2a01 cmp r2, #1 +{ + 800ae7e: 4605 mov r5, r0 + 800ae80: 460e mov r6, r1 + if(hhash->State == HAL_HASH_STATE_READY) + 800ae82: b2d4 uxtb r4, r2 + 800ae84: d12f bne.n 800aee6 + { + /* Check parameter */ + if (pOutBuffer == NULL) + 800ae86: b341 cbz r1, 800aeda + { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(hhash); + 800ae88: f890 2034 ldrb.w r2, [r0, #52] ; 0x34 + 800ae8c: 2a01 cmp r2, #1 + 800ae8e: f04f 0102 mov.w r1, #2 + 800ae92: d028 beq.n 800aee6 + 800ae94: f880 4034 strb.w r4, [r0, #52] ; 0x34 + + /* Change the HASH state to busy */ + hhash->State = HAL_HASH_STATE_BUSY; + 800ae98: f880 1035 strb.w r1, [r0, #53] ; 0x35 + + /* Wait for DCIS flag to be set */ + if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_DCIS, RESET, Timeout) != HAL_OK) + 800ae9c: 2200 movs r2, #0 + 800ae9e: f7ff fc3b bl 800a718 + 800aea2: 4604 mov r4, r0 + 800aea4: bb08 cbnz r0, 800aeea + { + return HAL_TIMEOUT; + } + + /* Read the message digest */ + HASH_GetDigest(pOutBuffer, HASH_DIGEST_LENGTH()); + 800aea6: 4a12 ldr r2, [pc, #72] ; (800aef0 ) + 800aea8: 4b12 ldr r3, [pc, #72] ; (800aef4 ) + 800aeaa: 6811 ldr r1, [r2, #0] + 800aeac: 4219 tst r1, r3 + 800aeae: d016 beq.n 800aede + 800aeb0: 6811 ldr r1, [r2, #0] + 800aeb2: 4019 ands r1, r3 + 800aeb4: f5b1 2f80 cmp.w r1, #262144 ; 0x40000 + 800aeb8: d013 beq.n 800aee2 + 800aeba: 6812 ldr r2, [r2, #0] + 800aebc: 4393 bics r3, r2 + 800aebe: bf0c ite eq + 800aec0: 2120 moveq r1, #32 + 800aec2: 2110 movne r1, #16 + 800aec4: 4630 mov r0, r6 + 800aec6: f7ff fbc5 bl 800a654 + + /* Change the HASH state to ready */ + hhash->State = HAL_HASH_STATE_READY; + 800aeca: 2301 movs r3, #1 + 800aecc: f885 3035 strb.w r3, [r5, #53] ; 0x35 + + /* Reset HASH state machine */ + hhash->Phase = HAL_HASH_PHASE_READY; + 800aed0: f885 302d strb.w r3, [r5, #45] ; 0x2d + + /* Process UnLock */ + __HAL_UNLOCK(hhash); + 800aed4: 2300 movs r3, #0 + 800aed6: f885 3034 strb.w r3, [r5, #52] ; 0x34 + else + { + return HAL_BUSY; + } + +} + 800aeda: 4620 mov r0, r4 + 800aedc: bd70 pop {r4, r5, r6, pc} + HASH_GetDigest(pOutBuffer, HASH_DIGEST_LENGTH()); + 800aede: 2114 movs r1, #20 + 800aee0: e7f0 b.n 800aec4 + 800aee2: 211c movs r1, #28 + 800aee4: e7ee b.n 800aec4 + return HAL_BUSY; + 800aee6: 2402 movs r4, #2 + 800aee8: e7f7 b.n 800aeda + return HAL_TIMEOUT; + 800aeea: 2403 movs r4, #3 + 800aeec: e7f5 b.n 800aeda + 800aeee: bf00 nop + 800aef0: 50060400 .word 0x50060400 + 800aef4: 00040080 .word 0x00040080 + +0800aef8 : + * @param Timeout Timeout value. + * @param Algorithm HASH algorithm. + * @retval HAL status + */ +HAL_StatusTypeDef HMAC_Start(HASH_HandleTypeDef *hhash, uint8_t *pInBuffer, uint32_t Size, uint8_t* pOutBuffer, uint32_t Timeout, uint32_t Algorithm) +{ + 800aef8: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + 800aefc: 4604 mov r4, r0 + HAL_HASH_StateTypeDef State_tmp = hhash->State; + 800aefe: f890 0035 ldrb.w r0, [r0, #53] ; 0x35 + + /* If State is ready or suspended, start or resume polling-based HASH processing */ +if((State_tmp == HAL_HASH_STATE_READY) || (State_tmp == HAL_HASH_STATE_SUSPENDED)) + 800af02: 2801 cmp r0, #1 +{ + 800af04: e9dd 7e06 ldrd r7, lr, [sp, #24] + HAL_HASH_StateTypeDef State_tmp = hhash->State; + 800af08: b2c5 uxtb r5, r0 +if((State_tmp == HAL_HASH_STATE_READY) || (State_tmp == HAL_HASH_STATE_SUSPENDED)) + 800af0a: d002 beq.n 800af12 + 800af0c: 2d08 cmp r5, #8 + 800af0e: f040 80df bne.w 800b0d0 + { + /* Check input parameters */ + if ((pInBuffer == NULL) || /*(Size == 0U) ||*/ (hhash->Init.pKey == NULL) || (hhash->Init.KeySize == 0U) || (pOutBuffer == NULL)) + 800af12: b139 cbz r1, 800af24 + 800af14: f8d4 c008 ldr.w ip, [r4, #8] + 800af18: f1bc 0f00 cmp.w ip, #0 + 800af1c: d002 beq.n 800af24 + 800af1e: 6865 ldr r5, [r4, #4] + 800af20: b105 cbz r5, 800af24 + 800af22: b923 cbnz r3, 800af2e + { + hhash->State = HAL_HASH_STATE_READY; + 800af24: 2001 movs r0, #1 + 800af26: f884 0035 strb.w r0, [r4, #53] ; 0x35 + return HMAC_Processing(hhash, Timeout); + + } + else + { + return HAL_BUSY; + 800af2a: 4605 mov r5, r0 + 800af2c: e05b b.n 800afe6 + __HAL_LOCK(hhash); + 800af2e: f894 0034 ldrb.w r0, [r4, #52] ; 0x34 + 800af32: 2801 cmp r0, #1 + 800af34: f04f 0002 mov.w r0, #2 + 800af38: d0f7 beq.n 800af2a + hhash->State = HAL_HASH_STATE_BUSY; + 800af3a: f884 0035 strb.w r0, [r4, #53] ; 0x35 + if(hhash->Phase == HAL_HASH_PHASE_READY) + 800af3e: f894 002d ldrb.w r0, [r4, #45] ; 0x2d + __HAL_LOCK(hhash); + 800af42: 2601 movs r6, #1 + if(hhash->Phase == HAL_HASH_PHASE_READY) + 800af44: 42b0 cmp r0, r6 + __HAL_LOCK(hhash); + 800af46: f884 6034 strb.w r6, [r4, #52] ; 0x34 + if(hhash->Phase == HAL_HASH_PHASE_READY) + 800af4a: d118 bne.n 800af7e + if(hhash->Init.KeySize > 64U) + 800af4c: 4e61 ldr r6, [pc, #388] ; (800b0d4 ) + 800af4e: f8df 818c ldr.w r8, [pc, #396] ; 800b0dc + MODIFY_REG(HASH->CR, HASH_CR_LKEY|HASH_CR_ALGO|HASH_CR_MODE|HASH_CR_INIT, Algorithm | HASH_ALGOMODE_HMAC | HASH_HMAC_KEYTYPE_LONGKEY | HASH_CR_INIT); + 800af52: 6830 ldr r0, [r6, #0] + 800af54: ea00 0008 and.w r0, r0, r8 + 800af58: ea40 000e orr.w r0, r0, lr + if(hhash->Init.KeySize > 64U) + 800af5c: 2d40 cmp r5, #64 ; 0x40 + MODIFY_REG(HASH->CR, HASH_CR_LKEY|HASH_CR_ALGO|HASH_CR_MODE|HASH_CR_INIT, Algorithm | HASH_ALGOMODE_HMAC | HASH_HMAC_KEYTYPE_LONGKEY | HASH_CR_INIT); + 800af5e: bf88 it hi + 800af60: f440 3080 orrhi.w r0, r0, #65536 ; 0x10000 + MODIFY_REG(HASH->CR, HASH_CR_LKEY|HASH_CR_ALGO|HASH_CR_MODE|HASH_CR_INIT, Algorithm | HASH_ALGOMODE_HMAC | HASH_CR_INIT); + 800af64: f040 0044 orr.w r0, r0, #68 ; 0x44 + 800af68: 6030 str r0, [r6, #0] + hhash->pHashInBuffPtr = pInBuffer; /* Input data address, HMAC_Processing input parameter for Step 2 */ + 800af6a: e9c4 1303 strd r1, r3, [r4, #12] + hhash->Phase = HAL_HASH_PHASE_HMAC_STEP_1; + 800af6e: 2003 movs r0, #3 + hhash->HashInCount = Size; /* Input data size, HMAC_Processing input parameter for Step 2 */ + 800af70: 6222 str r2, [r4, #32] + hhash->Phase = HAL_HASH_PHASE_HMAC_STEP_1; + 800af72: f884 002d strb.w r0, [r4, #45] ; 0x2d + hhash->HashBuffSize = Size; /* Store the input buffer size for the whole HMAC process */ + 800af76: 61e2 str r2, [r4, #28] + hhash->pHashKeyBuffPtr = hhash->Init.pKey; /* Key address, HMAC_Processing input parameter for Step 1 and Step 3 */ + 800af78: f8c4 c014 str.w ip, [r4, #20] + hhash->HashKeyCount = hhash->Init.KeySize; /* Key size, HMAC_Processing input parameter for Step 1 and Step 3 */ + 800af7c: 62a5 str r5, [r4, #40] ; 0x28 + if ((hhash->Phase != HAL_HASH_PHASE_HMAC_STEP_1) && (hhash->Phase != HAL_HASH_PHASE_HMAC_STEP_2) && (hhash->Phase != HAL_HASH_PHASE_HMAC_STEP_3)) + 800af7e: f894 302d ldrb.w r3, [r4, #45] ; 0x2d + 800af82: 1eda subs r2, r3, #3 + 800af84: 2a02 cmp r2, #2 + 800af86: d906 bls.n 800af96 + hhash->State = HAL_HASH_STATE_READY; + 800af88: 2001 movs r0, #1 + __HAL_UNLOCK(hhash); + 800af8a: 2300 movs r3, #0 + hhash->State = HAL_HASH_STATE_READY; + 800af8c: f884 0035 strb.w r0, [r4, #53] ; 0x35 + __HAL_UNLOCK(hhash); + 800af90: f884 3034 strb.w r3, [r4, #52] ; 0x34 + return HAL_ERROR; + 800af94: e7c9 b.n 800af2a + if (hhash->Phase == HAL_HASH_PHASE_HMAC_STEP_1) + 800af96: 2b03 cmp r3, #3 + 800af98: 4e4e ldr r6, [pc, #312] ; (800b0d4 ) + 800af9a: d155 bne.n 800b048 + __HAL_HASH_SET_NBVALIDBITS(hhash->Init.KeySize); + 800af9c: 68b3 ldr r3, [r6, #8] + hhash->Status = HASH_WriteData(hhash, hhash->pHashKeyBuffPtr, hhash->HashKeyCount); + 800af9e: 6961 ldr r1, [r4, #20] + __HAL_HASH_SET_NBVALIDBITS(hhash->Init.KeySize); + 800afa0: f023 031f bic.w r3, r3, #31 + 800afa4: f005 0503 and.w r5, r5, #3 + 800afa8: ea43 05c5 orr.w r5, r3, r5, lsl #3 + 800afac: 60b5 str r5, [r6, #8] + hhash->Status = HASH_WriteData(hhash, hhash->pHashKeyBuffPtr, hhash->HashKeyCount); + 800afae: 6aa2 ldr r2, [r4, #40] ; 0x28 + 800afb0: 4620 mov r0, r4 + 800afb2: f7ff fb0f bl 800a5d4 + 800afb6: 4605 mov r5, r0 + 800afb8: f884 002c strb.w r0, [r4, #44] ; 0x2c + if (hhash->Status != HAL_OK) + 800afbc: b998 cbnz r0, 800afe6 + if (hhash->State == HAL_HASH_STATE_SUSPENDED) + 800afbe: f894 3035 ldrb.w r3, [r4, #53] ; 0x35 + 800afc2: 2b08 cmp r3, #8 + 800afc4: d103 bne.n 800afce + __HAL_UNLOCK(hhash); + 800afc6: 2000 movs r0, #0 + 800afc8: f884 0034 strb.w r0, [r4, #52] ; 0x34 + return HAL_OK; + 800afcc: e7ad b.n 800af2a + __HAL_HASH_START_DIGEST(); + 800afce: 68b3 ldr r3, [r6, #8] + 800afd0: f443 7380 orr.w r3, r3, #256 ; 0x100 + 800afd4: 60b3 str r3, [r6, #8] + if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_BUSY, SET, Timeout) != HAL_OK) + 800afd6: 2201 movs r2, #1 + 800afd8: 463b mov r3, r7 + 800afda: 2108 movs r1, #8 + 800afdc: 4620 mov r0, r4 + 800afde: f7ff fb9b bl 800a718 + 800afe2: b118 cbz r0, 800afec + return HAL_TIMEOUT; + 800afe4: 2503 movs r5, #3 + } +} + 800afe6: 4628 mov r0, r5 + 800afe8: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + hhash->Phase = HAL_HASH_PHASE_HMAC_STEP_2; + 800afec: 2304 movs r3, #4 + 800afee: f884 302d strb.w r3, [r4, #45] ; 0x2d + __HAL_HASH_SET_NBVALIDBITS(hhash->HashBuffSize); + 800aff2: 68b3 ldr r3, [r6, #8] + 800aff4: 69e2 ldr r2, [r4, #28] + hhash->Status = HASH_WriteData(hhash, hhash->pHashInBuffPtr, hhash->HashInCount); + 800aff6: 68e1 ldr r1, [r4, #12] + __HAL_HASH_SET_NBVALIDBITS(hhash->HashBuffSize); + 800aff8: f002 0203 and.w r2, r2, #3 + 800affc: f023 031f bic.w r3, r3, #31 + 800b000: ea43 03c2 orr.w r3, r3, r2, lsl #3 + 800b004: 60b3 str r3, [r6, #8] + hhash->Status = HASH_WriteData(hhash, hhash->pHashInBuffPtr, hhash->HashInCount); + 800b006: 6a22 ldr r2, [r4, #32] + 800b008: 4620 mov r0, r4 + 800b00a: f7ff fae3 bl 800a5d4 + 800b00e: 4605 mov r5, r0 + 800b010: f884 002c strb.w r0, [r4, #44] ; 0x2c + if (hhash->Status != HAL_OK) + 800b014: 2800 cmp r0, #0 + 800b016: d1e6 bne.n 800afe6 + if (hhash->State == HAL_HASH_STATE_SUSPENDED) + 800b018: f894 3035 ldrb.w r3, [r4, #53] ; 0x35 + 800b01c: 2b08 cmp r3, #8 + 800b01e: d0d2 beq.n 800afc6 + __HAL_HASH_START_DIGEST(); + 800b020: 68b3 ldr r3, [r6, #8] + 800b022: f443 7380 orr.w r3, r3, #256 ; 0x100 + 800b026: 60b3 str r3, [r6, #8] + if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_BUSY, SET, Timeout) != HAL_OK) + 800b028: 2201 movs r2, #1 + 800b02a: 463b mov r3, r7 + 800b02c: 2108 movs r1, #8 + 800b02e: 4620 mov r0, r4 + 800b030: f7ff fb72 bl 800a718 + 800b034: 2800 cmp r0, #0 + 800b036: d1d5 bne.n 800afe4 + hhash->Phase = HAL_HASH_PHASE_HMAC_STEP_3; + 800b038: 2305 movs r3, #5 + 800b03a: f884 302d strb.w r3, [r4, #45] ; 0x2d + hhash->pHashKeyBuffPtr = hhash->Init.pKey; + 800b03e: 68a3 ldr r3, [r4, #8] + 800b040: 6163 str r3, [r4, #20] + hhash->HashKeyCount = hhash->Init.KeySize; + 800b042: 6863 ldr r3, [r4, #4] + 800b044: 62a3 str r3, [r4, #40] ; 0x28 + if (hhash->Phase == HAL_HASH_PHASE_HMAC_STEP_3) + 800b046: e001 b.n 800b04c + if (hhash->Phase == HAL_HASH_PHASE_HMAC_STEP_2) + 800b048: 2b04 cmp r3, #4 + 800b04a: d0d2 beq.n 800aff2 + __HAL_HASH_SET_NBVALIDBITS(hhash->Init.KeySize); + 800b04c: 68b3 ldr r3, [r6, #8] + 800b04e: 6862 ldr r2, [r4, #4] + hhash->Status = HASH_WriteData(hhash, hhash->pHashKeyBuffPtr, hhash->HashKeyCount); + 800b050: 6961 ldr r1, [r4, #20] + __HAL_HASH_SET_NBVALIDBITS(hhash->Init.KeySize); + 800b052: f002 0203 and.w r2, r2, #3 + 800b056: f023 031f bic.w r3, r3, #31 + 800b05a: ea43 03c2 orr.w r3, r3, r2, lsl #3 + 800b05e: 60b3 str r3, [r6, #8] + hhash->Status = HASH_WriteData(hhash, hhash->pHashKeyBuffPtr, hhash->HashKeyCount); + 800b060: 6aa2 ldr r2, [r4, #40] ; 0x28 + 800b062: 4620 mov r0, r4 + 800b064: f7ff fab6 bl 800a5d4 + 800b068: 4605 mov r5, r0 + 800b06a: f884 002c strb.w r0, [r4, #44] ; 0x2c + if (hhash->Status != HAL_OK) + 800b06e: 2800 cmp r0, #0 + 800b070: d1b9 bne.n 800afe6 + if (hhash->State == HAL_HASH_STATE_SUSPENDED) + 800b072: f894 3035 ldrb.w r3, [r4, #53] ; 0x35 + 800b076: 2b08 cmp r3, #8 + 800b078: d0a5 beq.n 800afc6 + __HAL_HASH_START_DIGEST(); + 800b07a: 68b3 ldr r3, [r6, #8] + 800b07c: f443 7380 orr.w r3, r3, #256 ; 0x100 + 800b080: 60b3 str r3, [r6, #8] + if (HASH_WaitOnFlagUntilTimeout(hhash, HASH_FLAG_DCIS, RESET, Timeout) != HAL_OK) + 800b082: 4602 mov r2, r0 + 800b084: 463b mov r3, r7 + 800b086: 2102 movs r1, #2 + 800b088: 4620 mov r0, r4 + 800b08a: f7ff fb45 bl 800a718 + 800b08e: 4605 mov r5, r0 + 800b090: 2800 cmp r0, #0 + 800b092: d1a7 bne.n 800afe4 + HASH_GetDigest(hhash->pHashOutBuffPtr, HASH_DIGEST_LENGTH()); + 800b094: 6832 ldr r2, [r6, #0] + 800b096: 4b10 ldr r3, [pc, #64] ; (800b0d8 ) + 800b098: 6920 ldr r0, [r4, #16] + 800b09a: 421a tst r2, r3 + 800b09c: d014 beq.n 800b0c8 + 800b09e: 6832 ldr r2, [r6, #0] + 800b0a0: 401a ands r2, r3 + 800b0a2: f5b2 2f80 cmp.w r2, #262144 ; 0x40000 + 800b0a6: d011 beq.n 800b0cc + 800b0a8: 6832 ldr r2, [r6, #0] + 800b0aa: 4393 bics r3, r2 + 800b0ac: bf0c ite eq + 800b0ae: 2120 moveq r1, #32 + 800b0b0: 2110 movne r1, #16 + 800b0b2: f7ff facf bl 800a654 + hhash->Phase = HAL_HASH_PHASE_READY; + 800b0b6: 2301 movs r3, #1 + 800b0b8: f884 302d strb.w r3, [r4, #45] ; 0x2d + hhash->State = HAL_HASH_STATE_READY; + 800b0bc: f884 3035 strb.w r3, [r4, #53] ; 0x35 + __HAL_UNLOCK(hhash); + 800b0c0: 2300 movs r3, #0 + 800b0c2: f884 3034 strb.w r3, [r4, #52] ; 0x34 + return HAL_OK; + 800b0c6: e78e b.n 800afe6 + HASH_GetDigest(hhash->pHashOutBuffPtr, HASH_DIGEST_LENGTH()); + 800b0c8: 2114 movs r1, #20 + 800b0ca: e7f2 b.n 800b0b2 + 800b0cc: 211c movs r1, #28 + 800b0ce: e7f0 b.n 800b0b2 + return HAL_BUSY; + 800b0d0: 2502 movs r5, #2 + 800b0d2: e788 b.n 800afe6 + 800b0d4: 50060400 .word 0x50060400 + 800b0d8: 00040080 .word 0x00040080 + 800b0dc: fffaff3b .word 0xfffaff3b + +0800b0e0 : + * @param Tickstart : Tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef OSPI_WaitFlagStateUntilTimeout(OSPI_HandleTypeDef *hospi, uint32_t Flag, + FlagStatus State, uint32_t Tickstart, uint32_t Timeout) +{ + 800b0e0: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + 800b0e4: f8dd 8018 ldr.w r8, [sp, #24] + 800b0e8: 4604 mov r4, r0 + 800b0ea: 460e mov r6, r1 + 800b0ec: 4615 mov r5, r2 + 800b0ee: 461f mov r7, r3 + /* Wait until flag is in expected state */ + while((__HAL_OSPI_GET_FLAG(hospi, Flag)) != State) + 800b0f0: 6822 ldr r2, [r4, #0] + 800b0f2: 6a13 ldr r3, [r2, #32] + 800b0f4: 4233 tst r3, r6 + 800b0f6: bf14 ite ne + 800b0f8: 2301 movne r3, #1 + 800b0fa: 2300 moveq r3, #0 + 800b0fc: 42ab cmp r3, r5 + 800b0fe: d101 bne.n 800b104 + + return HAL_ERROR; + } + } + } + return HAL_OK; + 800b100: 2000 movs r0, #0 + 800b102: e012 b.n 800b12a + if (Timeout != HAL_MAX_DELAY) + 800b104: f1b8 3fff cmp.w r8, #4294967295 ; 0xffffffff + 800b108: d0f3 beq.n 800b0f2 + if(((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U)) + 800b10a: f7fc f967 bl 80073dc + 800b10e: 1bc0 subs r0, r0, r7 + 800b110: 4540 cmp r0, r8 + 800b112: d802 bhi.n 800b11a + 800b114: f1b8 0f00 cmp.w r8, #0 + 800b118: d1ea bne.n 800b0f0 + hospi->State = HAL_OSPI_STATE_ERROR; + 800b11a: f44f 7300 mov.w r3, #512 ; 0x200 + 800b11e: 6463 str r3, [r4, #68] ; 0x44 + hospi->ErrorCode |= HAL_OSPI_ERROR_TIMEOUT; + 800b120: 6ca3 ldr r3, [r4, #72] ; 0x48 + 800b122: f043 0301 orr.w r3, r3, #1 + 800b126: 64a3 str r3, [r4, #72] ; 0x48 + 800b128: 2001 movs r0, #1 +} + 800b12a: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + +0800b12e : +} + 800b12e: 4770 bx lr + +0800b130 : +{ + 800b130: b5f0 push {r4, r5, r6, r7, lr} + 800b132: b085 sub sp, #20 + 800b134: 4604 mov r4, r0 + uint32_t tickstart = HAL_GetTick(); + 800b136: f7fc f951 bl 80073dc + 800b13a: 4603 mov r3, r0 + if (hospi == NULL) + 800b13c: 2c00 cmp r4, #0 + 800b13e: d05d beq.n 800b1fc + hospi->ErrorCode = HAL_OSPI_ERROR_NONE; + 800b140: 2000 movs r0, #0 + 800b142: 64a0 str r0, [r4, #72] ; 0x48 + if (hospi->State == HAL_OSPI_STATE_RESET) + 800b144: 6c66 ldr r6, [r4, #68] ; 0x44 + 800b146: 2e00 cmp r6, #0 + 800b148: d156 bne.n 800b1f8 + HAL_OSPI_MspInit(hospi); + 800b14a: 4620 mov r0, r4 + 800b14c: 9303 str r3, [sp, #12] + 800b14e: f7ff ffee bl 800b12e + MODIFY_REG(hospi->Instance->DCR1, + 800b152: 6b20 ldr r0, [r4, #48] ; 0x30 + 800b154: 68e1 ldr r1, [r4, #12] + 800b156: 6825 ldr r5, [r4, #0] + status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_BUSY, RESET, tickstart, hospi->Timeout); + 800b158: 9b03 ldr r3, [sp, #12] + MODIFY_REG(hospi->Instance->DCR1, + 800b15a: 68af ldr r7, [r5, #8] + 800b15c: 4301 orrs r1, r0 + 800b15e: 69e0 ldr r0, [r4, #28] + 800b160: 4301 orrs r1, r0 + 800b162: 4827 ldr r0, [pc, #156] ; (800b200 ) + 800b164: 4038 ands r0, r7 + 800b166: 4301 orrs r1, r0 + 800b168: 6920 ldr r0, [r4, #16] + 800b16a: 3801 subs r0, #1 + 800b16c: ea41 4100 orr.w r1, r1, r0, lsl #16 + 800b170: 6960 ldr r0, [r4, #20] + 800b172: 3801 subs r0, #1 + hospi->Timeout = Timeout; + 800b174: f241 3288 movw r2, #5000 ; 0x1388 + MODIFY_REG(hospi->Instance->DCR1, + 800b178: ea41 2100 orr.w r1, r1, r0, lsl #8 + hospi->Timeout = Timeout; + 800b17c: 64e2 str r2, [r4, #76] ; 0x4c + MODIFY_REG(hospi->Instance->DCR1, + 800b17e: 60a9 str r1, [r5, #8] + hospi->Instance->DCR3 = (hospi->Init.ChipSelectBoundary << OCTOSPI_DCR3_CSBOUND_Pos); + 800b180: 6ae1 ldr r1, [r4, #44] ; 0x2c + MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FTHRES, ((hospi->Init.FifoThreshold - 1U) << OCTOSPI_CR_FTHRES_Pos)); + 800b182: 6860 ldr r0, [r4, #4] + hospi->Instance->DCR3 = (hospi->Init.ChipSelectBoundary << OCTOSPI_DCR3_CSBOUND_Pos); + 800b184: 0409 lsls r1, r1, #16 + 800b186: 6129 str r1, [r5, #16] + MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FTHRES, ((hospi->Init.FifoThreshold - 1U) << OCTOSPI_CR_FTHRES_Pos)); + 800b188: 6829 ldr r1, [r5, #0] + 800b18a: 3801 subs r0, #1 + 800b18c: f421 51f8 bic.w r1, r1, #7936 ; 0x1f00 + 800b190: ea41 2100 orr.w r1, r1, r0, lsl #8 + 800b194: 6029 str r1, [r5, #0] + status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_BUSY, RESET, tickstart, hospi->Timeout); + 800b196: 4620 mov r0, r4 + 800b198: 9200 str r2, [sp, #0] + 800b19a: 2120 movs r1, #32 + 800b19c: 4632 mov r2, r6 + 800b19e: f7ff ff9f bl 800b0e0 + if (status == HAL_OK) + 800b1a2: bb48 cbnz r0, 800b1f8 + MODIFY_REG(hospi->Instance->DCR2, OCTOSPI_DCR2_PRESCALER, ((hospi->Init.ClockPrescaler - 1U) << OCTOSPI_DCR2_PRESCALER_Pos)); + 800b1a4: 6823 ldr r3, [r4, #0] + 800b1a6: 6a22 ldr r2, [r4, #32] + 800b1a8: 68d9 ldr r1, [r3, #12] + 800b1aa: 3a01 subs r2, #1 + 800b1ac: f021 01ff bic.w r1, r1, #255 ; 0xff + 800b1b0: 430a orrs r2, r1 + 800b1b2: 60da str r2, [r3, #12] + MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_DQM, hospi->Init.DualQuad); + 800b1b4: 681a ldr r2, [r3, #0] + 800b1b6: 68a1 ldr r1, [r4, #8] + 800b1b8: f022 0240 bic.w r2, r2, #64 ; 0x40 + 800b1bc: 430a orrs r2, r1 + 800b1be: 601a str r2, [r3, #0] + MODIFY_REG(hospi->Instance->TCR, (OCTOSPI_TCR_SSHIFT | OCTOSPI_TCR_DHQC), (hospi->Init.SampleShifting | hospi->Init.DelayHoldQuarterCycle)); + 800b1c0: e9d4 2509 ldrd r2, r5, [r4, #36] ; 0x24 + 800b1c4: f8d3 1108 ldr.w r1, [r3, #264] ; 0x108 + 800b1c8: 432a orrs r2, r5 + 800b1ca: f021 41a0 bic.w r1, r1, #1342177280 ; 0x50000000 + 800b1ce: 430a orrs r2, r1 + 800b1d0: f8c3 2108 str.w r2, [r3, #264] ; 0x108 + __HAL_OSPI_ENABLE(hospi); + 800b1d4: 681a ldr r2, [r3, #0] + 800b1d6: f042 0201 orr.w r2, r2, #1 + 800b1da: 601a str r2, [r3, #0] + if (hospi->Init.FreeRunningClock == HAL_OSPI_FREERUNCLK_ENABLE) + 800b1dc: 69a2 ldr r2, [r4, #24] + 800b1de: 2a02 cmp r2, #2 + SET_BIT(hospi->Instance->DCR1, OCTOSPI_DCR1_FRCK); + 800b1e0: bf02 ittt eq + 800b1e2: 689a ldreq r2, [r3, #8] + 800b1e4: f042 0202 orreq.w r2, r2, #2 + 800b1e8: 609a streq r2, [r3, #8] + if (hospi->Init.MemoryType == HAL_OSPI_MEMTYPE_HYPERBUS) + 800b1ea: 68e3 ldr r3, [r4, #12] + 800b1ec: f1b3 6f80 cmp.w r3, #67108864 ; 0x4000000 + hospi->State = HAL_OSPI_STATE_HYPERBUS_INIT; + 800b1f0: bf0c ite eq + 800b1f2: 2301 moveq r3, #1 + hospi->State = HAL_OSPI_STATE_READY; + 800b1f4: 2302 movne r3, #2 + 800b1f6: 6463 str r3, [r4, #68] ; 0x44 +} + 800b1f8: b005 add sp, #20 + 800b1fa: bdf0 pop {r4, r5, r6, r7, pc} + status = HAL_ERROR; + 800b1fc: 2001 movs r0, #1 + 800b1fe: e7fb b.n 800b1f8 + 800b200: f8e0f8f4 .word 0xf8e0f8f4 + +0800b204 : +{ + 800b204: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + 800b208: 4605 mov r5, r0 + 800b20a: b085 sub sp, #20 + 800b20c: 460c mov r4, r1 + 800b20e: 9202 str r2, [sp, #8] + uint32_t tickstart = HAL_GetTick(); + 800b210: f7fc f8e4 bl 80073dc + state = hospi->State; + 800b214: 6c6a ldr r2, [r5, #68] ; 0x44 + if (((state == HAL_OSPI_STATE_READY) && (hospi->Init.MemoryType != HAL_OSPI_MEMTYPE_HYPERBUS)) || + 800b216: 2a02 cmp r2, #2 + uint32_t tickstart = HAL_GetTick(); + 800b218: ee07 0a90 vmov s15, r0 + if (((state == HAL_OSPI_STATE_READY) && (hospi->Init.MemoryType != HAL_OSPI_MEMTYPE_HYPERBUS)) || + 800b21c: d105 bne.n 800b22a + 800b21e: 68ea ldr r2, [r5, #12] + 800b220: f1b2 6f80 cmp.w r2, #67108864 ; 0x4000000 + 800b224: d107 bne.n 800b236 + hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; + 800b226: 2310 movs r3, #16 + 800b228: e109 b.n 800b43e + if (((state == HAL_OSPI_STATE_READY) && (hospi->Init.MemoryType != HAL_OSPI_MEMTYPE_HYPERBUS)) || + 800b22a: 2a14 cmp r2, #20 + 800b22c: f040 8084 bne.w 800b338 + ((state == HAL_OSPI_STATE_READ_CMD_CFG) && (cmd->OperationType == HAL_OSPI_OPTYPE_WRITE_CFG)) || + 800b230: 6822 ldr r2, [r4, #0] + 800b232: 2a02 cmp r2, #2 + ((state == HAL_OSPI_STATE_WRITE_CMD_CFG) && (cmd->OperationType == HAL_OSPI_OPTYPE_READ_CFG))) + 800b234: d1f7 bne.n 800b226 + status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_BUSY, RESET, tickstart, Timeout); + 800b236: 9a02 ldr r2, [sp, #8] + 800b238: 9200 str r2, [sp, #0] + 800b23a: ee17 3a90 vmov r3, s15 + 800b23e: 2200 movs r2, #0 + 800b240: 2120 movs r1, #32 + 800b242: 4628 mov r0, r5 + 800b244: edcd 7a03 vstr s15, [sp, #12] + 800b248: f7ff ff4a bl 800b0e0 + if (status == HAL_OK) + 800b24c: eddd 7a03 vldr s15, [sp, #12] + 800b250: 2800 cmp r0, #0 + 800b252: f040 80b9 bne.w 800b3c8 +{ + HAL_StatusTypeDef status = HAL_OK; + __IO uint32_t *ccr_reg, *tcr_reg, *ir_reg, *abr_reg; + + /* Re-initialize the value of the functional mode */ + MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FMODE, 0U); + 800b256: 6829 ldr r1, [r5, #0] + hospi->ErrorCode = HAL_OSPI_ERROR_NONE; + 800b258: 64a8 str r0, [r5, #72] ; 0x48 + MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FMODE, 0U); + 800b25a: 680a ldr r2, [r1, #0] + 800b25c: f022 5240 bic.w r2, r2, #805306368 ; 0x30000000 + 800b260: 600a str r2, [r1, #0] + + /* Configure the flash ID */ + if (hospi->Init.DualQuad == HAL_OSPI_DUALQUAD_DISABLE) + 800b262: 68aa ldr r2, [r5, #8] + 800b264: b92a cbnz r2, 800b272 + { + MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FSEL, cmd->FlashId); + 800b266: 680a ldr r2, [r1, #0] + 800b268: 6866 ldr r6, [r4, #4] + 800b26a: f022 0280 bic.w r2, r2, #128 ; 0x80 + 800b26e: 4332 orrs r2, r6 + 800b270: 600a str r2, [r1, #0] + } + + if (cmd->OperationType == HAL_OSPI_OPTYPE_WRITE_CFG) + 800b272: 6822 ldr r2, [r4, #0] + ir_reg = &(hospi->Instance->IR); + abr_reg = &(hospi->Instance->ABR); + } + + /* Configure the CCR register with DQS and SIOO modes */ + *ccr_reg = (cmd->DQSMode | cmd->SIOOMode); + 800b274: e9d4 6712 ldrd r6, r7, [r4, #72] ; 0x48 + if (cmd->OperationType == HAL_OSPI_OPTYPE_WRITE_CFG) + 800b278: 2a02 cmp r2, #2 + ccr_reg = &(hospi->Instance->WCCR); + 800b27a: bf0c ite eq + 800b27c: f501 72c0 addeq.w r2, r1, #384 ; 0x180 + ccr_reg = &(hospi->Instance->CCR); + 800b280: f501 7280 addne.w r2, r1, #256 ; 0x100 + *ccr_reg = (cmd->DQSMode | cmd->SIOOMode); + 800b284: ea46 0607 orr.w r6, r6, r7 + 800b288: 6016 str r6, [r2, #0] + + if (cmd->AlternateBytesMode != HAL_OSPI_ALTERNATE_BYTES_NONE) + 800b28a: 6ae6 ldr r6, [r4, #44] ; 0x2c + tcr_reg = &(hospi->Instance->WTCR); + 800b28c: bf03 ittte eq + 800b28e: f501 7cc4 addeq.w ip, r1, #392 ; 0x188 + ir_reg = &(hospi->Instance->WIR); + 800b292: f501 7ec8 addeq.w lr, r1, #400 ; 0x190 + abr_reg = &(hospi->Instance->WABR); + 800b296: f501 78d0 addeq.w r8, r1, #416 ; 0x1a0 + tcr_reg = &(hospi->Instance->TCR); + 800b29a: f501 7c84 addne.w ip, r1, #264 ; 0x108 + ir_reg = &(hospi->Instance->IR); + 800b29e: bf1c itt ne + 800b2a0: f501 7e88 addne.w lr, r1, #272 ; 0x110 + abr_reg = &(hospi->Instance->ABR); + 800b2a4: f501 7890 addne.w r8, r1, #288 ; 0x120 + if (cmd->AlternateBytesMode != HAL_OSPI_ALTERNATE_BYTES_NONE) + 800b2a8: b16e cbz r6, 800b2c6 + { + /* Configure the ABR register with alternate bytes value */ + *abr_reg = cmd->AlternateBytes; + 800b2aa: 6aa6 ldr r6, [r4, #40] ; 0x28 + 800b2ac: f8c8 6000 str.w r6, [r8] + + /* Configure the CCR register with alternate bytes communication parameters */ + MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_ABMODE | OCTOSPI_CCR_ABDTR | OCTOSPI_CCR_ABSIZE), + 800b2b0: 6ae3 ldr r3, [r4, #44] ; 0x2c + 800b2b2: 6b67 ldr r7, [r4, #52] ; 0x34 + 800b2b4: 6816 ldr r6, [r2, #0] + 800b2b6: 431f orrs r7, r3 + 800b2b8: 6b23 ldr r3, [r4, #48] ; 0x30 + 800b2ba: f426 187c bic.w r8, r6, #4128768 ; 0x3f0000 + 800b2be: 431f orrs r7, r3 + 800b2c0: ea47 0708 orr.w r7, r7, r8 + 800b2c4: 6017 str r7, [r2, #0] + (cmd->AlternateBytesMode | cmd->AlternateBytesDtrMode | cmd->AlternateBytesSize)); + } + + /* Configure the TCR register with the number of dummy cycles */ + MODIFY_REG((*tcr_reg), OCTOSPI_TCR_DCYC, cmd->DummyCycles); + 800b2c6: f8dc 7000 ldr.w r7, [ip] + 800b2ca: 6c66 ldr r6, [r4, #68] ; 0x44 + 800b2cc: f027 071f bic.w r7, r7, #31 + 800b2d0: 433e orrs r6, r7 + 800b2d2: f8cc 6000 str.w r6, [ip] + + if (cmd->DataMode != HAL_OSPI_DATA_NONE) + 800b2d6: f8d4 c038 ldr.w ip, [r4, #56] ; 0x38 + 800b2da: f1bc 0f00 cmp.w ip, #0 + 800b2de: d004 beq.n 800b2ea + { + if (cmd->OperationType == HAL_OSPI_OPTYPE_COMMON_CFG) + 800b2e0: 6827 ldr r7, [r4, #0] + 800b2e2: b917 cbnz r7, 800b2ea + { + /* Configure the DLR register with the number of data */ + hospi->Instance->DLR = (cmd->NbData - 1U); + 800b2e4: 6be7 ldr r7, [r4, #60] ; 0x3c + 800b2e6: 3f01 subs r7, #1 + 800b2e8: 640f str r7, [r1, #64] ; 0x40 + } + } + + if (cmd->InstructionMode != HAL_OSPI_INSTRUCTION_NONE) + 800b2ea: 68e6 ldr r6, [r4, #12] + { + if (cmd->AddressMode != HAL_OSPI_ADDRESS_NONE) + 800b2ec: 69e7 ldr r7, [r4, #28] + if (cmd->InstructionMode != HAL_OSPI_INSTRUCTION_NONE) + 800b2ee: 2e00 cmp r6, #0 + 800b2f0: f000 8082 beq.w 800b3f8 + if (cmd->DataMode != HAL_OSPI_DATA_NONE) + { + /* ---- Command with instruction, address and data ---- */ + + /* Configure the CCR register with all communication parameters */ + MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_IMODE | OCTOSPI_CCR_IDTR | OCTOSPI_CCR_ISIZE | + 800b2f4: e9d4 8904 ldrd r8, r9, [r4, #16] + if (cmd->AddressMode != HAL_OSPI_ADDRESS_NONE) + 800b2f8: 2f00 cmp r7, #0 + 800b2fa: d040 beq.n 800b37e + MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_IMODE | OCTOSPI_CCR_IDTR | OCTOSPI_CCR_ISIZE | + 800b2fc: e9d4 ab08 ldrd sl, fp, [r4, #32] + if (cmd->DataMode != HAL_OSPI_DATA_NONE) + 800b300: f1bc 0f00 cmp.w ip, #0 + 800b304: d01e beq.n 800b344 + MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_IMODE | OCTOSPI_CCR_IDTR | OCTOSPI_CCR_ISIZE | + 800b306: ea4c 0606 orr.w r6, ip, r6 + 800b30a: 433e orrs r6, r7 + 800b30c: ea46 0909 orr.w r9, r6, r9 + 800b310: ea49 0808 orr.w r8, r9, r8 + 800b314: 6813 ldr r3, [r2, #0] + 800b316: 6c26 ldr r6, [r4, #64] ; 0x40 + 800b318: 4f52 ldr r7, [pc, #328] ; (800b464 ) + 800b31a: ea48 0b0b orr.w fp, r8, fp + 800b31e: ea4b 0b0a orr.w fp, fp, sl + 800b322: ea4b 0606 orr.w r6, fp, r6 + 800b326: 401f ands r7, r3 + 800b328: 433e orrs r6, r7 + + /* The DHQC bit is linked with DDTR bit which should be activated */ + if ((hospi->Init.DelayHoldQuarterCycle == HAL_OSPI_DHQC_ENABLE) && + (cmd->InstructionDtrMode == HAL_OSPI_INSTRUCTION_DTR_ENABLE)) + { + MODIFY_REG((*ccr_reg), OCTOSPI_CCR_DDTR, HAL_OSPI_DATA_DTR_ENABLE); + 800b32a: 6016 str r6, [r2, #0] + } + } + + /* Configure the IR register with the instruction value */ + *ir_reg = cmd->Instruction; + 800b32c: 68a2 ldr r2, [r4, #8] + 800b32e: f8ce 2000 str.w r2, [lr] + MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_ADMODE | OCTOSPI_CCR_ADDTR | OCTOSPI_CCR_ADSIZE), + (cmd->AddressMode | cmd->AddressDtrMode | cmd->AddressSize)); + } + + /* Configure the AR register with the instruction value */ + hospi->Instance->AR = cmd->Address; + 800b332: 69a2 ldr r2, [r4, #24] + 800b334: 648a str r2, [r1, #72] ; 0x48 + if (status == HAL_OK) + 800b336: e038 b.n 800b3aa + ((state == HAL_OSPI_STATE_READ_CMD_CFG) && (cmd->OperationType == HAL_OSPI_OPTYPE_WRITE_CFG)) || + 800b338: 2a24 cmp r2, #36 ; 0x24 + 800b33a: f47f af74 bne.w 800b226 + ((state == HAL_OSPI_STATE_WRITE_CMD_CFG) && (cmd->OperationType == HAL_OSPI_OPTYPE_READ_CFG))) + 800b33e: 6822 ldr r2, [r4, #0] + 800b340: 2a01 cmp r2, #1 + 800b342: e777 b.n 800b234 + MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_IMODE | OCTOSPI_CCR_IDTR | OCTOSPI_CCR_ISIZE | + 800b344: 433e orrs r6, r7 + 800b346: f8d2 c000 ldr.w ip, [r2] + 800b34a: ea46 0609 orr.w r6, r6, r9 + 800b34e: ea46 0608 orr.w r6, r6, r8 + 800b352: ea46 060b orr.w r6, r6, fp + 800b356: f42c 5c7c bic.w ip, ip, #16128 ; 0x3f00 + 800b35a: ea46 060a orr.w r6, r6, sl + 800b35e: f02c 0c3f bic.w ip, ip, #63 ; 0x3f + 800b362: ea46 060c orr.w r6, r6, ip + 800b366: 6016 str r6, [r2, #0] + if ((hospi->Init.DelayHoldQuarterCycle == HAL_OSPI_DHQC_ENABLE) && + 800b368: 6aae ldr r6, [r5, #40] ; 0x28 + 800b36a: f1b6 5f80 cmp.w r6, #268435456 ; 0x10000000 + 800b36e: d1dd bne.n 800b32c + 800b370: 6966 ldr r6, [r4, #20] + 800b372: 2e08 cmp r6, #8 + 800b374: d1da bne.n 800b32c + MODIFY_REG((*ccr_reg), OCTOSPI_CCR_DDTR, HAL_OSPI_DATA_DTR_ENABLE); + 800b376: 6816 ldr r6, [r2, #0] + 800b378: f046 6600 orr.w r6, r6, #134217728 ; 0x8000000 + 800b37c: e7d5 b.n 800b32a + if (cmd->DataMode != HAL_OSPI_DATA_NONE) + 800b37e: f1bc 0f00 cmp.w ip, #0 + 800b382: d024 beq.n 800b3ce + MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_IMODE | OCTOSPI_CCR_IDTR | OCTOSPI_CCR_ISIZE | + 800b384: ea4c 0106 orr.w r1, ip, r6 + 800b388: 6817 ldr r7, [r2, #0] + 800b38a: 6c26 ldr r6, [r4, #64] ; 0x40 + 800b38c: ea41 0109 orr.w r1, r1, r9 + 800b390: ea41 0108 orr.w r1, r1, r8 + 800b394: f027 6a70 bic.w sl, r7, #251658240 ; 0xf000000 + 800b398: 4331 orrs r1, r6 + 800b39a: f02a 0a3f bic.w sl, sl, #63 ; 0x3f + 800b39e: ea41 010a orr.w r1, r1, sl + MODIFY_REG((*ccr_reg), OCTOSPI_CCR_DDTR, HAL_OSPI_DATA_DTR_ENABLE); + 800b3a2: 6011 str r1, [r2, #0] + *ir_reg = cmd->Instruction; + 800b3a4: 68a2 ldr r2, [r4, #8] + 800b3a6: f8ce 2000 str.w r2, [lr] + if (cmd->DataMode == HAL_OSPI_DATA_NONE) + 800b3aa: 6ba2 ldr r2, [r4, #56] ; 0x38 + 800b3ac: 2a00 cmp r2, #0 + 800b3ae: d149 bne.n 800b444 + status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_TC, SET, tickstart, Timeout); + 800b3b0: 9b02 ldr r3, [sp, #8] + 800b3b2: 9300 str r3, [sp, #0] + 800b3b4: 2201 movs r2, #1 + 800b3b6: ee17 3a90 vmov r3, s15 + 800b3ba: 2102 movs r1, #2 + 800b3bc: 4628 mov r0, r5 + 800b3be: f7ff fe8f bl 800b0e0 + __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_TC); + 800b3c2: 682b ldr r3, [r5, #0] + 800b3c4: 2202 movs r2, #2 + 800b3c6: 625a str r2, [r3, #36] ; 0x24 +} + 800b3c8: b005 add sp, #20 + 800b3ca: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_IMODE | OCTOSPI_CCR_IDTR | OCTOSPI_CCR_ISIZE), + 800b3ce: 6811 ldr r1, [r2, #0] + 800b3d0: ea46 0609 orr.w r6, r6, r9 + 800b3d4: ea46 0808 orr.w r8, r6, r8 + 800b3d8: f021 063f bic.w r6, r1, #63 ; 0x3f + 800b3dc: ea48 0606 orr.w r6, r8, r6 + 800b3e0: 6016 str r6, [r2, #0] + if ((hospi->Init.DelayHoldQuarterCycle == HAL_OSPI_DHQC_ENABLE) && + 800b3e2: 6aa9 ldr r1, [r5, #40] ; 0x28 + 800b3e4: f1b1 5f80 cmp.w r1, #268435456 ; 0x10000000 + 800b3e8: d1dc bne.n 800b3a4 + 800b3ea: 6961 ldr r1, [r4, #20] + 800b3ec: 2908 cmp r1, #8 + 800b3ee: d1d9 bne.n 800b3a4 + MODIFY_REG((*ccr_reg), OCTOSPI_CCR_DDTR, HAL_OSPI_DATA_DTR_ENABLE); + 800b3f0: 6811 ldr r1, [r2, #0] + 800b3f2: f041 6100 orr.w r1, r1, #134217728 ; 0x8000000 + 800b3f6: e7d4 b.n 800b3a2 + if (cmd->AddressMode != HAL_OSPI_ADDRESS_NONE) + 800b3f8: b307 cbz r7, 800b43c + MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_IMODE | OCTOSPI_CCR_IDTR | OCTOSPI_CCR_ISIZE | + 800b3fa: e9d4 9808 ldrd r9, r8, [r4, #32] + if (cmd->DataMode != HAL_OSPI_DATA_NONE) + 800b3fe: f1bc 0f00 cmp.w ip, #0 + 800b402: d011 beq.n 800b428 + MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_ADMODE | OCTOSPI_CCR_ADDTR | OCTOSPI_CCR_ADSIZE | + 800b404: f8d2 e000 ldr.w lr, [r2] + 800b408: 6c23 ldr r3, [r4, #64] ; 0x40 + 800b40a: ea4c 0607 orr.w r6, ip, r7 + 800b40e: ea46 0608 orr.w r6, r6, r8 + 800b412: ea46 0609 orr.w r6, r6, r9 + 800b416: f02e 6e70 bic.w lr, lr, #251658240 ; 0xf000000 + 800b41a: 431e orrs r6, r3 + 800b41c: f42e 5e7c bic.w lr, lr, #16128 ; 0x3f00 + 800b420: ea46 060e orr.w r6, r6, lr + MODIFY_REG((*ccr_reg), (OCTOSPI_CCR_ADMODE | OCTOSPI_CCR_ADDTR | OCTOSPI_CCR_ADSIZE), + 800b424: 6016 str r6, [r2, #0] + 800b426: e784 b.n 800b332 + 800b428: f8d2 c000 ldr.w ip, [r2] + 800b42c: ea48 0607 orr.w r6, r8, r7 + 800b430: ea46 0609 orr.w r6, r6, r9 + 800b434: f42c 577c bic.w r7, ip, #16128 ; 0x3f00 + 800b438: 433e orrs r6, r7 + 800b43a: e7f3 b.n 800b424 + } + else + { + /* ---- Invalid command configuration (no instruction, no address) ---- */ + status = HAL_ERROR; + hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_PARAM; + 800b43c: 2308 movs r3, #8 + hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; + 800b43e: 64ab str r3, [r5, #72] ; 0x48 + status = HAL_ERROR; + 800b440: 2001 movs r0, #1 + 800b442: e7c1 b.n 800b3c8 + if (cmd->OperationType == HAL_OSPI_OPTYPE_COMMON_CFG) + 800b444: 6823 ldr r3, [r4, #0] + 800b446: b90b cbnz r3, 800b44c + hospi->State = HAL_OSPI_STATE_CMD_CFG; + 800b448: 2304 movs r3, #4 + 800b44a: e005 b.n 800b458 + else if (cmd->OperationType == HAL_OSPI_OPTYPE_READ_CFG) + 800b44c: 2b01 cmp r3, #1 + if (hospi->State == HAL_OSPI_STATE_WRITE_CMD_CFG) + 800b44e: 6c6b ldr r3, [r5, #68] ; 0x44 + else if (cmd->OperationType == HAL_OSPI_OPTYPE_READ_CFG) + 800b450: d104 bne.n 800b45c + if (hospi->State == HAL_OSPI_STATE_WRITE_CMD_CFG) + 800b452: 2b24 cmp r3, #36 ; 0x24 + 800b454: d0f8 beq.n 800b448 + hospi->State = HAL_OSPI_STATE_READ_CMD_CFG; + 800b456: 2314 movs r3, #20 + hospi->State = HAL_OSPI_STATE_WRITE_CMD_CFG; + 800b458: 646b str r3, [r5, #68] ; 0x44 + 800b45a: e7b5 b.n 800b3c8 + if (hospi->State == HAL_OSPI_STATE_READ_CMD_CFG) + 800b45c: 2b14 cmp r3, #20 + 800b45e: d0f3 beq.n 800b448 + hospi->State = HAL_OSPI_STATE_WRITE_CMD_CFG; + 800b460: 2324 movs r3, #36 ; 0x24 + 800b462: e7f9 b.n 800b458 + 800b464: f0ffc0c0 .word 0xf0ffc0c0 + +0800b468 : +{ + 800b468: b5f0 push {r4, r5, r6, r7, lr} + 800b46a: 4604 mov r4, r0 + 800b46c: b085 sub sp, #20 + 800b46e: 460f mov r7, r1 + 800b470: 4616 mov r6, r2 + uint32_t tickstart = HAL_GetTick(); + 800b472: f7fb ffb3 bl 80073dc + __IO uint32_t *data_reg = &hospi->Instance->DR; + 800b476: 6825 ldr r5, [r4, #0] + uint32_t tickstart = HAL_GetTick(); + 800b478: 4603 mov r3, r0 + uint32_t addr_reg = hospi->Instance->AR; + 800b47a: 6ca8 ldr r0, [r5, #72] ; 0x48 + uint32_t ir_reg = hospi->Instance->IR; + 800b47c: f8d5 c110 ldr.w ip, [r5, #272] ; 0x110 + if (pData == NULL) + 800b480: b91f cbnz r7, 800b48a + hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_PARAM; + 800b482: 2308 movs r3, #8 + hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; + 800b484: 64a3 str r3, [r4, #72] ; 0x48 + status = HAL_ERROR; + 800b486: 2001 movs r0, #1 + 800b488: e034 b.n 800b4f4 + if (hospi->State == HAL_OSPI_STATE_CMD_CFG) + 800b48a: 6c62 ldr r2, [r4, #68] ; 0x44 + 800b48c: 2a04 cmp r2, #4 + 800b48e: d13b bne.n 800b508 + hospi->XferCount = READ_REG(hospi->Instance->DLR) + 1U; + 800b490: 6c2a ldr r2, [r5, #64] ; 0x40 + hospi->pBuffPtr = pData; + 800b492: 6367 str r7, [r4, #52] ; 0x34 + hospi->XferCount = READ_REG(hospi->Instance->DLR) + 1U; + 800b494: 3201 adds r2, #1 + 800b496: 63e2 str r2, [r4, #60] ; 0x3c + hospi->XferSize = hospi->XferCount; + 800b498: 6be2 ldr r2, [r4, #60] ; 0x3c + 800b49a: 63a2 str r2, [r4, #56] ; 0x38 + MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FMODE, OSPI_FUNCTIONAL_MODE_INDIRECT_READ); + 800b49c: 6829 ldr r1, [r5, #0] + if (hospi->Init.MemoryType == HAL_OSPI_MEMTYPE_HYPERBUS) + 800b49e: 68e2 ldr r2, [r4, #12] + MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FMODE, OSPI_FUNCTIONAL_MODE_INDIRECT_READ); + 800b4a0: f021 5140 bic.w r1, r1, #805306368 ; 0x30000000 + 800b4a4: f041 5180 orr.w r1, r1, #268435456 ; 0x10000000 + if (hospi->Init.MemoryType == HAL_OSPI_MEMTYPE_HYPERBUS) + 800b4a8: f1b2 6f80 cmp.w r2, #67108864 ; 0x4000000 + MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FMODE, OSPI_FUNCTIONAL_MODE_INDIRECT_READ); + 800b4ac: 6029 str r1, [r5, #0] + if (hospi->Init.MemoryType == HAL_OSPI_MEMTYPE_HYPERBUS) + 800b4ae: d123 bne.n 800b4f8 + WRITE_REG(hospi->Instance->AR, addr_reg); + 800b4b0: 64a8 str r0, [r5, #72] ; 0x48 + status = OSPI_WaitFlagStateUntilTimeout(hospi, (HAL_OSPI_FLAG_FT | HAL_OSPI_FLAG_TC), SET, tickstart, Timeout); + 800b4b2: 9600 str r6, [sp, #0] + 800b4b4: 2201 movs r2, #1 + 800b4b6: 2106 movs r1, #6 + 800b4b8: 4620 mov r0, r4 + 800b4ba: 9303 str r3, [sp, #12] + 800b4bc: f7ff fe10 bl 800b0e0 + if (status != HAL_OK) + 800b4c0: b9c0 cbnz r0, 800b4f4 + *hospi->pBuffPtr = *((__IO uint8_t *)data_reg); + 800b4c2: 6b62 ldr r2, [r4, #52] ; 0x34 + 800b4c4: f895 1050 ldrb.w r1, [r5, #80] ; 0x50 + 800b4c8: 7011 strb r1, [r2, #0] + hospi->pBuffPtr++; + 800b4ca: 6b62 ldr r2, [r4, #52] ; 0x34 + } while(hospi->XferCount > 0U); + 800b4cc: 9b03 ldr r3, [sp, #12] + hospi->pBuffPtr++; + 800b4ce: 3201 adds r2, #1 + 800b4d0: 6362 str r2, [r4, #52] ; 0x34 + hospi->XferCount--; + 800b4d2: 6be2 ldr r2, [r4, #60] ; 0x3c + 800b4d4: 3a01 subs r2, #1 + 800b4d6: 63e2 str r2, [r4, #60] ; 0x3c + } while(hospi->XferCount > 0U); + 800b4d8: 6be2 ldr r2, [r4, #60] ; 0x3c + 800b4da: 2a00 cmp r2, #0 + 800b4dc: d1e9 bne.n 800b4b2 + status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_TC, SET, tickstart, Timeout); + 800b4de: 9600 str r6, [sp, #0] + 800b4e0: 2201 movs r2, #1 + 800b4e2: 2102 movs r1, #2 + 800b4e4: 4620 mov r0, r4 + 800b4e6: f7ff fdfb bl 800b0e0 + if (status == HAL_OK) + 800b4ea: b918 cbnz r0, 800b4f4 + __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_TC); + 800b4ec: 6822 ldr r2, [r4, #0] + 800b4ee: 2302 movs r3, #2 + 800b4f0: 6253 str r3, [r2, #36] ; 0x24 + hospi->State = HAL_OSPI_STATE_READY; + 800b4f2: 6463 str r3, [r4, #68] ; 0x44 +} + 800b4f4: b005 add sp, #20 + 800b4f6: bdf0 pop {r4, r5, r6, r7, pc} + if (READ_BIT(hospi->Instance->CCR, OCTOSPI_CCR_ADMODE) != HAL_OSPI_ADDRESS_NONE) + 800b4f8: f8d5 2100 ldr.w r2, [r5, #256] ; 0x100 + 800b4fc: f412 6fe0 tst.w r2, #1792 ; 0x700 + 800b500: d1d6 bne.n 800b4b0 + WRITE_REG(hospi->Instance->IR, ir_reg); + 800b502: f8c5 c110 str.w ip, [r5, #272] ; 0x110 + 800b506: e7d4 b.n 800b4b2 + hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; + 800b508: 2310 movs r3, #16 + 800b50a: e7bb b.n 800b484 + +0800b50c : +{ + 800b50c: e92d 41ff stmdb sp!, {r0, r1, r2, r3, r4, r5, r6, r7, r8, lr} + 800b510: 4604 mov r4, r0 + 800b512: 4616 mov r6, r2 + 800b514: 460d mov r5, r1 + uint32_t tickstart = HAL_GetTick(); + 800b516: f7fb ff61 bl 80073dc + uint32_t addr_reg = hospi->Instance->AR; + 800b51a: 6822 ldr r2, [r4, #0] + 800b51c: 6c97 ldr r7, [r2, #72] ; 0x48 + uint32_t ir_reg = hospi->Instance->IR; + 800b51e: f8d2 8110 ldr.w r8, [r2, #272] ; 0x110 + if ((hospi->State == HAL_OSPI_STATE_CMD_CFG) && (cfg->AutomaticStop == HAL_OSPI_AUTOMATIC_STOP_ENABLE)) + 800b522: 6c62 ldr r2, [r4, #68] ; 0x44 + 800b524: 2a04 cmp r2, #4 + uint32_t tickstart = HAL_GetTick(); + 800b526: 4603 mov r3, r0 + if ((hospi->State == HAL_OSPI_STATE_CMD_CFG) && (cfg->AutomaticStop == HAL_OSPI_AUTOMATIC_STOP_ENABLE)) + 800b528: d13c bne.n 800b5a4 + 800b52a: 68ea ldr r2, [r5, #12] + 800b52c: f5b2 0f80 cmp.w r2, #4194304 ; 0x400000 + 800b530: d138 bne.n 800b5a4 + status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_BUSY, RESET, tickstart, Timeout); + 800b532: 9003 str r0, [sp, #12] + 800b534: 9600 str r6, [sp, #0] + 800b536: 2200 movs r2, #0 + 800b538: 2120 movs r1, #32 + 800b53a: 4620 mov r0, r4 + 800b53c: f7ff fdd0 bl 800b0e0 + if (status == HAL_OK) + 800b540: bb28 cbnz r0, 800b58e + WRITE_REG (hospi->Instance->PSMAR, cfg->Match); + 800b542: 6822 ldr r2, [r4, #0] + 800b544: 6829 ldr r1, [r5, #0] + 800b546: f8c2 1088 str.w r1, [r2, #136] ; 0x88 + WRITE_REG (hospi->Instance->PSMKR, cfg->Mask); + 800b54a: 6869 ldr r1, [r5, #4] + 800b54c: f8c2 1080 str.w r1, [r2, #128] ; 0x80 + WRITE_REG (hospi->Instance->PIR, cfg->Interval); + 800b550: 6929 ldr r1, [r5, #16] + 800b552: f8c2 1090 str.w r1, [r2, #144] ; 0x90 + MODIFY_REG(hospi->Instance->CR, (OCTOSPI_CR_PMM | OCTOSPI_CR_APMS | OCTOSPI_CR_FMODE), + 800b556: e9d5 1502 ldrd r1, r5, [r5, #8] + 800b55a: 6810 ldr r0, [r2, #0] + if (hospi->Init.MemoryType == HAL_OSPI_MEMTYPE_HYPERBUS) + 800b55c: 9b03 ldr r3, [sp, #12] + MODIFY_REG(hospi->Instance->CR, (OCTOSPI_CR_PMM | OCTOSPI_CR_APMS | OCTOSPI_CR_FMODE), + 800b55e: 4329 orrs r1, r5 + 800b560: f020 5043 bic.w r0, r0, #817889280 ; 0x30c00000 + 800b564: 4301 orrs r1, r0 + 800b566: f041 5100 orr.w r1, r1, #536870912 ; 0x20000000 + 800b56a: 6011 str r1, [r2, #0] + if (hospi->Init.MemoryType == HAL_OSPI_MEMTYPE_HYPERBUS) + 800b56c: 68e1 ldr r1, [r4, #12] + 800b56e: f1b1 6f80 cmp.w r1, #67108864 ; 0x4000000 + 800b572: d10f bne.n 800b594 + WRITE_REG(hospi->Instance->AR, addr_reg); + 800b574: 6497 str r7, [r2, #72] ; 0x48 + status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_SM, SET, tickstart, Timeout); + 800b576: 9600 str r6, [sp, #0] + 800b578: 2201 movs r2, #1 + 800b57a: 2108 movs r1, #8 + 800b57c: 4620 mov r0, r4 + 800b57e: f7ff fdaf bl 800b0e0 + if (status == HAL_OK) + 800b582: b920 cbnz r0, 800b58e + __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_SM); + 800b584: 6823 ldr r3, [r4, #0] + 800b586: 2208 movs r2, #8 + 800b588: 625a str r2, [r3, #36] ; 0x24 + hospi->State = HAL_OSPI_STATE_READY; + 800b58a: 2302 movs r3, #2 + 800b58c: 6463 str r3, [r4, #68] ; 0x44 +} + 800b58e: b004 add sp, #16 + 800b590: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + if (READ_BIT(hospi->Instance->CCR, OCTOSPI_CCR_ADMODE) != HAL_OSPI_ADDRESS_NONE) + 800b594: f8d2 1100 ldr.w r1, [r2, #256] ; 0x100 + 800b598: f411 6fe0 tst.w r1, #1792 ; 0x700 + 800b59c: d1ea bne.n 800b574 + WRITE_REG(hospi->Instance->IR, ir_reg); + 800b59e: f8c2 8110 str.w r8, [r2, #272] ; 0x110 + 800b5a2: e7e8 b.n 800b576 + hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; + 800b5a4: 2310 movs r3, #16 + 800b5a6: 64a3 str r3, [r4, #72] ; 0x48 + status = HAL_ERROR; + 800b5a8: 2001 movs r0, #1 + 800b5aa: e7f0 b.n 800b58e + +0800b5ac : +{ + 800b5ac: b5f7 push {r0, r1, r2, r4, r5, r6, r7, lr} + 800b5ae: 4604 mov r4, r0 + 800b5b0: 460f mov r7, r1 + uint32_t tickstart = HAL_GetTick(); + 800b5b2: f7fb ff13 bl 80073dc + uint32_t addr_reg = hospi->Instance->AR; + 800b5b6: 6822 ldr r2, [r4, #0] + 800b5b8: 6c95 ldr r5, [r2, #72] ; 0x48 + uint32_t ir_reg = hospi->Instance->IR; + 800b5ba: f8d2 6110 ldr.w r6, [r2, #272] ; 0x110 + if (hospi->State == HAL_OSPI_STATE_CMD_CFG) + 800b5be: 6c62 ldr r2, [r4, #68] ; 0x44 + 800b5c0: 2a04 cmp r2, #4 + uint32_t tickstart = HAL_GetTick(); + 800b5c2: 4603 mov r3, r0 + if (hospi->State == HAL_OSPI_STATE_CMD_CFG) + 800b5c4: d132 bne.n 800b62c + status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_BUSY, RESET, tickstart, hospi->Timeout); + 800b5c6: 6ce2 ldr r2, [r4, #76] ; 0x4c + 800b5c8: 9200 str r2, [sp, #0] + 800b5ca: 2120 movs r1, #32 + 800b5cc: 2200 movs r2, #0 + 800b5ce: 4620 mov r0, r4 + 800b5d0: f7ff fd86 bl 800b0e0 + if (status == HAL_OK) + 800b5d4: bb00 cbnz r0, 800b618 + WRITE_REG (hospi->Instance->PSMAR, cfg->Match); + 800b5d6: 6823 ldr r3, [r4, #0] + 800b5d8: 683a ldr r2, [r7, #0] + 800b5da: f8c3 2088 str.w r2, [r3, #136] ; 0x88 + WRITE_REG (hospi->Instance->PSMKR, cfg->Mask); + 800b5de: 687a ldr r2, [r7, #4] + 800b5e0: f8c3 2080 str.w r2, [r3, #128] ; 0x80 + WRITE_REG (hospi->Instance->PIR, cfg->Interval); + 800b5e4: 693a ldr r2, [r7, #16] + 800b5e6: f8c3 2090 str.w r2, [r3, #144] ; 0x90 + MODIFY_REG(hospi->Instance->CR, (OCTOSPI_CR_PMM | OCTOSPI_CR_APMS | OCTOSPI_CR_FMODE), + 800b5ea: e9d7 2702 ldrd r2, r7, [r7, #8] + 800b5ee: 6819 ldr r1, [r3, #0] + 800b5f0: 433a orrs r2, r7 + 800b5f2: f021 5143 bic.w r1, r1, #817889280 ; 0x30c00000 + 800b5f6: 430a orrs r2, r1 + 800b5f8: f042 5200 orr.w r2, r2, #536870912 ; 0x20000000 + 800b5fc: 601a str r2, [r3, #0] + __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_TE | HAL_OSPI_FLAG_SM); + 800b5fe: 2209 movs r2, #9 + 800b600: 625a str r2, [r3, #36] ; 0x24 + hospi->State = HAL_OSPI_STATE_BUSY_AUTO_POLLING; + 800b602: 2248 movs r2, #72 ; 0x48 + 800b604: 6462 str r2, [r4, #68] ; 0x44 + __HAL_OSPI_ENABLE_IT(hospi, HAL_OSPI_IT_SM | HAL_OSPI_IT_TE); + 800b606: 681a ldr r2, [r3, #0] + 800b608: f442 2210 orr.w r2, r2, #589824 ; 0x90000 + 800b60c: 601a str r2, [r3, #0] + if (hospi->Init.MemoryType == HAL_OSPI_MEMTYPE_HYPERBUS) + 800b60e: 68e2 ldr r2, [r4, #12] + 800b610: f1b2 6f80 cmp.w r2, #67108864 ; 0x4000000 + 800b614: d102 bne.n 800b61c + WRITE_REG(hospi->Instance->AR, addr_reg); + 800b616: 649d str r5, [r3, #72] ; 0x48 +} + 800b618: b003 add sp, #12 + 800b61a: bdf0 pop {r4, r5, r6, r7, pc} + if (READ_BIT(hospi->Instance->CCR, OCTOSPI_CCR_ADMODE) != HAL_OSPI_ADDRESS_NONE) + 800b61c: f8d3 2100 ldr.w r2, [r3, #256] ; 0x100 + 800b620: f412 6fe0 tst.w r2, #1792 ; 0x700 + 800b624: d1f7 bne.n 800b616 + WRITE_REG(hospi->Instance->IR, ir_reg); + 800b626: f8c3 6110 str.w r6, [r3, #272] ; 0x110 + 800b62a: e7f5 b.n 800b618 + hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; + 800b62c: 2310 movs r3, #16 + 800b62e: 64a3 str r3, [r4, #72] ; 0x48 + status = HAL_ERROR; + 800b630: 2001 movs r0, #1 + 800b632: e7f1 b.n 800b618 + +0800b634 : +{ + 800b634: b573 push {r0, r1, r4, r5, r6, lr} + 800b636: 4604 mov r4, r0 + 800b638: 460d mov r5, r1 + uint32_t tickstart = HAL_GetTick(); + 800b63a: f7fb fecf bl 80073dc + if (hospi->State == HAL_OSPI_STATE_CMD_CFG) + 800b63e: 6c62 ldr r2, [r4, #68] ; 0x44 + 800b640: 2a04 cmp r2, #4 + uint32_t tickstart = HAL_GetTick(); + 800b642: 4603 mov r3, r0 + if (hospi->State == HAL_OSPI_STATE_CMD_CFG) + 800b644: d121 bne.n 800b68a + status = OSPI_WaitFlagStateUntilTimeout(hospi, HAL_OSPI_FLAG_BUSY, RESET, tickstart, hospi->Timeout); + 800b646: 6ce2 ldr r2, [r4, #76] ; 0x4c + 800b648: 9200 str r2, [sp, #0] + 800b64a: 2120 movs r1, #32 + 800b64c: 2200 movs r2, #0 + 800b64e: 4620 mov r0, r4 + 800b650: f7ff fd46 bl 800b0e0 + if (status == HAL_OK) + 800b654: b9b8 cbnz r0, 800b686 + if (cfg->TimeOutActivation == HAL_OSPI_TIMEOUT_COUNTER_ENABLE) + 800b656: 682e ldr r6, [r5, #0] + WRITE_REG(hospi->Instance->LPTR, cfg->TimeOutPeriod); + 800b658: 6822 ldr r2, [r4, #0] + hospi->State = HAL_OSPI_STATE_BUSY_MEM_MAPPED; + 800b65a: 2388 movs r3, #136 ; 0x88 + if (cfg->TimeOutActivation == HAL_OSPI_TIMEOUT_COUNTER_ENABLE) + 800b65c: 2e08 cmp r6, #8 + hospi->State = HAL_OSPI_STATE_BUSY_MEM_MAPPED; + 800b65e: 6463 str r3, [r4, #68] ; 0x44 + if (cfg->TimeOutActivation == HAL_OSPI_TIMEOUT_COUNTER_ENABLE) + 800b660: d108 bne.n 800b674 + WRITE_REG(hospi->Instance->LPTR, cfg->TimeOutPeriod); + 800b662: 686b ldr r3, [r5, #4] + 800b664: f8c2 3130 str.w r3, [r2, #304] ; 0x130 + __HAL_OSPI_CLEAR_FLAG(hospi, HAL_OSPI_FLAG_TO); + 800b668: 2310 movs r3, #16 + 800b66a: 6253 str r3, [r2, #36] ; 0x24 + __HAL_OSPI_ENABLE_IT(hospi, HAL_OSPI_IT_TO); + 800b66c: 6811 ldr r1, [r2, #0] + 800b66e: f441 1180 orr.w r1, r1, #1048576 ; 0x100000 + 800b672: 6011 str r1, [r2, #0] + MODIFY_REG(hospi->Instance->CR, (OCTOSPI_CR_TCEN | OCTOSPI_CR_FMODE), + 800b674: 6813 ldr r3, [r2, #0] + 800b676: f023 5340 bic.w r3, r3, #805306368 ; 0x30000000 + 800b67a: f023 0308 bic.w r3, r3, #8 + 800b67e: 4333 orrs r3, r6 + 800b680: f043 5340 orr.w r3, r3, #805306368 ; 0x30000000 + 800b684: 6013 str r3, [r2, #0] +} + 800b686: b002 add sp, #8 + 800b688: bd70 pop {r4, r5, r6, pc} + hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; + 800b68a: 2310 movs r3, #16 + 800b68c: 64a3 str r3, [r4, #72] ; 0x48 + status = HAL_ERROR; + 800b68e: 2001 movs r0, #1 + 800b690: e7f9 b.n 800b686 + +0800b692 : + if ((hospi->State & OSPI_BUSY_STATE_MASK) == 0U) + 800b692: 6c43 ldr r3, [r0, #68] ; 0x44 + 800b694: f013 0308 ands.w r3, r3, #8 + 800b698: d10a bne.n 800b6b0 + hospi->Init.FifoThreshold = Threshold; + 800b69a: 6041 str r1, [r0, #4] + MODIFY_REG(hospi->Instance->CR, OCTOSPI_CR_FTHRES, ((hospi->Init.FifoThreshold-1U) << OCTOSPI_CR_FTHRES_Pos)); + 800b69c: 6800 ldr r0, [r0, #0] + 800b69e: 6802 ldr r2, [r0, #0] + 800b6a0: 3901 subs r1, #1 + 800b6a2: f422 52f8 bic.w r2, r2, #7936 ; 0x1f00 + 800b6a6: ea42 2101 orr.w r1, r2, r1, lsl #8 + 800b6aa: 6001 str r1, [r0, #0] + HAL_StatusTypeDef status = HAL_OK; + 800b6ac: 4618 mov r0, r3 + 800b6ae: 4770 bx lr + hospi->ErrorCode = HAL_OSPI_ERROR_INVALID_SEQUENCE; + 800b6b0: 2310 movs r3, #16 + 800b6b2: 6483 str r3, [r0, #72] ; 0x48 + status = HAL_ERROR; + 800b6b4: 2001 movs r0, #1 +} + 800b6b6: 4770 bx lr + +0800b6b8 : + return ((READ_BIT(hospi->Instance->CR, OCTOSPI_CR_FTHRES) >> OCTOSPI_CR_FTHRES_Pos) + 1U); + 800b6b8: 6803 ldr r3, [r0, #0] + 800b6ba: 6818 ldr r0, [r3, #0] + 800b6bc: f3c0 2004 ubfx r0, r0, #8, #5 +} + 800b6c0: 3001 adds r0, #1 + 800b6c2: 4770 bx lr + +0800b6c4 : + hospi->Timeout = Timeout; + 800b6c4: 64c1 str r1, [r0, #76] ; 0x4c +} + 800b6c6: 2000 movs r0, #0 + 800b6c8: 4770 bx lr + +0800b6ca : + return hospi->ErrorCode; + 800b6ca: 6c80 ldr r0, [r0, #72] ; 0x48 +} + 800b6cc: 4770 bx lr + +0800b6ce : + return hospi->State; + 800b6ce: 6c40 ldr r0, [r0, #68] ; 0x44 +} + 800b6d0: 4770 bx lr + ... + +0800b6d4 : +{ + 800b6d4: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + if (hospi->Instance == OCTOSPI1) + 800b6d8: 6802 ldr r2, [r0, #0] + other_instance = 0U; + 800b6da: 4bbf ldr r3, [pc, #764] ; (800b9d8 ) + * @retval HAL status + */ +static HAL_StatusTypeDef OSPIM_GetConfig(uint8_t instance_nb, OSPIM_CfgTypeDef *cfg) +{ + HAL_StatusTypeDef status = HAL_OK; + uint32_t reg, value = 0U; + 800b6dc: f8df 8304 ldr.w r8, [pc, #772] ; 800b9e4 + other_instance = 0U; + 800b6e0: 429a cmp r2, r3 +{ + 800b6e2: b08b sub sp, #44 ; 0x2c + } + + /* Get the information about the instance */ + for (index = 0U; index < OSPI_IOM_NB_PORTS; index ++) + { + reg = OCTOSPIM->PCR[index]; + 800b6e4: 4bbd ldr r3, [pc, #756] ; (800b9dc ) + other_instance = 0U; + 800b6e6: bf0b itete eq + 800b6e8: f04f 0a01 moveq.w sl, #1 + 800b6ec: f04f 0a00 movne.w sl, #0 + 800b6f0: 2000 moveq r0, #0 + 800b6f2: 2001 movne r0, #1 + for (index = 0U; index < OSPI_NB_INSTANCE; index++) + 800b6f4: 466a mov r2, sp + instance = 1U; + 800b6f6: 2501 movs r5, #1 + cfg->ClkPort = 0U; + 800b6f8: 2700 movs r7, #0 + cfg->DQSPort = 0U; + 800b6fa: e9c2 7700 strd r7, r7, [r2] + cfg->IOLowPort = 0U; + 800b6fe: e9c2 7702 strd r7, r7, [r2, #8] + uint32_t reg, value = 0U; + 800b702: 2d02 cmp r5, #2 + 800b704: bf0c ite eq + 800b706: 46c4 moveq ip, r8 + 800b708: f04f 0c00 movne.w ip, #0 + cfg->IOHighPort = 0U; + 800b70c: 6117 str r7, [r2, #16] + for (index = 0U; index < OSPI_IOM_NB_PORTS; index ++) + 800b70e: f04f 0e00 mov.w lr, #0 + reg = OCTOSPIM->PCR[index]; + 800b712: eb03 048e add.w r4, r3, lr, lsl #2 + { + /* The clock is enabled on this port */ + if ((reg & OCTOSPIM_PCR_CLKSRC) == (value & OCTOSPIM_PCR_CLKSRC)) + { + /* The clock correspond to the instance passed as parameter */ + cfg->ClkPort = index+1U; + 800b716: f10e 0601 add.w r6, lr, #1 + reg = OCTOSPIM->PCR[index]; + 800b71a: 6864 ldr r4, [r4, #4] + if ((reg & OCTOSPIM_PCR_CLKEN) != 0U) + 800b71c: f014 0f01 tst.w r4, #1 + 800b720: d005 beq.n 800b72e + if ((reg & OCTOSPIM_PCR_CLKSRC) == (value & OCTOSPIM_PCR_CLKSRC)) + 800b722: ea84 0e0c eor.w lr, r4, ip + 800b726: f01e 0f02 tst.w lr, #2 + cfg->ClkPort = index+1U; + 800b72a: bf08 it eq + 800b72c: 6016 streq r6, [r2, #0] + } + } + + if ((reg & OCTOSPIM_PCR_DQSEN) != 0U) + 800b72e: f014 0f10 tst.w r4, #16 + 800b732: d005 beq.n 800b740 + { + /* The DQS is enabled on this port */ + if ((reg & OCTOSPIM_PCR_DQSSRC) == (value & OCTOSPIM_PCR_DQSSRC)) + 800b734: ea84 0e0c eor.w lr, r4, ip + 800b738: f01e 0f20 tst.w lr, #32 + { + /* The DQS correspond to the instance passed as parameter */ + cfg->DQSPort = index+1U; + 800b73c: bf08 it eq + 800b73e: 6056 streq r6, [r2, #4] + } + } + + if ((reg & OCTOSPIM_PCR_NCSEN) != 0U) + 800b740: f414 7f80 tst.w r4, #256 ; 0x100 + 800b744: d005 beq.n 800b752 + { + /* The nCS is enabled on this port */ + if ((reg & OCTOSPIM_PCR_NCSSRC) == (value & OCTOSPIM_PCR_NCSSRC)) + 800b746: ea84 0e0c eor.w lr, r4, ip + 800b74a: f41e 7f00 tst.w lr, #512 ; 0x200 + { + /* The nCS correspond to the instance passed as parameter */ + cfg->NCSPort = index+1U; + 800b74e: bf08 it eq + 800b750: 6096 streq r6, [r2, #8] + } + } + + if ((reg & OCTOSPIM_PCR_IOLEN) != 0U) + 800b752: f414 3f80 tst.w r4, #65536 ; 0x10000 + 800b756: d00d beq.n 800b774 + { + /* The IO Low is enabled on this port */ + if ((reg & OCTOSPIM_PCR_IOLSRC_1) == (value & OCTOSPIM_PCR_IOLSRC_1)) + 800b758: ea84 0e0c eor.w lr, r4, ip + 800b75c: f41e 2f80 tst.w lr, #262144 ; 0x40000 + 800b760: d108 bne.n 800b774 + { + /* The IO Low correspond to the instance passed as parameter */ + if ((reg & OCTOSPIM_PCR_IOLSRC_0) == 0U) + 800b762: f414 3f00 tst.w r4, #131072 ; 0x20000 + { + cfg->IOLowPort = (OCTOSPIM_PCR_IOLEN | (index+1U)); + 800b766: bf0c ite eq + 800b768: f446 3e80 orreq.w lr, r6, #65536 ; 0x10000 + } + else + { + cfg->IOLowPort = (OCTOSPIM_PCR_IOHEN | (index+1U)); + 800b76c: f046 7e80 orrne.w lr, r6, #16777216 ; 0x1000000 + 800b770: f8c2 e00c str.w lr, [r2, #12] + } + } + } + + if ((reg & OCTOSPIM_PCR_IOHEN) != 0U) + 800b774: f014 7f80 tst.w r4, #16777216 ; 0x1000000 + 800b778: d00b beq.n 800b792 + { + /* The IO High is enabled on this port */ + if ((reg & OCTOSPIM_PCR_IOHSRC_1) == (value & OCTOSPIM_PCR_IOHSRC_1)) + 800b77a: ea84 0e0c eor.w lr, r4, ip + 800b77e: f01e 6f80 tst.w lr, #67108864 ; 0x4000000 + 800b782: d106 bne.n 800b792 + { + /* The IO High correspond to the instance passed as parameter */ + if ((reg & OCTOSPIM_PCR_IOHSRC_0) == 0U) + 800b784: 01a4 lsls r4, r4, #6 + { + cfg->IOHighPort = (OCTOSPIM_PCR_IOLEN | (index+1U)); + 800b786: bf54 ite pl + 800b788: f446 3480 orrpl.w r4, r6, #65536 ; 0x10000 + } + else + { + cfg->IOHighPort = (OCTOSPIM_PCR_IOHEN | (index+1U)); + 800b78c: f046 7480 orrmi.w r4, r6, #16777216 ; 0x1000000 + 800b790: 6114 str r4, [r2, #16] + for (index = 0U; index < OSPI_IOM_NB_PORTS; index ++) + 800b792: 2e02 cmp r6, #2 + 800b794: f04f 0e01 mov.w lr, #1 + 800b798: d1bb bne.n 800b712 + for (index = 0U; index < OSPI_NB_INSTANCE; index++) + 800b79a: 2d02 cmp r5, #2 + 800b79c: f102 0214 add.w r2, r2, #20 + 800b7a0: f040 8117 bne.w 800b9d2 + if ((OCTOSPI1->CR & OCTOSPI_CR_EN) != 0U) + 800b7a4: 4c8c ldr r4, [pc, #560] ; (800b9d8 ) + 800b7a6: 6825 ldr r5, [r4, #0] + 800b7a8: ea15 050e ands.w r5, r5, lr + CLEAR_BIT(OCTOSPI1->CR, OCTOSPI_CR_EN); + 800b7ac: bf1e ittt ne + 800b7ae: 6822 ldrne r2, [r4, #0] + 800b7b0: f022 0201 bicne.w r2, r2, #1 + 800b7b4: 6022 strne r2, [r4, #0] + if ((OCTOSPI2->CR & OCTOSPI_CR_EN) != 0U) + 800b7b6: 4a8a ldr r2, [pc, #552] ; (800b9e0 ) + 800b7b8: 6814 ldr r4, [r2, #0] + ospi_enabled |= 0x1U; + 800b7ba: bf18 it ne + 800b7bc: 4675 movne r5, lr + if ((OCTOSPI2->CR & OCTOSPI_CR_EN) != 0U) + 800b7be: 07e6 lsls r6, r4, #31 + CLEAR_BIT(OCTOSPI2->CR, OCTOSPI_CR_EN); + 800b7c0: bf42 ittt mi + 800b7c2: 6814 ldrmi r4, [r2, #0] + 800b7c4: f024 0401 bicmi.w r4, r4, #1 + 800b7c8: 6014 strmi r4, [r2, #0] + CLEAR_BIT(OCTOSPIM->PCR[(IOM_cfg[instance].NCSPort-1U)], OCTOSPIM_PCR_NCSEN); + 800b7ca: aa0a add r2, sp, #40 ; 0x28 + 800b7cc: f04f 0414 mov.w r4, #20 + 800b7d0: fb04 2400 mla r4, r4, r0, r2 + ospi_enabled |= 0x2U; + 800b7d4: bf48 it mi + 800b7d6: f045 0b02 orrmi.w fp, r5, #2 + CLEAR_BIT(OCTOSPIM->PCR[(IOM_cfg[instance].NCSPort-1U)], OCTOSPIM_PCR_NCSEN); + 800b7da: f854 2c20 ldr.w r2, [r4, #-32] + 800b7de: f102 32ff add.w r2, r2, #4294967295 ; 0xffffffff + 800b7e2: eb03 0282 add.w r2, r3, r2, lsl #2 + 800b7e6: bf58 it pl + 800b7e8: 46ab movpl fp, r5 + 800b7ea: 6856 ldr r6, [r2, #4] + 800b7ec: f426 7680 bic.w r6, r6, #256 ; 0x100 + 800b7f0: 6056 str r6, [r2, #4] + if (IOM_cfg[instance].ClkPort != 0U) + 800b7f2: f854 2c28 ldr.w r2, [r4, #-40] + 800b7f6: b382 cbz r2, 800b85a + CLEAR_BIT(OCTOSPIM->PCR[(IOM_cfg[instance].ClkPort-1U)], OCTOSPIM_PCR_CLKEN); + 800b7f8: 3a01 subs r2, #1 + 800b7fa: eb03 0282 add.w r2, r3, r2, lsl #2 + 800b7fe: 6856 ldr r6, [r2, #4] + 800b800: f026 0601 bic.w r6, r6, #1 + 800b804: 6056 str r6, [r2, #4] + if (IOM_cfg[instance].DQSPort != 0U) + 800b806: f854 2c24 ldr.w r2, [r4, #-36] + 800b80a: b132 cbz r2, 800b81a + CLEAR_BIT(OCTOSPIM->PCR[(IOM_cfg[instance].DQSPort-1U)], OCTOSPIM_PCR_DQSEN); + 800b80c: 3a01 subs r2, #1 + 800b80e: eb03 0282 add.w r2, r3, r2, lsl #2 + 800b812: 6854 ldr r4, [r2, #4] + 800b814: f024 0410 bic.w r4, r4, #16 + 800b818: 6054 str r4, [r2, #4] + if (IOM_cfg[instance].IOLowPort != HAL_OSPIM_IOPORT_NONE) + 800b81a: 2214 movs r2, #20 + 800b81c: ac0a add r4, sp, #40 ; 0x28 + 800b81e: fb02 4200 mla r2, r2, r0, r4 + 800b822: f852 2c1c ldr.w r2, [r2, #-28] + 800b826: b142 cbz r2, 800b83a + CLEAR_BIT(OCTOSPIM->PCR[((IOM_cfg[instance].IOLowPort-1U)& OSPI_IOM_PORT_MASK)], OCTOSPIM_PCR_IOLEN); + 800b828: 3a01 subs r2, #1 + 800b82a: f002 0201 and.w r2, r2, #1 + 800b82e: eb03 0282 add.w r2, r3, r2, lsl #2 + 800b832: 6854 ldr r4, [r2, #4] + 800b834: f424 3480 bic.w r4, r4, #65536 ; 0x10000 + 800b838: 6054 str r4, [r2, #4] + if (IOM_cfg[instance].IOHighPort != HAL_OSPIM_IOPORT_NONE) + 800b83a: 2214 movs r2, #20 + 800b83c: ac0a add r4, sp, #40 ; 0x28 + 800b83e: fb02 4200 mla r2, r2, r0, r4 + 800b842: f852 2c18 ldr.w r2, [r2, #-24] + 800b846: b142 cbz r2, 800b85a + CLEAR_BIT(OCTOSPIM->PCR[((IOM_cfg[instance].IOHighPort-1U)& OSPI_IOM_PORT_MASK)], OCTOSPIM_PCR_IOHEN); + 800b848: 3a01 subs r2, #1 + 800b84a: f002 0201 and.w r2, r2, #1 + 800b84e: eb03 0282 add.w r2, r3, r2, lsl #2 + 800b852: 6854 ldr r4, [r2, #4] + 800b854: f024 7480 bic.w r4, r4, #16777216 ; 0x1000000 + 800b858: 6054 str r4, [r2, #4] + if ((cfg->ClkPort == IOM_cfg[other_instance].ClkPort) || (cfg->DQSPort == IOM_cfg[other_instance].DQSPort) || + 800b85a: aa0a add r2, sp, #40 ; 0x28 + 800b85c: f04f 0914 mov.w r9, #20 + 800b860: fb09 290a mla r9, r9, sl, r2 + 800b864: f8d1 c000 ldr.w ip, [r1] + 800b868: f859 8c28 ldr.w r8, [r9, #-40] + (cfg->IOHighPort == IOM_cfg[other_instance].IOHighPort)) + 800b86c: f859 4c18 ldr.w r4, [r9, #-24] + if ((cfg->ClkPort == IOM_cfg[other_instance].ClkPort) || (cfg->DQSPort == IOM_cfg[other_instance].DQSPort) || + 800b870: 45c4 cmp ip, r8 + (cfg->NCSPort == IOM_cfg[other_instance].NCSPort) || (cfg->IOLowPort == IOM_cfg[other_instance].IOLowPort) || + 800b872: e9d1 6e01 ldrd r6, lr, [r1, #4] + (cfg->IOHighPort == IOM_cfg[other_instance].IOHighPort)) + 800b876: e9d1 2103 ldrd r2, r1, [r1, #12] + if ((cfg->ClkPort == IOM_cfg[other_instance].ClkPort) || (cfg->DQSPort == IOM_cfg[other_instance].DQSPort) || + 800b87a: d00d beq.n 800b898 + 800b87c: f859 7c24 ldr.w r7, [r9, #-36] + 800b880: 42b7 cmp r7, r6 + 800b882: d009 beq.n 800b898 + 800b884: f859 7c20 ldr.w r7, [r9, #-32] + 800b888: 45be cmp lr, r7 + 800b88a: d005 beq.n 800b898 + (cfg->NCSPort == IOM_cfg[other_instance].NCSPort) || (cfg->IOLowPort == IOM_cfg[other_instance].IOLowPort) || + 800b88c: f859 7c1c ldr.w r7, [r9, #-28] + 800b890: 4297 cmp r7, r2 + 800b892: d001 beq.n 800b898 + 800b894: 428c cmp r4, r1 + 800b896: d142 bne.n 800b91e + CLEAR_BIT(OCTOSPIM->PCR[(IOM_cfg[other_instance].ClkPort-1U)], OCTOSPIM_PCR_CLKEN); + 800b898: f108 38ff add.w r8, r8, #4294967295 ; 0xffffffff + 800b89c: eb03 0888 add.w r8, r3, r8, lsl #2 + 800b8a0: f8d8 7004 ldr.w r7, [r8, #4] + 800b8a4: f027 0701 bic.w r7, r7, #1 + 800b8a8: f8c8 7004 str.w r7, [r8, #4] + if (IOM_cfg[other_instance].DQSPort != 0U) + 800b8ac: 2714 movs r7, #20 + 800b8ae: f10d 0828 add.w r8, sp, #40 ; 0x28 + 800b8b2: fb07 870a mla r7, r7, sl, r8 + 800b8b6: f857 7c24 ldr.w r7, [r7, #-36] + 800b8ba: b147 cbz r7, 800b8ce + CLEAR_BIT(OCTOSPIM->PCR[(IOM_cfg[other_instance].DQSPort-1U)], OCTOSPIM_PCR_DQSEN); + 800b8bc: 3f01 subs r7, #1 + 800b8be: eb03 0787 add.w r7, r3, r7, lsl #2 + 800b8c2: f8d7 8004 ldr.w r8, [r7, #4] + 800b8c6: f028 0810 bic.w r8, r8, #16 + 800b8ca: f8c7 8004 str.w r8, [r7, #4] + CLEAR_BIT(OCTOSPIM->PCR[(IOM_cfg[other_instance].NCSPort-1U)], OCTOSPIM_PCR_NCSEN); + 800b8ce: 2714 movs r7, #20 + 800b8d0: f10d 0828 add.w r8, sp, #40 ; 0x28 + 800b8d4: fb07 8a0a mla sl, r7, sl, r8 + 800b8d8: f85a 7c20 ldr.w r7, [sl, #-32] + 800b8dc: 3f01 subs r7, #1 + 800b8de: eb03 0787 add.w r7, r3, r7, lsl #2 + 800b8e2: f8d7 8004 ldr.w r8, [r7, #4] + 800b8e6: f428 7880 bic.w r8, r8, #256 ; 0x100 + 800b8ea: f8c7 8004 str.w r8, [r7, #4] + if (IOM_cfg[other_instance].IOLowPort != HAL_OSPIM_IOPORT_NONE) + 800b8ee: f85a 7c1c ldr.w r7, [sl, #-28] + 800b8f2: b157 cbz r7, 800b90a + CLEAR_BIT(OCTOSPIM->PCR[((IOM_cfg[other_instance].IOLowPort-1U)& OSPI_IOM_PORT_MASK)], OCTOSPIM_PCR_IOLEN); + 800b8f4: 3f01 subs r7, #1 + 800b8f6: f007 0701 and.w r7, r7, #1 + 800b8fa: eb03 0787 add.w r7, r3, r7, lsl #2 + 800b8fe: f8d7 8004 ldr.w r8, [r7, #4] + 800b902: f428 3880 bic.w r8, r8, #65536 ; 0x10000 + 800b906: f8c7 8004 str.w r8, [r7, #4] + if (IOM_cfg[other_instance].IOHighPort != HAL_OSPIM_IOPORT_NONE) + 800b90a: b144 cbz r4, 800b91e + CLEAR_BIT(OCTOSPIM->PCR[((IOM_cfg[other_instance].IOHighPort-1U)& OSPI_IOM_PORT_MASK)], OCTOSPIM_PCR_IOHEN); + 800b90c: 3c01 subs r4, #1 + 800b90e: f004 0401 and.w r4, r4, #1 + 800b912: eb03 0484 add.w r4, r3, r4, lsl #2 + 800b916: 6867 ldr r7, [r4, #4] + 800b918: f027 7780 bic.w r7, r7, #16777216 ; 0x1000000 + 800b91c: 6067 str r7, [r4, #4] + MODIFY_REG(OCTOSPIM->PCR[(cfg->NCSPort-1U)], (OCTOSPIM_PCR_NCSEN | OCTOSPIM_PCR_NCSSRC), (OCTOSPIM_PCR_NCSEN | (instance << OCTOSPIM_PCR_NCSSRC_Pos))); + 800b91e: f10e 3eff add.w lr, lr, #4294967295 ; 0xffffffff + 800b922: eb03 0e8e add.w lr, r3, lr, lsl #2 + MODIFY_REG(OCTOSPIM->PCR[(cfg->ClkPort-1U)], (OCTOSPIM_PCR_CLKEN | OCTOSPIM_PCR_CLKSRC), (OCTOSPIM_PCR_CLKEN | (instance << OCTOSPIM_PCR_CLKSRC_Pos))); + 800b926: f10c 3cff add.w ip, ip, #4294967295 ; 0xffffffff + MODIFY_REG(OCTOSPIM->PCR[(cfg->NCSPort-1U)], (OCTOSPIM_PCR_NCSEN | OCTOSPIM_PCR_NCSSRC), (OCTOSPIM_PCR_NCSEN | (instance << OCTOSPIM_PCR_NCSSRC_Pos))); + 800b92a: f8de 4004 ldr.w r4, [lr, #4] + 800b92e: f424 7440 bic.w r4, r4, #768 ; 0x300 + 800b932: ea44 2440 orr.w r4, r4, r0, lsl #9 + 800b936: f444 7480 orr.w r4, r4, #256 ; 0x100 + MODIFY_REG(OCTOSPIM->PCR[(cfg->ClkPort-1U)], (OCTOSPIM_PCR_CLKEN | OCTOSPIM_PCR_CLKSRC), (OCTOSPIM_PCR_CLKEN | (instance << OCTOSPIM_PCR_CLKSRC_Pos))); + 800b93a: eb03 0c8c add.w ip, r3, ip, lsl #2 + MODIFY_REG(OCTOSPIM->PCR[(cfg->NCSPort-1U)], (OCTOSPIM_PCR_NCSEN | OCTOSPIM_PCR_NCSSRC), (OCTOSPIM_PCR_NCSEN | (instance << OCTOSPIM_PCR_NCSSRC_Pos))); + 800b93e: f8ce 4004 str.w r4, [lr, #4] + MODIFY_REG(OCTOSPIM->PCR[(cfg->ClkPort-1U)], (OCTOSPIM_PCR_CLKEN | OCTOSPIM_PCR_CLKSRC), (OCTOSPIM_PCR_CLKEN | (instance << OCTOSPIM_PCR_CLKSRC_Pos))); + 800b942: f8dc 4004 ldr.w r4, [ip, #4] + 800b946: f024 0403 bic.w r4, r4, #3 + 800b94a: ea44 0440 orr.w r4, r4, r0, lsl #1 + 800b94e: f044 0401 orr.w r4, r4, #1 + 800b952: f8cc 4004 str.w r4, [ip, #4] + if (cfg->DQSPort != 0U) + 800b956: b156 cbz r6, 800b96e + MODIFY_REG(OCTOSPIM->PCR[(cfg->DQSPort-1U)], (OCTOSPIM_PCR_DQSEN | OCTOSPIM_PCR_DQSSRC), (OCTOSPIM_PCR_DQSEN | (instance << OCTOSPIM_PCR_DQSSRC_Pos))); + 800b958: 3e01 subs r6, #1 + 800b95a: eb03 0686 add.w r6, r3, r6, lsl #2 + 800b95e: 6874 ldr r4, [r6, #4] + 800b960: f024 0430 bic.w r4, r4, #48 ; 0x30 + 800b964: ea44 1440 orr.w r4, r4, r0, lsl #5 + 800b968: f044 0410 orr.w r4, r4, #16 + 800b96c: 6074 str r4, [r6, #4] + if ((cfg->IOLowPort & OCTOSPIM_PCR_IOLEN) != 0U) + 800b96e: 03d4 lsls r4, r2, #15 + 800b970: d53a bpl.n 800b9e8 + MODIFY_REG(OCTOSPIM->PCR[((cfg->IOLowPort-1U)& OSPI_IOM_PORT_MASK)], (OCTOSPIM_PCR_IOLEN | OCTOSPIM_PCR_IOLSRC), + 800b972: 3a01 subs r2, #1 + 800b974: f002 0201 and.w r2, r2, #1 + 800b978: eb03 0282 add.w r2, r3, r2, lsl #2 + 800b97c: 6854 ldr r4, [r2, #4] + 800b97e: f424 24e0 bic.w r4, r4, #458752 ; 0x70000 + 800b982: ea44 4480 orr.w r4, r4, r0, lsl #18 + 800b986: f444 3480 orr.w r4, r4, #65536 ; 0x10000 + MODIFY_REG(OCTOSPIM->PCR[((cfg->IOLowPort-1U)& OSPI_IOM_PORT_MASK)], (OCTOSPIM_PCR_IOHEN | OCTOSPIM_PCR_IOHSRC), + 800b98a: 6054 str r4, [r2, #4] + if ((cfg->IOHighPort & OCTOSPIM_PCR_IOLEN) != 0U) + 800b98c: 03ca lsls r2, r1, #15 + 800b98e: d53a bpl.n 800ba06 + MODIFY_REG(OCTOSPIM->PCR[((cfg->IOHighPort-1U)& OSPI_IOM_PORT_MASK)], (OCTOSPIM_PCR_IOLEN | OCTOSPIM_PCR_IOLSRC), + 800b990: 3901 subs r1, #1 + 800b992: f001 0101 and.w r1, r1, #1 + 800b996: eb03 0381 add.w r3, r3, r1, lsl #2 + 800b99a: 685a ldr r2, [r3, #4] + 800b99c: f422 22e0 bic.w r2, r2, #458752 ; 0x70000 + 800b9a0: ea42 4080 orr.w r0, r2, r0, lsl #18 + 800b9a4: f440 3040 orr.w r0, r0, #196608 ; 0x30000 + MODIFY_REG(OCTOSPIM->PCR[((cfg->IOHighPort-1U)& OSPI_IOM_PORT_MASK)], (OCTOSPIM_PCR_IOHEN | OCTOSPIM_PCR_IOHSRC), + 800b9a8: 6058 str r0, [r3, #4] + if ((ospi_enabled & 0x1U) != 0U) + 800b9aa: b125 cbz r5, 800b9b6 + SET_BIT(OCTOSPI1->CR, OCTOSPI_CR_EN); + 800b9ac: 4a0a ldr r2, [pc, #40] ; (800b9d8 ) + 800b9ae: 6813 ldr r3, [r2, #0] + 800b9b0: f043 0301 orr.w r3, r3, #1 + 800b9b4: 6013 str r3, [r2, #0] + if ((ospi_enabled & 0x2U) != 0U) + 800b9b6: f01b 0f02 tst.w fp, #2 + SET_BIT(OCTOSPI2->CR, OCTOSPI_CR_EN); + 800b9ba: bf1c itt ne + 800b9bc: 4a08 ldrne r2, [pc, #32] ; (800b9e0 ) + 800b9be: 6813 ldrne r3, [r2, #0] +} + 800b9c0: f04f 0000 mov.w r0, #0 + SET_BIT(OCTOSPI2->CR, OCTOSPI_CR_EN); + 800b9c4: bf1c itt ne + 800b9c6: f043 0301 orrne.w r3, r3, #1 + 800b9ca: 6013 strne r3, [r2, #0] +} + 800b9cc: b00b add sp, #44 ; 0x2c + 800b9ce: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + 800b9d2: 4635 mov r5, r6 + 800b9d4: e691 b.n 800b6fa + 800b9d6: bf00 nop + 800b9d8: a0001000 .word 0xa0001000 + 800b9dc: 50061c00 .word 0x50061c00 + 800b9e0: a0001400 .word 0xa0001400 + 800b9e4: 04040222 .word 0x04040222 + else if (cfg->IOLowPort != HAL_OSPIM_IOPORT_NONE) + 800b9e8: 2a00 cmp r2, #0 + 800b9ea: d0cf beq.n 800b98c + MODIFY_REG(OCTOSPIM->PCR[((cfg->IOLowPort-1U)& OSPI_IOM_PORT_MASK)], (OCTOSPIM_PCR_IOHEN | OCTOSPIM_PCR_IOHSRC), + 800b9ec: 3a01 subs r2, #1 + 800b9ee: f002 0201 and.w r2, r2, #1 + 800b9f2: eb03 0282 add.w r2, r3, r2, lsl #2 + 800b9f6: 6854 ldr r4, [r2, #4] + 800b9f8: f024 64e0 bic.w r4, r4, #117440512 ; 0x7000000 + 800b9fc: ea44 6480 orr.w r4, r4, r0, lsl #26 + 800ba00: f044 7480 orr.w r4, r4, #16777216 ; 0x1000000 + 800ba04: e7c1 b.n 800b98a + else if (cfg->IOHighPort != HAL_OSPIM_IOPORT_NONE) + 800ba06: 2900 cmp r1, #0 + 800ba08: d0cf beq.n 800b9aa + MODIFY_REG(OCTOSPIM->PCR[((cfg->IOHighPort-1U)& OSPI_IOM_PORT_MASK)], (OCTOSPIM_PCR_IOHEN | OCTOSPIM_PCR_IOHSRC), + 800ba0a: 3901 subs r1, #1 + 800ba0c: f001 0101 and.w r1, r1, #1 + 800ba10: eb03 0381 add.w r3, r3, r1, lsl #2 + 800ba14: 685a ldr r2, [r3, #4] + 800ba16: f022 62e0 bic.w r2, r2, #117440512 ; 0x7000000 + 800ba1a: ea42 6080 orr.w r0, r2, r0, lsl #26 + 800ba1e: f040 7040 orr.w r0, r0, #50331648 ; 0x3000000 + 800ba22: e7c1 b.n 800b9a8 + +0800ba24 : + * @arg @ref I2C_GENERATE_START_WRITE Generate Restart for write request. + * @retval None + */ +static void I2C_TransferConfig(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t Size, uint32_t Mode, + uint32_t Request) +{ + 800ba24: b530 push {r4, r5, lr} + 800ba26: 9d03 ldr r5, [sp, #12] + assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance)); + assert_param(IS_TRANSFER_MODE(Mode)); + assert_param(IS_TRANSFER_REQUEST(Request)); + + /* update CR2 register */ + MODIFY_REG(hi2c->Instance->CR2, + 800ba28: 6804 ldr r4, [r0, #0] + 800ba2a: ea45 4202 orr.w r2, r5, r2, lsl #16 + 800ba2e: 431a orrs r2, r3 + 800ba30: 4b05 ldr r3, [pc, #20] ; (800ba48 ) + 800ba32: 6860 ldr r0, [r4, #4] + 800ba34: f3c1 0109 ubfx r1, r1, #0, #10 + 800ba38: ea43 5355 orr.w r3, r3, r5, lsr #21 + 800ba3c: 430a orrs r2, r1 + 800ba3e: ea20 0003 bic.w r0, r0, r3 + 800ba42: 4302 orrs r2, r0 + 800ba44: 6062 str r2, [r4, #4] + ((I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_AUTOEND | \ + (I2C_CR2_RD_WRN & (uint32_t)(Request >> (31U - I2C_CR2_RD_WRN_Pos))) | I2C_CR2_START | I2C_CR2_STOP)), \ + (uint32_t)(((uint32_t)DevAddress & I2C_CR2_SADD) | + (((uint32_t)Size << I2C_CR2_NBYTES_Pos) & I2C_CR2_NBYTES) | (uint32_t)Mode | (uint32_t)Request)); +} + 800ba46: bd30 pop {r4, r5, pc} + 800ba48: 03ff63ff .word 0x03ff63ff + +0800ba4c : + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) + 800ba4c: 6803 ldr r3, [r0, #0] +{ + 800ba4e: b570 push {r4, r5, r6, lr} + 800ba50: 4604 mov r4, r0 + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) + 800ba52: 6998 ldr r0, [r3, #24] + 800ba54: f010 0010 ands.w r0, r0, #16 +{ + 800ba58: 460d mov r5, r1 + 800ba5a: 4616 mov r6, r2 + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) + 800ba5c: d116 bne.n 800ba8c +} + 800ba5e: bd70 pop {r4, r5, r6, pc} + if (Timeout != HAL_MAX_DELAY) + 800ba60: 1c6a adds r2, r5, #1 + 800ba62: d014 beq.n 800ba8e + if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U)) + 800ba64: f7fb fcba bl 80073dc + 800ba68: 1b80 subs r0, r0, r6 + 800ba6a: 4285 cmp r5, r0 + 800ba6c: d300 bcc.n 800ba70 + 800ba6e: b96d cbnz r5, 800ba8c + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + 800ba70: 6c63 ldr r3, [r4, #68] ; 0x44 + 800ba72: f043 0320 orr.w r3, r3, #32 + hi2c->ErrorCode |= HAL_I2C_ERROR_AF; + 800ba76: 6463 str r3, [r4, #68] ; 0x44 + hi2c->State = HAL_I2C_STATE_READY; + 800ba78: 2320 movs r3, #32 + 800ba7a: f884 3041 strb.w r3, [r4, #65] ; 0x41 + hi2c->Mode = HAL_I2C_MODE_NONE; + 800ba7e: 2300 movs r3, #0 + 800ba80: f884 3042 strb.w r3, [r4, #66] ; 0x42 + __HAL_UNLOCK(hi2c); + 800ba84: f884 3040 strb.w r3, [r4, #64] ; 0x40 + return HAL_ERROR; + 800ba88: 2001 movs r0, #1 + 800ba8a: e7e8 b.n 800ba5e + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == RESET) + 800ba8c: 6823 ldr r3, [r4, #0] + 800ba8e: 699a ldr r2, [r3, #24] + 800ba90: 0690 lsls r0, r2, #26 + 800ba92: d5e5 bpl.n 800ba60 + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); + 800ba94: 2210 movs r2, #16 + 800ba96: 61da str r2, [r3, #28] + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF); + 800ba98: 2220 movs r2, #32 + 800ba9a: 61da str r2, [r3, #28] + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXIS) != RESET) + 800ba9c: 699a ldr r2, [r3, #24] + 800ba9e: 0791 lsls r1, r2, #30 + hi2c->Instance->TXDR = 0x00U; + 800baa0: bf44 itt mi + 800baa2: 2200 movmi r2, #0 + 800baa4: 629a strmi r2, [r3, #40] ; 0x28 + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXE) == RESET) + 800baa6: 699a ldr r2, [r3, #24] + 800baa8: 07d2 lsls r2, r2, #31 + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_TXE); + 800baaa: bf5e ittt pl + 800baac: 699a ldrpl r2, [r3, #24] + 800baae: f042 0201 orrpl.w r2, r2, #1 + 800bab2: 619a strpl r2, [r3, #24] + I2C_RESET_CR2(hi2c); + 800bab4: 685a ldr r2, [r3, #4] + 800bab6: f022 72ff bic.w r2, r2, #33423360 ; 0x1fe0000 + 800baba: f422 328b bic.w r2, r2, #71168 ; 0x11600 + 800babe: f422 72ff bic.w r2, r2, #510 ; 0x1fe + 800bac2: f022 0201 bic.w r2, r2, #1 + 800bac6: 605a str r2, [r3, #4] + hi2c->ErrorCode |= HAL_I2C_ERROR_AF; + 800bac8: 6c63 ldr r3, [r4, #68] ; 0x44 + 800baca: f043 0304 orr.w r3, r3, #4 + 800bace: e7d2 b.n 800ba76 + +0800bad0 : +{ + 800bad0: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + 800bad4: 9f06 ldr r7, [sp, #24] + 800bad6: 4604 mov r4, r0 + 800bad8: 4688 mov r8, r1 + 800bada: 4616 mov r6, r2 + 800badc: 461d mov r5, r3 + while (__HAL_I2C_GET_FLAG(hi2c, Flag) == Status) + 800bade: 6822 ldr r2, [r4, #0] + 800bae0: 6993 ldr r3, [r2, #24] + 800bae2: ea38 0303 bics.w r3, r8, r3 + 800bae6: bf0c ite eq + 800bae8: 2301 moveq r3, #1 + 800baea: 2300 movne r3, #0 + 800baec: 42b3 cmp r3, r6 + 800baee: d001 beq.n 800baf4 + return HAL_OK; + 800baf0: 2000 movs r0, #0 + 800baf2: e015 b.n 800bb20 + if (Timeout != HAL_MAX_DELAY) + 800baf4: 1c6b adds r3, r5, #1 + 800baf6: d0f3 beq.n 800bae0 + if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U)) + 800baf8: f7fb fc70 bl 80073dc + 800bafc: 1bc0 subs r0, r0, r7 + 800bafe: 42a8 cmp r0, r5 + 800bb00: d801 bhi.n 800bb06 + 800bb02: 2d00 cmp r5, #0 + 800bb04: d1eb bne.n 800bade + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + 800bb06: 6c63 ldr r3, [r4, #68] ; 0x44 + 800bb08: f043 0320 orr.w r3, r3, #32 + 800bb0c: 6463 str r3, [r4, #68] ; 0x44 + hi2c->State = HAL_I2C_STATE_READY; + 800bb0e: 2320 movs r3, #32 + 800bb10: f884 3041 strb.w r3, [r4, #65] ; 0x41 + hi2c->Mode = HAL_I2C_MODE_NONE; + 800bb14: 2300 movs r3, #0 + 800bb16: f884 3042 strb.w r3, [r4, #66] ; 0x42 + __HAL_UNLOCK(hi2c); + 800bb1a: f884 3040 strb.w r3, [r4, #64] ; 0x40 + 800bb1e: 2001 movs r0, #1 +} + 800bb20: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + +0800bb24 : +{ + 800bb24: b570 push {r4, r5, r6, lr} + 800bb26: 4604 mov r4, r0 + 800bb28: 460d mov r5, r1 + 800bb2a: 4616 mov r6, r2 + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == RESET) + 800bb2c: 6823 ldr r3, [r4, #0] + 800bb2e: 699b ldr r3, [r3, #24] + 800bb30: 069b lsls r3, r3, #26 + 800bb32: d501 bpl.n 800bb38 + return HAL_OK; + 800bb34: 2000 movs r0, #0 +} + 800bb36: bd70 pop {r4, r5, r6, pc} + if (I2C_IsAcknowledgeFailed(hi2c, Timeout, Tickstart) != HAL_OK) + 800bb38: 4632 mov r2, r6 + 800bb3a: 4629 mov r1, r5 + 800bb3c: 4620 mov r0, r4 + 800bb3e: f7ff ff85 bl 800ba4c + 800bb42: b990 cbnz r0, 800bb6a + if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U)) + 800bb44: f7fb fc4a bl 80073dc + 800bb48: 1b80 subs r0, r0, r6 + 800bb4a: 42a8 cmp r0, r5 + 800bb4c: d801 bhi.n 800bb52 + 800bb4e: 2d00 cmp r5, #0 + 800bb50: d1ec bne.n 800bb2c + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + 800bb52: 6c63 ldr r3, [r4, #68] ; 0x44 + 800bb54: f043 0320 orr.w r3, r3, #32 + 800bb58: 6463 str r3, [r4, #68] ; 0x44 + hi2c->State = HAL_I2C_STATE_READY; + 800bb5a: 2320 movs r3, #32 + 800bb5c: f884 3041 strb.w r3, [r4, #65] ; 0x41 + hi2c->Mode = HAL_I2C_MODE_NONE; + 800bb60: 2300 movs r3, #0 + 800bb62: f884 3042 strb.w r3, [r4, #66] ; 0x42 + __HAL_UNLOCK(hi2c); + 800bb66: f884 3040 strb.w r3, [r4, #64] ; 0x40 + return HAL_ERROR; + 800bb6a: 2001 movs r0, #1 + 800bb6c: e7e3 b.n 800bb36 + +0800bb6e : +} + 800bb6e: 4770 bx lr + +0800bb70 : +{ + 800bb70: b510 push {r4, lr} + if (hi2c == NULL) + 800bb72: 4604 mov r4, r0 + 800bb74: 2800 cmp r0, #0 + 800bb76: d04a beq.n 800bc0e + if (hi2c->State == HAL_I2C_STATE_RESET) + 800bb78: f890 3041 ldrb.w r3, [r0, #65] ; 0x41 + 800bb7c: f003 02ff and.w r2, r3, #255 ; 0xff + 800bb80: b91b cbnz r3, 800bb8a + hi2c->Lock = HAL_UNLOCKED; + 800bb82: f880 2040 strb.w r2, [r0, #64] ; 0x40 + HAL_I2C_MspInit(hi2c); + 800bb86: f7ff fff2 bl 800bb6e + hi2c->State = HAL_I2C_STATE_BUSY; + 800bb8a: 2324 movs r3, #36 ; 0x24 + 800bb8c: f884 3041 strb.w r3, [r4, #65] ; 0x41 + __HAL_I2C_DISABLE(hi2c); + 800bb90: 6823 ldr r3, [r4, #0] + 800bb92: 681a ldr r2, [r3, #0] + 800bb94: f022 0201 bic.w r2, r2, #1 + 800bb98: 601a str r2, [r3, #0] + hi2c->Instance->TIMINGR = hi2c->Init.Timing & TIMING_CLEAR_MASK; + 800bb9a: 6862 ldr r2, [r4, #4] + 800bb9c: f022 6270 bic.w r2, r2, #251658240 ; 0xf000000 + 800bba0: 611a str r2, [r3, #16] + hi2c->Instance->OAR1 &= ~I2C_OAR1_OA1EN; + 800bba2: 689a ldr r2, [r3, #8] + 800bba4: f422 4200 bic.w r2, r2, #32768 ; 0x8000 + 800bba8: 609a str r2, [r3, #8] + hi2c->Instance->OAR1 = (I2C_OAR1_OA1EN | hi2c->Init.OwnAddress1); + 800bbaa: e9d4 2102 ldrd r2, r1, [r4, #8] + if (hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_7BIT) + 800bbae: 2901 cmp r1, #1 + 800bbb0: d124 bne.n 800bbfc + hi2c->Instance->OAR1 = (I2C_OAR1_OA1EN | hi2c->Init.OwnAddress1); + 800bbb2: f442 4200 orr.w r2, r2, #32768 ; 0x8000 + 800bbb6: 609a str r2, [r3, #8] + hi2c->Instance->CR2 |= (I2C_CR2_AUTOEND | I2C_CR2_NACK); + 800bbb8: 685a ldr r2, [r3, #4] + 800bbba: f042 7200 orr.w r2, r2, #33554432 ; 0x2000000 + 800bbbe: f442 4200 orr.w r2, r2, #32768 ; 0x8000 + 800bbc2: 605a str r2, [r3, #4] + hi2c->Instance->OAR2 &= ~I2C_DUALADDRESS_ENABLE; + 800bbc4: 68da ldr r2, [r3, #12] + 800bbc6: f422 4200 bic.w r2, r2, #32768 ; 0x8000 + 800bbca: 60da str r2, [r3, #12] + hi2c->Instance->OAR2 = (hi2c->Init.DualAddressMode | hi2c->Init.OwnAddress2 | (hi2c->Init.OwnAddress2Masks << 8)); + 800bbcc: e9d4 2104 ldrd r2, r1, [r4, #16] + 800bbd0: 430a orrs r2, r1 + 800bbd2: 69a1 ldr r1, [r4, #24] + 800bbd4: ea42 2201 orr.w r2, r2, r1, lsl #8 + 800bbd8: 60da str r2, [r3, #12] + hi2c->Instance->CR1 = (hi2c->Init.GeneralCallMode | hi2c->Init.NoStretchMode); + 800bbda: e9d4 2107 ldrd r2, r1, [r4, #28] + 800bbde: 430a orrs r2, r1 + 800bbe0: 601a str r2, [r3, #0] + __HAL_I2C_ENABLE(hi2c); + 800bbe2: 681a ldr r2, [r3, #0] + 800bbe4: f042 0201 orr.w r2, r2, #1 + 800bbe8: 601a str r2, [r3, #0] + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + 800bbea: 2000 movs r0, #0 + hi2c->State = HAL_I2C_STATE_READY; + 800bbec: 2320 movs r3, #32 + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + 800bbee: 6460 str r0, [r4, #68] ; 0x44 + hi2c->State = HAL_I2C_STATE_READY; + 800bbf0: f884 3041 strb.w r3, [r4, #65] ; 0x41 + hi2c->PreviousState = I2C_STATE_NONE; + 800bbf4: 6320 str r0, [r4, #48] ; 0x30 + hi2c->Mode = HAL_I2C_MODE_NONE; + 800bbf6: f884 0042 strb.w r0, [r4, #66] ; 0x42 +} + 800bbfa: bd10 pop {r4, pc} + hi2c->Instance->OAR1 = (I2C_OAR1_OA1EN | I2C_OAR1_OA1MODE | hi2c->Init.OwnAddress1); + 800bbfc: f442 4204 orr.w r2, r2, #33792 ; 0x8400 + if (hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_10BIT) + 800bc00: 2902 cmp r1, #2 + hi2c->Instance->OAR1 = (I2C_OAR1_OA1EN | I2C_OAR1_OA1MODE | hi2c->Init.OwnAddress1); + 800bc02: 609a str r2, [r3, #8] + hi2c->Instance->CR2 = (I2C_CR2_ADD10); + 800bc04: bf04 itt eq + 800bc06: f44f 6200 moveq.w r2, #2048 ; 0x800 + 800bc0a: 605a streq r2, [r3, #4] + 800bc0c: e7d4 b.n 800bbb8 + return HAL_ERROR; + 800bc0e: 2001 movs r0, #1 + 800bc10: e7f3 b.n 800bbfa + +0800bc12 : + 800bc12: 4770 bx lr + +0800bc14 : +{ + 800bc14: e92d 47f3 stmdb sp!, {r0, r1, r4, r5, r6, r7, r8, r9, sl, lr} + 800bc18: 4698 mov r8, r3 + if (hi2c->State == HAL_I2C_STATE_READY) + 800bc1a: f890 3041 ldrb.w r3, [r0, #65] ; 0x41 +{ + 800bc1e: 9f0a ldr r7, [sp, #40] ; 0x28 + if (hi2c->State == HAL_I2C_STATE_READY) + 800bc20: 2b20 cmp r3, #32 +{ + 800bc22: 4604 mov r4, r0 + 800bc24: 460e mov r6, r1 + 800bc26: 4691 mov r9, r2 + if (hi2c->State == HAL_I2C_STATE_READY) + 800bc28: f040 80a3 bne.w 800bd72 + __HAL_LOCK(hi2c); + 800bc2c: f890 3040 ldrb.w r3, [r0, #64] ; 0x40 + 800bc30: 2b01 cmp r3, #1 + 800bc32: f000 809e beq.w 800bd72 + 800bc36: f04f 0a01 mov.w sl, #1 + 800bc3a: f880 a040 strb.w sl, [r0, #64] ; 0x40 + tickstart = HAL_GetTick(); + 800bc3e: f7fb fbcd bl 80073dc + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY, tickstart) != HAL_OK) + 800bc42: 2319 movs r3, #25 + tickstart = HAL_GetTick(); + 800bc44: 4605 mov r5, r0 + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY, tickstart) != HAL_OK) + 800bc46: 9000 str r0, [sp, #0] + 800bc48: 4652 mov r2, sl + 800bc4a: f44f 4100 mov.w r1, #32768 ; 0x8000 + 800bc4e: 4620 mov r0, r4 + 800bc50: f7ff ff3e bl 800bad0 + 800bc54: b118 cbz r0, 800bc5e + return HAL_ERROR; + 800bc56: 2001 movs r0, #1 +} + 800bc58: b002 add sp, #8 + 800bc5a: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + hi2c->State = HAL_I2C_STATE_BUSY_TX; + 800bc5e: 2321 movs r3, #33 ; 0x21 + 800bc60: f884 3041 strb.w r3, [r4, #65] ; 0x41 + hi2c->Mode = HAL_I2C_MODE_MASTER; + 800bc64: 2310 movs r3, #16 + 800bc66: f884 3042 strb.w r3, [r4, #66] ; 0x42 + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + 800bc6a: 6460 str r0, [r4, #68] ; 0x44 + hi2c->XferCount = Size; + 800bc6c: f8a4 802a strh.w r8, [r4, #42] ; 0x2a + if (hi2c->XferCount > MAX_NBYTE_SIZE) + 800bc70: 8d63 ldrh r3, [r4, #42] ; 0x2a + hi2c->pBuffPtr = pData; + 800bc72: f8c4 9024 str.w r9, [r4, #36] ; 0x24 + if (hi2c->XferCount > MAX_NBYTE_SIZE) + 800bc76: b29b uxth r3, r3 + 800bc78: 2bff cmp r3, #255 ; 0xff + hi2c->XferISR = NULL; + 800bc7a: 6360 str r0, [r4, #52] ; 0x34 + if (hi2c->XferCount > MAX_NBYTE_SIZE) + 800bc7c: 4b3e ldr r3, [pc, #248] ; (800bd78 ) + 800bc7e: d927 bls.n 800bcd0 + hi2c->XferSize = MAX_NBYTE_SIZE; + 800bc80: 22ff movs r2, #255 ; 0xff + 800bc82: 8522 strh r2, [r4, #40] ; 0x28 + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_RELOAD_MODE, I2C_GENERATE_START_WRITE); + 800bc84: 9300 str r3, [sp, #0] + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_RELOAD_MODE, I2C_NO_STARTSTOP); + 800bc86: f04f 7380 mov.w r3, #16777216 ; 0x1000000 + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); + 800bc8a: 4631 mov r1, r6 + 800bc8c: 4620 mov r0, r4 + 800bc8e: f7ff fec9 bl 800ba24 + while (hi2c->XferCount > 0U) + 800bc92: 8d63 ldrh r3, [r4, #42] ; 0x2a + 800bc94: b29b uxth r3, r3 + 800bc96: 2b00 cmp r3, #0 + 800bc98: d13e bne.n 800bd18 + if (I2C_WaitOnSTOPFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + 800bc9a: 462a mov r2, r5 + 800bc9c: 4639 mov r1, r7 + 800bc9e: 4620 mov r0, r4 + 800bca0: f7ff ff40 bl 800bb24 + 800bca4: 2800 cmp r0, #0 + 800bca6: d1d6 bne.n 800bc56 + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF); + 800bca8: 6823 ldr r3, [r4, #0] + 800bcaa: 2120 movs r1, #32 + 800bcac: 61d9 str r1, [r3, #28] + I2C_RESET_CR2(hi2c); + 800bcae: 685a ldr r2, [r3, #4] + 800bcb0: f022 72ff bic.w r2, r2, #33423360 ; 0x1fe0000 + 800bcb4: f422 328b bic.w r2, r2, #71168 ; 0x11600 + 800bcb8: f422 72ff bic.w r2, r2, #510 ; 0x1fe + 800bcbc: f022 0201 bic.w r2, r2, #1 + 800bcc0: 605a str r2, [r3, #4] + hi2c->State = HAL_I2C_STATE_READY; + 800bcc2: f884 1041 strb.w r1, [r4, #65] ; 0x41 + __HAL_UNLOCK(hi2c); + 800bcc6: f884 0040 strb.w r0, [r4, #64] ; 0x40 + hi2c->Mode = HAL_I2C_MODE_NONE; + 800bcca: f884 0042 strb.w r0, [r4, #66] ; 0x42 + return HAL_OK; + 800bcce: e7c3 b.n 800bc58 + hi2c->XferSize = hi2c->XferCount; + 800bcd0: 8d62 ldrh r2, [r4, #42] ; 0x2a + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_GENERATE_START_WRITE); + 800bcd2: 9300 str r3, [sp, #0] + hi2c->XferSize = hi2c->XferCount; + 800bcd4: b292 uxth r2, r2 + 800bcd6: 8522 strh r2, [r4, #40] ; 0x28 + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); + 800bcd8: f04f 7300 mov.w r3, #33554432 ; 0x2000000 + 800bcdc: b2d2 uxtb r2, r2 + 800bcde: e7d4 b.n 800bc8a + if (I2C_IsAcknowledgeFailed(hi2c, Timeout, Tickstart) != HAL_OK) + 800bce0: 462a mov r2, r5 + 800bce2: 4639 mov r1, r7 + 800bce4: 4620 mov r0, r4 + 800bce6: f7ff feb1 bl 800ba4c + 800bcea: 2800 cmp r0, #0 + 800bcec: d1b3 bne.n 800bc56 + if (Timeout != HAL_MAX_DELAY) + 800bcee: 1c7a adds r2, r7, #1 + 800bcf0: d012 beq.n 800bd18 + if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U)) + 800bcf2: f7fb fb73 bl 80073dc + 800bcf6: 1b40 subs r0, r0, r5 + 800bcf8: 4287 cmp r7, r0 + 800bcfa: d300 bcc.n 800bcfe + 800bcfc: b967 cbnz r7, 800bd18 + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + 800bcfe: 6c63 ldr r3, [r4, #68] ; 0x44 + 800bd00: f043 0320 orr.w r3, r3, #32 + 800bd04: 6463 str r3, [r4, #68] ; 0x44 + hi2c->State = HAL_I2C_STATE_READY; + 800bd06: 2320 movs r3, #32 + 800bd08: f884 3041 strb.w r3, [r4, #65] ; 0x41 + hi2c->Mode = HAL_I2C_MODE_NONE; + 800bd0c: 2300 movs r3, #0 + 800bd0e: f884 3042 strb.w r3, [r4, #66] ; 0x42 + __HAL_UNLOCK(hi2c); + 800bd12: f884 3040 strb.w r3, [r4, #64] ; 0x40 + 800bd16: e79e b.n 800bc56 + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXIS) == RESET) + 800bd18: 6822 ldr r2, [r4, #0] + 800bd1a: 6993 ldr r3, [r2, #24] + 800bd1c: 079b lsls r3, r3, #30 + 800bd1e: d5df bpl.n 800bce0 + hi2c->Instance->TXDR = *hi2c->pBuffPtr; + 800bd20: 6a63 ldr r3, [r4, #36] ; 0x24 + 800bd22: f813 1b01 ldrb.w r1, [r3], #1 + 800bd26: 6291 str r1, [r2, #40] ; 0x28 + hi2c->pBuffPtr++; + 800bd28: 6263 str r3, [r4, #36] ; 0x24 + hi2c->XferCount--; + 800bd2a: 8d63 ldrh r3, [r4, #42] ; 0x2a + hi2c->XferSize--; + 800bd2c: 8d22 ldrh r2, [r4, #40] ; 0x28 + hi2c->XferCount--; + 800bd2e: 3b01 subs r3, #1 + 800bd30: b29b uxth r3, r3 + 800bd32: 8563 strh r3, [r4, #42] ; 0x2a + if ((hi2c->XferCount != 0U) && (hi2c->XferSize == 0U)) + 800bd34: 8d63 ldrh r3, [r4, #42] ; 0x2a + hi2c->XferSize--; + 800bd36: 3a01 subs r2, #1 + 800bd38: b292 uxth r2, r2 + if ((hi2c->XferCount != 0U) && (hi2c->XferSize == 0U)) + 800bd3a: b29b uxth r3, r3 + hi2c->XferSize--; + 800bd3c: 8522 strh r2, [r4, #40] ; 0x28 + if ((hi2c->XferCount != 0U) && (hi2c->XferSize == 0U)) + 800bd3e: 2b00 cmp r3, #0 + 800bd40: d0a7 beq.n 800bc92 + 800bd42: 2a00 cmp r2, #0 + 800bd44: d1a5 bne.n 800bc92 + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_TCR, RESET, Timeout, tickstart) != HAL_OK) + 800bd46: 9500 str r5, [sp, #0] + 800bd48: 463b mov r3, r7 + 800bd4a: 2180 movs r1, #128 ; 0x80 + 800bd4c: 4620 mov r0, r4 + 800bd4e: f7ff febf bl 800bad0 + 800bd52: 2800 cmp r0, #0 + 800bd54: f47f af7f bne.w 800bc56 + if (hi2c->XferCount > MAX_NBYTE_SIZE) + 800bd58: 8d63 ldrh r3, [r4, #42] ; 0x2a + 800bd5a: b29b uxth r3, r3 + 800bd5c: 2bff cmp r3, #255 ; 0xff + 800bd5e: d903 bls.n 800bd68 + hi2c->XferSize = MAX_NBYTE_SIZE; + 800bd60: 22ff movs r2, #255 ; 0xff + 800bd62: 8522 strh r2, [r4, #40] ; 0x28 + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_RELOAD_MODE, I2C_NO_STARTSTOP); + 800bd64: 9000 str r0, [sp, #0] + 800bd66: e78e b.n 800bc86 + hi2c->XferSize = hi2c->XferCount; + 800bd68: 8d62 ldrh r2, [r4, #42] ; 0x2a + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); + 800bd6a: 9000 str r0, [sp, #0] + hi2c->XferSize = hi2c->XferCount; + 800bd6c: b292 uxth r2, r2 + 800bd6e: 8522 strh r2, [r4, #40] ; 0x28 + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); + 800bd70: e7b2 b.n 800bcd8 + return HAL_BUSY; + 800bd72: 2002 movs r0, #2 + 800bd74: e770 b.n 800bc58 + 800bd76: bf00 nop + 800bd78: 80002000 .word 0x80002000 + +0800bd7c : +{ + 800bd7c: e92d 47f3 stmdb sp!, {r0, r1, r4, r5, r6, r7, r8, r9, sl, lr} + 800bd80: 4698 mov r8, r3 + if (hi2c->State == HAL_I2C_STATE_READY) + 800bd82: f890 3041 ldrb.w r3, [r0, #65] ; 0x41 +{ + 800bd86: 9f0a ldr r7, [sp, #40] ; 0x28 + if (hi2c->State == HAL_I2C_STATE_READY) + 800bd88: 2b20 cmp r3, #32 +{ + 800bd8a: 4604 mov r4, r0 + 800bd8c: 460e mov r6, r1 + 800bd8e: 4691 mov r9, r2 + if (hi2c->State == HAL_I2C_STATE_READY) + 800bd90: f040 80be bne.w 800bf10 + __HAL_LOCK(hi2c); + 800bd94: f890 3040 ldrb.w r3, [r0, #64] ; 0x40 + 800bd98: 2b01 cmp r3, #1 + 800bd9a: f000 80b9 beq.w 800bf10 + 800bd9e: f04f 0a01 mov.w sl, #1 + 800bda2: f880 a040 strb.w sl, [r0, #64] ; 0x40 + tickstart = HAL_GetTick(); + 800bda6: f7fb fb19 bl 80073dc + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY, tickstart) != HAL_OK) + 800bdaa: 2319 movs r3, #25 + tickstart = HAL_GetTick(); + 800bdac: 4605 mov r5, r0 + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY, tickstart) != HAL_OK) + 800bdae: 9000 str r0, [sp, #0] + 800bdb0: 4652 mov r2, sl + 800bdb2: f44f 4100 mov.w r1, #32768 ; 0x8000 + 800bdb6: 4620 mov r0, r4 + 800bdb8: f7ff fe8a bl 800bad0 + 800bdbc: b118 cbz r0, 800bdc6 + return HAL_ERROR; + 800bdbe: 2001 movs r0, #1 +} + 800bdc0: b002 add sp, #8 + 800bdc2: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + hi2c->State = HAL_I2C_STATE_BUSY_RX; + 800bdc6: 2322 movs r3, #34 ; 0x22 + 800bdc8: f884 3041 strb.w r3, [r4, #65] ; 0x41 + hi2c->Mode = HAL_I2C_MODE_MASTER; + 800bdcc: 2310 movs r3, #16 + 800bdce: f884 3042 strb.w r3, [r4, #66] ; 0x42 + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + 800bdd2: 6460 str r0, [r4, #68] ; 0x44 + hi2c->XferCount = Size; + 800bdd4: f8a4 802a strh.w r8, [r4, #42] ; 0x2a + if (hi2c->XferCount > MAX_NBYTE_SIZE) + 800bdd8: 8d63 ldrh r3, [r4, #42] ; 0x2a + hi2c->pBuffPtr = pData; + 800bdda: f8c4 9024 str.w r9, [r4, #36] ; 0x24 + if (hi2c->XferCount > MAX_NBYTE_SIZE) + 800bdde: b29b uxth r3, r3 + 800bde0: 2bff cmp r3, #255 ; 0xff + hi2c->XferISR = NULL; + 800bde2: 6360 str r0, [r4, #52] ; 0x34 + if (hi2c->XferCount > MAX_NBYTE_SIZE) + 800bde4: 4b4b ldr r3, [pc, #300] ; (800bf14 ) + 800bde6: d909 bls.n 800bdfc + hi2c->XferSize = MAX_NBYTE_SIZE; + 800bde8: 22ff movs r2, #255 ; 0xff + 800bdea: 8522 strh r2, [r4, #40] ; 0x28 + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_RELOAD_MODE, I2C_GENERATE_START_READ); + 800bdec: 9300 str r3, [sp, #0] + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_RELOAD_MODE, I2C_NO_STARTSTOP); + 800bdee: f04f 7380 mov.w r3, #16777216 ; 0x1000000 + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); + 800bdf2: 4631 mov r1, r6 + 800bdf4: 4620 mov r0, r4 + 800bdf6: f7ff fe15 bl 800ba24 + 800bdfa: e052 b.n 800bea2 + hi2c->XferSize = hi2c->XferCount; + 800bdfc: 8d62 ldrh r2, [r4, #42] ; 0x2a + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_GENERATE_START_READ); + 800bdfe: 9300 str r3, [sp, #0] + hi2c->XferSize = hi2c->XferCount; + 800be00: b292 uxth r2, r2 + 800be02: 8522 strh r2, [r4, #40] ; 0x28 + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); + 800be04: f04f 7300 mov.w r3, #33554432 ; 0x2000000 + 800be08: b2d2 uxtb r2, r2 + 800be0a: e7f2 b.n 800bdf2 + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF); + 800be0c: 2120 movs r1, #32 + 800be0e: 61d9 str r1, [r3, #28] + I2C_RESET_CR2(hi2c); + 800be10: 685a ldr r2, [r3, #4] + 800be12: f022 72ff bic.w r2, r2, #33423360 ; 0x1fe0000 + 800be16: f422 328b bic.w r2, r2, #71168 ; 0x11600 + 800be1a: f422 72ff bic.w r2, r2, #510 ; 0x1fe + 800be1e: f022 0201 bic.w r2, r2, #1 + 800be22: 605a str r2, [r3, #4] + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + 800be24: 2300 movs r3, #0 + 800be26: 6463 str r3, [r4, #68] ; 0x44 + hi2c->State = HAL_I2C_STATE_READY; + 800be28: f884 1041 strb.w r1, [r4, #65] ; 0x41 + hi2c->Mode = HAL_I2C_MODE_NONE; + 800be2c: f884 3042 strb.w r3, [r4, #66] ; 0x42 + __HAL_UNLOCK(hi2c); + 800be30: f884 3040 strb.w r3, [r4, #64] ; 0x40 + 800be34: e7c3 b.n 800bdbe + if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U)) + 800be36: f7fb fad1 bl 80073dc + 800be3a: 1b40 subs r0, r0, r5 + 800be3c: 4287 cmp r7, r0 + 800be3e: d300 bcc.n 800be42 + 800be40: b947 cbnz r7, 800be54 + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + 800be42: 6c63 ldr r3, [r4, #68] ; 0x44 + 800be44: f043 0320 orr.w r3, r3, #32 + 800be48: 6463 str r3, [r4, #68] ; 0x44 + hi2c->State = HAL_I2C_STATE_READY; + 800be4a: 2320 movs r3, #32 + 800be4c: f884 3041 strb.w r3, [r4, #65] ; 0x41 + __HAL_UNLOCK(hi2c); + 800be50: 2300 movs r3, #0 + 800be52: e7ed b.n 800be30 + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == RESET) + 800be54: 6823 ldr r3, [r4, #0] + 800be56: 699b ldr r3, [r3, #24] + 800be58: 075b lsls r3, r3, #29 + 800be5a: d410 bmi.n 800be7e + if (I2C_IsAcknowledgeFailed(hi2c, Timeout, Tickstart) != HAL_OK) + 800be5c: 462a mov r2, r5 + 800be5e: 4639 mov r1, r7 + 800be60: 4620 mov r0, r4 + 800be62: f7ff fdf3 bl 800ba4c + 800be66: 2800 cmp r0, #0 + 800be68: d1a9 bne.n 800bdbe + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == SET) + 800be6a: 6823 ldr r3, [r4, #0] + 800be6c: 699a ldr r2, [r3, #24] + 800be6e: 0691 lsls r1, r2, #26 + 800be70: d5e1 bpl.n 800be36 + if ((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == SET) && (hi2c->XferSize > 0U)) + 800be72: 699a ldr r2, [r3, #24] + 800be74: 0752 lsls r2, r2, #29 + 800be76: d5c9 bpl.n 800be0c + 800be78: 8d22 ldrh r2, [r4, #40] ; 0x28 + 800be7a: 2a00 cmp r2, #0 + 800be7c: d0c6 beq.n 800be0c + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->RXDR; + 800be7e: 6823 ldr r3, [r4, #0] + 800be80: 6a5a ldr r2, [r3, #36] ; 0x24 + 800be82: 6a63 ldr r3, [r4, #36] ; 0x24 + 800be84: 701a strb r2, [r3, #0] + hi2c->pBuffPtr++; + 800be86: 6a63 ldr r3, [r4, #36] ; 0x24 + hi2c->XferSize--; + 800be88: 8d22 ldrh r2, [r4, #40] ; 0x28 + hi2c->pBuffPtr++; + 800be8a: 3301 adds r3, #1 + 800be8c: 6263 str r3, [r4, #36] ; 0x24 + hi2c->XferCount--; + 800be8e: 8d63 ldrh r3, [r4, #42] ; 0x2a + 800be90: 3b01 subs r3, #1 + 800be92: b29b uxth r3, r3 + 800be94: 8563 strh r3, [r4, #42] ; 0x2a + if ((hi2c->XferCount != 0U) && (hi2c->XferSize == 0U)) + 800be96: 8d63 ldrh r3, [r4, #42] ; 0x2a + hi2c->XferSize--; + 800be98: 3a01 subs r2, #1 + 800be9a: b292 uxth r2, r2 + if ((hi2c->XferCount != 0U) && (hi2c->XferSize == 0U)) + 800be9c: b29b uxth r3, r3 + hi2c->XferSize--; + 800be9e: 8522 strh r2, [r4, #40] ; 0x28 + if ((hi2c->XferCount != 0U) && (hi2c->XferSize == 0U)) + 800bea0: b9f3 cbnz r3, 800bee0 + while (hi2c->XferCount > 0U) + 800bea2: 8d63 ldrh r3, [r4, #42] ; 0x2a + 800bea4: b29b uxth r3, r3 + 800bea6: 2b00 cmp r3, #0 + 800bea8: d1d4 bne.n 800be54 + if (I2C_WaitOnSTOPFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + 800beaa: 462a mov r2, r5 + 800beac: 4639 mov r1, r7 + 800beae: 4620 mov r0, r4 + 800beb0: f7ff fe38 bl 800bb24 + 800beb4: 2800 cmp r0, #0 + 800beb6: d182 bne.n 800bdbe + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF); + 800beb8: 6823 ldr r3, [r4, #0] + 800beba: 2120 movs r1, #32 + 800bebc: 61d9 str r1, [r3, #28] + I2C_RESET_CR2(hi2c); + 800bebe: 685a ldr r2, [r3, #4] + 800bec0: f022 72ff bic.w r2, r2, #33423360 ; 0x1fe0000 + 800bec4: f422 328b bic.w r2, r2, #71168 ; 0x11600 + 800bec8: f422 72ff bic.w r2, r2, #510 ; 0x1fe + 800becc: f022 0201 bic.w r2, r2, #1 + 800bed0: 605a str r2, [r3, #4] + hi2c->State = HAL_I2C_STATE_READY; + 800bed2: f884 1041 strb.w r1, [r4, #65] ; 0x41 + __HAL_UNLOCK(hi2c); + 800bed6: f884 0040 strb.w r0, [r4, #64] ; 0x40 + hi2c->Mode = HAL_I2C_MODE_NONE; + 800beda: f884 0042 strb.w r0, [r4, #66] ; 0x42 + return HAL_OK; + 800bede: e76f b.n 800bdc0 + if ((hi2c->XferCount != 0U) && (hi2c->XferSize == 0U)) + 800bee0: 2a00 cmp r2, #0 + 800bee2: d1de bne.n 800bea2 + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_TCR, RESET, Timeout, tickstart) != HAL_OK) + 800bee4: 9500 str r5, [sp, #0] + 800bee6: 463b mov r3, r7 + 800bee8: 2180 movs r1, #128 ; 0x80 + 800beea: 4620 mov r0, r4 + 800beec: f7ff fdf0 bl 800bad0 + 800bef0: 2800 cmp r0, #0 + 800bef2: f47f af64 bne.w 800bdbe + if (hi2c->XferCount > MAX_NBYTE_SIZE) + 800bef6: 8d63 ldrh r3, [r4, #42] ; 0x2a + 800bef8: b29b uxth r3, r3 + 800befa: 2bff cmp r3, #255 ; 0xff + 800befc: d903 bls.n 800bf06 + hi2c->XferSize = MAX_NBYTE_SIZE; + 800befe: 22ff movs r2, #255 ; 0xff + 800bf00: 8522 strh r2, [r4, #40] ; 0x28 + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_RELOAD_MODE, I2C_NO_STARTSTOP); + 800bf02: 9000 str r0, [sp, #0] + 800bf04: e773 b.n 800bdee + hi2c->XferSize = hi2c->XferCount; + 800bf06: 8d62 ldrh r2, [r4, #42] ; 0x2a + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); + 800bf08: 9000 str r0, [sp, #0] + hi2c->XferSize = hi2c->XferCount; + 800bf0a: b292 uxth r2, r2 + 800bf0c: 8522 strh r2, [r4, #40] ; 0x28 + I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); + 800bf0e: e779 b.n 800be04 + return HAL_BUSY; + 800bf10: 2002 movs r0, #2 + 800bf12: e755 b.n 800bdc0 + 800bf14: 80002400 .word 0x80002400 + +0800bf18 : + * @param hsd Pointer to SD handle + * @param pSCR pointer to the buffer that will contain the SCR value + * @retval error state + */ +static uint32_t SD_FindSCR(SD_HandleTypeDef *hsd, uint32_t *pSCR) +{ + 800bf18: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + 800bf1c: b086 sub sp, #24 + 800bf1e: 4605 mov r5, r0 + 800bf20: 4688 mov r8, r1 + SDMMC_DataInitTypeDef config; + uint32_t errorstate; + uint32_t tickstart = HAL_GetTick(); + 800bf22: f7fb fa5b bl 80073dc + uint32_t index = 0U; + uint32_t tempscr[2U] = {0UL, 0UL}; + uint32_t *scr = pSCR; + + /* Set Block Size To 8 Bytes */ + errorstate = SDMMC_CmdBlockLength(hsd->Instance, 8U); + 800bf26: 2108 movs r1, #8 + uint32_t tickstart = HAL_GetTick(); + 800bf28: 4681 mov r9, r0 + errorstate = SDMMC_CmdBlockLength(hsd->Instance, 8U); + 800bf2a: 6828 ldr r0, [r5, #0] + 800bf2c: f001 f996 bl 800d25c + if(errorstate != HAL_SD_ERROR_NONE) + 800bf30: 4604 mov r4, r0 + 800bf32: bb48 cbnz r0, 800bf88 + { + return errorstate; + } + + /* Send CMD55 APP_CMD with argument as card's RCA */ + errorstate = SDMMC_CmdAppCommand(hsd->Instance, (uint32_t)((hsd->SdCard.RelCardAdd) << 16U)); + 800bf34: 6ca9 ldr r1, [r5, #72] ; 0x48 + 800bf36: 6828 ldr r0, [r5, #0] + 800bf38: 0409 lsls r1, r1, #16 + 800bf3a: f001 fac8 bl 800d4ce + if(errorstate != HAL_SD_ERROR_NONE) + 800bf3e: 4604 mov r4, r0 + 800bf40: bb10 cbnz r0, 800bf88 + { + return errorstate; + } + + config.DataTimeOut = SDMMC_DATATIMEOUT; + config.DataLength = 8U; + 800bf42: f04f 30ff mov.w r0, #4294967295 ; 0xffffffff + 800bf46: 2308 movs r3, #8 + 800bf48: e9cd 0300 strd r0, r3, [sp] + config.DataBlockSize = SDMMC_DATABLOCK_SIZE_8B; + config.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + 800bf4c: 2630 movs r6, #48 ; 0x30 + 800bf4e: 2302 movs r3, #2 + 800bf50: e9cd 6302 strd r6, r3, [sp, #8] + config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + config.DPSM = SDMMC_DPSM_ENABLE; + (void)SDMMC_ConfigData(hsd->Instance, &config); + 800bf54: 4669 mov r1, sp + config.DPSM = SDMMC_DPSM_ENABLE; + 800bf56: 2301 movs r3, #1 + (void)SDMMC_ConfigData(hsd->Instance, &config); + 800bf58: 6828 ldr r0, [r5, #0] + config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + 800bf5a: 9404 str r4, [sp, #16] + config.DPSM = SDMMC_DPSM_ENABLE; + 800bf5c: 9305 str r3, [sp, #20] + (void)SDMMC_ConfigData(hsd->Instance, &config); + 800bf5e: f001 f8a1 bl 800d0a4 + + /* Send ACMD51 SD_APP_SEND_SCR with argument as 0 */ + errorstate = SDMMC_CmdSendSCR(hsd->Instance); + 800bf62: 6828 ldr r0, [r5, #0] + 800bf64: f001 fae7 bl 800d536 + if(errorstate != HAL_SD_ERROR_NONE) + 800bf68: 4604 mov r4, r0 + 800bf6a: b968 cbnz r0, 800bf88 + uint32_t tempscr[2U] = {0UL, 0UL}; + 800bf6c: 4607 mov r7, r0 + 800bf6e: 4606 mov r6, r0 + { + return errorstate; + } + +#if defined(STM32L4P5xx) || defined(STM32L4Q5xx) || defined(STM32L4R5xx) || defined(STM32L4R7xx) || defined(STM32L4R9xx) || defined(STM32L4S5xx) || defined(STM32L4S7xx) || defined(STM32L4S9xx) + while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND | SDMMC_FLAG_DATAEND)) + 800bf70: f240 5a2a movw sl, #1322 ; 0x52a + 800bf74: 6828 ldr r0, [r5, #0] + 800bf76: 6b42 ldr r2, [r0, #52] ; 0x34 + 800bf78: ea12 0f0a tst.w r2, sl + { + if((!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOE)) && (index == 0U)) + 800bf7c: 6b42 ldr r2, [r0, #52] ; 0x34 + while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND | SDMMC_FLAG_DATAEND)) + 800bf7e: d007 beq.n 800bf90 + return HAL_SD_ERROR_TIMEOUT; + } + } +#endif /* STM32L4P5xx || STM32L4Q5xx || STM32L4R5xx || STM32L4R7xx || STM32L4R9xx || STM32L4S5xx || STM32L4S7xx || STM32L4S9xx */ + + if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT)) + 800bf80: 0712 lsls r2, r2, #28 + 800bf82: d519 bpl.n 800bfb8 + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DTIMEOUT); + 800bf84: 2408 movs r4, #8 + + return HAL_SD_ERROR_DATA_CRC_FAIL; + } + else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)) + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_RXOVERR); + 800bf86: 6384 str r4, [r0, #56] ; 0x38 + ((tempscr[0] & SDMMC_16TO23BITS) >> 8) | ((tempscr[0] & SDMMC_24TO31BITS) >> 24)); + + } + + return HAL_SD_ERROR_NONE; +} + 800bf88: 4620 mov r0, r4 + 800bf8a: b006 add sp, #24 + 800bf8c: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + if((!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOE)) && (index == 0U)) + 800bf90: 0311 lsls r1, r2, #12 + 800bf92: d408 bmi.n 800bfa6 + 800bf94: b93c cbnz r4, 800bfa6 + tempscr[0] = SDMMC_ReadFIFO(hsd->Instance); + 800bf96: f001 f849 bl 800d02c + 800bf9a: 4606 mov r6, r0 + tempscr[1] = SDMMC_ReadFIFO(hsd->Instance); + 800bf9c: 6828 ldr r0, [r5, #0] + 800bf9e: f001 f845 bl 800d02c + index++; + 800bfa2: 2401 movs r4, #1 + tempscr[1] = SDMMC_ReadFIFO(hsd->Instance); + 800bfa4: 4607 mov r7, r0 + if((HAL_GetTick() - tickstart) >= SDMMC_DATATIMEOUT) + 800bfa6: f7fb fa19 bl 80073dc + 800bfaa: eba0 0009 sub.w r0, r0, r9 + 800bfae: 3001 adds r0, #1 + 800bfb0: d1e0 bne.n 800bf74 + return HAL_SD_ERROR_TIMEOUT; + 800bfb2: f04f 4400 mov.w r4, #2147483648 ; 0x80000000 + 800bfb6: e7e7 b.n 800bf88 + else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL)) + 800bfb8: 6b42 ldr r2, [r0, #52] ; 0x34 + 800bfba: 0793 lsls r3, r2, #30 + 800bfbc: d501 bpl.n 800bfc2 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DCRCFAIL); + 800bfbe: 2402 movs r4, #2 + 800bfc0: e7e1 b.n 800bf86 + else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)) + 800bfc2: 6b44 ldr r4, [r0, #52] ; 0x34 + 800bfc4: f014 0420 ands.w r4, r4, #32 + 800bfc8: d001 beq.n 800bfce + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_RXOVERR); + 800bfca: 2420 movs r4, #32 + 800bfcc: e7db b.n 800bf86 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + 800bfce: 4a04 ldr r2, [pc, #16] ; (800bfe0 ) + 800bfd0: 6382 str r2, [r0, #56] ; 0x38 + *scr = (((tempscr[1] & SDMMC_0TO7BITS) << 24) | ((tempscr[1] & SDMMC_8TO15BITS) << 8) |\ + 800bfd2: ba3f rev r7, r7 + 800bfd4: ba36 rev r6, r6 + 800bfd6: f8c8 7000 str.w r7, [r8] + *scr = (((tempscr[0] & SDMMC_0TO7BITS) << 24) | ((tempscr[0] & SDMMC_8TO15BITS) << 8) |\ + 800bfda: f8c8 6004 str.w r6, [r8, #4] + return HAL_SD_ERROR_NONE; + 800bfde: e7d3 b.n 800bf88 + 800bfe0: 18000f3a .word 0x18000f3a + +0800bfe4 : + * of PLL to have SDMMCCK clock between 50 and 120 MHz + * @param hsd SD handle + * @retval SD Card error state + */ +static uint32_t SD_UltraHighSpeed(SD_HandleTypeDef *hsd) +{ + 800bfe4: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + uint32_t errorstate = HAL_SD_ERROR_NONE; + SDMMC_DataInitTypeDef sdmmc_datainitstructure; + uint32_t SD_hs[16] = {0}; + 800bfe8: 2640 movs r6, #64 ; 0x40 +{ + 800bfea: b096 sub sp, #88 ; 0x58 + 800bfec: 4605 mov r5, r0 + uint32_t SD_hs[16] = {0}; + 800bfee: 4632 mov r2, r6 + 800bff0: 2100 movs r1, #0 + 800bff2: a806 add r0, sp, #24 + 800bff4: f001 fc96 bl 800d924 + uint32_t count, loop = 0 ; + uint32_t Timeout = HAL_GetTick(); + 800bff8: f7fb f9f0 bl 80073dc + + if(hsd->SdCard.CardSpeed == CARD_NORMAL_SPEED) + 800bffc: 6deb ldr r3, [r5, #92] ; 0x5c + uint32_t Timeout = HAL_GetTick(); + 800bffe: 4680 mov r8, r0 + if(hsd->SdCard.CardSpeed == CARD_NORMAL_SPEED) + 800c000: 2b00 cmp r3, #0 + 800c002: d067 beq.n 800c0d4 + { + /* Standard Speed Card <= 12.5Mhz */ + return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE; + } + + if((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) && + 800c004: f5b3 7f00 cmp.w r3, #512 ; 0x200 + 800c008: d167 bne.n 800c0da + 800c00a: 69af ldr r7, [r5, #24] + 800c00c: 2f01 cmp r7, #1 + 800c00e: d164 bne.n 800c0da + (hsd->Init.Transceiver == SDMMC_TRANSCEIVER_ENABLE)) + { + /* Initialize the Data control register */ + hsd->Instance->DCTRL = 0; + 800c010: 6828 ldr r0, [r5, #0] + 800c012: 2300 movs r3, #0 + 800c014: 62c3 str r3, [r0, #44] ; 0x2c + errorstate = SDMMC_CmdBlockLength(hsd->Instance, 64U); + 800c016: 4631 mov r1, r6 + 800c018: f001 f920 bl 800d25c + + if (errorstate != HAL_SD_ERROR_NONE) + 800c01c: 4604 mov r4, r0 + 800c01e: 2800 cmp r0, #0 + 800c020: d13e bne.n 800c0a0 + { + return errorstate; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + sdmmc_datainitstructure.DataTimeOut = SDMMC_DATATIMEOUT; + 800c022: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + sdmmc_datainitstructure.DataLength = 64U; + 800c026: e9cd 3600 strd r3, r6, [sp] + sdmmc_datainitstructure.DataBlockSize = SDMMC_DATABLOCK_SIZE_64B ; + sdmmc_datainitstructure.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + sdmmc_datainitstructure.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + sdmmc_datainitstructure.DPSM = SDMMC_DPSM_ENABLE; + 800c02a: e9cd 0704 strd r0, r7, [sp, #16] + sdmmc_datainitstructure.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + 800c02e: 2660 movs r6, #96 ; 0x60 + 800c030: 2302 movs r3, #2 + + if ( SDMMC_ConfigData(hsd->Instance, &sdmmc_datainitstructure) != HAL_OK) + 800c032: 6828 ldr r0, [r5, #0] + 800c034: 4669 mov r1, sp + sdmmc_datainitstructure.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + 800c036: e9cd 6302 strd r6, r3, [sp, #8] + if ( SDMMC_ConfigData(hsd->Instance, &sdmmc_datainitstructure) != HAL_OK) + 800c03a: f001 f833 bl 800d0a4 + 800c03e: 2800 cmp r0, #0 + 800c040: d14d bne.n 800c0de + { + return (HAL_SD_ERROR_GENERAL_UNKNOWN_ERR); + } + + errorstate = SDMMC_CmdSwitch(hsd->Instance, SDMMC_SDR104_SWITCH_PATTERN); + 800c042: 492a ldr r1, [pc, #168] ; (800c0ec ) + 800c044: 6828 ldr r0, [r5, #0] + 800c046: f001 fa74 bl 800d532 + if(errorstate != HAL_SD_ERROR_NONE) + 800c04a: 4604 mov r4, r0 + 800c04c: bb40 cbnz r0, 800c0a0 + uint32_t count, loop = 0 ; + 800c04e: 4607 mov r7, r0 + { + return errorstate; + } + + while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND| SDMMC_FLAG_DATAEND )) + 800c050: f240 592a movw r9, #1322 ; 0x52a + 800c054: 682b ldr r3, [r5, #0] + 800c056: 6b5e ldr r6, [r3, #52] ; 0x34 + 800c058: ea16 0609 ands.w r6, r6, r9 + 800c05c: d005 beq.n 800c06a + hsd->State= HAL_SD_STATE_READY; + return HAL_SD_ERROR_TIMEOUT; + } + } + + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT)) + 800c05e: 6b5a ldr r2, [r3, #52] ; 0x34 + 800c060: 0711 lsls r1, r2, #28 + 800c062: d521 bpl.n 800c0a8 + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DTIMEOUT); + 800c064: 2208 movs r2, #8 + 800c066: 639a str r2, [r3, #56] ; 0x38 + + return errorstate; + 800c068: e01a b.n 800c0a0 + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOHF)) + 800c06a: 6b5b ldr r3, [r3, #52] ; 0x34 + 800c06c: 0418 lsls r0, r3, #16 + 800c06e: d50b bpl.n 800c088 + 800c070: ab06 add r3, sp, #24 + 800c072: eb03 1a47 add.w sl, r3, r7, lsl #5 + SD_hs[(8U*loop)+count] = SDMMC_ReadFIFO(hsd->Instance); + 800c076: 6828 ldr r0, [r5, #0] + 800c078: f000 ffd8 bl 800d02c + for (count = 0U; count < 8U; count++) + 800c07c: 3601 adds r6, #1 + 800c07e: 2e08 cmp r6, #8 + SD_hs[(8U*loop)+count] = SDMMC_ReadFIFO(hsd->Instance); + 800c080: f84a 0b04 str.w r0, [sl], #4 + for (count = 0U; count < 8U; count++) + 800c084: d1f7 bne.n 800c076 + loop ++; + 800c086: 3701 adds r7, #1 + if((HAL_GetTick()-Timeout) >= SDMMC_DATATIMEOUT) + 800c088: f7fb f9a8 bl 80073dc + 800c08c: eba0 0008 sub.w r0, r0, r8 + 800c090: 3001 adds r0, #1 + 800c092: d1df bne.n 800c054 + hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT; + 800c094: f04f 4400 mov.w r4, #2147483648 ; 0x80000000 + hsd->State= HAL_SD_STATE_READY; + 800c098: 2301 movs r3, #1 + hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT; + 800c09a: 63ac str r4, [r5, #56] ; 0x38 + hsd->State= HAL_SD_STATE_READY; + 800c09c: f885 3034 strb.w r3, [r5, #52] ; 0x34 +#endif /* (DLYB_SDMMC1) || (DLYB_SDMMC2) */ + } + } + + return errorstate; +} + 800c0a0: 4620 mov r0, r4 + 800c0a2: b016 add sp, #88 ; 0x58 + 800c0a4: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL)) + 800c0a8: 6b5a ldr r2, [r3, #52] ; 0x34 + 800c0aa: 0792 lsls r2, r2, #30 + 800c0ac: d502 bpl.n 800c0b4 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DCRCFAIL); + 800c0ae: 2402 movs r4, #2 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_RXOVERR); + 800c0b0: 639c str r4, [r3, #56] ; 0x38 + return errorstate; + 800c0b2: e7f5 b.n 800c0a0 + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)) + 800c0b4: 6b5c ldr r4, [r3, #52] ; 0x34 + 800c0b6: f014 0420 ands.w r4, r4, #32 + 800c0ba: d001 beq.n 800c0c0 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_RXOVERR); + 800c0bc: 2420 movs r4, #32 + 800c0be: e7f7 b.n 800c0b0 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + 800c0c0: 4a0b ldr r2, [pc, #44] ; (800c0f0 ) + 800c0c2: 639a str r2, [r3, #56] ; 0x38 + if ((((uint8_t*)SD_hs)[13] & 2U) != 2U) + 800c0c4: f89d 3025 ldrb.w r3, [sp, #37] ; 0x25 + 800c0c8: 079b lsls r3, r3, #30 + 800c0ca: d50b bpl.n 800c0e4 + HAL_SDEx_DriveTransceiver_1_8V_Callback(SET); + 800c0cc: 2001 movs r0, #1 + 800c0ce: f7fb f9f5 bl 80074bc + 800c0d2: e7e5 b.n 800c0a0 + return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE; + 800c0d4: f04f 6480 mov.w r4, #67108864 ; 0x4000000 + 800c0d8: e7e2 b.n 800c0a0 + uint32_t errorstate = HAL_SD_ERROR_NONE; + 800c0da: 2400 movs r4, #0 + 800c0dc: e7e0 b.n 800c0a0 + return (HAL_SD_ERROR_GENERAL_UNKNOWN_ERR); + 800c0de: f44f 3480 mov.w r4, #65536 ; 0x10000 + 800c0e2: e7dd b.n 800c0a0 + errorstate = SDMMC_ERROR_UNSUPPORTED_FEATURE; + 800c0e4: f04f 5480 mov.w r4, #268435456 ; 0x10000000 + 800c0e8: e7da b.n 800c0a0 + 800c0ea: bf00 nop + 800c0ec: 80ff1f03 .word 0x80ff1f03 + 800c0f0: 18000f3a .word 0x18000f3a + +0800c0f4 : +} + 800c0f4: 4770 bx lr + +0800c0f6 : + 800c0f6: 4770 bx lr + +0800c0f8 : +{ + 800c0f8: b510 push {r4, lr} + if(hsd == NULL) + 800c0fa: 4604 mov r4, r0 + 800c0fc: b198 cbz r0, 800c126 + hsd->State = HAL_SD_STATE_BUSY; + 800c0fe: 2303 movs r3, #3 + 800c100: f880 3034 strb.w r3, [r0, #52] ; 0x34 + if(hsd->Init.Transceiver == SDMMC_TRANSCEIVER_ENABLE) + 800c104: 6983 ldr r3, [r0, #24] + 800c106: 2b01 cmp r3, #1 + 800c108: d102 bne.n 800c110 + HAL_SDEx_DriveTransceiver_1_8V_Callback(RESET); + 800c10a: 2000 movs r0, #0 + 800c10c: f7fb f9d6 bl 80074bc + (void)SDMMC_PowerState_OFF(hsd->Instance); + 800c110: 6820 ldr r0, [r4, #0] + 800c112: f000 ffa3 bl 800d05c + HAL_SD_MspDeInit(hsd); + 800c116: 4620 mov r0, r4 + 800c118: f7ff ffed bl 800c0f6 + hsd->ErrorCode = HAL_SD_ERROR_NONE; + 800c11c: 2000 movs r0, #0 + 800c11e: 63a0 str r0, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_RESET; + 800c120: f884 0034 strb.w r0, [r4, #52] ; 0x34 +} + 800c124: bd10 pop {r4, pc} + return HAL_ERROR; + 800c126: 2001 movs r0, #1 + 800c128: e7fc b.n 800c124 + ... + +0800c12c : +{ + 800c12c: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + 800c130: b087 sub sp, #28 + 800c132: 4604 mov r4, r0 + 800c134: 460e mov r6, r1 + 800c136: 4692 mov sl, r2 + 800c138: 461f mov r7, r3 + uint32_t tickstart = HAL_GetTick(); + 800c13a: f7fb f94f bl 80073dc + 800c13e: 4681 mov r9, r0 + if(NULL == pData) + 800c140: b936 cbnz r6, 800c150 + hsd->ErrorCode |= HAL_SD_ERROR_PARAM; + 800c142: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c144: f043 6300 orr.w r3, r3, #134217728 ; 0x8000000 + hsd->ErrorCode |= HAL_SD_ERROR_BUSY; + 800c148: 63a3 str r3, [r4, #56] ; 0x38 + return HAL_ERROR; + 800c14a: f04f 0801 mov.w r8, #1 + 800c14e: e011 b.n 800c174 + if(hsd->State == HAL_SD_STATE_READY) + 800c150: f894 3034 ldrb.w r3, [r4, #52] ; 0x34 + 800c154: 2b01 cmp r3, #1 + 800c156: fa5f f883 uxtb.w r8, r3 + 800c15a: f040 80c3 bne.w 800c2e4 + if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr)) + 800c15e: 6d62 ldr r2, [r4, #84] ; 0x54 + 800c160: eb0a 0307 add.w r3, sl, r7 + hsd->ErrorCode = HAL_SD_ERROR_NONE; + 800c164: 2100 movs r1, #0 + if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr)) + 800c166: 4293 cmp r3, r2 + hsd->ErrorCode = HAL_SD_ERROR_NONE; + 800c168: 63a1 str r1, [r4, #56] ; 0x38 + if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr)) + 800c16a: d907 bls.n 800c17c + hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE; + 800c16c: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c16e: f043 7300 orr.w r3, r3, #33554432 ; 0x2000000 + 800c172: 63a3 str r3, [r4, #56] ; 0x38 +} + 800c174: 4640 mov r0, r8 + 800c176: b007 add sp, #28 + 800c178: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + hsd->State = HAL_SD_STATE_BUSY; + 800c17c: 2303 movs r3, #3 + 800c17e: f884 3034 strb.w r3, [r4, #52] ; 0x34 + if(hsd->SdCard.CardType != CARD_SDHC_SDXC) + 800c182: 6be3 ldr r3, [r4, #60] ; 0x3c + hsd->Instance->DCTRL = 0U; + 800c184: 6820 ldr r0, [r4, #0] + if(hsd->SdCard.CardType != CARD_SDHC_SDXC) + 800c186: 2b01 cmp r3, #1 + config.DataTimeOut = SDMMC_DATATIMEOUT; + 800c188: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 800c18c: 9300 str r3, [sp, #0] + config.DataLength = NumberOfBlocks * BLOCKSIZE; + 800c18e: ea4f 2347 mov.w r3, r7, lsl #9 + 800c192: 9301 str r3, [sp, #4] + config.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + 800c194: f04f 0502 mov.w r5, #2 + 800c198: f04f 0390 mov.w r3, #144 ; 0x90 + 800c19c: e9cd 3502 strd r3, r5, [sp, #8] + hsd->Instance->DCTRL = 0U; + 800c1a0: 62c1 str r1, [r0, #44] ; 0x2c + config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + 800c1a2: f04f 0300 mov.w r3, #0 + (void)SDMMC_ConfigData(hsd->Instance, &config); + 800c1a6: 4669 mov r1, sp + config.DPSM = SDMMC_DPSM_DISABLE; + 800c1a8: e9cd 3304 strd r3, r3, [sp, #16] + add *= 512U; + 800c1ac: bf18 it ne + 800c1ae: ea4f 2a4a movne.w sl, sl, lsl #9 + (void)SDMMC_ConfigData(hsd->Instance, &config); + 800c1b2: f000 ff77 bl 800d0a4 + __SDMMC_CMDTRANS_ENABLE( hsd->Instance); + 800c1b6: 6820 ldr r0, [r4, #0] + 800c1b8: 68c3 ldr r3, [r0, #12] + if(NumberOfBlocks > 1U) + 800c1ba: 2f01 cmp r7, #1 + __SDMMC_CMDTRANS_ENABLE( hsd->Instance); + 800c1bc: f043 0340 orr.w r3, r3, #64 ; 0x40 + 800c1c0: 60c3 str r3, [r0, #12] + if(NumberOfBlocks > 1U) + 800c1c2: d910 bls.n 800c1e6 + hsd->Context = SD_CONTEXT_READ_MULTIPLE_BLOCK; + 800c1c4: 6325 str r5, [r4, #48] ; 0x30 + errorstate = SDMMC_CmdReadMultiBlock(hsd->Instance, add); + 800c1c6: 4651 mov r1, sl + 800c1c8: f001 f87a bl 800d2c0 + if(errorstate != HAL_SD_ERROR_NONE) + 800c1cc: b188 cbz r0, 800c1f2 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c1ce: 6823 ldr r3, [r4, #0] + 800c1d0: 4a46 ldr r2, [pc, #280] ; (800c2ec ) + 800c1d2: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= errorstate; + 800c1d4: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c1d6: 4318 orrs r0, r3 + 800c1d8: 63a0 str r0, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c1da: 2301 movs r3, #1 + 800c1dc: f884 3034 strb.w r3, [r4, #52] ; 0x34 + hsd->Context = SD_CONTEXT_NONE; + 800c1e0: 2300 movs r3, #0 + 800c1e2: 6323 str r3, [r4, #48] ; 0x30 + return HAL_ERROR; + 800c1e4: e7c6 b.n 800c174 + hsd->Context = SD_CONTEXT_READ_SINGLE_BLOCK; + 800c1e6: 2301 movs r3, #1 + 800c1e8: 6323 str r3, [r4, #48] ; 0x30 + errorstate = SDMMC_CmdReadSingleBlock(hsd->Instance, add); + 800c1ea: 4651 mov r1, sl + 800c1ec: f001 f84f bl 800d28e + 800c1f0: e7ec b.n 800c1cc + dataremaining = config.DataLength; + 800c1f2: 9d01 ldr r5, [sp, #4] + while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DATAEND)) + 800c1f4: 6820 ldr r0, [r4, #0] + 800c1f6: 6b43 ldr r3, [r0, #52] ; 0x34 + 800c1f8: f413 7f95 tst.w r3, #298 ; 0x12a + 800c1fc: d01b beq.n 800c236 + __SDMMC_CMDTRANS_DISABLE( hsd->Instance); + 800c1fe: 68c3 ldr r3, [r0, #12] + 800c200: f023 0340 bic.w r3, r3, #64 ; 0x40 + 800c204: 60c3 str r3, [r0, #12] + if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DATAEND) && (NumberOfBlocks > 1U)) + 800c206: 6b43 ldr r3, [r0, #52] ; 0x34 + 800c208: 05db lsls r3, r3, #23 + 800c20a: d508 bpl.n 800c21e + 800c20c: 2f01 cmp r7, #1 + 800c20e: d906 bls.n 800c21e + if(hsd->SdCard.CardType != CARD_SECURED) + 800c210: 6be3 ldr r3, [r4, #60] ; 0x3c + 800c212: 2b03 cmp r3, #3 + 800c214: d003 beq.n 800c21e + errorstate = SDMMC_CmdStopTransfer(hsd->Instance); + 800c216: f001 f91b bl 800d450 + if(errorstate != HAL_SD_ERROR_NONE) + 800c21a: 2800 cmp r0, #0 + 800c21c: d1d7 bne.n 800c1ce + if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT)) + 800c21e: 6823 ldr r3, [r4, #0] + 800c220: 6b58 ldr r0, [r3, #52] ; 0x34 + 800c222: f010 0008 ands.w r0, r0, #8 + 800c226: d038 beq.n 800c29a + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c228: 4a30 ldr r2, [pc, #192] ; (800c2ec ) + 800c22a: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= HAL_SD_ERROR_DATA_TIMEOUT; + 800c22c: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c22e: f043 0308 orr.w r3, r3, #8 + 800c232: 63a3 str r3, [r4, #56] ; 0x38 + 800c234: e7d1 b.n 800c1da + if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOHF) && (dataremaining > 0U)) + 800c236: 6b43 ldr r3, [r0, #52] ; 0x34 + 800c238: 041a lsls r2, r3, #16 + 800c23a: d518 bpl.n 800c26e + 800c23c: b1bd cbz r5, 800c26e + 800c23e: f106 0a04 add.w sl, r6, #4 + 800c242: f106 0b24 add.w fp, r6, #36 ; 0x24 + data = SDMMC_ReadFIFO(hsd->Instance); + 800c246: 6820 ldr r0, [r4, #0] + 800c248: f000 fef0 bl 800d02c + *tempbuff = (uint8_t)((data >> 8U) & 0xFFU); + 800c24c: 0a02 lsrs r2, r0, #8 + 800c24e: f80a 2c03 strb.w r2, [sl, #-3] + *tempbuff = (uint8_t)((data >> 16U) & 0xFFU); + 800c252: 0c02 lsrs r2, r0, #16 + 800c254: f80a 2c02 strb.w r2, [sl, #-2] + *tempbuff = (uint8_t)((data >> 24U) & 0xFFU); + 800c258: 0e02 lsrs r2, r0, #24 + *tempbuff = (uint8_t)(data & 0xFFU); + 800c25a: f80a 0c04 strb.w r0, [sl, #-4] + *tempbuff = (uint8_t)((data >> 24U) & 0xFFU); + 800c25e: f80a 2c01 strb.w r2, [sl, #-1] + for(count = 0U; count < 8U; count++) + 800c262: f10a 0a04 add.w sl, sl, #4 + 800c266: 45d3 cmp fp, sl + 800c268: d1ed bne.n 800c246 + tempbuff++; + 800c26a: 3620 adds r6, #32 + dataremaining--; + 800c26c: 3d20 subs r5, #32 + if(((HAL_GetTick()-tickstart) >= Timeout) || (Timeout == 0U)) + 800c26e: f7fb f8b5 bl 80073dc + 800c272: 9b10 ldr r3, [sp, #64] ; 0x40 + 800c274: eba0 0009 sub.w r0, r0, r9 + 800c278: 4298 cmp r0, r3 + 800c27a: d3bb bcc.n 800c1f4 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c27c: 6823 ldr r3, [r4, #0] + 800c27e: 4a1b ldr r2, [pc, #108] ; (800c2ec ) + 800c280: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= HAL_SD_ERROR_TIMEOUT; + 800c282: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c284: f043 4300 orr.w r3, r3, #2147483648 ; 0x80000000 + 800c288: 63a3 str r3, [r4, #56] ; 0x38 + hsd->State= HAL_SD_STATE_READY; + 800c28a: 2301 movs r3, #1 + 800c28c: f884 3034 strb.w r3, [r4, #52] ; 0x34 + hsd->Context = SD_CONTEXT_NONE; + 800c290: 2300 movs r3, #0 + 800c292: 6323 str r3, [r4, #48] ; 0x30 + return HAL_TIMEOUT; + 800c294: f04f 0803 mov.w r8, #3 + 800c298: e76c b.n 800c174 + else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL)) + 800c29a: 6b59 ldr r1, [r3, #52] ; 0x34 + 800c29c: f011 0102 ands.w r1, r1, #2 + 800c2a0: d00a beq.n 800c2b8 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c2a2: 4a12 ldr r2, [pc, #72] ; (800c2ec ) + 800c2a4: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= HAL_SD_ERROR_DATA_CRC_FAIL; + 800c2a6: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c2a8: f043 0302 orr.w r3, r3, #2 + 800c2ac: 63a3 str r3, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c2ae: 2301 movs r3, #1 + 800c2b0: f884 3034 strb.w r3, [r4, #52] ; 0x34 + hsd->Context = SD_CONTEXT_NONE; + 800c2b4: 6320 str r0, [r4, #48] ; 0x30 + return HAL_ERROR; + 800c2b6: e75d b.n 800c174 + else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)) + 800c2b8: 6b5a ldr r2, [r3, #52] ; 0x34 + 800c2ba: f012 0220 ands.w r2, r2, #32 + 800c2be: d00a beq.n 800c2d6 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c2c0: 4a0a ldr r2, [pc, #40] ; (800c2ec ) + 800c2c2: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= HAL_SD_ERROR_RX_OVERRUN; + 800c2c4: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c2c6: f043 0320 orr.w r3, r3, #32 + 800c2ca: 63a3 str r3, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c2cc: 2301 movs r3, #1 + 800c2ce: f884 3034 strb.w r3, [r4, #52] ; 0x34 + hsd->Context = SD_CONTEXT_NONE; + 800c2d2: 6321 str r1, [r4, #48] ; 0x30 + return HAL_ERROR; + 800c2d4: e74e b.n 800c174 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + 800c2d6: 4906 ldr r1, [pc, #24] ; (800c2f0 ) + 800c2d8: 6399 str r1, [r3, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c2da: 2301 movs r3, #1 + 800c2dc: f884 3034 strb.w r3, [r4, #52] ; 0x34 + return HAL_OK; + 800c2e0: 4690 mov r8, r2 + 800c2e2: e747 b.n 800c174 + hsd->ErrorCode |= HAL_SD_ERROR_BUSY; + 800c2e4: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c2e6: f043 5300 orr.w r3, r3, #536870912 ; 0x20000000 + 800c2ea: e72d b.n 800c148 + 800c2ec: 1fe00fff .word 0x1fe00fff + 800c2f0: 18000f3a .word 0x18000f3a + +0800c2f4 : +{ + 800c2f4: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} + 800c2f8: b089 sub sp, #36 ; 0x24 + 800c2fa: 4604 mov r4, r0 + 800c2fc: 460d mov r5, r1 + 800c2fe: 4692 mov sl, r2 + 800c300: 461f mov r7, r3 + uint32_t tickstart = HAL_GetTick(); + 800c302: f7fb f86b bl 80073dc + 800c306: 4681 mov r9, r0 + if(NULL == pData) + 800c308: b935 cbnz r5, 800c318 + hsd->ErrorCode |= HAL_SD_ERROR_PARAM; + 800c30a: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c30c: f043 6300 orr.w r3, r3, #134217728 ; 0x8000000 + hsd->ErrorCode |= HAL_SD_ERROR_BUSY; + 800c310: 63a3 str r3, [r4, #56] ; 0x38 + return HAL_ERROR; + 800c312: f04f 0801 mov.w r8, #1 + 800c316: e011 b.n 800c33c + if(hsd->State == HAL_SD_STATE_READY) + 800c318: f894 3034 ldrb.w r3, [r4, #52] ; 0x34 + 800c31c: 2b01 cmp r3, #1 + 800c31e: fa5f f883 uxtb.w r8, r3 + 800c322: f040 80b4 bne.w 800c48e + if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr)) + 800c326: 6d62 ldr r2, [r4, #84] ; 0x54 + 800c328: eb0a 0307 add.w r3, sl, r7 + hsd->ErrorCode = HAL_SD_ERROR_NONE; + 800c32c: 2100 movs r1, #0 + if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr)) + 800c32e: 4293 cmp r3, r2 + hsd->ErrorCode = HAL_SD_ERROR_NONE; + 800c330: 63a1 str r1, [r4, #56] ; 0x38 + if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr)) + 800c332: d907 bls.n 800c344 + hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE; + 800c334: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c336: f043 7300 orr.w r3, r3, #33554432 ; 0x2000000 + 800c33a: 63a3 str r3, [r4, #56] ; 0x38 +} + 800c33c: 4640 mov r0, r8 + 800c33e: b009 add sp, #36 ; 0x24 + 800c340: e8bd 8ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} + hsd->State = HAL_SD_STATE_BUSY; + 800c344: 2303 movs r3, #3 + 800c346: f884 3034 strb.w r3, [r4, #52] ; 0x34 + if(hsd->SdCard.CardType != CARD_SDHC_SDXC) + 800c34a: 6be3 ldr r3, [r4, #60] ; 0x3c + hsd->Instance->DCTRL = 0U; + 800c34c: 6820 ldr r0, [r4, #0] + if(hsd->SdCard.CardType != CARD_SDHC_SDXC) + 800c34e: 2b01 cmp r3, #1 + config.DataTimeOut = SDMMC_DATATIMEOUT; + 800c350: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + 800c354: 9302 str r3, [sp, #8] + config.DataLength = NumberOfBlocks * BLOCKSIZE; + 800c356: ea4f 2347 mov.w r3, r7, lsl #9 + hsd->Instance->DCTRL = 0U; + 800c35a: 62c1 str r1, [r0, #44] ; 0x2c + config.DataLength = NumberOfBlocks * BLOCKSIZE; + 800c35c: 9303 str r3, [sp, #12] + config.TransferDir = SDMMC_TRANSFER_DIR_TO_CARD; + 800c35e: f04f 0190 mov.w r1, #144 ; 0x90 + 800c362: f04f 0300 mov.w r3, #0 + 800c366: e9cd 1304 strd r1, r3, [sp, #16] + (void)SDMMC_ConfigData(hsd->Instance, &config); + 800c36a: a902 add r1, sp, #8 + config.DPSM = SDMMC_DPSM_DISABLE; + 800c36c: e9cd 3306 strd r3, r3, [sp, #24] + add *= 512U; + 800c370: bf18 it ne + 800c372: ea4f 2a4a movne.w sl, sl, lsl #9 + (void)SDMMC_ConfigData(hsd->Instance, &config); + 800c376: f000 fe95 bl 800d0a4 + __SDMMC_CMDTRANS_ENABLE( hsd->Instance); + 800c37a: 6820 ldr r0, [r4, #0] + 800c37c: 68c3 ldr r3, [r0, #12] + if(NumberOfBlocks > 1U) + 800c37e: 2f01 cmp r7, #1 + __SDMMC_CMDTRANS_ENABLE( hsd->Instance); + 800c380: f043 0340 orr.w r3, r3, #64 ; 0x40 + 800c384: 60c3 str r3, [r0, #12] + if(NumberOfBlocks > 1U) + 800c386: d911 bls.n 800c3ac + hsd->Context = SD_CONTEXT_WRITE_MULTIPLE_BLOCK; + 800c388: 2320 movs r3, #32 + 800c38a: 6323 str r3, [r4, #48] ; 0x30 + errorstate = SDMMC_CmdWriteMultiBlock(hsd->Instance, add); + 800c38c: 4651 mov r1, sl + 800c38e: f000 ffc9 bl 800d324 + if(errorstate != HAL_SD_ERROR_NONE) + 800c392: b188 cbz r0, 800c3b8 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c394: 6823 ldr r3, [r4, #0] + 800c396: 4a40 ldr r2, [pc, #256] ; (800c498 ) + 800c398: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= errorstate; + 800c39a: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c39c: 4318 orrs r0, r3 + 800c39e: 63a0 str r0, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c3a0: 2301 movs r3, #1 + 800c3a2: f884 3034 strb.w r3, [r4, #52] ; 0x34 + hsd->Context = SD_CONTEXT_NONE; + 800c3a6: 2300 movs r3, #0 + 800c3a8: 6323 str r3, [r4, #48] ; 0x30 + return HAL_ERROR; + 800c3aa: e7c7 b.n 800c33c + hsd->Context = SD_CONTEXT_WRITE_SINGLE_BLOCK; + 800c3ac: 2310 movs r3, #16 + 800c3ae: 6323 str r3, [r4, #48] ; 0x30 + errorstate = SDMMC_CmdWriteSingleBlock(hsd->Instance, add); + 800c3b0: 4651 mov r1, sl + 800c3b2: f000 ff9e bl 800d2f2 + 800c3b6: e7ec b.n 800c392 + dataremaining = config.DataLength; + 800c3b8: 9e03 ldr r6, [sp, #12] + while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_TXUNDERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DATAEND)) + 800c3ba: 6820 ldr r0, [r4, #0] + 800c3bc: 6b43 ldr r3, [r0, #52] ; 0x34 + 800c3be: f413 7f8d tst.w r3, #282 ; 0x11a + 800c3c2: d01b beq.n 800c3fc + __SDMMC_CMDTRANS_DISABLE( hsd->Instance); + 800c3c4: 68c3 ldr r3, [r0, #12] + 800c3c6: f023 0340 bic.w r3, r3, #64 ; 0x40 + 800c3ca: 60c3 str r3, [r0, #12] + if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DATAEND) && (NumberOfBlocks > 1U)) + 800c3cc: 6b43 ldr r3, [r0, #52] ; 0x34 + 800c3ce: 05db lsls r3, r3, #23 + 800c3d0: d508 bpl.n 800c3e4 + 800c3d2: 2f01 cmp r7, #1 + 800c3d4: d906 bls.n 800c3e4 + if(hsd->SdCard.CardType != CARD_SECURED) + 800c3d6: 6be3 ldr r3, [r4, #60] ; 0x3c + 800c3d8: 2b03 cmp r3, #3 + 800c3da: d003 beq.n 800c3e4 + errorstate = SDMMC_CmdStopTransfer(hsd->Instance); + 800c3dc: f001 f838 bl 800d450 + if(errorstate != HAL_SD_ERROR_NONE) + 800c3e0: 2800 cmp r0, #0 + 800c3e2: d1d7 bne.n 800c394 + if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT)) + 800c3e4: 6823 ldr r3, [r4, #0] + 800c3e6: 6b58 ldr r0, [r3, #52] ; 0x34 + 800c3e8: f010 0008 ands.w r0, r0, #8 + 800c3ec: d02a beq.n 800c444 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c3ee: 4a2a ldr r2, [pc, #168] ; (800c498 ) + 800c3f0: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= HAL_SD_ERROR_DATA_TIMEOUT; + 800c3f2: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c3f4: f043 0308 orr.w r3, r3, #8 + 800c3f8: 63a3 str r3, [r4, #56] ; 0x38 + 800c3fa: e7d1 b.n 800c3a0 + if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_TXFIFOHE) && (dataremaining > 0U)) + 800c3fc: 6b43 ldr r3, [r0, #52] ; 0x34 + 800c3fe: 045a lsls r2, r3, #17 + 800c400: d50c bpl.n 800c41c + 800c402: b15e cbz r6, 800c41c + 800c404: f105 0b20 add.w fp, r5, #32 + data |= ((uint32_t)(*tempbuff) << 24U); + 800c408: f855 3b04 ldr.w r3, [r5], #4 + (void)SDMMC_WriteFIFO(hsd->Instance, &data); + 800c40c: 6820 ldr r0, [r4, #0] + data |= ((uint32_t)(*tempbuff) << 24U); + 800c40e: 9301 str r3, [sp, #4] + (void)SDMMC_WriteFIFO(hsd->Instance, &data); + 800c410: a901 add r1, sp, #4 + 800c412: f000 fe0e bl 800d032 + for(count = 0U; count < 8U; count++) + 800c416: 45ab cmp fp, r5 + 800c418: d1f6 bne.n 800c408 + dataremaining--; + 800c41a: 3e20 subs r6, #32 + if(((HAL_GetTick()-tickstart) >= Timeout) || (Timeout == 0U)) + 800c41c: f7fa ffde bl 80073dc + 800c420: 9b12 ldr r3, [sp, #72] ; 0x48 + 800c422: eba0 0009 sub.w r0, r0, r9 + 800c426: 4298 cmp r0, r3 + 800c428: d3c7 bcc.n 800c3ba + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c42a: 6823 ldr r3, [r4, #0] + 800c42c: 4a1a ldr r2, [pc, #104] ; (800c498 ) + 800c42e: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= errorstate; + 800c430: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c432: 63a3 str r3, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c434: 2301 movs r3, #1 + 800c436: f884 3034 strb.w r3, [r4, #52] ; 0x34 + hsd->Context = SD_CONTEXT_NONE; + 800c43a: 2300 movs r3, #0 + 800c43c: 6323 str r3, [r4, #48] ; 0x30 + return HAL_TIMEOUT; + 800c43e: f04f 0803 mov.w r8, #3 + 800c442: e77b b.n 800c33c + else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL)) + 800c444: 6b59 ldr r1, [r3, #52] ; 0x34 + 800c446: f011 0102 ands.w r1, r1, #2 + 800c44a: d00a beq.n 800c462 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c44c: 4a12 ldr r2, [pc, #72] ; (800c498 ) + 800c44e: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= HAL_SD_ERROR_DATA_CRC_FAIL; + 800c450: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c452: f043 0302 orr.w r3, r3, #2 + 800c456: 63a3 str r3, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c458: 2301 movs r3, #1 + 800c45a: f884 3034 strb.w r3, [r4, #52] ; 0x34 + hsd->Context = SD_CONTEXT_NONE; + 800c45e: 6320 str r0, [r4, #48] ; 0x30 + return HAL_ERROR; + 800c460: e76c b.n 800c33c + else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_TXUNDERR)) + 800c462: 6b5a ldr r2, [r3, #52] ; 0x34 + 800c464: f012 0210 ands.w r2, r2, #16 + 800c468: d00a beq.n 800c480 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c46a: 4a0b ldr r2, [pc, #44] ; (800c498 ) + 800c46c: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= HAL_SD_ERROR_TX_UNDERRUN; + 800c46e: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c470: f043 0310 orr.w r3, r3, #16 + 800c474: 63a3 str r3, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c476: 2301 movs r3, #1 + 800c478: f884 3034 strb.w r3, [r4, #52] ; 0x34 + hsd->Context = SD_CONTEXT_NONE; + 800c47c: 6321 str r1, [r4, #48] ; 0x30 + return HAL_ERROR; + 800c47e: e75d b.n 800c33c + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + 800c480: 4906 ldr r1, [pc, #24] ; (800c49c ) + 800c482: 6399 str r1, [r3, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c484: 2301 movs r3, #1 + 800c486: f884 3034 strb.w r3, [r4, #52] ; 0x34 + return HAL_OK; + 800c48a: 4690 mov r8, r2 + 800c48c: e756 b.n 800c33c + hsd->ErrorCode |= HAL_SD_ERROR_BUSY; + 800c48e: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c490: f043 5300 orr.w r3, r3, #536870912 ; 0x20000000 + 800c494: e73c b.n 800c310 + 800c496: bf00 nop + 800c498: 1fe00fff .word 0x1fe00fff + 800c49c: 18000f3a .word 0x18000f3a + +0800c4a0 : + return hsd->State; + 800c4a0: f890 0034 ldrb.w r0, [r0, #52] ; 0x34 +} + 800c4a4: 4770 bx lr + +0800c4a6 : + return hsd->ErrorCode; + 800c4a6: 6b80 ldr r0, [r0, #56] ; 0x38 +} + 800c4a8: 4770 bx lr + +0800c4aa : + 800c4aa: 4770 bx lr + +0800c4ac : + 800c4ac: 4770 bx lr + +0800c4ae : + 800c4ae: 4770 bx lr + +0800c4b0 : + 800c4b0: 4770 bx lr + ... + +0800c4b4 : + pCSD->CSDStruct = (uint8_t)((hsd->CSD[0] & 0xC0000000U) >> 30U); + 800c4b4: 6e03 ldr r3, [r0, #96] ; 0x60 + 800c4b6: 0f9a lsrs r2, r3, #30 + 800c4b8: 700a strb r2, [r1, #0] + pCSD->SysSpecVersion = (uint8_t)((hsd->CSD[0] & 0x3C000000U) >> 26U); + 800c4ba: f3c3 6283 ubfx r2, r3, #26, #4 + 800c4be: 704a strb r2, [r1, #1] + pCSD->Reserved1 = (uint8_t)((hsd->CSD[0] & 0x03000000U) >> 24U); + 800c4c0: f3c3 6201 ubfx r2, r3, #24, #2 + 800c4c4: 708a strb r2, [r1, #2] + pCSD->TAAC = (uint8_t)((hsd->CSD[0] & 0x00FF0000U) >> 16U); + 800c4c6: f3c3 4207 ubfx r2, r3, #16, #8 + 800c4ca: 70ca strb r2, [r1, #3] + pCSD->NSAC = (uint8_t)((hsd->CSD[0] & 0x0000FF00U) >> 8U); + 800c4cc: f3c3 2207 ubfx r2, r3, #8, #8 + pCSD->MaxBusClkFrec = (uint8_t)(hsd->CSD[0] & 0x000000FFU); + 800c4d0: b2db uxtb r3, r3 + pCSD->NSAC = (uint8_t)((hsd->CSD[0] & 0x0000FF00U) >> 8U); + 800c4d2: 710a strb r2, [r1, #4] + pCSD->MaxBusClkFrec = (uint8_t)(hsd->CSD[0] & 0x000000FFU); + 800c4d4: 714b strb r3, [r1, #5] + pCSD->CardComdClasses = (uint16_t)((hsd->CSD[1] & 0xFFF00000U) >> 20U); + 800c4d6: 6e43 ldr r3, [r0, #100] ; 0x64 + 800c4d8: 0d1a lsrs r2, r3, #20 + 800c4da: 80ca strh r2, [r1, #6] + pCSD->RdBlockLen = (uint8_t)((hsd->CSD[1] & 0x000F0000U) >> 16U); + 800c4dc: f3c3 4203 ubfx r2, r3, #16, #4 + 800c4e0: 720a strb r2, [r1, #8] + pCSD->PartBlockRead = (uint8_t)((hsd->CSD[1] & 0x00008000U) >> 15U); + 800c4e2: f3c3 32c0 ubfx r2, r3, #15, #1 + 800c4e6: 724a strb r2, [r1, #9] + pCSD->WrBlockMisalign = (uint8_t)((hsd->CSD[1] & 0x00004000U) >> 14U); + 800c4e8: f3c3 3280 ubfx r2, r3, #14, #1 + 800c4ec: 728a strb r2, [r1, #10] + pCSD->RdBlockMisalign = (uint8_t)((hsd->CSD[1] & 0x00002000U) >> 13U); + 800c4ee: f3c3 3240 ubfx r2, r3, #13, #1 + 800c4f2: 72ca strb r2, [r1, #11] + pCSD->DSRImpl = (uint8_t)((hsd->CSD[1] & 0x00001000U) >> 12U); + 800c4f4: f3c3 3200 ubfx r2, r3, #12, #1 + 800c4f8: 730a strb r2, [r1, #12] + pCSD->Reserved2 = 0U; /*!< Reserved */ + 800c4fa: 2200 movs r2, #0 + 800c4fc: 734a strb r2, [r1, #13] + if(hsd->SdCard.CardType == CARD_SDSC) + 800c4fe: 6bc2 ldr r2, [r0, #60] ; 0x3c +{ + 800c500: b510 push {r4, lr} + if(hsd->SdCard.CardType == CARD_SDSC) + 800c502: 2a00 cmp r2, #0 + 800c504: d16c bne.n 800c5e0 + pCSD->DeviceSize = (((hsd->CSD[1] & 0x000003FFU) << 2U) | ((hsd->CSD[2] & 0xC0000000U) >> 30U)); + 800c506: 6e82 ldr r2, [r0, #104] ; 0x68 + 800c508: f640 74fc movw r4, #4092 ; 0xffc + 800c50c: ea04 0383 and.w r3, r4, r3, lsl #2 + 800c510: ea43 7392 orr.w r3, r3, r2, lsr #30 + 800c514: 610b str r3, [r1, #16] + pCSD->MaxRdCurrentVDDMin = (uint8_t)((hsd->CSD[2] & 0x38000000U) >> 27U); + 800c516: f3c2 63c2 ubfx r3, r2, #27, #3 + 800c51a: 750b strb r3, [r1, #20] + pCSD->MaxRdCurrentVDDMax = (uint8_t)((hsd->CSD[2] & 0x07000000U) >> 24U); + 800c51c: f3c2 6302 ubfx r3, r2, #24, #3 + 800c520: 754b strb r3, [r1, #21] + pCSD->MaxWrCurrentVDDMin = (uint8_t)((hsd->CSD[2] & 0x00E00000U) >> 21U); + 800c522: f3c2 5342 ubfx r3, r2, #21, #3 + 800c526: 758b strb r3, [r1, #22] + pCSD->MaxWrCurrentVDDMax = (uint8_t)((hsd->CSD[2] & 0x001C0000U) >> 18U); + 800c528: f3c2 4382 ubfx r3, r2, #18, #3 + pCSD->DeviceSizeMul = (uint8_t)((hsd->CSD[2] & 0x00038000U) >> 15U); + 800c52c: f3c2 32c2 ubfx r2, r2, #15, #3 + pCSD->MaxWrCurrentVDDMax = (uint8_t)((hsd->CSD[2] & 0x001C0000U) >> 18U); + 800c530: 75cb strb r3, [r1, #23] + pCSD->DeviceSizeMul = (uint8_t)((hsd->CSD[2] & 0x00038000U) >> 15U); + 800c532: 760a strb r2, [r1, #24] + hsd->SdCard.BlockNbr = (pCSD->DeviceSize + 1U) ; + 800c534: 690b ldr r3, [r1, #16] + hsd->SdCard.BlockNbr *= (1UL << ((pCSD->DeviceSizeMul & 0x07U) + 2U)); + 800c536: 7e0a ldrb r2, [r1, #24] + 800c538: f002 0207 and.w r2, r2, #7 + hsd->SdCard.BlockNbr = (pCSD->DeviceSize + 1U) ; + 800c53c: 3301 adds r3, #1 + hsd->SdCard.BlockNbr *= (1UL << ((pCSD->DeviceSizeMul & 0x07U) + 2U)); + 800c53e: 3202 adds r2, #2 + 800c540: fa03 f202 lsl.w r2, r3, r2 + 800c544: 64c2 str r2, [r0, #76] ; 0x4c + hsd->SdCard.BlockSize = (1UL << (pCSD->RdBlockLen & 0x0FU)); + 800c546: 7a0b ldrb r3, [r1, #8] + 800c548: f003 040f and.w r4, r3, #15 + 800c54c: 2301 movs r3, #1 + 800c54e: 40a3 lsls r3, r4 + 800c550: 6503 str r3, [r0, #80] ; 0x50 + hsd->SdCard.LogBlockNbr = (hsd->SdCard.BlockNbr) * ((hsd->SdCard.BlockSize) / 512U); + 800c552: 0a5b lsrs r3, r3, #9 + 800c554: 4353 muls r3, r2 + 800c556: 6543 str r3, [r0, #84] ; 0x54 + hsd->SdCard.LogBlockSize = 512U; + 800c558: f44f 7300 mov.w r3, #512 ; 0x200 + hsd->SdCard.LogBlockSize = hsd->SdCard.BlockSize; + 800c55c: 6583 str r3, [r0, #88] ; 0x58 + pCSD->EraseGrSize = (uint8_t)((hsd->CSD[2] & 0x00004000U) >> 14U); + 800c55e: 6e83 ldr r3, [r0, #104] ; 0x68 + 800c560: f3c3 3280 ubfx r2, r3, #14, #1 + 800c564: 764a strb r2, [r1, #25] + pCSD->EraseGrMul = (uint8_t)((hsd->CSD[2] & 0x00003F80U) >> 7U); + 800c566: f3c3 12c6 ubfx r2, r3, #7, #7 + pCSD->WrProtectGrSize = (uint8_t)(hsd->CSD[2] & 0x0000007FU); + 800c56a: f003 037f and.w r3, r3, #127 ; 0x7f + pCSD->EraseGrMul = (uint8_t)((hsd->CSD[2] & 0x00003F80U) >> 7U); + 800c56e: 768a strb r2, [r1, #26] + pCSD->WrProtectGrSize = (uint8_t)(hsd->CSD[2] & 0x0000007FU); + 800c570: 76cb strb r3, [r1, #27] + pCSD->WrProtectGrEnable = (uint8_t)((hsd->CSD[3] & 0x80000000U) >> 31U); + 800c572: 6ec3 ldr r3, [r0, #108] ; 0x6c + 800c574: 0fda lsrs r2, r3, #31 + 800c576: 770a strb r2, [r1, #28] + pCSD->ManDeflECC = (uint8_t)((hsd->CSD[3] & 0x60000000U) >> 29U); + 800c578: f3c3 7241 ubfx r2, r3, #29, #2 + 800c57c: 774a strb r2, [r1, #29] + pCSD->WrSpeedFact = (uint8_t)((hsd->CSD[3] & 0x1C000000U) >> 26U); + 800c57e: f3c3 6282 ubfx r2, r3, #26, #3 + 800c582: 778a strb r2, [r1, #30] + pCSD->MaxWrBlockLen= (uint8_t)((hsd->CSD[3] & 0x03C00000U) >> 22U); + 800c584: f3c3 5283 ubfx r2, r3, #22, #4 + 800c588: 77ca strb r2, [r1, #31] + pCSD->WriteBlockPaPartial = (uint8_t)((hsd->CSD[3] & 0x00200000U) >> 21U); + 800c58a: f3c3 5240 ubfx r2, r3, #21, #1 + 800c58e: f881 2020 strb.w r2, [r1, #32] + pCSD->Reserved3 = 0; + 800c592: 2000 movs r0, #0 + pCSD->ContentProtectAppli = (uint8_t)((hsd->CSD[3] & 0x00010000U) >> 16U); + 800c594: f3c3 4200 ubfx r2, r3, #16, #1 + pCSD->Reserved3 = 0; + 800c598: f881 0021 strb.w r0, [r1, #33] ; 0x21 + pCSD->ContentProtectAppli = (uint8_t)((hsd->CSD[3] & 0x00010000U) >> 16U); + 800c59c: f881 2022 strb.w r2, [r1, #34] ; 0x22 + pCSD->FileFormatGroup = (uint8_t)((hsd->CSD[3] & 0x00008000U) >> 15U); + 800c5a0: f3c3 32c0 ubfx r2, r3, #15, #1 + 800c5a4: f881 2023 strb.w r2, [r1, #35] ; 0x23 + pCSD->CopyFlag = (uint8_t)((hsd->CSD[3] & 0x00004000U) >> 14U); + 800c5a8: f3c3 3280 ubfx r2, r3, #14, #1 + 800c5ac: f881 2024 strb.w r2, [r1, #36] ; 0x24 + pCSD->PermWrProtect = (uint8_t)((hsd->CSD[3] & 0x00002000U) >> 13U); + 800c5b0: f3c3 3240 ubfx r2, r3, #13, #1 + 800c5b4: f881 2025 strb.w r2, [r1, #37] ; 0x25 + pCSD->TempWrProtect = (uint8_t)((hsd->CSD[3] & 0x00001000U) >> 12U); + 800c5b8: f3c3 3200 ubfx r2, r3, #12, #1 + 800c5bc: f881 2026 strb.w r2, [r1, #38] ; 0x26 + pCSD->FileFormat = (uint8_t)((hsd->CSD[3] & 0x00000C00U) >> 10U); + 800c5c0: f3c3 2281 ubfx r2, r3, #10, #2 + 800c5c4: f881 2027 strb.w r2, [r1, #39] ; 0x27 + pCSD->ECC= (uint8_t)((hsd->CSD[3] & 0x00000300U) >> 8U); + 800c5c8: f3c3 2201 ubfx r2, r3, #8, #2 + pCSD->CSD_CRC = (uint8_t)((hsd->CSD[3] & 0x000000FEU) >> 1U); + 800c5cc: f3c3 0346 ubfx r3, r3, #1, #7 + pCSD->ECC= (uint8_t)((hsd->CSD[3] & 0x00000300U) >> 8U); + 800c5d0: f881 2028 strb.w r2, [r1, #40] ; 0x28 + pCSD->CSD_CRC = (uint8_t)((hsd->CSD[3] & 0x000000FEU) >> 1U); + 800c5d4: f881 3029 strb.w r3, [r1, #41] ; 0x29 + pCSD->Reserved4 = 1; + 800c5d8: 2301 movs r3, #1 + 800c5da: f881 302a strb.w r3, [r1, #42] ; 0x2a +} + 800c5de: bd10 pop {r4, pc} + else if(hsd->SdCard.CardType == CARD_SDHC_SDXC) + 800c5e0: 2a01 cmp r2, #1 + 800c5e2: d10f bne.n 800c604 + pCSD->DeviceSize = (((hsd->CSD[1] & 0x0000003FU) << 16U) | ((hsd->CSD[2] & 0xFFFF0000U) >> 16U)); + 800c5e4: f8b0 206a ldrh.w r2, [r0, #106] ; 0x6a + 800c5e8: 041b lsls r3, r3, #16 + 800c5ea: f403 137c and.w r3, r3, #4128768 ; 0x3f0000 + 800c5ee: 4313 orrs r3, r2 + 800c5f0: 610b str r3, [r1, #16] + hsd->SdCard.BlockNbr = ((pCSD->DeviceSize + 1U) * 1024U); + 800c5f2: 690b ldr r3, [r1, #16] + 800c5f4: 3301 adds r3, #1 + 800c5f6: 029b lsls r3, r3, #10 + 800c5f8: 64c3 str r3, [r0, #76] ; 0x4c + hsd->SdCard.LogBlockNbr = hsd->SdCard.BlockNbr; + 800c5fa: 6543 str r3, [r0, #84] ; 0x54 + hsd->SdCard.BlockSize = 512U; + 800c5fc: f44f 7300 mov.w r3, #512 ; 0x200 + 800c600: 6503 str r3, [r0, #80] ; 0x50 + 800c602: e7ab b.n 800c55c + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c604: 6803 ldr r3, [r0, #0] + 800c606: 4a05 ldr r2, [pc, #20] ; (800c61c ) + 800c608: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + 800c60a: 6b83 ldr r3, [r0, #56] ; 0x38 + 800c60c: f043 5380 orr.w r3, r3, #268435456 ; 0x10000000 + 800c610: 6383 str r3, [r0, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c612: 2301 movs r3, #1 + 800c614: f880 3034 strb.w r3, [r0, #52] ; 0x34 + return HAL_ERROR; + 800c618: 4618 mov r0, r3 + 800c61a: e7e0 b.n 800c5de + 800c61c: 1fe00fff .word 0x1fe00fff + +0800c620 : +{ + 800c620: e92d 43f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, lr} + Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING; + 800c624: 2300 movs r3, #0 +{ + 800c626: b099 sub sp, #100 ; 0x64 + 800c628: 4604 mov r4, r0 + sdmmc_clk = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SDMMC1); + 800c62a: f44f 2000 mov.w r0, #524288 ; 0x80000 + Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; + 800c62e: e9cd 3307 strd r3, r3, [sp, #28] + Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; + 800c632: e9cd 3309 strd r3, r3, [sp, #36] ; 0x24 + sdmmc_clk = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SDMMC1); + 800c636: f7fd fb2d bl 8009c94 + if (sdmmc_clk == 0U) + 800c63a: 4605 mov r5, r0 + 800c63c: b948 cbnz r0, 800c652 + hsd->State = HAL_SD_STATE_READY; + 800c63e: 2501 movs r5, #1 + hsd->ErrorCode = SDMMC_ERROR_INVALID_PARAMETER; + 800c640: f04f 6300 mov.w r3, #134217728 ; 0x8000000 + hsd->State = HAL_SD_STATE_READY; + 800c644: f884 5034 strb.w r5, [r4, #52] ; 0x34 + hsd->ErrorCode = SDMMC_ERROR_INVALID_PARAMETER; + 800c648: 63a3 str r3, [r4, #56] ; 0x38 +} + 800c64a: 4628 mov r0, r5 + 800c64c: b019 add sp, #100 ; 0x64 + 800c64e: e8bd 83f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, pc} + Init.Transceiver = hsd->Init.Transceiver; + 800c652: 69a3 ldr r3, [r4, #24] + hsd->Instance->POWER |= SDMMC_POWER_DIRPOL; + 800c654: 6827 ldr r7, [r4, #0] + Init.Transceiver = hsd->Init.Transceiver; + 800c656: 930c str r3, [sp, #48] ; 0x30 + if(hsd->Init.Transceiver == SDMMC_TRANSCEIVER_ENABLE) + 800c658: 2b01 cmp r3, #1 + hsd->Instance->POWER |= SDMMC_POWER_DIRPOL; + 800c65a: bf08 it eq + 800c65c: 683b ldreq r3, [r7, #0] + Init.ClockDiv = sdmmc_clk / (2U * SD_INIT_FREQ); + 800c65e: 4e99 ldr r6, [pc, #612] ; (800c8c4 ) + 800c660: fbb0 f6f6 udiv r6, r0, r6 + hsd->Instance->POWER |= SDMMC_POWER_DIRPOL; + 800c664: bf04 itt eq + 800c666: f043 0310 orreq.w r3, r3, #16 + 800c66a: 603b streq r3, [r7, #0] + status = SDMMC_Init(hsd->Instance, Init); + 800c66c: 960b str r6, [sp, #44] ; 0x2c + 800c66e: ab0a add r3, sp, #40 ; 0x28 + 800c670: e893 0007 ldmia.w r3, {r0, r1, r2} + 800c674: e88d 0007 stmia.w sp, {r0, r1, r2} + 800c678: ab07 add r3, sp, #28 + 800c67a: cb0e ldmia r3, {r1, r2, r3} + 800c67c: 4638 mov r0, r7 + 800c67e: f000 fcbb bl 800cff8 + if(status != HAL_OK) + 800c682: b108 cbz r0, 800c688 + return HAL_ERROR; + 800c684: 2501 movs r5, #1 + 800c686: e7e0 b.n 800c64a + status = SDMMC_PowerState_ON(hsd->Instance); + 800c688: 6820 ldr r0, [r4, #0] + 800c68a: f000 fcd7 bl 800d03c + if(status != HAL_OK) + 800c68e: 4607 mov r7, r0 + 800c690: 2800 cmp r0, #0 + 800c692: d1f7 bne.n 800c684 + sdmmc_clk = sdmmc_clk/(2U*Init.ClockDiv); + 800c694: 0076 lsls r6, r6, #1 + HAL_Delay(1U+ (74U*1000U/(sdmmc_clk))); + 800c696: 488c ldr r0, [pc, #560] ; (800c8c8 ) + sdmmc_clk = sdmmc_clk/(2U*Init.ClockDiv); + 800c698: fbb5 f5f6 udiv r5, r5, r6 + HAL_Delay(1U+ (74U*1000U/(sdmmc_clk))); + 800c69c: fbb0 f0f5 udiv r0, r0, r5 + 800c6a0: 3001 adds r0, #1 + 800c6a2: f7f7 f9fc bl 8003a9e + __IO uint32_t count = 0U; + 800c6a6: 9706 str r7, [sp, #24] + uint32_t tickstart = HAL_GetTick(); + 800c6a8: f7fa fe98 bl 80073dc + 800c6ac: 4606 mov r6, r0 + errorstate = SDMMC_CmdGoIdleState(hsd->Instance); + 800c6ae: 6820 ldr r0, [r4, #0] + 800c6b0: f000 fd18 bl 800d0e4 + if(errorstate != HAL_SD_ERROR_NONE) + 800c6b4: 4605 mov r5, r0 + 800c6b6: b940 cbnz r0, 800c6ca + errorstate = SDMMC_CmdOperCond(hsd->Instance); + 800c6b8: 6820 ldr r0, [r4, #0] + 800c6ba: f001 f8fd bl 800d8b8 + if(errorstate != HAL_SD_ERROR_NONE) + 800c6be: b158 cbz r0, 800c6d8 + errorstate = SDMMC_CmdGoIdleState(hsd->Instance); + 800c6c0: 6820 ldr r0, [r4, #0] + hsd->SdCard.CardVersion = CARD_V1_X; + 800c6c2: 6425 str r5, [r4, #64] ; 0x40 + errorstate = SDMMC_CmdGoIdleState(hsd->Instance); + 800c6c4: f000 fd0e bl 800d0e4 + if(errorstate != HAL_SD_ERROR_NONE) + 800c6c8: b180 cbz r0, 800c6ec + hsd->State = HAL_SD_STATE_READY; + 800c6ca: 2501 movs r5, #1 + 800c6cc: f884 5034 strb.w r5, [r4, #52] ; 0x34 + hsd->ErrorCode |= errorstate; + 800c6d0: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c6d2: 4318 orrs r0, r3 + 800c6d4: 63a0 str r0, [r4, #56] ; 0x38 + return HAL_ERROR; + 800c6d6: e7b8 b.n 800c64a + hsd->SdCard.CardVersion = CARD_V2_X; + 800c6d8: 2301 movs r3, #1 + 800c6da: 6423 str r3, [r4, #64] ; 0x40 + errorstate = SDMMC_CmdAppCommand(hsd->Instance, 0); + 800c6dc: 6820 ldr r0, [r4, #0] + 800c6de: 2100 movs r1, #0 + 800c6e0: f000 fef5 bl 800d4ce + if(errorstate != HAL_SD_ERROR_NONE) + 800c6e4: b128 cbz r0, 800c6f2 + return HAL_SD_ERROR_UNSUPPORTED_FEATURE; + 800c6e6: f04f 5080 mov.w r0, #268435456 ; 0x10000000 + 800c6ea: e7ee b.n 800c6ca + if( hsd->SdCard.CardVersion == CARD_V2_X) + 800c6ec: 6c23 ldr r3, [r4, #64] ; 0x40 + 800c6ee: 2b01 cmp r3, #1 + 800c6f0: d0f4 beq.n 800c6dc + errorstate = SDMMC_CmdAppOperCommand(hsd->Instance, SDMMC_VOLTAGE_WINDOW_SD | SDMMC_HIGH_CAPACITY | SD_SWITCH_1_8V_CAPACITY); + 800c6f2: f8df 91dc ldr.w r9, [pc, #476] ; 800c8d0 +{ + 800c6f6: 2700 movs r7, #0 + while((count < SDMMC_MAX_VOLT_TRIAL) && (validvoltage == 0U)) + 800c6f8: f64f 78fe movw r8, #65534 ; 0xfffe + 800c6fc: 9b06 ldr r3, [sp, #24] + 800c6fe: 4543 cmp r3, r8 + 800c700: d800 bhi.n 800c704 + 800c702: b12f cbz r7, 800c710 + if(count >= SDMMC_MAX_VOLT_TRIAL) + 800c704: 9b06 ldr r3, [sp, #24] + 800c706: 4543 cmp r3, r8 + 800c708: d918 bls.n 800c73c + return HAL_SD_ERROR_INVALID_VOLTRANGE; + 800c70a: f04f 7080 mov.w r0, #16777216 ; 0x1000000 + 800c70e: e7dc b.n 800c6ca + errorstate = SDMMC_CmdAppCommand(hsd->Instance, 0); + 800c710: 6820 ldr r0, [r4, #0] + 800c712: 4639 mov r1, r7 + 800c714: f000 fedb bl 800d4ce + if(errorstate != HAL_SD_ERROR_NONE) + 800c718: 2800 cmp r0, #0 + 800c71a: d1d6 bne.n 800c6ca + errorstate = SDMMC_CmdAppOperCommand(hsd->Instance, SDMMC_VOLTAGE_WINDOW_SD | SDMMC_HIGH_CAPACITY | SD_SWITCH_1_8V_CAPACITY); + 800c71c: 6820 ldr r0, [r4, #0] + 800c71e: 4649 mov r1, r9 + 800c720: f001 f816 bl 800d750 + if(errorstate != HAL_SD_ERROR_NONE) + 800c724: 2800 cmp r0, #0 + 800c726: d1de bne.n 800c6e6 + response = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1); + 800c728: 4639 mov r1, r7 + 800c72a: 6820 ldr r0, [r4, #0] + 800c72c: f000 fcb7 bl 800d09e + count++; + 800c730: 9b06 ldr r3, [sp, #24] + 800c732: 3301 adds r3, #1 + response = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1); + 800c734: 4605 mov r5, r0 + validvoltage = (((response >> 31U) == 1U) ? 1U : 0U); + 800c736: 0fc7 lsrs r7, r0, #31 + count++; + 800c738: 9306 str r3, [sp, #24] + 800c73a: e7df b.n 800c6fc + if((response & SDMMC_HIGH_CAPACITY) == SDMMC_HIGH_CAPACITY) /* (response &= SD_HIGH_CAPACITY) */ + 800c73c: f015 4380 ands.w r3, r5, #1073741824 ; 0x40000000 + 800c740: d04b beq.n 800c7da + hsd->SdCard.CardType = CARD_SDHC_SDXC; + 800c742: 2301 movs r3, #1 + 800c744: 63e3 str r3, [r4, #60] ; 0x3c + if(hsd->Init.Transceiver == SDMMC_TRANSCEIVER_ENABLE) + 800c746: 69a3 ldr r3, [r4, #24] + errorstate = SDMMC_CmdAppCommand(hsd->Instance, 0); + 800c748: 6820 ldr r0, [r4, #0] + if(hsd->Init.Transceiver == SDMMC_TRANSCEIVER_ENABLE) + 800c74a: 2b01 cmp r3, #1 + 800c74c: d12d bne.n 800c7aa + if((response & SD_SWITCH_1_8V_CAPACITY) == SD_SWITCH_1_8V_CAPACITY) + 800c74e: 01ef lsls r7, r5, #7 + 800c750: d52b bpl.n 800c7aa + hsd->SdCard.CardSpeed = CARD_ULTRA_HIGH_SPEED; + 800c752: f44f 7300 mov.w r3, #512 ; 0x200 + 800c756: 65e3 str r3, [r4, #92] ; 0x5c + hsd->Instance->POWER |= SDMMC_POWER_VSWITCHEN; + 800c758: 6803 ldr r3, [r0, #0] + 800c75a: f043 0308 orr.w r3, r3, #8 + 800c75e: 6003 str r3, [r0, #0] + errorstate = SDMMC_CmdVoltageSwitch(hsd->Instance); + 800c760: f000 ff4e bl 800d600 + if(errorstate != HAL_SD_ERROR_NONE) + 800c764: 2800 cmp r0, #0 + 800c766: d1b0 bne.n 800c6ca + while(( hsd->Instance->STA & SDMMC_FLAG_CKSTOP) != SDMMC_FLAG_CKSTOP) + 800c768: 6823 ldr r3, [r4, #0] + 800c76a: 6b5a ldr r2, [r3, #52] ; 0x34 + 800c76c: 0155 lsls r5, r2, #5 + 800c76e: d526 bpl.n 800c7be + hsd->Instance->ICR = SDMMC_FLAG_CKSTOP; + 800c770: f04f 6280 mov.w r2, #67108864 ; 0x4000000 + 800c774: 639a str r2, [r3, #56] ; 0x38 + if(( hsd->Instance->STA & SDMMC_FLAG_BUSYD0) != SDMMC_FLAG_BUSYD0) + 800c776: 6b5b ldr r3, [r3, #52] ; 0x34 + 800c778: 02d8 lsls r0, r3, #11 + 800c77a: d5b4 bpl.n 800c6e6 + HAL_SDEx_DriveTransceiver_1_8V_Callback(SET); + 800c77c: 2001 movs r0, #1 + 800c77e: f7fa fe9d bl 80074bc + hsd->Instance->POWER |= SDMMC_POWER_VSWITCH; + 800c782: 6822 ldr r2, [r4, #0] + 800c784: 6813 ldr r3, [r2, #0] + 800c786: f043 0304 orr.w r3, r3, #4 + 800c78a: 6013 str r3, [r2, #0] + while(( hsd->Instance->STA & SDMMC_FLAG_VSWEND) != SDMMC_FLAG_VSWEND) + 800c78c: 6823 ldr r3, [r4, #0] + 800c78e: 6b5a ldr r2, [r3, #52] ; 0x34 + 800c790: 0191 lsls r1, r2, #6 + 800c792: d51c bpl.n 800c7ce + hsd->Instance->ICR = SDMMC_FLAG_VSWEND; + 800c794: f04f 7200 mov.w r2, #33554432 ; 0x2000000 + 800c798: 639a str r2, [r3, #56] ; 0x38 + if(( hsd->Instance->STA & SDMMC_FLAG_BUSYD0) == SDMMC_FLAG_BUSYD0) + 800c79a: 6b5a ldr r2, [r3, #52] ; 0x34 + 800c79c: 02d2 lsls r2, r2, #11 + 800c79e: d4b4 bmi.n 800c70a + hsd->Instance->POWER = 0x13U; + 800c7a0: 2213 movs r2, #19 + 800c7a2: 601a str r2, [r3, #0] + hsd->Instance->ICR = 0xFFFFFFFFU; + 800c7a4: f04f 32ff mov.w r2, #4294967295 ; 0xffffffff + 800c7a8: 639a str r2, [r3, #56] ; 0x38 + uint16_t sd_rca = 1U; + 800c7aa: 2301 movs r3, #1 + if(SDMMC_GetPowerState(hsd->Instance) == 0U) + 800c7ac: 6820 ldr r0, [r4, #0] + uint16_t sd_rca = 1U; + 800c7ae: f8ad 3016 strh.w r3, [sp, #22] + if(SDMMC_GetPowerState(hsd->Instance) == 0U) + 800c7b2: f000 fc59 bl 800d068 + 800c7b6: b990 cbnz r0, 800c7de + return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE; + 800c7b8: f04f 6080 mov.w r0, #67108864 ; 0x4000000 + 800c7bc: e785 b.n 800c6ca + if((HAL_GetTick() - tickstart) >= SDMMC_DATATIMEOUT) + 800c7be: f7fa fe0d bl 80073dc + 800c7c2: 1b80 subs r0, r0, r6 + 800c7c4: 3001 adds r0, #1 + 800c7c6: d1cf bne.n 800c768 + return HAL_SD_ERROR_TIMEOUT; + 800c7c8: f04f 4000 mov.w r0, #2147483648 ; 0x80000000 + 800c7cc: e77d b.n 800c6ca + if((HAL_GetTick() - tickstart) >= SDMMC_DATATIMEOUT) + 800c7ce: f7fa fe05 bl 80073dc + 800c7d2: 1b80 subs r0, r0, r6 + 800c7d4: 3001 adds r0, #1 + 800c7d6: d1d9 bne.n 800c78c + 800c7d8: e7f6 b.n 800c7c8 + hsd->SdCard.CardType = CARD_SDSC; + 800c7da: 63e3 str r3, [r4, #60] ; 0x3c + if(errorstate != HAL_SD_ERROR_NONE) + 800c7dc: e7e5 b.n 800c7aa + if(hsd->SdCard.CardType != CARD_SECURED) + 800c7de: 6be3 ldr r3, [r4, #60] ; 0x3c + 800c7e0: 2b03 cmp r3, #3 + 800c7e2: d045 beq.n 800c870 + errorstate = SDMMC_CmdSendCID(hsd->Instance); + 800c7e4: 6820 ldr r0, [r4, #0] + 800c7e6: f000 ff65 bl 800d6b4 + if(errorstate != HAL_SD_ERROR_NONE) + 800c7ea: 2800 cmp r0, #0 + 800c7ec: f47f af6d bne.w 800c6ca + hsd->CID[0U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1); + 800c7f0: 4601 mov r1, r0 + 800c7f2: 6820 ldr r0, [r4, #0] + 800c7f4: f000 fc53 bl 800d09e + hsd->CID[1U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP2); + 800c7f8: 2104 movs r1, #4 + hsd->CID[0U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1); + 800c7fa: 6720 str r0, [r4, #112] ; 0x70 + hsd->CID[1U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP2); + 800c7fc: 6820 ldr r0, [r4, #0] + 800c7fe: f000 fc4e bl 800d09e + hsd->CID[2U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP3); + 800c802: 2108 movs r1, #8 + hsd->CID[1U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP2); + 800c804: 6760 str r0, [r4, #116] ; 0x74 + hsd->CID[2U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP3); + 800c806: 6820 ldr r0, [r4, #0] + 800c808: f000 fc49 bl 800d09e + hsd->CID[3U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP4); + 800c80c: 210c movs r1, #12 + hsd->CID[2U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP3); + 800c80e: 67a0 str r0, [r4, #120] ; 0x78 + hsd->CID[3U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP4); + 800c810: 6820 ldr r0, [r4, #0] + 800c812: f000 fc44 bl 800d09e + if(hsd->SdCard.CardType != CARD_SECURED) + 800c816: 6be3 ldr r3, [r4, #60] ; 0x3c + hsd->CID[3U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP4); + 800c818: 67e0 str r0, [r4, #124] ; 0x7c + if(hsd->SdCard.CardType != CARD_SECURED) + 800c81a: 2b03 cmp r3, #3 + 800c81c: d028 beq.n 800c870 + errorstate = SDMMC_CmdSetRelAdd(hsd->Instance, &sd_rca); + 800c81e: 6820 ldr r0, [r4, #0] + 800c820: f10d 0116 add.w r1, sp, #22 + 800c824: f001 f804 bl 800d830 + if(errorstate != HAL_SD_ERROR_NONE) + 800c828: 2800 cmp r0, #0 + 800c82a: f47f af4e bne.w 800c6ca + if(hsd->SdCard.CardType != CARD_SECURED) + 800c82e: 6be3 ldr r3, [r4, #60] ; 0x3c + errorstate = SDMMC_CmdSendCSD(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); + 800c830: 6820 ldr r0, [r4, #0] + if(hsd->SdCard.CardType != CARD_SECURED) + 800c832: 2b03 cmp r3, #3 + 800c834: d01c beq.n 800c870 + hsd->SdCard.RelCardAdd = sd_rca; + 800c836: f8bd 1016 ldrh.w r1, [sp, #22] + 800c83a: 64a1 str r1, [r4, #72] ; 0x48 + errorstate = SDMMC_CmdSendCSD(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); + 800c83c: 0409 lsls r1, r1, #16 + 800c83e: f000 ff4f bl 800d6e0 + if(errorstate != HAL_SD_ERROR_NONE) + 800c842: 2800 cmp r0, #0 + 800c844: f47f af41 bne.w 800c6ca + hsd->CSD[0U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1); + 800c848: 4601 mov r1, r0 + 800c84a: 6820 ldr r0, [r4, #0] + 800c84c: f000 fc27 bl 800d09e + hsd->CSD[1U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP2); + 800c850: 2104 movs r1, #4 + hsd->CSD[0U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1); + 800c852: 6620 str r0, [r4, #96] ; 0x60 + hsd->CSD[1U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP2); + 800c854: 6820 ldr r0, [r4, #0] + 800c856: f000 fc22 bl 800d09e + hsd->CSD[2U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP3); + 800c85a: 2108 movs r1, #8 + hsd->CSD[1U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP2); + 800c85c: 6660 str r0, [r4, #100] ; 0x64 + hsd->CSD[2U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP3); + 800c85e: 6820 ldr r0, [r4, #0] + 800c860: f000 fc1d bl 800d09e + hsd->CSD[3U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP4); + 800c864: 210c movs r1, #12 + hsd->CSD[2U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP3); + 800c866: 66a0 str r0, [r4, #104] ; 0x68 + hsd->CSD[3U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP4); + 800c868: 6820 ldr r0, [r4, #0] + 800c86a: f000 fc18 bl 800d09e + 800c86e: 66e0 str r0, [r4, #108] ; 0x6c + hsd->SdCard.Class = (SDMMC_GetResponse(hsd->Instance, SDMMC_RESP2) >> 20U); + 800c870: 2104 movs r1, #4 + 800c872: 6820 ldr r0, [r4, #0] + 800c874: f000 fc13 bl 800d09e + 800c878: 0d00 lsrs r0, r0, #20 + 800c87a: 6460 str r0, [r4, #68] ; 0x44 + if (HAL_SD_GetCardCSD(hsd, &CSD) != HAL_OK) + 800c87c: a90d add r1, sp, #52 ; 0x34 + 800c87e: 4620 mov r0, r4 + 800c880: f7ff fe18 bl 800c4b4 + 800c884: 4605 mov r5, r0 + 800c886: 2800 cmp r0, #0 + 800c888: f47f af2d bne.w 800c6e6 + errorstate = SDMMC_CmdSelDesel(hsd->Instance, (uint32_t)(((uint32_t)hsd->SdCard.RelCardAdd) << 16U)); + 800c88c: 6ca2 ldr r2, [r4, #72] ; 0x48 + 800c88e: 4603 mov r3, r0 + 800c890: 0412 lsls r2, r2, #16 + 800c892: 6820 ldr r0, [r4, #0] + 800c894: f000 fe02 bl 800d49c + if(errorstate != HAL_SD_ERROR_NONE) + 800c898: 2800 cmp r0, #0 + 800c89a: f47f af16 bne.w 800c6ca + errorstate = SDMMC_CmdBlockLength(hsd->Instance, BLOCKSIZE); + 800c89e: 6820 ldr r0, [r4, #0] + 800c8a0: f44f 7100 mov.w r1, #512 ; 0x200 + 800c8a4: f000 fcda bl 800d25c + if(errorstate != HAL_SD_ERROR_NONE) + 800c8a8: 2800 cmp r0, #0 + 800c8aa: f43f aece beq.w 800c64a + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c8ae: 6823 ldr r3, [r4, #0] + 800c8b0: 4a06 ldr r2, [pc, #24] ; (800c8cc ) + 800c8b2: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= errorstate; + 800c8b4: 6ba3 ldr r3, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c8b6: 2501 movs r5, #1 + hsd->ErrorCode |= errorstate; + 800c8b8: 4318 orrs r0, r3 + 800c8ba: 63a0 str r0, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c8bc: f884 5034 strb.w r5, [r4, #52] ; 0x34 + return HAL_ERROR; + 800c8c0: e6c3 b.n 800c64a + 800c8c2: bf00 nop + 800c8c4: 000c3500 .word 0x000c3500 + 800c8c8: 00012110 .word 0x00012110 + 800c8cc: 1fe00fff .word 0x1fe00fff + 800c8d0: c1100000 .word 0xc1100000 + +0800c8d4 : +{ + 800c8d4: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr} + 800c8d8: b096 sub sp, #88 ; 0x58 + 800c8da: 4604 mov r4, r0 + 800c8dc: 460d mov r5, r1 + uint32_t tickstart = HAL_GetTick(); + 800c8de: f7fa fd7d bl 80073dc + if((SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED) + 800c8e2: 2100 movs r1, #0 + uint32_t tickstart = HAL_GetTick(); + 800c8e4: 4606 mov r6, r0 + if((SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED) + 800c8e6: 6820 ldr r0, [r4, #0] + 800c8e8: f000 fbd9 bl 800d09e + 800c8ec: 0183 lsls r3, r0, #6 + 800c8ee: d50b bpl.n 800c908 + return HAL_SD_ERROR_LOCK_UNLOCK_FAILED; + 800c8f0: f44f 6000 mov.w r0, #2048 ; 0x800 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800c8f4: 6823 ldr r3, [r4, #0] + 800c8f6: 4a54 ldr r2, [pc, #336] ; (800ca48 ) + 800c8f8: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= errorstate; + 800c8fa: 6ba3 ldr r3, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c8fc: 2501 movs r5, #1 + hsd->ErrorCode |= errorstate; + 800c8fe: 4318 orrs r0, r3 + 800c900: 63a0 str r0, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800c902: f884 5034 strb.w r5, [r4, #52] ; 0x34 + status = HAL_ERROR; + 800c906: e08a b.n 800ca1e + errorstate = SDMMC_CmdBlockLength(hsd->Instance, 64U); + 800c908: 6820 ldr r0, [r4, #0] + 800c90a: 2140 movs r1, #64 ; 0x40 + 800c90c: f000 fca6 bl 800d25c + if(errorstate != HAL_SD_ERROR_NONE) + 800c910: b110 cbz r0, 800c918 + hsd->ErrorCode |= HAL_SD_ERROR_NONE; + 800c912: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800c914: 63a3 str r3, [r4, #56] ; 0x38 + return errorstate; + 800c916: e7ed b.n 800c8f4 + errorstate = SDMMC_CmdAppCommand(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); + 800c918: 6ca1 ldr r1, [r4, #72] ; 0x48 + 800c91a: 6820 ldr r0, [r4, #0] + 800c91c: 0409 lsls r1, r1, #16 + 800c91e: f000 fdd6 bl 800d4ce + if(errorstate != HAL_SD_ERROR_NONE) + 800c922: 2800 cmp r0, #0 + 800c924: d1f5 bne.n 800c912 + config.DataLength = 64U; + 800c926: 2340 movs r3, #64 ; 0x40 + 800c928: f04f 37ff mov.w r7, #4294967295 ; 0xffffffff + 800c92c: e9cd 7300 strd r7, r3, [sp] + config.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + 800c930: f04f 0c60 mov.w ip, #96 ; 0x60 + 800c934: 2302 movs r3, #2 + 800c936: e9cd c302 strd ip, r3, [sp, #8] + config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + 800c93a: 9004 str r0, [sp, #16] + config.DPSM = SDMMC_DPSM_ENABLE; + 800c93c: 2301 movs r3, #1 + (void)SDMMC_ConfigData(hsd->Instance, &config); + 800c93e: 6820 ldr r0, [r4, #0] + config.DPSM = SDMMC_DPSM_ENABLE; + 800c940: 9305 str r3, [sp, #20] + (void)SDMMC_ConfigData(hsd->Instance, &config); + 800c942: 4669 mov r1, sp + 800c944: f000 fbae bl 800d0a4 + errorstate = SDMMC_CmdStatusRegister(hsd->Instance); + 800c948: 6820 ldr r0, [r4, #0] + 800c94a: f000 fe40 bl 800d5ce + if(errorstate != HAL_SD_ERROR_NONE) + 800c94e: 2800 cmp r0, #0 + 800c950: d1df bne.n 800c912 + uint32_t *pData = pSDstatus; + 800c952: af06 add r7, sp, #24 + while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DATAEND)) + 800c954: 6823 ldr r3, [r4, #0] + 800c956: 6b5a ldr r2, [r3, #52] ; 0x34 + 800c958: f412 7f95 tst.w r2, #298 ; 0x12a + 800c95c: d00a beq.n 800c974 + if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT)) + 800c95e: 6b5a ldr r2, [r3, #52] ; 0x34 + 800c960: 0711 lsls r1, r2, #28 + 800c962: d46f bmi.n 800ca44 + else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL)) + 800c964: 6b5a ldr r2, [r3, #52] ; 0x34 + 800c966: 0792 lsls r2, r2, #30 + 800c968: d46a bmi.n 800ca40 + else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)) + 800c96a: 6b5b ldr r3, [r3, #52] ; 0x34 + 800c96c: 069b lsls r3, r3, #26 + 800c96e: d51e bpl.n 800c9ae + return HAL_SD_ERROR_RX_OVERRUN; + 800c970: 2020 movs r0, #32 + 800c972: e7bf b.n 800c8f4 + if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOHF)) + 800c974: 6b5b ldr r3, [r3, #52] ; 0x34 + 800c976: 0418 lsls r0, r3, #16 + 800c978: d508 bpl.n 800c98c + 800c97a: f107 0820 add.w r8, r7, #32 + *pData = SDMMC_ReadFIFO(hsd->Instance); + 800c97e: 6820 ldr r0, [r4, #0] + 800c980: f000 fb54 bl 800d02c + 800c984: f847 0b04 str.w r0, [r7], #4 + for(count = 0U; count < 8U; count++) + 800c988: 45b8 cmp r8, r7 + 800c98a: d1f8 bne.n 800c97e + if((HAL_GetTick() - tickstart) >= SDMMC_DATATIMEOUT) + 800c98c: f7fa fd26 bl 80073dc + 800c990: 1b80 subs r0, r0, r6 + 800c992: 3001 adds r0, #1 + 800c994: d1de bne.n 800c954 + return HAL_SD_ERROR_TIMEOUT; + 800c996: f04f 4000 mov.w r0, #2147483648 ; 0x80000000 + if(errorstate != HAL_SD_ERROR_NONE) + 800c99a: e7ab b.n 800c8f4 + *pData = SDMMC_ReadFIFO(hsd->Instance); + 800c99c: f000 fb46 bl 800d02c + 800c9a0: f847 0b04 str.w r0, [r7], #4 + if((HAL_GetTick() - tickstart) >= SDMMC_DATATIMEOUT) + 800c9a4: f7fa fd1a bl 80073dc + 800c9a8: 1b80 subs r0, r0, r6 + 800c9aa: 3001 adds r0, #1 + 800c9ac: d0f3 beq.n 800c996 + while ((__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DPSMACT))) + 800c9ae: 6820 ldr r0, [r4, #0] + 800c9b0: 6b43 ldr r3, [r0, #52] ; 0x34 + 800c9b2: f413 5380 ands.w r3, r3, #4096 ; 0x1000 + 800c9b6: d1f1 bne.n 800c99c + pStatus->DataBusWidth = (uint8_t)((sd_status[0] & 0xC0U) >> 6U); + 800c9b8: 9906 ldr r1, [sp, #24] + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + 800c9ba: 4a24 ldr r2, [pc, #144] ; (800ca4c ) + 800c9bc: 6382 str r2, [r0, #56] ; 0x38 + pStatus->DataBusWidth = (uint8_t)((sd_status[0] & 0xC0U) >> 6U); + 800c9be: f3c1 1281 ubfx r2, r1, #6, #2 + 800c9c2: 702a strb r2, [r5, #0] + pStatus->SecuredMode = (uint8_t)((sd_status[0] & 0x20U) >> 5U); + 800c9c4: f3c1 1240 ubfx r2, r1, #5, #1 + 800c9c8: 706a strb r2, [r5, #1] + pStatus->CardType = (uint16_t)(((sd_status[0] & 0x00FF0000U) >> 8U) | ((sd_status[0] & 0xFF000000U) >> 24U)); + 800c9ca: 0a0a lsrs r2, r1, #8 + 800c9cc: f022 02ff bic.w r2, r2, #255 ; 0xff + 800c9d0: ea42 6211 orr.w r2, r2, r1, lsr #24 + 800c9d4: b292 uxth r2, r2 + 800c9d6: 806a strh r2, [r5, #2] + pStatus->ProtectedAreaSize = (((sd_status[1] & 0xFFU) << 24U) | ((sd_status[1] & 0xFF00U) << 8U) | + 800c9d8: 9a07 ldr r2, [sp, #28] + 800c9da: ba12 rev r2, r2 + 800c9dc: 606a str r2, [r5, #4] + pStatus->SpeedClass = (uint8_t)(sd_status[2] & 0xFFU); + 800c9de: 9a08 ldr r2, [sp, #32] + 800c9e0: b2d1 uxtb r1, r2 + 800c9e2: 7229 strb r1, [r5, #8] + pStatus->PerformanceMove = (uint8_t)((sd_status[2] & 0xFF00U) >> 8U); + 800c9e4: f3c2 2107 ubfx r1, r2, #8, #8 + 800c9e8: 7269 strb r1, [r5, #9] + pStatus->AllocationUnitSize = (uint8_t)((sd_status[2] & 0xF00000U) >> 20U); + 800c9ea: f3c2 5103 ubfx r1, r2, #20, #4 + 800c9ee: 72a9 strb r1, [r5, #10] + pStatus->EraseSize = (uint16_t)(((sd_status[2] & 0xFF000000U) >> 16U) | (sd_status[3] & 0xFFU)); + 800c9f0: 9909 ldr r1, [sp, #36] ; 0x24 + 800c9f2: 0c12 lsrs r2, r2, #16 + 800c9f4: b2c8 uxtb r0, r1 + 800c9f6: f022 02ff bic.w r2, r2, #255 ; 0xff + 800c9fa: 4302 orrs r2, r0 + 800c9fc: 81aa strh r2, [r5, #12] + pStatus->EraseTimeout = (uint8_t)((sd_status[3] & 0xFC00U) >> 10U); + 800c9fe: f3c1 2285 ubfx r2, r1, #10, #6 + 800ca02: 73aa strb r2, [r5, #14] + pStatus->EraseOffset = (uint8_t)((sd_status[3] & 0x0300U) >> 8U); + 800ca04: f3c1 2201 ubfx r2, r1, #8, #2 + 800ca08: 73ea strb r2, [r5, #15] + pStatus->UhsSpeedGrade = (uint8_t)((sd_status[3] & 0x00F0U) >> 4U); + 800ca0a: f3c1 1203 ubfx r2, r1, #4, #4 + 800ca0e: 742a strb r2, [r5, #16] + pStatus->UhsAllocationUnitSize = (uint8_t)(sd_status[3] & 0x000FU) ; + 800ca10: f001 010f and.w r1, r1, #15 + pStatus->VideoSpeedClass = (uint8_t)((sd_status[4] & 0xFF000000U) >> 24U); + 800ca14: f89d 202b ldrb.w r2, [sp, #43] ; 0x2b + pStatus->UhsAllocationUnitSize = (uint8_t)(sd_status[3] & 0x000FU) ; + 800ca18: 7469 strb r1, [r5, #17] + pStatus->VideoSpeedClass = (uint8_t)((sd_status[4] & 0xFF000000U) >> 24U); + 800ca1a: 74aa strb r2, [r5, #18] + HAL_StatusTypeDef status = HAL_OK; + 800ca1c: 461d mov r5, r3 + errorstate = SDMMC_CmdBlockLength(hsd->Instance, BLOCKSIZE); + 800ca1e: 6820 ldr r0, [r4, #0] + 800ca20: f44f 7100 mov.w r1, #512 ; 0x200 + 800ca24: f000 fc1a bl 800d25c + if(errorstate != HAL_SD_ERROR_NONE) + 800ca28: b130 cbz r0, 800ca38 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800ca2a: 6823 ldr r3, [r4, #0] + 800ca2c: 4a06 ldr r2, [pc, #24] ; (800ca48 ) + 800ca2e: 639a str r2, [r3, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800ca30: 2501 movs r5, #1 + hsd->ErrorCode = errorstate; + 800ca32: 63a0 str r0, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800ca34: f884 5034 strb.w r5, [r4, #52] ; 0x34 +} + 800ca38: 4628 mov r0, r5 + 800ca3a: b016 add sp, #88 ; 0x58 + 800ca3c: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc} + return HAL_SD_ERROR_DATA_CRC_FAIL; + 800ca40: 2002 movs r0, #2 + 800ca42: e757 b.n 800c8f4 + return HAL_SD_ERROR_DATA_TIMEOUT; + 800ca44: 2008 movs r0, #8 + 800ca46: e755 b.n 800c8f4 + 800ca48: 1fe00fff .word 0x1fe00fff + 800ca4c: 18000f3a .word 0x18000f3a + +0800ca50 : + pCardInfo->CardType = (uint32_t)(hsd->SdCard.CardType); + 800ca50: 6bc3 ldr r3, [r0, #60] ; 0x3c + 800ca52: 600b str r3, [r1, #0] + pCardInfo->CardVersion = (uint32_t)(hsd->SdCard.CardVersion); + 800ca54: 6c03 ldr r3, [r0, #64] ; 0x40 + 800ca56: 604b str r3, [r1, #4] + pCardInfo->Class = (uint32_t)(hsd->SdCard.Class); + 800ca58: 6c43 ldr r3, [r0, #68] ; 0x44 + 800ca5a: 608b str r3, [r1, #8] + pCardInfo->RelCardAdd = (uint32_t)(hsd->SdCard.RelCardAdd); + 800ca5c: 6c83 ldr r3, [r0, #72] ; 0x48 + 800ca5e: 60cb str r3, [r1, #12] + pCardInfo->BlockNbr = (uint32_t)(hsd->SdCard.BlockNbr); + 800ca60: 6cc3 ldr r3, [r0, #76] ; 0x4c + 800ca62: 610b str r3, [r1, #16] + pCardInfo->BlockSize = (uint32_t)(hsd->SdCard.BlockSize); + 800ca64: 6d03 ldr r3, [r0, #80] ; 0x50 + 800ca66: 614b str r3, [r1, #20] + pCardInfo->LogBlockNbr = (uint32_t)(hsd->SdCard.LogBlockNbr); + 800ca68: 6d43 ldr r3, [r0, #84] ; 0x54 + 800ca6a: 618b str r3, [r1, #24] + pCardInfo->LogBlockSize = (uint32_t)(hsd->SdCard.LogBlockSize); + 800ca6c: 6d83 ldr r3, [r0, #88] ; 0x58 + 800ca6e: 61cb str r3, [r1, #28] +} + 800ca70: 2000 movs r0, #0 + 800ca72: 4770 bx lr + +0800ca74 : +{ + 800ca74: b530 push {r4, r5, lr} + hsd->State = HAL_SD_STATE_BUSY; + 800ca76: 2303 movs r3, #3 + 800ca78: f880 3034 strb.w r3, [r0, #52] ; 0x34 + if(hsd->SdCard.CardType != CARD_SECURED) + 800ca7c: 6bc3 ldr r3, [r0, #60] ; 0x3c + 800ca7e: 2b03 cmp r3, #3 +{ + 800ca80: b08b sub sp, #44 ; 0x2c + 800ca82: 4604 mov r4, r0 + 800ca84: 460d mov r5, r1 + if(hsd->SdCard.CardType != CARD_SECURED) + 800ca86: d002 beq.n 800ca8e + if(WideMode == SDMMC_BUS_WIDE_8B) + 800ca88: f5b1 4f00 cmp.w r1, #32768 ; 0x8000 + 800ca8c: d103 bne.n 800ca96 + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + 800ca8e: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800ca90: f043 5380 orr.w r3, r3, #268435456 ; 0x10000000 + 800ca94: e049 b.n 800cb2a + else if(WideMode == SDMMC_BUS_WIDE_4B) + 800ca96: f5b1 4f80 cmp.w r1, #16384 ; 0x4000 + 800ca9a: d123 bne.n 800cae4 + uint32_t scr[2U] = {0UL, 0UL}; + 800ca9c: 2100 movs r1, #0 + if((SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED) + 800ca9e: 6800 ldr r0, [r0, #0] + uint32_t scr[2U] = {0UL, 0UL}; + 800caa0: e9cd 1104 strd r1, r1, [sp, #16] + if((SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED) + 800caa4: f000 fafb bl 800d09e + 800caa8: 0180 lsls r0, r0, #6 + 800caaa: d435 bmi.n 800cb18 + errorstate = SD_FindSCR(hsd, scr); + 800caac: a904 add r1, sp, #16 + 800caae: 4620 mov r0, r4 + 800cab0: f7ff fa32 bl 800bf18 + if(errorstate != HAL_SD_ERROR_NONE) + 800cab4: b960 cbnz r0, 800cad0 + if((scr[1U] & SDMMC_WIDE_BUS_SUPPORT) != SDMMC_ALLZERO) + 800cab6: 9b05 ldr r3, [sp, #20] + 800cab8: 0359 lsls r1, r3, #13 + 800caba: d530 bpl.n 800cb1e + errorstate = SDMMC_CmdAppCommand(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); + 800cabc: 6ca1 ldr r1, [r4, #72] ; 0x48 + 800cabe: 6820 ldr r0, [r4, #0] + 800cac0: 0409 lsls r1, r1, #16 + 800cac2: f000 fd04 bl 800d4ce + if(errorstate != HAL_SD_ERROR_NONE) + 800cac6: b918 cbnz r0, 800cad0 + errorstate = SDMMC_CmdBusWidth(hsd->Instance, 2U); + 800cac8: 2102 movs r1, #2 + errorstate = SDMMC_CmdBusWidth(hsd->Instance, 0U); + 800caca: 6820 ldr r0, [r4, #0] + 800cacc: f000 fd18 bl 800d500 + hsd->ErrorCode |= errorstate; + 800cad0: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800cad2: 4318 orrs r0, r3 + 800cad4: 63a0 str r0, [r4, #56] ; 0x38 + if(hsd->ErrorCode != HAL_SD_ERROR_NONE) + 800cad6: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800cad8: b34b cbz r3, 800cb2e + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800cada: 6823 ldr r3, [r4, #0] + 800cadc: 4a42 ldr r2, [pc, #264] ; (800cbe8 ) + 800cade: 639a str r2, [r3, #56] ; 0x38 + status = HAL_ERROR; + 800cae0: 2501 movs r5, #1 + 800cae2: e054 b.n 800cb8e + else if(WideMode == SDMMC_BUS_WIDE_1B) + 800cae4: b9f1 cbnz r1, 800cb24 + if((SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED) + 800cae6: 6800 ldr r0, [r0, #0] + uint32_t scr[2U] = {0UL, 0UL}; + 800cae8: e9cd 1104 strd r1, r1, [sp, #16] + if((SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED) + 800caec: f000 fad7 bl 800d09e + 800caf0: 0182 lsls r2, r0, #6 + 800caf2: d411 bmi.n 800cb18 + errorstate = SD_FindSCR(hsd, scr); + 800caf4: a904 add r1, sp, #16 + 800caf6: 4620 mov r0, r4 + 800caf8: f7ff fa0e bl 800bf18 + if(errorstate != HAL_SD_ERROR_NONE) + 800cafc: 2800 cmp r0, #0 + 800cafe: d1e7 bne.n 800cad0 + if((scr[1U] & SDMMC_SINGLE_BUS_SUPPORT) != SDMMC_ALLZERO) + 800cb00: 9b05 ldr r3, [sp, #20] + 800cb02: 03db lsls r3, r3, #15 + 800cb04: d50b bpl.n 800cb1e + errorstate = SDMMC_CmdAppCommand(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); + 800cb06: 6ca1 ldr r1, [r4, #72] ; 0x48 + 800cb08: 6820 ldr r0, [r4, #0] + 800cb0a: 0409 lsls r1, r1, #16 + 800cb0c: f000 fcdf bl 800d4ce + if(errorstate != HAL_SD_ERROR_NONE) + 800cb10: 2800 cmp r0, #0 + 800cb12: d1dd bne.n 800cad0 + errorstate = SDMMC_CmdBusWidth(hsd->Instance, 0U); + 800cb14: 4601 mov r1, r0 + 800cb16: e7d8 b.n 800caca + return HAL_SD_ERROR_LOCK_UNLOCK_FAILED; + 800cb18: f44f 6000 mov.w r0, #2048 ; 0x800 + 800cb1c: e7d8 b.n 800cad0 + return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE; + 800cb1e: f04f 6080 mov.w r0, #67108864 ; 0x4000000 + 800cb22: e7d5 b.n 800cad0 + hsd->ErrorCode |= HAL_SD_ERROR_PARAM; + 800cb24: 6b83 ldr r3, [r0, #56] ; 0x38 + 800cb26: f043 6300 orr.w r3, r3, #134217728 ; 0x8000000 + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + 800cb2a: 63a3 str r3, [r4, #56] ; 0x38 + 800cb2c: e7d3 b.n 800cad6 + sdmmc_clk = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SDMMC1); + 800cb2e: f44f 2000 mov.w r0, #524288 ; 0x80000 + 800cb32: f7fd f8af bl 8009c94 + if (sdmmc_clk != 0U) + 800cb36: 2800 cmp r0, #0 + 800cb38: d051 beq.n 800cbde + Init.ClockEdge = hsd->Init.ClockEdge; + 800cb3a: 6863 ldr r3, [r4, #4] + 800cb3c: 9304 str r3, [sp, #16] + Init.ClockPowerSave = hsd->Init.ClockPowerSave; + 800cb3e: 68a3 ldr r3, [r4, #8] + if (hsd->Init.ClockDiv >= (sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ))) + 800cb40: 492a ldr r1, [pc, #168] ; (800cbec ) + 800cb42: fbb0 f2f1 udiv r2, r0, r1 + Init.BusWide = WideMode; + 800cb46: e9cd 3505 strd r3, r5, [sp, #20] + Init.HardwareFlowControl = hsd->Init.HardwareFlowControl; + 800cb4a: 6923 ldr r3, [r4, #16] + 800cb4c: 9307 str r3, [sp, #28] + if (hsd->Init.ClockDiv >= (sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ))) + 800cb4e: 6963 ldr r3, [r4, #20] + 800cb50: 4293 cmp r3, r2 + 800cb52: d301 bcc.n 800cb58 + Init.ClockDiv = sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ); + 800cb54: 9308 str r3, [sp, #32] + 800cb56: e00d b.n 800cb74 + else if (hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) + 800cb58: 6de5 ldr r5, [r4, #92] ; 0x5c + 800cb5a: f5b5 7f00 cmp.w r5, #512 ; 0x200 + 800cb5e: d0f9 beq.n 800cb54 + else if (hsd->SdCard.CardSpeed == CARD_HIGH_SPEED) + 800cb60: f5b5 7f80 cmp.w r5, #256 ; 0x100 + 800cb64: d12e bne.n 800cbc4 + if (hsd->Init.ClockDiv == 0U) + 800cb66: bb3b cbnz r3, 800cbb8 + if (sdmmc_clk > SD_HIGH_SPEED_FREQ) + 800cb68: 4288 cmp r0, r1 + 800cb6a: d923 bls.n 800cbb4 + Init.ClockDiv = sdmmc_clk / (2U * SD_HIGH_SPEED_FREQ); + 800cb6c: 4b20 ldr r3, [pc, #128] ; (800cbf0 ) + 800cb6e: fbb0 f0f3 udiv r0, r0, r3 + 800cb72: 9008 str r0, [sp, #32] + Init.Transceiver = hsd->Init.Transceiver; + 800cb74: 69a3 ldr r3, [r4, #24] + 800cb76: 9309 str r3, [sp, #36] ; 0x24 + (void)SDMMC_Init(hsd->Instance, Init); + 800cb78: ab0a add r3, sp, #40 ; 0x28 + 800cb7a: e913 0007 ldmdb r3, {r0, r1, r2} + 800cb7e: e88d 0007 stmia.w sp, {r0, r1, r2} + 800cb82: ab04 add r3, sp, #16 + 800cb84: cb0e ldmia r3, {r1, r2, r3} + 800cb86: 6820 ldr r0, [r4, #0] + 800cb88: f000 fa36 bl 800cff8 + HAL_StatusTypeDef status = HAL_OK; + 800cb8c: 2500 movs r5, #0 + errorstate = SDMMC_CmdBlockLength(hsd->Instance, BLOCKSIZE); + 800cb8e: 6820 ldr r0, [r4, #0] + 800cb90: f44f 7100 mov.w r1, #512 ; 0x200 + 800cb94: f000 fb62 bl 800d25c + if(errorstate != HAL_SD_ERROR_NONE) + 800cb98: b130 cbz r0, 800cba8 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800cb9a: 6823 ldr r3, [r4, #0] + 800cb9c: 4a12 ldr r2, [pc, #72] ; (800cbe8 ) + 800cb9e: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= errorstate; + 800cba0: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800cba2: 4318 orrs r0, r3 + 800cba4: 63a0 str r0, [r4, #56] ; 0x38 + status = HAL_ERROR; + 800cba6: 2501 movs r5, #1 + hsd->State = HAL_SD_STATE_READY; + 800cba8: 2301 movs r3, #1 +} + 800cbaa: 4628 mov r0, r5 + hsd->State = HAL_SD_STATE_READY; + 800cbac: f884 3034 strb.w r3, [r4, #52] ; 0x34 +} + 800cbb0: b00b add sp, #44 ; 0x2c + 800cbb2: bd30 pop {r4, r5, pc} + Init.ClockDiv = hsd->Init.ClockDiv; + 800cbb4: 2300 movs r3, #0 + 800cbb6: e7cd b.n 800cb54 + if ((sdmmc_clk/(2U * hsd->Init.ClockDiv)) > SD_HIGH_SPEED_FREQ) + 800cbb8: 005a lsls r2, r3, #1 + 800cbba: fbb0 f2f2 udiv r2, r0, r2 + 800cbbe: 428a cmp r2, r1 + 800cbc0: d9c8 bls.n 800cb54 + 800cbc2: e7d3 b.n 800cb6c + if (hsd->Init.ClockDiv == 0U) + 800cbc4: 490b ldr r1, [pc, #44] ; (800cbf4 ) + 800cbc6: b91b cbnz r3, 800cbd0 + if (sdmmc_clk > SD_NORMAL_SPEED_FREQ) + 800cbc8: 4288 cmp r0, r1 + 800cbca: d9f3 bls.n 800cbb4 + Init.ClockDiv = sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ); + 800cbcc: 9208 str r2, [sp, #32] + 800cbce: e7d1 b.n 800cb74 + if ((sdmmc_clk/(2U * hsd->Init.ClockDiv)) > SD_NORMAL_SPEED_FREQ) + 800cbd0: 005d lsls r5, r3, #1 + 800cbd2: fbb0 f0f5 udiv r0, r0, r5 + Init.ClockDiv = sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ); + 800cbd6: 4288 cmp r0, r1 + 800cbd8: bf88 it hi + 800cbda: 4613 movhi r3, r2 + 800cbdc: e7ba b.n 800cb54 + hsd->ErrorCode |= SDMMC_ERROR_INVALID_PARAMETER; + 800cbde: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800cbe0: f043 6300 orr.w r3, r3, #134217728 ; 0x8000000 + 800cbe4: 63a3 str r3, [r4, #56] ; 0x38 + 800cbe6: e77b b.n 800cae0 + 800cbe8: 1fe00fff .word 0x1fe00fff + 800cbec: 02faf080 .word 0x02faf080 + 800cbf0: 05f5e100 .word 0x05f5e100 + 800cbf4: 017d7840 .word 0x017d7840 + +0800cbf8 : + errorstate = SDMMC_CmdSendStatus(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); + 800cbf8: 6c81 ldr r1, [r0, #72] ; 0x48 +{ + 800cbfa: b510 push {r4, lr} + errorstate = SDMMC_CmdSendStatus(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); + 800cbfc: 0409 lsls r1, r1, #16 +{ + 800cbfe: 4604 mov r4, r0 + errorstate = SDMMC_CmdSendStatus(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); + 800cc00: 6800 ldr r0, [r0, #0] + 800cc02: f000 fccb bl 800d59c + if(errorstate != HAL_SD_ERROR_NONE) + 800cc06: 4601 mov r1, r0 + 800cc08: b928 cbnz r0, 800cc16 + *pCardStatus = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1); + 800cc0a: 6820 ldr r0, [r4, #0] + 800cc0c: f000 fa47 bl 800d09e +} + 800cc10: f3c0 2043 ubfx r0, r0, #9, #4 + 800cc14: bd10 pop {r4, pc} + hsd->ErrorCode |= errorstate; + 800cc16: 6ba0 ldr r0, [r4, #56] ; 0x38 + 800cc18: 4308 orrs r0, r1 + 800cc1a: 63a0 str r0, [r4, #56] ; 0x38 + uint32_t resp1 = 0; + 800cc1c: 2000 movs r0, #0 + 800cc1e: e7f7 b.n 800cc10 + +0800cc20 : +{ + 800cc20: b570 push {r4, r5, r6, lr} + if(hsd == NULL) + 800cc22: 4604 mov r4, r0 +{ + 800cc24: b086 sub sp, #24 + if(hsd == NULL) + 800cc26: b918 cbnz r0, 800cc30 + return HAL_ERROR; + 800cc28: 2501 movs r5, #1 +} + 800cc2a: 4628 mov r0, r5 + 800cc2c: b006 add sp, #24 + 800cc2e: bd70 pop {r4, r5, r6, pc} + if(hsd->State == HAL_SD_STATE_RESET) + 800cc30: f890 3034 ldrb.w r3, [r0, #52] ; 0x34 + 800cc34: f003 02ff and.w r2, r3, #255 ; 0xff + 800cc38: b913 cbnz r3, 800cc40 + hsd->Lock = HAL_UNLOCKED; + 800cc3a: 7702 strb r2, [r0, #28] + HAL_SD_MspInit(hsd); + 800cc3c: f7ff fa5a bl 800c0f4 + hsd->State = HAL_SD_STATE_BUSY; + 800cc40: 2303 movs r3, #3 + 800cc42: f884 3034 strb.w r3, [r4, #52] ; 0x34 + if (HAL_SD_InitCard(hsd) != HAL_OK) + 800cc46: 4620 mov r0, r4 + 800cc48: f7ff fcea bl 800c620 + 800cc4c: 2800 cmp r0, #0 + 800cc4e: d1eb bne.n 800cc28 + if( HAL_SD_GetCardStatus(hsd, &CardStatus) != HAL_OK) + 800cc50: a901 add r1, sp, #4 + 800cc52: 4620 mov r0, r4 + 800cc54: f7ff fe3e bl 800c8d4 + 800cc58: 2800 cmp r0, #0 + 800cc5a: d1e5 bne.n 800cc28 + if ((hsd->SdCard.CardType == CARD_SDHC_SDXC) && ((speedgrade != 0U) || (unitsize != 0U))) + 800cc5c: 6be1 ldr r1, [r4, #60] ; 0x3c + speedgrade = CardStatus.UhsSpeedGrade; + 800cc5e: f89d 2014 ldrb.w r2, [sp, #20] + unitsize = CardStatus.UhsAllocationUnitSize; + 800cc62: f89d 3015 ldrb.w r3, [sp, #21] + if ((hsd->SdCard.CardType == CARD_SDHC_SDXC) && ((speedgrade != 0U) || (unitsize != 0U))) + 800cc66: 2901 cmp r1, #1 + speedgrade = CardStatus.UhsSpeedGrade; + 800cc68: b2d2 uxtb r2, r2 + unitsize = CardStatus.UhsAllocationUnitSize; + 800cc6a: b2db uxtb r3, r3 + if ((hsd->SdCard.CardType == CARD_SDHC_SDXC) && ((speedgrade != 0U) || (unitsize != 0U))) + 800cc6c: d11c bne.n 800cca8 + 800cc6e: 4313 orrs r3, r2 + hsd->SdCard.CardSpeed = CARD_ULTRA_HIGH_SPEED; + 800cc70: bf14 ite ne + 800cc72: f44f 7300 movne.w r3, #512 ; 0x200 + hsd->SdCard.CardSpeed = CARD_HIGH_SPEED; + 800cc76: f44f 7380 moveq.w r3, #256 ; 0x100 + 800cc7a: 65e3 str r3, [r4, #92] ; 0x5c + if(HAL_SD_ConfigWideBusOperation(hsd, hsd->Init.BusWide) != HAL_OK) + 800cc7c: 68e1 ldr r1, [r4, #12] + 800cc7e: 4620 mov r0, r4 + 800cc80: f7ff fef8 bl 800ca74 + 800cc84: 4605 mov r5, r0 + 800cc86: 2800 cmp r0, #0 + 800cc88: d1ce bne.n 800cc28 + tickstart = HAL_GetTick(); + 800cc8a: f7fa fba7 bl 80073dc + 800cc8e: 4606 mov r6, r0 + while((HAL_SD_GetCardState(hsd) != HAL_SD_CARD_TRANSFER)) + 800cc90: 4620 mov r0, r4 + 800cc92: f7ff ffb1 bl 800cbf8 + 800cc96: 2804 cmp r0, #4 + 800cc98: d108 bne.n 800ccac + hsd->ErrorCode = HAL_SD_ERROR_NONE; + 800cc9a: 2300 movs r3, #0 + 800cc9c: 63a3 str r3, [r4, #56] ; 0x38 + hsd->Context = SD_CONTEXT_NONE; + 800cc9e: 6323 str r3, [r4, #48] ; 0x30 + hsd->State = HAL_SD_STATE_READY; + 800cca0: 2301 movs r3, #1 + 800cca2: f884 3034 strb.w r3, [r4, #52] ; 0x34 + return HAL_OK; + 800cca6: e7c0 b.n 800cc2a + hsd->SdCard.CardSpeed = CARD_NORMAL_SPEED; + 800cca8: 65e0 str r0, [r4, #92] ; 0x5c + 800ccaa: e7e7 b.n 800cc7c + if((HAL_GetTick()-tickstart) >= SDMMC_DATATIMEOUT) + 800ccac: f7fa fb96 bl 80073dc + 800ccb0: 1b80 subs r0, r0, r6 + 800ccb2: 3001 adds r0, #1 + 800ccb4: d1ec bne.n 800cc90 + hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT; + 800ccb6: f04f 4300 mov.w r3, #2147483648 ; 0x80000000 + 800ccba: 63a3 str r3, [r4, #56] ; 0x38 + hsd->State= HAL_SD_STATE_READY; + 800ccbc: 2301 movs r3, #1 + 800ccbe: f884 3034 strb.w r3, [r4, #52] ; 0x34 + hsd->Context = SD_CONTEXT_NONE; + 800ccc2: 2300 movs r3, #0 + 800ccc4: 6323 str r3, [r4, #48] ; 0x30 + return HAL_TIMEOUT; + 800ccc6: 2503 movs r5, #3 + 800ccc8: e7af b.n 800cc2a + ... + +0800cccc : +{ + 800cccc: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + uint32_t SD_hs[16] = {0}; + 800ccd0: 2640 movs r6, #64 ; 0x40 +{ + 800ccd2: b096 sub sp, #88 ; 0x58 + 800ccd4: 4605 mov r5, r0 + uint32_t SD_hs[16] = {0}; + 800ccd6: 4632 mov r2, r6 + 800ccd8: 2100 movs r1, #0 + 800ccda: a806 add r0, sp, #24 + 800ccdc: f000 fe22 bl 800d924 + uint32_t Timeout = HAL_GetTick(); + 800cce0: f7fa fb7c bl 80073dc + if(hsd->SdCard.CardSpeed == CARD_NORMAL_SPEED) + 800cce4: 6deb ldr r3, [r5, #92] ; 0x5c + uint32_t Timeout = HAL_GetTick(); + 800cce6: 4680 mov r8, r0 + if(hsd->SdCard.CardSpeed == CARD_NORMAL_SPEED) + 800cce8: 2b00 cmp r3, #0 + 800ccea: d066 beq.n 800cdba + if(hsd->SdCard.CardSpeed == CARD_HIGH_SPEED) + 800ccec: f5b3 7f80 cmp.w r3, #256 ; 0x100 + 800ccf0: d004 beq.n 800ccfc + uint32_t errorstate = HAL_SD_ERROR_NONE; + 800ccf2: 2400 movs r4, #0 +} + 800ccf4: 4620 mov r0, r4 + 800ccf6: b016 add sp, #88 ; 0x58 + 800ccf8: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + hsd->Instance->DCTRL = 0; + 800ccfc: 6828 ldr r0, [r5, #0] + 800ccfe: 2300 movs r3, #0 + 800cd00: 62c3 str r3, [r0, #44] ; 0x2c + errorstate = SDMMC_CmdBlockLength(hsd->Instance, 64U); + 800cd02: 4631 mov r1, r6 + 800cd04: f000 faaa bl 800d25c + if (errorstate != HAL_SD_ERROR_NONE) + 800cd08: 4604 mov r4, r0 + 800cd0a: 2800 cmp r0, #0 + 800cd0c: d1f2 bne.n 800ccf4 + sdmmc_datainitstructure.DataTimeOut = SDMMC_DATATIMEOUT; + 800cd0e: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + sdmmc_datainitstructure.DataLength = 64U; + 800cd12: e9cd 3600 strd r3, r6, [sp] + sdmmc_datainitstructure.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + 800cd16: 2260 movs r2, #96 ; 0x60 + 800cd18: 2302 movs r3, #2 + 800cd1a: e9cd 2302 strd r2, r3, [sp, #8] + sdmmc_datainitstructure.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + 800cd1e: 9004 str r0, [sp, #16] + sdmmc_datainitstructure.DPSM = SDMMC_DPSM_ENABLE; + 800cd20: 2301 movs r3, #1 + if ( SDMMC_ConfigData(hsd->Instance, &sdmmc_datainitstructure) != HAL_OK) + 800cd22: 6828 ldr r0, [r5, #0] + sdmmc_datainitstructure.DPSM = SDMMC_DPSM_ENABLE; + 800cd24: 9305 str r3, [sp, #20] + if ( SDMMC_ConfigData(hsd->Instance, &sdmmc_datainitstructure) != HAL_OK) + 800cd26: 4669 mov r1, sp + 800cd28: f000 f9bc bl 800d0a4 + 800cd2c: 2800 cmp r0, #0 + 800cd2e: d147 bne.n 800cdc0 + errorstate = SDMMC_CmdSwitch(hsd->Instance,SDMMC_SDR25_SWITCH_PATTERN); + 800cd30: 4925 ldr r1, [pc, #148] ; (800cdc8 ) + 800cd32: 6828 ldr r0, [r5, #0] + 800cd34: f000 fbfd bl 800d532 + if(errorstate != HAL_SD_ERROR_NONE) + 800cd38: 4604 mov r4, r0 + 800cd3a: 2800 cmp r0, #0 + 800cd3c: d1da bne.n 800ccf4 + uint32_t count, loop = 0 ; + 800cd3e: 4607 mov r7, r0 + while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND| SDMMC_FLAG_DATAEND )) + 800cd40: f240 592a movw r9, #1322 ; 0x52a + 800cd44: 682b ldr r3, [r5, #0] + 800cd46: 6b5e ldr r6, [r3, #52] ; 0x34 + 800cd48: ea16 0609 ands.w r6, r6, r9 + 800cd4c: d005 beq.n 800cd5a + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT)) + 800cd4e: 6b5a ldr r2, [r3, #52] ; 0x34 + 800cd50: 0710 lsls r0, r2, #28 + 800cd52: d51e bpl.n 800cd92 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DTIMEOUT); + 800cd54: 2208 movs r2, #8 + 800cd56: 639a str r2, [r3, #56] ; 0x38 + return errorstate; + 800cd58: e7cc b.n 800ccf4 + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOHF)) + 800cd5a: 6b5b ldr r3, [r3, #52] ; 0x34 + 800cd5c: 041b lsls r3, r3, #16 + 800cd5e: d50b bpl.n 800cd78 + 800cd60: ab06 add r3, sp, #24 + 800cd62: eb03 1a47 add.w sl, r3, r7, lsl #5 + SD_hs[(8U*loop)+count] = SDMMC_ReadFIFO(hsd->Instance); + 800cd66: 6828 ldr r0, [r5, #0] + 800cd68: f000 f960 bl 800d02c + for (count = 0U; count < 8U; count++) + 800cd6c: 3601 adds r6, #1 + 800cd6e: 2e08 cmp r6, #8 + SD_hs[(8U*loop)+count] = SDMMC_ReadFIFO(hsd->Instance); + 800cd70: f84a 0b04 str.w r0, [sl], #4 + for (count = 0U; count < 8U; count++) + 800cd74: d1f7 bne.n 800cd66 + loop ++; + 800cd76: 3701 adds r7, #1 + if((HAL_GetTick()-Timeout) >= SDMMC_DATATIMEOUT) + 800cd78: f7fa fb30 bl 80073dc + 800cd7c: eba0 0008 sub.w r0, r0, r8 + 800cd80: 3001 adds r0, #1 + 800cd82: d1df bne.n 800cd44 + hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT; + 800cd84: f04f 4400 mov.w r4, #2147483648 ; 0x80000000 + hsd->State= HAL_SD_STATE_READY; + 800cd88: 2301 movs r3, #1 + hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT; + 800cd8a: 63ac str r4, [r5, #56] ; 0x38 + hsd->State= HAL_SD_STATE_READY; + 800cd8c: f885 3034 strb.w r3, [r5, #52] ; 0x34 + return HAL_SD_ERROR_TIMEOUT; + 800cd90: e7b0 b.n 800ccf4 + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL)) + 800cd92: 6b5a ldr r2, [r3, #52] ; 0x34 + 800cd94: 0791 lsls r1, r2, #30 + 800cd96: d502 bpl.n 800cd9e + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DCRCFAIL); + 800cd98: 2402 movs r4, #2 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_RXOVERR); + 800cd9a: 639c str r4, [r3, #56] ; 0x38 + return errorstate; + 800cd9c: e7aa b.n 800ccf4 + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)) + 800cd9e: 6b5a ldr r2, [r3, #52] ; 0x34 + 800cda0: 0692 lsls r2, r2, #26 + 800cda2: d501 bpl.n 800cda8 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_RXOVERR); + 800cda4: 2420 movs r4, #32 + 800cda6: e7f8 b.n 800cd9a + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + 800cda8: 4a08 ldr r2, [pc, #32] ; (800cdcc ) + 800cdaa: 639a str r2, [r3, #56] ; 0x38 + if ((((uint8_t*)SD_hs)[13] & 2U) != 2U) + 800cdac: f89d 3025 ldrb.w r3, [sp, #37] ; 0x25 + 800cdb0: 079b lsls r3, r3, #30 + 800cdb2: d49e bmi.n 800ccf2 + errorstate = SDMMC_ERROR_UNSUPPORTED_FEATURE; + 800cdb4: f04f 5480 mov.w r4, #268435456 ; 0x10000000 + 800cdb8: e79c b.n 800ccf4 + return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE; + 800cdba: f04f 6480 mov.w r4, #67108864 ; 0x4000000 + 800cdbe: e799 b.n 800ccf4 + return (HAL_SD_ERROR_GENERAL_UNKNOWN_ERR); + 800cdc0: f44f 3480 mov.w r4, #65536 ; 0x10000 + 800cdc4: e796 b.n 800ccf4 + 800cdc6: bf00 nop + 800cdc8: 80ffff01 .word 0x80ffff01 + 800cdcc: 18000f3a .word 0x18000f3a + +0800cdd0 : +{ + 800cdd0: e92d 47f0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, lr} + hsd->State = HAL_SD_STATE_BUSY; + 800cdd4: 2303 movs r3, #3 + 800cdd6: f880 3034 strb.w r3, [r0, #52] ; 0x34 + if(hsd->Init.Transceiver == SDMMC_TRANSCEIVER_ENABLE) + 800cdda: 6983 ldr r3, [r0, #24] + 800cddc: 2b01 cmp r3, #1 +{ + 800cdde: b096 sub sp, #88 ; 0x58 + 800cde0: 4604 mov r4, r0 + if(hsd->Init.Transceiver == SDMMC_TRANSCEIVER_ENABLE) + 800cde2: f040 80cf bne.w 800cf84 + switch (SpeedMode) + 800cde6: 2904 cmp r1, #4 + 800cde8: f200 80eb bhi.w 800cfc2 + 800cdec: e8df f011 tbh [pc, r1, lsl #1] + 800cdf0: 00150005 .word 0x00150005 + 800cdf4: 001e00dc .word 0x001e00dc + 800cdf8: 0031 .short 0x0031 + if ((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) || + 800cdfa: 6dc3 ldr r3, [r0, #92] ; 0x5c + 800cdfc: f5b3 7f00 cmp.w r3, #512 ; 0x200 + 800ce00: d002 beq.n 800ce08 + 800ce02: 6bc2 ldr r2, [r0, #60] ; 0x3c + 800ce04: 2a01 cmp r2, #1 + 800ce06: d10a bne.n 800ce1e + hsd->Instance->CLKCR |= 0x00100000U; + 800ce08: 6822 ldr r2, [r4, #0] + 800ce0a: 6853 ldr r3, [r2, #4] + 800ce0c: f443 1380 orr.w r3, r3, #1048576 ; 0x100000 + 800ce10: 6053 str r3, [r2, #4] + if (SD_UltraHighSpeed(hsd) != HAL_SD_ERROR_NONE) + 800ce12: 4620 mov r0, r4 + 800ce14: f7ff f8e6 bl 800bfe4 + 800ce18: b920 cbnz r0, 800ce24 + switch (SpeedMode) + 800ce1a: 2500 movs r5, #0 + 800ce1c: e063 b.n 800cee6 + else if (hsd->SdCard.CardSpeed == CARD_HIGH_SPEED) + 800ce1e: f5b3 7f80 cmp.w r3, #256 ; 0x100 + (hsd->SdCard.CardSpeed == CARD_HIGH_SPEED) || + 800ce22: d1fa bne.n 800ce1a + if (SD_HighSpeed(hsd) != HAL_SD_ERROR_NONE) + 800ce24: 4620 mov r0, r4 + 800ce26: f7ff ff51 bl 800cccc + 800ce2a: e00f b.n 800ce4c + if ((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) || + 800ce2c: 6dc3 ldr r3, [r0, #92] ; 0x5c + 800ce2e: f5b3 7f00 cmp.w r3, #512 ; 0x200 + 800ce32: d003 beq.n 800ce3c + 800ce34: 6bc3 ldr r3, [r0, #60] ; 0x3c + 800ce36: 2b01 cmp r3, #1 + 800ce38: f040 8089 bne.w 800cf4e + hsd->Instance->CLKCR |= 0x00100000U; + 800ce3c: 6822 ldr r2, [r4, #0] + 800ce3e: 6853 ldr r3, [r2, #4] + 800ce40: f443 1380 orr.w r3, r3, #1048576 ; 0x100000 + 800ce44: 6053 str r3, [r2, #4] + if (SD_UltraHighSpeed(hsd) != HAL_SD_ERROR_NONE) + 800ce46: 4620 mov r0, r4 + 800ce48: f7ff f8cc bl 800bfe4 + if (SD_HighSpeed(hsd) != HAL_SD_ERROR_NONE) + 800ce4c: 2800 cmp r0, #0 + 800ce4e: d0e4 beq.n 800ce1a + 800ce50: e07d b.n 800cf4e + if ((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) || + 800ce52: 6dc3 ldr r3, [r0, #92] ; 0x5c + 800ce54: f5b3 7f00 cmp.w r3, #512 ; 0x200 + 800ce58: d002 beq.n 800ce60 + 800ce5a: 6bc3 ldr r3, [r0, #60] ; 0x3c + 800ce5c: 2b01 cmp r3, #1 + 800ce5e: d176 bne.n 800cf4e + hsd->Instance->CLKCR |= 0x00100000U; + 800ce60: 6822 ldr r2, [r4, #0] + 800ce62: 6853 ldr r3, [r2, #4] + */ +static uint32_t SD_DDR_Mode(SD_HandleTypeDef *hsd) +{ + uint32_t errorstate = HAL_SD_ERROR_NONE; + SDMMC_DataInitTypeDef sdmmc_datainitstructure; + uint32_t SD_hs[16] = {0}; + 800ce64: 2540 movs r5, #64 ; 0x40 + hsd->Instance->CLKCR |= 0x00100000U; + 800ce66: f443 1380 orr.w r3, r3, #1048576 ; 0x100000 + 800ce6a: 6053 str r3, [r2, #4] + uint32_t SD_hs[16] = {0}; + 800ce6c: 2100 movs r1, #0 + 800ce6e: 462a mov r2, r5 + 800ce70: a806 add r0, sp, #24 + 800ce72: f000 fd57 bl 800d924 + uint32_t count, loop = 0 ; + uint32_t Timeout = HAL_GetTick(); + 800ce76: f7fa fab1 bl 80073dc + + if(hsd->SdCard.CardSpeed == CARD_NORMAL_SPEED) + 800ce7a: 6de3 ldr r3, [r4, #92] ; 0x5c + uint32_t Timeout = HAL_GetTick(); + 800ce7c: 4680 mov r8, r0 + if(hsd->SdCard.CardSpeed == CARD_NORMAL_SPEED) + 800ce7e: 2b00 cmp r3, #0 + 800ce80: d065 beq.n 800cf4e + { + /* Standard Speed Card <= 12.5Mhz */ + return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE; + } + + if((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) && + 800ce82: f5b3 7f00 cmp.w r3, #512 ; 0x200 + 800ce86: d1c8 bne.n 800ce1a + 800ce88: 69a6 ldr r6, [r4, #24] + 800ce8a: 2e01 cmp r6, #1 + 800ce8c: d1c5 bne.n 800ce1a + (hsd->Init.Transceiver == SDMMC_TRANSCEIVER_ENABLE)) + { + /* Initialize the Data control register */ + hsd->Instance->DCTRL = 0; + 800ce8e: 6820 ldr r0, [r4, #0] + 800ce90: 2300 movs r3, #0 + 800ce92: 62c3 str r3, [r0, #44] ; 0x2c + errorstate = SDMMC_CmdBlockLength(hsd->Instance, 64U); + 800ce94: 4629 mov r1, r5 + 800ce96: f000 f9e1 bl 800d25c + + if (errorstate != HAL_SD_ERROR_NONE) + 800ce9a: 2800 cmp r0, #0 + 800ce9c: d157 bne.n 800cf4e + { + return errorstate; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + sdmmc_datainitstructure.DataTimeOut = SDMMC_DATATIMEOUT; + 800ce9e: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff + sdmmc_datainitstructure.DataLength = 64U; + 800cea2: e9cd 3500 strd r3, r5, [sp] + sdmmc_datainitstructure.DataBlockSize = SDMMC_DATABLOCK_SIZE_64B ; + sdmmc_datainitstructure.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + sdmmc_datainitstructure.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + sdmmc_datainitstructure.DPSM = SDMMC_DPSM_ENABLE; + 800cea6: e9cd 0604 strd r0, r6, [sp, #16] + sdmmc_datainitstructure.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + 800ceaa: 2260 movs r2, #96 ; 0x60 + 800ceac: 2302 movs r3, #2 + + if ( SDMMC_ConfigData(hsd->Instance, &sdmmc_datainitstructure) != HAL_OK) + 800ceae: 6820 ldr r0, [r4, #0] + 800ceb0: 4669 mov r1, sp + sdmmc_datainitstructure.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + 800ceb2: e9cd 2302 strd r2, r3, [sp, #8] + if ( SDMMC_ConfigData(hsd->Instance, &sdmmc_datainitstructure) != HAL_OK) + 800ceb6: f000 f8f5 bl 800d0a4 + 800ceba: 4605 mov r5, r0 + 800cebc: 2800 cmp r0, #0 + 800cebe: d146 bne.n 800cf4e + { + return (HAL_SD_ERROR_GENERAL_UNKNOWN_ERR); + } + + errorstate = SDMMC_CmdSwitch(hsd->Instance, SDMMC_DDR50_SWITCH_PATTERN); + 800cec0: 494a ldr r1, [pc, #296] ; (800cfec ) + 800cec2: 6820 ldr r0, [r4, #0] + 800cec4: f000 fb35 bl 800d532 + if(errorstate != HAL_SD_ERROR_NONE) + 800cec8: 4607 mov r7, r0 + 800ceca: 2800 cmp r0, #0 + 800cecc: d13f bne.n 800cf4e + { + return errorstate; + } + + while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND| SDMMC_FLAG_DATAEND )) + 800cece: f240 592a movw r9, #1322 ; 0x52a + 800ced2: 6823 ldr r3, [r4, #0] + 800ced4: 6b5e ldr r6, [r3, #52] ; 0x34 + 800ced6: ea16 0609 ands.w r6, r6, r9 + 800ceda: d01d beq.n 800cf18 + hsd->State= HAL_SD_STATE_READY; + return HAL_SD_ERROR_TIMEOUT; + } + } + + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT)) + 800cedc: 6b5a ldr r2, [r3, #52] ; 0x34 + 800cede: 0710 lsls r0, r2, #28 + 800cee0: d53b bpl.n 800cf5a + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DTIMEOUT); + 800cee2: 2208 movs r2, #8 + 800cee4: 639a str r2, [r3, #56] ; 0x38 + tickstart = HAL_GetTick(); + 800cee6: f7fa fa79 bl 80073dc + 800ceea: 4606 mov r6, r0 + while ((HAL_SD_GetCardState(hsd) != HAL_SD_CARD_TRANSFER)) + 800ceec: 4620 mov r0, r4 + 800ceee: f7ff fe83 bl 800cbf8 + 800cef2: 2804 cmp r0, #4 + 800cef4: d169 bne.n 800cfca + errorstate = SDMMC_CmdBlockLength(hsd->Instance, BLOCKSIZE); + 800cef6: 6820 ldr r0, [r4, #0] + 800cef8: f44f 7100 mov.w r1, #512 ; 0x200 + 800cefc: f000 f9ae bl 800d25c + if(errorstate != HAL_SD_ERROR_NONE) + 800cf00: b130 cbz r0, 800cf10 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + 800cf02: 6823 ldr r3, [r4, #0] + 800cf04: 4a3a ldr r2, [pc, #232] ; (800cff0 ) + 800cf06: 639a str r2, [r3, #56] ; 0x38 + hsd->ErrorCode |= errorstate; + 800cf08: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800cf0a: 4318 orrs r0, r3 + 800cf0c: 63a0 str r0, [r4, #56] ; 0x38 + status = HAL_ERROR; + 800cf0e: 2501 movs r5, #1 + hsd->State = HAL_SD_STATE_READY; + 800cf10: 2301 movs r3, #1 + 800cf12: f884 3034 strb.w r3, [r4, #52] ; 0x34 + return status; + 800cf16: e064 b.n 800cfe2 + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOHF)) + 800cf18: 6b5b ldr r3, [r3, #52] ; 0x34 + 800cf1a: 041b lsls r3, r3, #16 + 800cf1c: d50b bpl.n 800cf36 + 800cf1e: ab06 add r3, sp, #24 + 800cf20: eb03 1a47 add.w sl, r3, r7, lsl #5 + SD_hs[(8U*loop)+count] = SDMMC_ReadFIFO(hsd->Instance); + 800cf24: 6820 ldr r0, [r4, #0] + 800cf26: f000 f881 bl 800d02c + for (count = 0U; count < 8U; count++) + 800cf2a: 3601 adds r6, #1 + 800cf2c: 2e08 cmp r6, #8 + SD_hs[(8U*loop)+count] = SDMMC_ReadFIFO(hsd->Instance); + 800cf2e: f84a 0b04 str.w r0, [sl], #4 + for (count = 0U; count < 8U; count++) + 800cf32: d1f7 bne.n 800cf24 + loop ++; + 800cf34: 3701 adds r7, #1 + if((HAL_GetTick()-Timeout) >= SDMMC_DATATIMEOUT) + 800cf36: f7fa fa51 bl 80073dc + 800cf3a: eba0 0008 sub.w r0, r0, r8 + 800cf3e: 3001 adds r0, #1 + 800cf40: d1c7 bne.n 800ced2 + hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT; + 800cf42: f04f 4300 mov.w r3, #2147483648 ; 0x80000000 + 800cf46: 63a3 str r3, [r4, #56] ; 0x38 + hsd->State= HAL_SD_STATE_READY; + 800cf48: 2301 movs r3, #1 + 800cf4a: f884 3034 strb.w r3, [r4, #52] ; 0x34 + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + 800cf4e: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800cf50: f043 5380 orr.w r3, r3, #268435456 ; 0x10000000 + hsd->ErrorCode |= HAL_SD_ERROR_PARAM; + 800cf54: 63a3 str r3, [r4, #56] ; 0x38 + status = HAL_ERROR; + 800cf56: 2501 movs r5, #1 + break; + 800cf58: e7c5 b.n 800cee6 + + return errorstate; + } + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL)) + 800cf5a: 6b5a ldr r2, [r3, #52] ; 0x34 + 800cf5c: 0791 lsls r1, r2, #30 + 800cf5e: d502 bpl.n 800cf66 + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DCRCFAIL); + 800cf60: 2202 movs r2, #2 + + return errorstate; + } + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)) + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_RXOVERR); + 800cf62: 639a str r2, [r3, #56] ; 0x38 + + errorstate = SDMMC_ERROR_RX_OVERRUN; + + return errorstate; + 800cf64: e7f3 b.n 800cf4e + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)) + 800cf66: 6b5a ldr r2, [r3, #52] ; 0x34 + 800cf68: 0692 lsls r2, r2, #26 + 800cf6a: d501 bpl.n 800cf70 + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_RXOVERR); + 800cf6c: 2220 movs r2, #32 + 800cf6e: e7f8 b.n 800cf62 + { + /* No error flag set */ + } + + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + 800cf70: 4a20 ldr r2, [pc, #128] ; (800cff4 ) + 800cf72: 639a str r2, [r3, #56] ; 0x38 + + /* Test if the switch mode is ok */ + if ((((uint8_t*)SD_hs)[13] & 2U) != 2U) + 800cf74: f89d 3025 ldrb.w r3, [sp, #37] ; 0x25 + 800cf78: 079b lsls r3, r3, #30 + 800cf7a: d5e8 bpl.n 800cf4e + else + { +#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U) + hsd->DriveTransceiver_1_8V_Callback(SET); +#else + HAL_SDEx_DriveTransceiver_1_8V_Callback(SET); + 800cf7c: 2001 movs r0, #1 + 800cf7e: f7fa fa9d bl 80074bc + 800cf82: e7b0 b.n 800cee6 + switch (SpeedMode) + 800cf84: 2901 cmp r1, #1 + 800cf86: f43f af48 beq.w 800ce1a + 800cf8a: 2902 cmp r1, #2 + 800cf8c: d00c beq.n 800cfa8 + 800cf8e: b9c1 cbnz r1, 800cfc2 + if ((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) || + 800cf90: 6dc3 ldr r3, [r0, #92] ; 0x5c + 800cf92: f5b3 7f00 cmp.w r3, #512 ; 0x200 + 800cf96: f43f af45 beq.w 800ce24 + 800cf9a: f5b3 7f80 cmp.w r3, #256 ; 0x100 + 800cf9e: f43f af41 beq.w 800ce24 + (hsd->SdCard.CardSpeed == CARD_HIGH_SPEED) || + 800cfa2: 6bc3 ldr r3, [r0, #60] ; 0x3c + 800cfa4: 2b01 cmp r3, #1 + 800cfa6: e73c b.n 800ce22 + if ((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) || + 800cfa8: 6de3 ldr r3, [r4, #92] ; 0x5c + 800cfaa: f5b3 7f00 cmp.w r3, #512 ; 0x200 + 800cfae: f43f af39 beq.w 800ce24 + 800cfb2: f5b3 7f80 cmp.w r3, #256 ; 0x100 + 800cfb6: f43f af35 beq.w 800ce24 + (hsd->SdCard.CardSpeed == CARD_HIGH_SPEED) || + 800cfba: 6be3 ldr r3, [r4, #60] ; 0x3c + 800cfbc: 2b01 cmp r3, #1 + 800cfbe: d1c6 bne.n 800cf4e + 800cfc0: e730 b.n 800ce24 + hsd->ErrorCode |= HAL_SD_ERROR_PARAM; + 800cfc2: 6ba3 ldr r3, [r4, #56] ; 0x38 + 800cfc4: f043 6300 orr.w r3, r3, #134217728 ; 0x8000000 + 800cfc8: e7c4 b.n 800cf54 + if ((HAL_GetTick() - tickstart) >= SDMMC_DATATIMEOUT) + 800cfca: f7fa fa07 bl 80073dc + 800cfce: 1b80 subs r0, r0, r6 + 800cfd0: 3001 adds r0, #1 + 800cfd2: d18b bne.n 800ceec + hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT; + 800cfd4: f04f 4300 mov.w r3, #2147483648 ; 0x80000000 + 800cfd8: 63a3 str r3, [r4, #56] ; 0x38 + hsd->State = HAL_SD_STATE_READY; + 800cfda: 2301 movs r3, #1 + 800cfdc: f884 3034 strb.w r3, [r4, #52] ; 0x34 + return HAL_TIMEOUT; + 800cfe0: 2503 movs r5, #3 +} + 800cfe2: 4628 mov r0, r5 + 800cfe4: b016 add sp, #88 ; 0x58 + 800cfe6: e8bd 87f0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, pc} + 800cfea: bf00 nop + 800cfec: 80ffff04 .word 0x80ffff04 + 800cff0: 1fe00fff .word 0x1fe00fff + 800cff4: 18000f3a .word 0x18000f3a + +0800cff8 : + * @param SDMMCx Pointer to SDMMC register base + * @param Init SDMMC initialization structure + * @retval HAL status + */ +HAL_StatusTypeDef SDMMC_Init(SDMMC_TypeDef *SDMMCx, SDMMC_InitTypeDef Init) +{ + 800cff8: b084 sub sp, #16 + 800cffa: b510 push {r4, lr} + 800cffc: ac03 add r4, sp, #12 + 800cffe: e884 000e stmia.w r4, {r1, r2, r3} + + /* Set SDMMC configuration parameters */ +#if !defined(STM32L4P5xx) && !defined(STM32L4Q5xx) && !defined(STM32L4R5xx) && !defined(STM32L4R7xx) && !defined(STM32L4R9xx) && !defined(STM32L4S5xx) && !defined(STM32L4S7xx) && !defined(STM32L4S9xx) + tmpreg |= Init.ClockBypass; +#endif + tmpreg |= (Init.ClockEdge |\ + 800d002: 9b03 ldr r3, [sp, #12] + Init.HardwareFlowControl |\ + Init.ClockDiv + ); + + /* Write to SDMMC CLKCR */ + MODIFY_REG(SDMMCx->CLKCR, CLKCR_CLEAR_MASK, tmpreg); + 800d004: 6841 ldr r1, [r0, #4] + tmpreg |= (Init.ClockEdge |\ + 800d006: 4313 orrs r3, r2 + Init.ClockPowerSave |\ + 800d008: 9a05 ldr r2, [sp, #20] + 800d00a: 4313 orrs r3, r2 + Init.BusWide |\ + 800d00c: 9a06 ldr r2, [sp, #24] + 800d00e: 4313 orrs r3, r2 + Init.HardwareFlowControl |\ + 800d010: 9a07 ldr r2, [sp, #28] + + return HAL_OK; +} + 800d012: e8bd 4010 ldmia.w sp!, {r4, lr} + Init.HardwareFlowControl |\ + 800d016: 4313 orrs r3, r2 + MODIFY_REG(SDMMCx->CLKCR, CLKCR_CLEAR_MASK, tmpreg); + 800d018: 4a03 ldr r2, [pc, #12] ; (800d028 ) + 800d01a: 400a ands r2, r1 + 800d01c: 4313 orrs r3, r2 + 800d01e: 6043 str r3, [r0, #4] +} + 800d020: b004 add sp, #16 + 800d022: 2000 movs r0, #0 + 800d024: 4770 bx lr + 800d026: bf00 nop + 800d028: ffc02c00 .word 0xffc02c00 + +0800d02c : + * @retval HAL status + */ +uint32_t SDMMC_ReadFIFO(SDMMC_TypeDef *SDMMCx) +{ + /* Read data from Rx FIFO */ + return (SDMMCx->FIFO); + 800d02c: f8d0 0080 ldr.w r0, [r0, #128] ; 0x80 +} + 800d030: 4770 bx lr + +0800d032 : + * @retval HAL status + */ +HAL_StatusTypeDef SDMMC_WriteFIFO(SDMMC_TypeDef *SDMMCx, uint32_t *pWriteData) +{ + /* Write data to FIFO */ + SDMMCx->FIFO = *pWriteData; + 800d032: 680b ldr r3, [r1, #0] + 800d034: f8c0 3080 str.w r3, [r0, #128] ; 0x80 + + return HAL_OK; +} + 800d038: 2000 movs r0, #0 + 800d03a: 4770 bx lr + +0800d03c : + * @brief Set SDMMC Power state to ON. + * @param SDMMCx Pointer to SDMMC register base + * @retval HAL status + */ +HAL_StatusTypeDef SDMMC_PowerState_ON(SDMMC_TypeDef *SDMMCx) +{ + 800d03c: b508 push {r3, lr} + /* Set power state to ON */ +#if defined(STM32L4P5xx) || defined(STM32L4Q5xx) || defined(STM32L4R5xx) || defined(STM32L4R7xx) || defined(STM32L4R9xx) || defined(STM32L4S5xx) || defined(STM32L4S7xx) || defined(STM32L4S9xx) + SDMMCx->POWER |= SDMMC_POWER_PWRCTRL; + 800d03e: 6803 ldr r3, [r0, #0] + 800d040: f043 0303 orr.w r3, r3, #3 + 800d044: 6003 str r3, [r0, #0] + SDMMCx->POWER = SDMMC_POWER_PWRCTRL; +#endif /* STM32L4P5xx || STM32L4Q5xx || STM32L4R5xx || STM32L4R7xx || STM32L4R9xx || STM32L4S5xx || STM32L4S7xx || STM32L4S9xx */ + + /* 1ms: required power up waiting time before starting the SD initialization + sequence */ + HAL_Delay(2); + 800d046: 2002 movs r0, #2 + 800d048: f7f6 fd29 bl 8003a9e + + return HAL_OK; +} + 800d04c: 2000 movs r0, #0 + 800d04e: bd08 pop {r3, pc} + +0800d050 : + * @retval HAL status + */ +HAL_StatusTypeDef SDMMC_PowerState_Cycle(SDMMC_TypeDef *SDMMCx) +{ + /* Set power state to Power Cycle*/ + SDMMCx->POWER |= SDMMC_POWER_PWRCTRL_1; + 800d050: 6803 ldr r3, [r0, #0] + 800d052: f043 0302 orr.w r3, r3, #2 + 800d056: 6003 str r3, [r0, #0] + + return HAL_OK; +} + 800d058: 2000 movs r0, #0 + 800d05a: 4770 bx lr + +0800d05c : + */ +HAL_StatusTypeDef SDMMC_PowerState_OFF(SDMMC_TypeDef *SDMMCx) +{ + /* Set power state to OFF */ +#if defined(STM32L4P5xx) || defined(STM32L4Q5xx) || defined(STM32L4R5xx) || defined(STM32L4R7xx) || defined(STM32L4R9xx) || defined(STM32L4S5xx) || defined(STM32L4S7xx) || defined(STM32L4S9xx) + SDMMCx->POWER &= ~(SDMMC_POWER_PWRCTRL); + 800d05c: 6803 ldr r3, [r0, #0] + 800d05e: f023 0303 bic.w r3, r3, #3 + 800d062: 6003 str r3, [r0, #0] +#else + SDMMCx->POWER = (uint32_t)0x00000000; +#endif /* STM32L4P5xx || STM32L4Q5xx || STM32L4R5xx || STM32L4R7xx || STM32L4R9xx || STM32L4S5xx || STM32L4S7xx || STM32L4S9xx */ + + return HAL_OK; +} + 800d064: 2000 movs r0, #0 + 800d066: 4770 bx lr + +0800d068 : + * - 0x02: Power UP + * - 0x03: Power ON + */ +uint32_t SDMMC_GetPowerState(SDMMC_TypeDef *SDMMCx) +{ + return (SDMMCx->POWER & SDMMC_POWER_PWRCTRL); + 800d068: 6800 ldr r0, [r0, #0] +} + 800d06a: f000 0003 and.w r0, r0, #3 + 800d06e: 4770 bx lr + +0800d070 : + assert_param(IS_SDMMC_RESPONSE(Command->Response)); + assert_param(IS_SDMMC_WAIT(Command->WaitForInterrupt)); + assert_param(IS_SDMMC_CPSM(Command->CPSM)); + + /* Set the SDMMC Argument value */ + SDMMCx->ARG = Command->Argument; + 800d070: 680b ldr r3, [r1, #0] +{ + 800d072: b510 push {r4, lr} + SDMMCx->ARG = Command->Argument; + 800d074: 6083 str r3, [r0, #8] + + /* Set SDMMC command parameters */ + tmpreg |= (uint32_t)(Command->CmdIndex |\ + 800d076: e9d1 3201 ldrd r3, r2, [r1, #4] + 800d07a: 4313 orrs r3, r2 + Command->Response |\ + 800d07c: 68ca ldr r2, [r1, #12] + Command->WaitForInterrupt |\ + Command->CPSM); + + /* Write to SDMMC CMD register */ + MODIFY_REG(SDMMCx->CMD, CMD_CLEAR_MASK, tmpreg); + 800d07e: 68c4 ldr r4, [r0, #12] + Command->Response |\ + 800d080: 4313 orrs r3, r2 + Command->WaitForInterrupt |\ + 800d082: 690a ldr r2, [r1, #16] + 800d084: 4313 orrs r3, r2 + MODIFY_REG(SDMMCx->CMD, CMD_CLEAR_MASK, tmpreg); + 800d086: 4a03 ldr r2, [pc, #12] ; (800d094 ) + 800d088: 4022 ands r2, r4 + 800d08a: 4313 orrs r3, r2 + 800d08c: 60c3 str r3, [r0, #12] + + return HAL_OK; +} + 800d08e: 2000 movs r0, #0 + 800d090: bd10 pop {r4, pc} + 800d092: bf00 nop + 800d094: fffee0c0 .word 0xfffee0c0 + +0800d098 : + * @param SDMMCx Pointer to SDMMC register base + * @retval Command index of the last command response received + */ +uint8_t SDMMC_GetCommandResponse(SDMMC_TypeDef *SDMMCx) +{ + return (uint8_t)(SDMMCx->RESPCMD); + 800d098: 6900 ldr r0, [r0, #16] +} + 800d09a: b2c0 uxtb r0, r0 + 800d09c: 4770 bx lr + +0800d09e : + + /* Check the parameters */ + assert_param(IS_SDMMC_RESP(Response)); + + /* Get the response */ + tmp = (uint32_t)(&(SDMMCx->RESP1)) + Response; + 800d09e: 3014 adds r0, #20 + + return (*(__IO uint32_t *) tmp); + 800d0a0: 5840 ldr r0, [r0, r1] +} + 800d0a2: 4770 bx lr + +0800d0a4 : + assert_param(IS_SDMMC_TRANSFER_DIR(Data->TransferDir)); + assert_param(IS_SDMMC_TRANSFER_MODE(Data->TransferMode)); + assert_param(IS_SDMMC_DPSM(Data->DPSM)); + + /* Set the SDMMC Data TimeOut value */ + SDMMCx->DTIMER = Data->DataTimeOut; + 800d0a4: 680b ldr r3, [r1, #0] +{ + 800d0a6: b510 push {r4, lr} + SDMMCx->DTIMER = Data->DataTimeOut; + 800d0a8: 6243 str r3, [r0, #36] ; 0x24 + + /* Set the SDMMC DataLength value */ + SDMMCx->DLEN = Data->DataLength; + 800d0aa: 684b ldr r3, [r1, #4] + 800d0ac: 6283 str r3, [r0, #40] ; 0x28 + + /* Set the SDMMC data configuration parameters */ + tmpreg |= (uint32_t)(Data->DataBlockSize |\ + 800d0ae: e9d1 3402 ldrd r3, r4, [r1, #8] + 800d0b2: 4323 orrs r3, r4 + Data->TransferDir |\ + 800d0b4: 690c ldr r4, [r1, #16] + Data->TransferMode |\ + Data->DPSM); + + /* Write to SDMMC DCTRL */ + MODIFY_REG(SDMMCx->DCTRL, DCTRL_CLEAR_MASK, tmpreg); + 800d0b6: 6ac2 ldr r2, [r0, #44] ; 0x2c + Data->TransferMode |\ + 800d0b8: 6949 ldr r1, [r1, #20] + Data->TransferDir |\ + 800d0ba: 4323 orrs r3, r4 + Data->TransferMode |\ + 800d0bc: 430b orrs r3, r1 + MODIFY_REG(SDMMCx->DCTRL, DCTRL_CLEAR_MASK, tmpreg); + 800d0be: f022 02ff bic.w r2, r2, #255 ; 0xff + 800d0c2: 4313 orrs r3, r2 + 800d0c4: 62c3 str r3, [r0, #44] ; 0x2c + + return HAL_OK; + +} + 800d0c6: 2000 movs r0, #0 + 800d0c8: bd10 pop {r4, pc} + +0800d0ca : + * @param SDMMCx Pointer to SDMMC register base + * @retval Number of remaining data bytes to be transferred + */ +uint32_t SDMMC_GetDataCounter(SDMMC_TypeDef *SDMMCx) +{ + return (SDMMCx->DCOUNT); + 800d0ca: 6b00 ldr r0, [r0, #48] ; 0x30 +} + 800d0cc: 4770 bx lr + +0800d0ce : + 800d0ce: f8d0 0080 ldr.w r0, [r0, #128] ; 0x80 + 800d0d2: 4770 bx lr + +0800d0d4 : +{ + /* Check the parameters */ + assert_param(IS_SDMMC_READWAIT_MODE(SDMMC_ReadWaitMode)); + + /* Set SDMMC read wait mode */ + MODIFY_REG(SDMMCx->DCTRL, SDMMC_DCTRL_RWMOD, SDMMC_ReadWaitMode); + 800d0d4: 6ac3 ldr r3, [r0, #44] ; 0x2c + 800d0d6: f423 6380 bic.w r3, r3, #1024 ; 0x400 + 800d0da: 4319 orrs r1, r3 + 800d0dc: 62c1 str r1, [r0, #44] ; 0x2c + + return HAL_OK; +} + 800d0de: 2000 movs r0, #0 + 800d0e0: 4770 bx lr + ... + +0800d0e4 : + * @brief Send the Go Idle State command and check the response. + * @param SDMMCx Pointer to SDMMC register base + * @retval HAL status + */ +uint32_t SDMMC_CmdGoIdleState(SDMMC_TypeDef *SDMMCx) +{ + 800d0e4: b510 push {r4, lr} + SDMMC_CmdInitTypeDef sdmmc_cmdinit; + uint32_t errorstate; + + sdmmc_cmdinit.Argument = 0U; + 800d0e6: 2300 movs r3, #0 +{ + 800d0e8: b086 sub sp, #24 + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_GO_IDLE_STATE; + 800d0ea: e9cd 3301 strd r3, r3, [sp, #4] + sdmmc_cmdinit.Response = SDMMC_RESPONSE_NO; + sdmmc_cmdinit.WaitForInterrupt = SDMMC_WAIT_NO; + 800d0ee: e9cd 3303 strd r3, r3, [sp, #12] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d0f2: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d0f4: f44f 5380 mov.w r3, #4096 ; 0x1000 + 800d0f8: 9305 str r3, [sp, #20] +{ + 800d0fa: 4604 mov r4, r0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d0fc: f7ff ffb8 bl 800d070 + */ +static uint32_t SDMMC_GetCmdError(SDMMC_TypeDef *SDMMCx) +{ + /* 8 is the number of required instructions cycles for the below loop statement. + The SDMMC_CMDTIMEOUT is expressed in ms */ + uint32_t count = SDMMC_CMDTIMEOUT * (SystemCoreClock / 8U /1000U); + 800d100: 4b0a ldr r3, [pc, #40] ; (800d12c ) + 800d102: f44f 52fa mov.w r2, #8000 ; 0x1f40 + 800d106: 681b ldr r3, [r3, #0] + 800d108: fbb3 f3f2 udiv r3, r3, r2 + 800d10c: f241 3288 movw r2, #5000 ; 0x1388 + 800d110: 4353 muls r3, r2 + + do + { + if (count-- == 0U) + 800d112: 3b01 subs r3, #1 + 800d114: d307 bcc.n 800d126 + { + return SDMMC_ERROR_TIMEOUT; + } + + }while(!__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CMDSENT)); + 800d116: 6b62 ldr r2, [r4, #52] ; 0x34 + 800d118: 0612 lsls r2, r2, #24 + 800d11a: d5fa bpl.n 800d112 + + /* Clear all the static flags */ + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_STATIC_CMD_FLAGS); + 800d11c: 4b04 ldr r3, [pc, #16] ; (800d130 ) + 800d11e: 63a3 str r3, [r4, #56] ; 0x38 + + return SDMMC_ERROR_NONE; + 800d120: 2000 movs r0, #0 +} + 800d122: b006 add sp, #24 + 800d124: bd10 pop {r4, pc} + return SDMMC_ERROR_TIMEOUT; + 800d126: f04f 4000 mov.w r0, #2147483648 ; 0x80000000 + return errorstate; + 800d12a: e7fa b.n 800d122 + 800d12c: 2009e2ac .word 0x2009e2ac + 800d130: 002000c5 .word 0x002000c5 + +0800d134 : + uint32_t count = Timeout * (SystemCoreClock / 8U /1000U); + 800d134: 4b45 ldr r3, [pc, #276] ; (800d24c ) +{ + 800d136: b510 push {r4, lr} + uint32_t count = Timeout * (SystemCoreClock / 8U /1000U); + 800d138: 681b ldr r3, [r3, #0] +{ + 800d13a: 4604 mov r4, r0 + uint32_t count = Timeout * (SystemCoreClock / 8U /1000U); + 800d13c: f44f 50fa mov.w r0, #8000 ; 0x1f40 + 800d140: fbb3 f3f0 udiv r3, r3, r0 + }while(((sta_reg & (SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT | SDMMC_FLAG_BUSYD0END)) == 0U) || + 800d144: 4842 ldr r0, [pc, #264] ; (800d250 ) + uint32_t count = Timeout * (SystemCoreClock / 8U /1000U); + 800d146: 435a muls r2, r3 + if (count-- == 0U) + 800d148: 2a00 cmp r2, #0 + 800d14a: d048 beq.n 800d1de + sta_reg = SDMMCx->STA; + 800d14c: 6b63 ldr r3, [r4, #52] ; 0x34 + ((sta_reg & SDMMC_FLAG_CMDACT) != 0U )); + 800d14e: 4203 tst r3, r0 + 800d150: d007 beq.n 800d162 + }while(((sta_reg & (SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT | SDMMC_FLAG_BUSYD0END)) == 0U) || + 800d152: 049b lsls r3, r3, #18 + 800d154: d405 bmi.n 800d162 + if(__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT)) + 800d156: 6b63 ldr r3, [r4, #52] ; 0x34 + 800d158: 0758 lsls r0, r3, #29 + 800d15a: d504 bpl.n 800d166 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT); + 800d15c: 2004 movs r0, #4 + 800d15e: 63a0 str r0, [r4, #56] ; 0x38 +} + 800d160: bd10 pop {r4, pc} + 800d162: 3a01 subs r2, #1 + 800d164: e7f0 b.n 800d148 + else if(__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CCRCFAIL)) + 800d166: 6b60 ldr r0, [r4, #52] ; 0x34 + 800d168: f010 0001 ands.w r0, r0, #1 + 800d16c: d002 beq.n 800d174 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CCRCFAIL); + 800d16e: 2301 movs r3, #1 + 800d170: 63a3 str r3, [r4, #56] ; 0x38 + return SDMMC_ERROR_CMD_CRC_FAIL; + 800d172: e7f5 b.n 800d160 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_STATIC_CMD_FLAGS); + 800d174: 4b37 ldr r3, [pc, #220] ; (800d254 ) + 800d176: 63a3 str r3, [r4, #56] ; 0x38 + return (uint8_t)(SDMMCx->RESPCMD); + 800d178: 6923 ldr r3, [r4, #16] + if(SDMMC_GetCommandResponse(SDMMCx) != SD_CMD) + 800d17a: b2db uxtb r3, r3 + 800d17c: 4299 cmp r1, r3 + 800d17e: d131 bne.n 800d1e4 + return (*(__IO uint32_t *) tmp); + 800d180: 6963 ldr r3, [r4, #20] + if((response_r1 & SDMMC_OCR_ERRORBITS) == SDMMC_ALLZERO) + 800d182: 4835 ldr r0, [pc, #212] ; (800d258 ) + 800d184: 4018 ands r0, r3 + 800d186: 2800 cmp r0, #0 + 800d188: d0ea beq.n 800d160 + else if((response_r1 & SDMMC_OCR_ADDR_OUT_OF_RANGE) == SDMMC_OCR_ADDR_OUT_OF_RANGE) + 800d18a: 2b00 cmp r3, #0 + 800d18c: db2c blt.n 800d1e8 + else if((response_r1 & SDMMC_OCR_ADDR_MISALIGNED) == SDMMC_OCR_ADDR_MISALIGNED) + 800d18e: 005a lsls r2, r3, #1 + 800d190: d42d bmi.n 800d1ee + else if((response_r1 & SDMMC_OCR_BLOCK_LEN_ERR) == SDMMC_OCR_BLOCK_LEN_ERR) + 800d192: 009c lsls r4, r3, #2 + 800d194: d42d bmi.n 800d1f2 + else if((response_r1 & SDMMC_OCR_ERASE_SEQ_ERR) == SDMMC_OCR_ERASE_SEQ_ERR) + 800d196: 00d9 lsls r1, r3, #3 + 800d198: d42d bmi.n 800d1f6 + else if((response_r1 & SDMMC_OCR_BAD_ERASE_PARAM) == SDMMC_OCR_BAD_ERASE_PARAM) + 800d19a: 011a lsls r2, r3, #4 + 800d19c: d42e bmi.n 800d1fc + else if((response_r1 & SDMMC_OCR_WRITE_PROT_VIOLATION) == SDMMC_OCR_WRITE_PROT_VIOLATION) + 800d19e: 015c lsls r4, r3, #5 + 800d1a0: d42f bmi.n 800d202 + else if((response_r1 & SDMMC_OCR_LOCK_UNLOCK_FAILED) == SDMMC_OCR_LOCK_UNLOCK_FAILED) + 800d1a2: 01d9 lsls r1, r3, #7 + 800d1a4: d430 bmi.n 800d208 + else if((response_r1 & SDMMC_OCR_COM_CRC_FAILED) == SDMMC_OCR_COM_CRC_FAILED) + 800d1a6: 021a lsls r2, r3, #8 + 800d1a8: d431 bmi.n 800d20e + else if((response_r1 & SDMMC_OCR_ILLEGAL_CMD) == SDMMC_OCR_ILLEGAL_CMD) + 800d1aa: 025c lsls r4, r3, #9 + 800d1ac: d432 bmi.n 800d214 + else if((response_r1 & SDMMC_OCR_CARD_ECC_FAILED) == SDMMC_OCR_CARD_ECC_FAILED) + 800d1ae: 0299 lsls r1, r3, #10 + 800d1b0: d433 bmi.n 800d21a + else if((response_r1 & SDMMC_OCR_CC_ERROR) == SDMMC_OCR_CC_ERROR) + 800d1b2: 02da lsls r2, r3, #11 + 800d1b4: d434 bmi.n 800d220 + else if((response_r1 & SDMMC_OCR_STREAM_READ_UNDERRUN) == SDMMC_OCR_STREAM_READ_UNDERRUN) + 800d1b6: 035c lsls r4, r3, #13 + 800d1b8: d435 bmi.n 800d226 + else if((response_r1 & SDMMC_OCR_STREAM_WRITE_OVERRUN) == SDMMC_OCR_STREAM_WRITE_OVERRUN) + 800d1ba: 0399 lsls r1, r3, #14 + 800d1bc: d436 bmi.n 800d22c + else if((response_r1 & SDMMC_OCR_CID_CSD_OVERWRITE) == SDMMC_OCR_CID_CSD_OVERWRITE) + 800d1be: 03da lsls r2, r3, #15 + 800d1c0: d437 bmi.n 800d232 + else if((response_r1 & SDMMC_OCR_WP_ERASE_SKIP) == SDMMC_OCR_WP_ERASE_SKIP) + 800d1c2: 041c lsls r4, r3, #16 + 800d1c4: d438 bmi.n 800d238 + else if((response_r1 & SDMMC_OCR_CARD_ECC_DISABLED) == SDMMC_OCR_CARD_ECC_DISABLED) + 800d1c6: 0459 lsls r1, r3, #17 + 800d1c8: d439 bmi.n 800d23e + else if((response_r1 & SDMMC_OCR_ERASE_RESET) == SDMMC_OCR_ERASE_RESET) + 800d1ca: 049a lsls r2, r3, #18 + 800d1cc: d43a bmi.n 800d244 + return SDMMC_ERROR_GENERAL_UNKNOWN_ERR; + 800d1ce: f013 0f08 tst.w r3, #8 + 800d1d2: bf14 ite ne + 800d1d4: f44f 0000 movne.w r0, #8388608 ; 0x800000 + 800d1d8: f44f 3080 moveq.w r0, #65536 ; 0x10000 + 800d1dc: e7c0 b.n 800d160 + return SDMMC_ERROR_TIMEOUT; + 800d1de: f04f 4000 mov.w r0, #2147483648 ; 0x80000000 + 800d1e2: e7bd b.n 800d160 + return SDMMC_ERROR_CMD_CRC_FAIL; + 800d1e4: 2001 movs r0, #1 + 800d1e6: e7bb b.n 800d160 + return SDMMC_ERROR_ADDR_OUT_OF_RANGE; + 800d1e8: f04f 7000 mov.w r0, #33554432 ; 0x2000000 + 800d1ec: e7b8 b.n 800d160 + return SDMMC_ERROR_ADDR_MISALIGNED; + 800d1ee: 2040 movs r0, #64 ; 0x40 + 800d1f0: e7b6 b.n 800d160 + return SDMMC_ERROR_BLOCK_LEN_ERR; + 800d1f2: 2080 movs r0, #128 ; 0x80 + 800d1f4: e7b4 b.n 800d160 + return SDMMC_ERROR_ERASE_SEQ_ERR; + 800d1f6: f44f 7080 mov.w r0, #256 ; 0x100 + 800d1fa: e7b1 b.n 800d160 + return SDMMC_ERROR_BAD_ERASE_PARAM; + 800d1fc: f44f 7000 mov.w r0, #512 ; 0x200 + 800d200: e7ae b.n 800d160 + return SDMMC_ERROR_WRITE_PROT_VIOLATION; + 800d202: f44f 6080 mov.w r0, #1024 ; 0x400 + 800d206: e7ab b.n 800d160 + return SDMMC_ERROR_LOCK_UNLOCK_FAILED; + 800d208: f44f 6000 mov.w r0, #2048 ; 0x800 + 800d20c: e7a8 b.n 800d160 + return SDMMC_ERROR_COM_CRC_FAILED; + 800d20e: f44f 5080 mov.w r0, #4096 ; 0x1000 + 800d212: e7a5 b.n 800d160 + return SDMMC_ERROR_ILLEGAL_CMD; + 800d214: f44f 5000 mov.w r0, #8192 ; 0x2000 + 800d218: e7a2 b.n 800d160 + return SDMMC_ERROR_CARD_ECC_FAILED; + 800d21a: f44f 4080 mov.w r0, #16384 ; 0x4000 + 800d21e: e79f b.n 800d160 + return SDMMC_ERROR_CC_ERR; + 800d220: f44f 4000 mov.w r0, #32768 ; 0x8000 + 800d224: e79c b.n 800d160 + return SDMMC_ERROR_STREAM_READ_UNDERRUN; + 800d226: f44f 3000 mov.w r0, #131072 ; 0x20000 + 800d22a: e799 b.n 800d160 + return SDMMC_ERROR_STREAM_WRITE_OVERRUN; + 800d22c: f44f 2080 mov.w r0, #262144 ; 0x40000 + 800d230: e796 b.n 800d160 + return SDMMC_ERROR_CID_CSD_OVERWRITE; + 800d232: f44f 2000 mov.w r0, #524288 ; 0x80000 + 800d236: e793 b.n 800d160 + return SDMMC_ERROR_WP_ERASE_SKIP; + 800d238: f44f 1080 mov.w r0, #1048576 ; 0x100000 + 800d23c: e790 b.n 800d160 + return SDMMC_ERROR_CARD_ECC_DISABLED; + 800d23e: f44f 1000 mov.w r0, #2097152 ; 0x200000 + 800d242: e78d b.n 800d160 + return SDMMC_ERROR_ERASE_RESET; + 800d244: f44f 0080 mov.w r0, #4194304 ; 0x400000 + 800d248: e78a b.n 800d160 + 800d24a: bf00 nop + 800d24c: 2009e2ac .word 0x2009e2ac + 800d250: 00200045 .word 0x00200045 + 800d254: 002000c5 .word 0x002000c5 + 800d258: fdffe008 .word 0xfdffe008 + +0800d25c : +{ + 800d25c: b530 push {r4, r5, lr} + 800d25e: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d260: 2510 movs r5, #16 + 800d262: f44f 7380 mov.w r3, #256 ; 0x100 + 800d266: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d26a: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d26c: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)BlockSize; + 800d270: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d272: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d274: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d276: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d27a: f7ff fef9 bl 800d070 + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_SET_BLOCKLEN, SDMMC_CMDTIMEOUT); + 800d27e: f241 3288 movw r2, #5000 ; 0x1388 + 800d282: 4629 mov r1, r5 + 800d284: 4620 mov r0, r4 + 800d286: f7ff ff55 bl 800d134 +} + 800d28a: b007 add sp, #28 + 800d28c: bd30 pop {r4, r5, pc} + +0800d28e : +{ + 800d28e: b530 push {r4, r5, lr} + 800d290: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d292: 2511 movs r5, #17 + 800d294: f44f 7380 mov.w r3, #256 ; 0x100 + 800d298: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d29c: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d29e: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)ReadAdd; + 800d2a2: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d2a4: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d2a6: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d2a8: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d2ac: f7ff fee0 bl 800d070 + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_READ_SINGLE_BLOCK, SDMMC_CMDTIMEOUT); + 800d2b0: f241 3288 movw r2, #5000 ; 0x1388 + 800d2b4: 4629 mov r1, r5 + 800d2b6: 4620 mov r0, r4 + 800d2b8: f7ff ff3c bl 800d134 +} + 800d2bc: b007 add sp, #28 + 800d2be: bd30 pop {r4, r5, pc} + +0800d2c0 : +{ + 800d2c0: b530 push {r4, r5, lr} + 800d2c2: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d2c4: 2512 movs r5, #18 + 800d2c6: f44f 7380 mov.w r3, #256 ; 0x100 + 800d2ca: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d2ce: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d2d0: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)ReadAdd; + 800d2d4: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d2d6: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d2d8: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d2da: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d2de: f7ff fec7 bl 800d070 + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_READ_MULT_BLOCK, SDMMC_CMDTIMEOUT); + 800d2e2: f241 3288 movw r2, #5000 ; 0x1388 + 800d2e6: 4629 mov r1, r5 + 800d2e8: 4620 mov r0, r4 + 800d2ea: f7ff ff23 bl 800d134 +} + 800d2ee: b007 add sp, #28 + 800d2f0: bd30 pop {r4, r5, pc} + +0800d2f2 : +{ + 800d2f2: b530 push {r4, r5, lr} + 800d2f4: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d2f6: 2518 movs r5, #24 + 800d2f8: f44f 7380 mov.w r3, #256 ; 0x100 + 800d2fc: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d300: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d302: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)WriteAdd; + 800d306: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d308: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d30a: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d30c: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d310: f7ff feae bl 800d070 + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_WRITE_SINGLE_BLOCK, SDMMC_CMDTIMEOUT); + 800d314: f241 3288 movw r2, #5000 ; 0x1388 + 800d318: 4629 mov r1, r5 + 800d31a: 4620 mov r0, r4 + 800d31c: f7ff ff0a bl 800d134 +} + 800d320: b007 add sp, #28 + 800d322: bd30 pop {r4, r5, pc} + +0800d324 : +{ + 800d324: b530 push {r4, r5, lr} + 800d326: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d328: 2519 movs r5, #25 + 800d32a: f44f 7380 mov.w r3, #256 ; 0x100 + 800d32e: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d332: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d334: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)WriteAdd; + 800d338: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d33a: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d33c: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d33e: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d342: f7ff fe95 bl 800d070 + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_WRITE_MULT_BLOCK, SDMMC_CMDTIMEOUT); + 800d346: f241 3288 movw r2, #5000 ; 0x1388 + 800d34a: 4629 mov r1, r5 + 800d34c: 4620 mov r0, r4 + 800d34e: f7ff fef1 bl 800d134 +} + 800d352: b007 add sp, #28 + 800d354: bd30 pop {r4, r5, pc} + +0800d356 : +{ + 800d356: b530 push {r4, r5, lr} + 800d358: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d35a: 2520 movs r5, #32 + 800d35c: f44f 7380 mov.w r3, #256 ; 0x100 + 800d360: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d364: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d366: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)StartAdd; + 800d36a: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d36c: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d36e: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d370: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d374: f7ff fe7c bl 800d070 + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_SD_ERASE_GRP_START, SDMMC_CMDTIMEOUT); + 800d378: f241 3288 movw r2, #5000 ; 0x1388 + 800d37c: 4629 mov r1, r5 + 800d37e: 4620 mov r0, r4 + 800d380: f7ff fed8 bl 800d134 +} + 800d384: b007 add sp, #28 + 800d386: bd30 pop {r4, r5, pc} + +0800d388 : +{ + 800d388: b530 push {r4, r5, lr} + 800d38a: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d38c: 2521 movs r5, #33 ; 0x21 + 800d38e: f44f 7380 mov.w r3, #256 ; 0x100 + 800d392: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d396: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d398: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)EndAdd; + 800d39c: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d39e: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d3a0: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d3a2: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d3a6: f7ff fe63 bl 800d070 + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_SD_ERASE_GRP_END, SDMMC_CMDTIMEOUT); + 800d3aa: f241 3288 movw r2, #5000 ; 0x1388 + 800d3ae: 4629 mov r1, r5 + 800d3b0: 4620 mov r0, r4 + 800d3b2: f7ff febf bl 800d134 +} + 800d3b6: b007 add sp, #28 + 800d3b8: bd30 pop {r4, r5, pc} + +0800d3ba : +{ + 800d3ba: b530 push {r4, r5, lr} + 800d3bc: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d3be: 2523 movs r5, #35 ; 0x23 + 800d3c0: f44f 7380 mov.w r3, #256 ; 0x100 + 800d3c4: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d3c8: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d3ca: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)StartAdd; + 800d3ce: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d3d0: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d3d2: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d3d4: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d3d8: f7ff fe4a bl 800d070 + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_ERASE_GRP_START, SDMMC_CMDTIMEOUT); + 800d3dc: f241 3288 movw r2, #5000 ; 0x1388 + 800d3e0: 4629 mov r1, r5 + 800d3e2: 4620 mov r0, r4 + 800d3e4: f7ff fea6 bl 800d134 +} + 800d3e8: b007 add sp, #28 + 800d3ea: bd30 pop {r4, r5, pc} + +0800d3ec : +{ + 800d3ec: b530 push {r4, r5, lr} + 800d3ee: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d3f0: 2524 movs r5, #36 ; 0x24 + 800d3f2: f44f 7380 mov.w r3, #256 ; 0x100 + 800d3f6: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d3fa: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d3fc: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)EndAdd; + 800d400: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d402: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d404: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d406: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d40a: f7ff fe31 bl 800d070 + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_ERASE_GRP_END, SDMMC_CMDTIMEOUT); + 800d40e: f241 3288 movw r2, #5000 ; 0x1388 + 800d412: 4629 mov r1, r5 + 800d414: 4620 mov r0, r4 + 800d416: f7ff fe8d bl 800d134 +} + 800d41a: b007 add sp, #28 + 800d41c: bd30 pop {r4, r5, pc} + +0800d41e : +{ + 800d41e: b530 push {r4, r5, lr} + 800d420: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d422: 2526 movs r5, #38 ; 0x26 + 800d424: f44f 7380 mov.w r3, #256 ; 0x100 + 800d428: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d42c: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d42e: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = EraseType; + 800d432: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d434: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d436: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d438: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d43c: f7ff fe18 bl 800d070 + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_ERASE, SDMMC_MAXERASETIMEOUT); + 800d440: f24f 6218 movw r2, #63000 ; 0xf618 + 800d444: 4629 mov r1, r5 + 800d446: 4620 mov r0, r4 + 800d448: f7ff fe74 bl 800d134 +} + 800d44c: b007 add sp, #28 + 800d44e: bd30 pop {r4, r5, pc} + +0800d450 : +{ + 800d450: b530 push {r4, r5, lr} + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_STOP_TRANSMISSION; + 800d452: 2300 movs r3, #0 +{ + 800d454: b087 sub sp, #28 + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_STOP_TRANSMISSION; + 800d456: 250c movs r5, #12 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d458: f44f 7280 mov.w r2, #256 ; 0x100 + sdmmc_cmdinit.WaitForInterrupt = SDMMC_WAIT_NO; + 800d45c: e9cd 2303 strd r2, r3, [sp, #12] + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_STOP_TRANSMISSION; + 800d460: e9cd 3501 strd r3, r5, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d464: f44f 5380 mov.w r3, #4096 ; 0x1000 + 800d468: 9305 str r3, [sp, #20] + __SDMMC_CMDSTOP_ENABLE(SDMMCx); + 800d46a: 68c3 ldr r3, [r0, #12] + 800d46c: f043 0380 orr.w r3, r3, #128 ; 0x80 + 800d470: 60c3 str r3, [r0, #12] + __SDMMC_CMDTRANS_DISABLE(SDMMCx); + 800d472: 68c3 ldr r3, [r0, #12] + 800d474: f023 0340 bic.w r3, r3, #64 ; 0x40 +{ + 800d478: 4604 mov r4, r0 + __SDMMC_CMDTRANS_DISABLE(SDMMCx); + 800d47a: 60c3 str r3, [r0, #12] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d47c: a901 add r1, sp, #4 + 800d47e: f7ff fdf7 bl 800d070 + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_STOP_TRANSMISSION, SDMMC_STOPTRANSFERTIMEOUT); + 800d482: 4a05 ldr r2, [pc, #20] ; (800d498 ) + 800d484: 4629 mov r1, r5 + 800d486: 4620 mov r0, r4 + 800d488: f7ff fe54 bl 800d134 + __SDMMC_CMDSTOP_DISABLE(SDMMCx); + 800d48c: 68e3 ldr r3, [r4, #12] + 800d48e: f023 0380 bic.w r3, r3, #128 ; 0x80 + 800d492: 60e3 str r3, [r4, #12] +} + 800d494: b007 add sp, #28 + 800d496: bd30 pop {r4, r5, pc} + 800d498: 05f5e100 .word 0x05f5e100 + +0800d49c : +{ + 800d49c: b530 push {r4, r5, lr} + 800d49e: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d4a0: 2507 movs r5, #7 + 800d4a2: f44f 7380 mov.w r3, #256 ; 0x100 + 800d4a6: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d4aa: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d4ac: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)Addr; + 800d4b0: 9201 str r2, [sp, #4] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d4b2: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d4b4: 2200 movs r2, #0 + 800d4b6: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d4ba: f7ff fdd9 bl 800d070 + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_SEL_DESEL_CARD, SDMMC_CMDTIMEOUT); + 800d4be: f241 3288 movw r2, #5000 ; 0x1388 + 800d4c2: 4629 mov r1, r5 + 800d4c4: 4620 mov r0, r4 + 800d4c6: f7ff fe35 bl 800d134 +} + 800d4ca: b007 add sp, #28 + 800d4cc: bd30 pop {r4, r5, pc} + +0800d4ce : +{ + 800d4ce: b530 push {r4, r5, lr} + 800d4d0: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d4d2: 2537 movs r5, #55 ; 0x37 + 800d4d4: f44f 7380 mov.w r3, #256 ; 0x100 + 800d4d8: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d4dc: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d4de: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)Argument; + 800d4e2: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d4e4: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d4e6: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d4e8: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d4ec: f7ff fdc0 bl 800d070 + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_APP_CMD, SDMMC_CMDTIMEOUT); + 800d4f0: f241 3288 movw r2, #5000 ; 0x1388 + 800d4f4: 4629 mov r1, r5 + 800d4f6: 4620 mov r0, r4 + 800d4f8: f7ff fe1c bl 800d134 +} + 800d4fc: b007 add sp, #28 + 800d4fe: bd30 pop {r4, r5, pc} + +0800d500 : +{ + 800d500: b530 push {r4, r5, lr} + 800d502: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d504: 2506 movs r5, #6 + 800d506: f44f 7380 mov.w r3, #256 ; 0x100 + 800d50a: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d50e: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d510: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = (uint32_t)BusWidth; + 800d514: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d516: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d518: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d51a: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d51e: f7ff fda7 bl 800d070 + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_APP_SD_SET_BUSWIDTH, SDMMC_CMDTIMEOUT); + 800d522: f241 3288 movw r2, #5000 ; 0x1388 + 800d526: 4629 mov r1, r5 + 800d528: 4620 mov r0, r4 + 800d52a: f7ff fe03 bl 800d134 +} + 800d52e: b007 add sp, #28 + 800d530: bd30 pop {r4, r5, pc} + +0800d532 : + 800d532: f7ff bfe5 b.w 800d500 + +0800d536 : +{ + 800d536: b530 push {r4, r5, lr} + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SD_APP_SEND_SCR; + 800d538: 2300 movs r3, #0 +{ + 800d53a: b087 sub sp, #28 + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SD_APP_SEND_SCR; + 800d53c: 2533 movs r5, #51 ; 0x33 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d53e: f44f 7280 mov.w r2, #256 ; 0x100 + sdmmc_cmdinit.WaitForInterrupt = SDMMC_WAIT_NO; + 800d542: e9cd 2303 strd r2, r3, [sp, #12] + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SD_APP_SEND_SCR; + 800d546: e9cd 3501 strd r3, r5, [sp, #4] +{ + 800d54a: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d54c: f44f 5380 mov.w r3, #4096 ; 0x1000 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d550: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d552: 9305 str r3, [sp, #20] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d554: f7ff fd8c bl 800d070 + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_SD_APP_SEND_SCR, SDMMC_CMDTIMEOUT); + 800d558: f241 3288 movw r2, #5000 ; 0x1388 + 800d55c: 4629 mov r1, r5 + 800d55e: 4620 mov r0, r4 + 800d560: f7ff fde8 bl 800d134 +} + 800d564: b007 add sp, #28 + 800d566: bd30 pop {r4, r5, pc} + +0800d568 : +{ + 800d568: b530 push {r4, r5, lr} + 800d56a: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d56c: 2503 movs r5, #3 + sdmmc_cmdinit.Argument = ((uint32_t)RCA << 16U); + 800d56e: 0409 lsls r1, r1, #16 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d570: f44f 7380 mov.w r3, #256 ; 0x100 + 800d574: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d578: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d57a: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = ((uint32_t)RCA << 16U); + 800d57e: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d580: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d582: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d584: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d588: f7ff fd72 bl 800d070 + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_SET_REL_ADDR, SDMMC_CMDTIMEOUT); + 800d58c: f241 3288 movw r2, #5000 ; 0x1388 + 800d590: 4629 mov r1, r5 + 800d592: 4620 mov r0, r4 + 800d594: f7ff fdce bl 800d134 +} + 800d598: b007 add sp, #28 + 800d59a: bd30 pop {r4, r5, pc} + +0800d59c : +{ + 800d59c: b530 push {r4, r5, lr} + 800d59e: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d5a0: 250d movs r5, #13 + 800d5a2: f44f 7380 mov.w r3, #256 ; 0x100 + 800d5a6: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d5aa: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d5ac: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = Argument; + 800d5b0: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d5b2: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d5b4: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d5b6: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d5ba: f7ff fd59 bl 800d070 + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_SEND_STATUS, SDMMC_CMDTIMEOUT); + 800d5be: f241 3288 movw r2, #5000 ; 0x1388 + 800d5c2: 4629 mov r1, r5 + 800d5c4: 4620 mov r0, r4 + 800d5c6: f7ff fdb5 bl 800d134 +} + 800d5ca: b007 add sp, #28 + 800d5cc: bd30 pop {r4, r5, pc} + +0800d5ce : +{ + 800d5ce: b530 push {r4, r5, lr} + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SD_APP_STATUS; + 800d5d0: 2300 movs r3, #0 +{ + 800d5d2: b087 sub sp, #28 + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SD_APP_STATUS; + 800d5d4: 250d movs r5, #13 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d5d6: f44f 7280 mov.w r2, #256 ; 0x100 + sdmmc_cmdinit.WaitForInterrupt = SDMMC_WAIT_NO; + 800d5da: e9cd 2303 strd r2, r3, [sp, #12] + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SD_APP_STATUS; + 800d5de: e9cd 3501 strd r3, r5, [sp, #4] +{ + 800d5e2: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d5e4: f44f 5380 mov.w r3, #4096 ; 0x1000 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d5e8: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d5ea: 9305 str r3, [sp, #20] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d5ec: f7ff fd40 bl 800d070 + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_SD_APP_STATUS, SDMMC_CMDTIMEOUT); + 800d5f0: f241 3288 movw r2, #5000 ; 0x1388 + 800d5f4: 4629 mov r1, r5 + 800d5f6: 4620 mov r0, r4 + 800d5f8: f7ff fd9c bl 800d134 +} + 800d5fc: b007 add sp, #28 + 800d5fe: bd30 pop {r4, r5, pc} + +0800d600 : +{ + 800d600: b530 push {r4, r5, lr} + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_VOLTAGE_SWITCH; + 800d602: 2300 movs r3, #0 +{ + 800d604: b087 sub sp, #28 + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_VOLTAGE_SWITCH; + 800d606: 250b movs r5, #11 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d608: f44f 7280 mov.w r2, #256 ; 0x100 + sdmmc_cmdinit.WaitForInterrupt = SDMMC_WAIT_NO; + 800d60c: e9cd 2303 strd r2, r3, [sp, #12] + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_VOLTAGE_SWITCH; + 800d610: e9cd 3501 strd r3, r5, [sp, #4] +{ + 800d614: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d616: f44f 5380 mov.w r3, #4096 ; 0x1000 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d61a: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d61c: 9305 str r3, [sp, #20] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d61e: f7ff fd27 bl 800d070 + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_VOLTAGE_SWITCH, SDMMC_CMDTIMEOUT); + 800d622: f241 3288 movw r2, #5000 ; 0x1388 + 800d626: 4629 mov r1, r5 + 800d628: 4620 mov r0, r4 + 800d62a: f7ff fd83 bl 800d134 +} + 800d62e: b007 add sp, #28 + 800d630: bd30 pop {r4, r5, pc} + +0800d632 : +{ + 800d632: b530 push {r4, r5, lr} + 800d634: b087 sub sp, #28 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d636: 2508 movs r5, #8 + 800d638: f44f 7380 mov.w r3, #256 ; 0x100 + 800d63c: e9cd 5302 strd r5, r3, [sp, #8] +{ + 800d640: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d642: f44f 5380 mov.w r3, #4096 ; 0x1000 + sdmmc_cmdinit.Argument = Argument; + 800d646: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d648: 2200 movs r2, #0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d64a: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d64c: e9cd 2304 strd r2, r3, [sp, #16] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d650: f7ff fd0e bl 800d070 + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_HS_SEND_EXT_CSD,SDMMC_CMDTIMEOUT); + 800d654: f241 3288 movw r2, #5000 ; 0x1388 + 800d658: 4629 mov r1, r5 + 800d65a: 4620 mov r0, r4 + 800d65c: f7ff fd6a bl 800d134 +} + 800d660: b007 add sp, #28 + 800d662: bd30 pop {r4, r5, pc} + +0800d664 : + uint32_t count = SDMMC_CMDTIMEOUT * (SystemCoreClock / 8U /1000U); + 800d664: 4b11 ldr r3, [pc, #68] ; (800d6ac ) + 800d666: f44f 51fa mov.w r1, #8000 ; 0x1f40 + 800d66a: 681b ldr r3, [r3, #0] + 800d66c: fbb3 f3f1 udiv r3, r3, r1 + 800d670: f241 3188 movw r1, #5000 ; 0x1388 +{ + 800d674: 4602 mov r2, r0 + uint32_t count = SDMMC_CMDTIMEOUT * (SystemCoreClock / 8U /1000U); + 800d676: 434b muls r3, r1 + if (count-- == 0U) + 800d678: 3b01 subs r3, #1 + 800d67a: d313 bcc.n 800d6a4 + sta_reg = SDMMCx->STA; + 800d67c: 6b51 ldr r1, [r2, #52] ; 0x34 + ((sta_reg & SDMMC_FLAG_CMDACT) != 0U )); + 800d67e: f011 0f45 tst.w r1, #69 ; 0x45 + 800d682: d0f9 beq.n 800d678 + }while(((sta_reg & (SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT)) == 0U) || + 800d684: 0489 lsls r1, r1, #18 + 800d686: d4f7 bmi.n 800d678 + if (__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT)) + 800d688: 6b53 ldr r3, [r2, #52] ; 0x34 + 800d68a: 075b lsls r3, r3, #29 + 800d68c: d502 bpl.n 800d694 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT); + 800d68e: 2004 movs r0, #4 + 800d690: 6390 str r0, [r2, #56] ; 0x38 + return SDMMC_ERROR_CMD_RSP_TIMEOUT; + 800d692: 4770 bx lr + else if (__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CCRCFAIL)) + 800d694: 6b50 ldr r0, [r2, #52] ; 0x34 + 800d696: f010 0001 ands.w r0, r0, #1 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_STATIC_CMD_FLAGS); + 800d69a: bf0c ite eq + 800d69c: 4b04 ldreq r3, [pc, #16] ; (800d6b0 ) + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CCRCFAIL); + 800d69e: 2301 movne r3, #1 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_STATIC_CMD_FLAGS); + 800d6a0: 6393 str r3, [r2, #56] ; 0x38 + return SDMMC_ERROR_NONE; + 800d6a2: 4770 bx lr + return SDMMC_ERROR_TIMEOUT; + 800d6a4: f04f 4000 mov.w r0, #2147483648 ; 0x80000000 +} + 800d6a8: 4770 bx lr + 800d6aa: bf00 nop + 800d6ac: 2009e2ac .word 0x2009e2ac + 800d6b0: 002000c5 .word 0x002000c5 + +0800d6b4 : +{ + 800d6b4: b510 push {r4, lr} + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_ALL_SEND_CID; + 800d6b6: 2300 movs r3, #0 +{ + 800d6b8: b086 sub sp, #24 + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_ALL_SEND_CID; + 800d6ba: 2202 movs r2, #2 + 800d6bc: e9cd 3201 strd r3, r2, [sp, #4] + sdmmc_cmdinit.Response = SDMMC_RESPONSE_LONG; + 800d6c0: f44f 7240 mov.w r2, #768 ; 0x300 + sdmmc_cmdinit.WaitForInterrupt = SDMMC_WAIT_NO; + 800d6c4: e9cd 2303 strd r2, r3, [sp, #12] +{ + 800d6c8: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d6ca: f44f 5380 mov.w r3, #4096 ; 0x1000 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d6ce: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d6d0: 9305 str r3, [sp, #20] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d6d2: f7ff fccd bl 800d070 + errorstate = SDMMC_GetCmdResp2(SDMMCx); + 800d6d6: 4620 mov r0, r4 + 800d6d8: f7ff ffc4 bl 800d664 +} + 800d6dc: b006 add sp, #24 + 800d6de: bd10 pop {r4, pc} + +0800d6e0 : +{ + 800d6e0: b510 push {r4, lr} + 800d6e2: b086 sub sp, #24 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_LONG; + 800d6e4: 2209 movs r2, #9 + 800d6e6: f44f 7340 mov.w r3, #768 ; 0x300 + 800d6ea: e9cd 2302 strd r2, r3, [sp, #8] + sdmmc_cmdinit.Argument = Argument; + 800d6ee: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d6f0: f44f 5380 mov.w r3, #4096 ; 0x1000 + 800d6f4: 2100 movs r1, #0 + 800d6f6: e9cd 1304 strd r1, r3, [sp, #16] +{ + 800d6fa: 4604 mov r4, r0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d6fc: a901 add r1, sp, #4 + 800d6fe: f7ff fcb7 bl 800d070 + errorstate = SDMMC_GetCmdResp2(SDMMCx); + 800d702: 4620 mov r0, r4 + 800d704: f7ff ffae bl 800d664 +} + 800d708: b006 add sp, #24 + 800d70a: bd10 pop {r4, pc} + +0800d70c : + uint32_t count = SDMMC_CMDTIMEOUT * (SystemCoreClock / 8U /1000U); + 800d70c: 4b0e ldr r3, [pc, #56] ; (800d748 ) + 800d70e: f44f 51fa mov.w r1, #8000 ; 0x1f40 + 800d712: 681b ldr r3, [r3, #0] + 800d714: fbb3 f3f1 udiv r3, r3, r1 + 800d718: f241 3188 movw r1, #5000 ; 0x1388 +{ + 800d71c: 4602 mov r2, r0 + uint32_t count = SDMMC_CMDTIMEOUT * (SystemCoreClock / 8U /1000U); + 800d71e: 434b muls r3, r1 + if (count-- == 0U) + 800d720: 3b01 subs r3, #1 + 800d722: d30e bcc.n 800d742 + sta_reg = SDMMCx->STA; + 800d724: 6b51 ldr r1, [r2, #52] ; 0x34 + ((sta_reg & SDMMC_FLAG_CMDACT) != 0U )); + 800d726: f011 0f45 tst.w r1, #69 ; 0x45 + 800d72a: d0f9 beq.n 800d720 + }while(((sta_reg & (SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT)) == 0U) || + 800d72c: 0489 lsls r1, r1, #18 + 800d72e: d4f7 bmi.n 800d720 + if(__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT)) + 800d730: 6b50 ldr r0, [r2, #52] ; 0x34 + 800d732: f010 0004 ands.w r0, r0, #4 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT); + 800d736: bf15 itete ne + 800d738: 2004 movne r0, #4 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_STATIC_CMD_FLAGS); + 800d73a: 4b04 ldreq r3, [pc, #16] ; (800d74c ) + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT); + 800d73c: 6390 strne r0, [r2, #56] ; 0x38 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_STATIC_CMD_FLAGS); + 800d73e: 6393 streq r3, [r2, #56] ; 0x38 + return SDMMC_ERROR_NONE; + 800d740: 4770 bx lr + return SDMMC_ERROR_TIMEOUT; + 800d742: f04f 4000 mov.w r0, #2147483648 ; 0x80000000 +} + 800d746: 4770 bx lr + 800d748: 2009e2ac .word 0x2009e2ac + 800d74c: 002000c5 .word 0x002000c5 + +0800d750 : +{ + 800d750: b510 push {r4, lr} + 800d752: b086 sub sp, #24 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d754: 2229 movs r2, #41 ; 0x29 + 800d756: f44f 7380 mov.w r3, #256 ; 0x100 + 800d75a: e9cd 2302 strd r2, r3, [sp, #8] + sdmmc_cmdinit.Argument = Argument; + 800d75e: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d760: f44f 5380 mov.w r3, #4096 ; 0x1000 + 800d764: 2100 movs r1, #0 + 800d766: e9cd 1304 strd r1, r3, [sp, #16] +{ + 800d76a: 4604 mov r4, r0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d76c: a901 add r1, sp, #4 + 800d76e: f7ff fc7f bl 800d070 + errorstate = SDMMC_GetCmdResp3(SDMMCx); + 800d772: 4620 mov r0, r4 + 800d774: f7ff ffca bl 800d70c +} + 800d778: b006 add sp, #24 + 800d77a: bd10 pop {r4, pc} + +0800d77c : +{ + 800d77c: b510 push {r4, lr} + 800d77e: b086 sub sp, #24 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d780: 2201 movs r2, #1 + 800d782: f44f 7380 mov.w r3, #256 ; 0x100 + 800d786: e9cd 2302 strd r2, r3, [sp, #8] + sdmmc_cmdinit.Argument = Argument; + 800d78a: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d78c: f44f 5380 mov.w r3, #4096 ; 0x1000 + 800d790: 2100 movs r1, #0 + 800d792: e9cd 1304 strd r1, r3, [sp, #16] +{ + 800d796: 4604 mov r4, r0 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d798: a901 add r1, sp, #4 + 800d79a: f7ff fc69 bl 800d070 + errorstate = SDMMC_GetCmdResp3(SDMMCx); + 800d79e: 4620 mov r0, r4 + 800d7a0: f7ff ffb4 bl 800d70c +} + 800d7a4: b006 add sp, #24 + 800d7a6: bd10 pop {r4, pc} + +0800d7a8 : + uint32_t count = SDMMC_CMDTIMEOUT * (SystemCoreClock / 8U /1000U); + 800d7a8: 4b1f ldr r3, [pc, #124] ; (800d828 ) +{ + 800d7aa: b510 push {r4, lr} + uint32_t count = SDMMC_CMDTIMEOUT * (SystemCoreClock / 8U /1000U); + 800d7ac: 681b ldr r3, [r3, #0] +{ + 800d7ae: 4604 mov r4, r0 + uint32_t count = SDMMC_CMDTIMEOUT * (SystemCoreClock / 8U /1000U); + 800d7b0: f44f 50fa mov.w r0, #8000 ; 0x1f40 + 800d7b4: fbb3 f3f0 udiv r3, r3, r0 + 800d7b8: f241 3088 movw r0, #5000 ; 0x1388 + 800d7bc: 4343 muls r3, r0 + if (count-- == 0U) + 800d7be: 3b01 subs r3, #1 + 800d7c0: d329 bcc.n 800d816 + sta_reg = SDMMCx->STA; + 800d7c2: 6b60 ldr r0, [r4, #52] ; 0x34 + ((sta_reg & SDMMC_FLAG_CMDACT) != 0U )); + 800d7c4: f010 0f45 tst.w r0, #69 ; 0x45 + 800d7c8: d0f9 beq.n 800d7be + }while(((sta_reg & (SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT)) == 0U) || + 800d7ca: 0480 lsls r0, r0, #18 + 800d7cc: d4f7 bmi.n 800d7be + if(__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT)) + 800d7ce: 6b63 ldr r3, [r4, #52] ; 0x34 + 800d7d0: 0758 lsls r0, r3, #29 + 800d7d2: d502 bpl.n 800d7da + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT); + 800d7d4: 2004 movs r0, #4 + 800d7d6: 63a0 str r0, [r4, #56] ; 0x38 +} + 800d7d8: bd10 pop {r4, pc} + else if(__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CCRCFAIL)) + 800d7da: 6b60 ldr r0, [r4, #52] ; 0x34 + 800d7dc: f010 0001 ands.w r0, r0, #1 + 800d7e0: d002 beq.n 800d7e8 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CCRCFAIL); + 800d7e2: 2301 movs r3, #1 + 800d7e4: 63a3 str r3, [r4, #56] ; 0x38 + return SDMMC_ERROR_CMD_CRC_FAIL; + 800d7e6: e7f7 b.n 800d7d8 + return (uint8_t)(SDMMCx->RESPCMD); + 800d7e8: 6923 ldr r3, [r4, #16] + if(SDMMC_GetCommandResponse(SDMMCx) != SD_CMD) + 800d7ea: b2db uxtb r3, r3 + 800d7ec: 4299 cmp r1, r3 + 800d7ee: d115 bne.n 800d81c + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_STATIC_CMD_FLAGS); + 800d7f0: 4b0e ldr r3, [pc, #56] ; (800d82c ) + 800d7f2: 63a3 str r3, [r4, #56] ; 0x38 + return (*(__IO uint32_t *) tmp); + 800d7f4: 6963 ldr r3, [r4, #20] + if((response_r1 & (SDMMC_R6_GENERAL_UNKNOWN_ERROR | SDMMC_R6_ILLEGAL_CMD | SDMMC_R6_COM_CRC_FAILED)) == SDMMC_ALLZERO) + 800d7f6: f413 4060 ands.w r0, r3, #57344 ; 0xe000 + 800d7fa: d102 bne.n 800d802 + *pRCA = (uint16_t) (response_r1 >> 16); + 800d7fc: 0c1b lsrs r3, r3, #16 + 800d7fe: 8013 strh r3, [r2, #0] + return SDMMC_ERROR_NONE; + 800d800: e7ea b.n 800d7d8 + else if((response_r1 & SDMMC_R6_ILLEGAL_CMD) == SDMMC_R6_ILLEGAL_CMD) + 800d802: 045a lsls r2, r3, #17 + 800d804: d40c bmi.n 800d820 + return SDMMC_ERROR_GENERAL_UNKNOWN_ERR; + 800d806: f413 4f00 tst.w r3, #32768 ; 0x8000 + 800d80a: bf14 ite ne + 800d80c: f44f 5080 movne.w r0, #4096 ; 0x1000 + 800d810: f44f 3080 moveq.w r0, #65536 ; 0x10000 + 800d814: e7e0 b.n 800d7d8 + return SDMMC_ERROR_TIMEOUT; + 800d816: f04f 4000 mov.w r0, #2147483648 ; 0x80000000 + 800d81a: e7dd b.n 800d7d8 + return SDMMC_ERROR_CMD_CRC_FAIL; + 800d81c: 2001 movs r0, #1 + 800d81e: e7db b.n 800d7d8 + return SDMMC_ERROR_ILLEGAL_CMD; + 800d820: f44f 5000 mov.w r0, #8192 ; 0x2000 + 800d824: e7d8 b.n 800d7d8 + 800d826: bf00 nop + 800d828: 2009e2ac .word 0x2009e2ac + 800d82c: 002000c5 .word 0x002000c5 + +0800d830 : +{ + 800d830: b530 push {r4, r5, lr} + 800d832: b089 sub sp, #36 ; 0x24 + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SET_REL_ADDR; + 800d834: 2300 movs r3, #0 +{ + 800d836: 9101 str r1, [sp, #4] + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SET_REL_ADDR; + 800d838: 2503 movs r5, #3 + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + 800d83a: f44f 7180 mov.w r1, #256 ; 0x100 + sdmmc_cmdinit.WaitForInterrupt = SDMMC_WAIT_NO; + 800d83e: e9cd 1305 strd r1, r3, [sp, #20] + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SET_REL_ADDR; + 800d842: e9cd 3503 strd r3, r5, [sp, #12] +{ + 800d846: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d848: f44f 5380 mov.w r3, #4096 ; 0x1000 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d84c: a903 add r1, sp, #12 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d84e: 9307 str r3, [sp, #28] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d850: f7ff fc0e bl 800d070 + errorstate = SDMMC_GetCmdResp6(SDMMCx, SDMMC_CMD_SET_REL_ADDR, pRCA); + 800d854: 9a01 ldr r2, [sp, #4] + 800d856: 4629 mov r1, r5 + 800d858: 4620 mov r0, r4 + 800d85a: f7ff ffa5 bl 800d7a8 +} + 800d85e: b009 add sp, #36 ; 0x24 + 800d860: bd30 pop {r4, r5, pc} + ... + +0800d864 : + uint32_t count = SDMMC_CMDTIMEOUT * (SystemCoreClock / 8U /1000U); + 800d864: 4b13 ldr r3, [pc, #76] ; (800d8b4 ) + 800d866: f44f 51fa mov.w r1, #8000 ; 0x1f40 + 800d86a: 681b ldr r3, [r3, #0] + 800d86c: fbb3 f3f1 udiv r3, r3, r1 + 800d870: f241 3188 movw r1, #5000 ; 0x1388 +{ + 800d874: 4602 mov r2, r0 + uint32_t count = SDMMC_CMDTIMEOUT * (SystemCoreClock / 8U /1000U); + 800d876: 434b muls r3, r1 + if (count-- == 0U) + 800d878: 3b01 subs r3, #1 + 800d87a: d317 bcc.n 800d8ac + sta_reg = SDMMCx->STA; + 800d87c: 6b51 ldr r1, [r2, #52] ; 0x34 + ((sta_reg & SDMMC_FLAG_CMDACT) != 0U )); + 800d87e: f011 0f45 tst.w r1, #69 ; 0x45 + 800d882: d0f9 beq.n 800d878 + }while(((sta_reg & (SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT)) == 0U) || + 800d884: 0488 lsls r0, r1, #18 + 800d886: d4f7 bmi.n 800d878 + if(__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT)) + 800d888: 6b53 ldr r3, [r2, #52] ; 0x34 + 800d88a: 0759 lsls r1, r3, #29 + 800d88c: d502 bpl.n 800d894 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CTIMEOUT); + 800d88e: 2004 movs r0, #4 + 800d890: 6390 str r0, [r2, #56] ; 0x38 + return SDMMC_ERROR_CMD_RSP_TIMEOUT; + 800d892: 4770 bx lr + else if(__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CCRCFAIL)) + 800d894: 6b50 ldr r0, [r2, #52] ; 0x34 + 800d896: f010 0001 ands.w r0, r0, #1 + 800d89a: d002 beq.n 800d8a2 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CCRCFAIL); + 800d89c: 2301 movs r3, #1 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CMDREND); + 800d89e: 6393 str r3, [r2, #56] ; 0x38 + 800d8a0: 4770 bx lr + if(__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CMDREND)) + 800d8a2: 6b53 ldr r3, [r2, #52] ; 0x34 + 800d8a4: 065b lsls r3, r3, #25 + 800d8a6: d503 bpl.n 800d8b0 + __SDMMC_CLEAR_FLAG(SDMMCx, SDMMC_FLAG_CMDREND); + 800d8a8: 2340 movs r3, #64 ; 0x40 + 800d8aa: e7f8 b.n 800d89e + return SDMMC_ERROR_TIMEOUT; + 800d8ac: f04f 4000 mov.w r0, #2147483648 ; 0x80000000 +} + 800d8b0: 4770 bx lr + 800d8b2: bf00 nop + 800d8b4: 2009e2ac .word 0x2009e2ac + +0800d8b8 : +{ + 800d8b8: b510 push {r4, lr} + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_HS_SEND_EXT_CSD; + 800d8ba: f44f 72d5 mov.w r2, #426 ; 0x1aa +{ + 800d8be: b086 sub sp, #24 + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_HS_SEND_EXT_CSD; + 800d8c0: 2308 movs r3, #8 + 800d8c2: e9cd 2301 strd r2, r3, [sp, #4] + sdmmc_cmdinit.WaitForInterrupt = SDMMC_WAIT_NO; + 800d8c6: f44f 7180 mov.w r1, #256 ; 0x100 + 800d8ca: 2300 movs r3, #0 + 800d8cc: e9cd 1303 strd r1, r3, [sp, #12] +{ + 800d8d0: 4604 mov r4, r0 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d8d2: f44f 5380 mov.w r3, #4096 ; 0x1000 + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d8d6: a901 add r1, sp, #4 + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + 800d8d8: 9305 str r3, [sp, #20] + (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + 800d8da: f7ff fbc9 bl 800d070 + errorstate = SDMMC_GetCmdResp7(SDMMCx); + 800d8de: 4620 mov r0, r4 + 800d8e0: f7ff ffc0 bl 800d864 +} + 800d8e4: b006 add sp, #24 + 800d8e6: bd10 pop {r4, pc} + +0800d8e8 : + 800d8e8: b510 push {r4, lr} + 800d8ea: 3901 subs r1, #1 + 800d8ec: 4402 add r2, r0 + 800d8ee: 4290 cmp r0, r2 + 800d8f0: d101 bne.n 800d8f6 + 800d8f2: 2000 movs r0, #0 + 800d8f4: e005 b.n 800d902 + 800d8f6: 7803 ldrb r3, [r0, #0] + 800d8f8: f811 4f01 ldrb.w r4, [r1, #1]! + 800d8fc: 42a3 cmp r3, r4 + 800d8fe: d001 beq.n 800d904 + 800d900: 1b18 subs r0, r3, r4 + 800d902: bd10 pop {r4, pc} + 800d904: 3001 adds r0, #1 + 800d906: e7f2 b.n 800d8ee + +0800d908 : + 800d908: 440a add r2, r1 + 800d90a: 4291 cmp r1, r2 + 800d90c: f100 33ff add.w r3, r0, #4294967295 ; 0xffffffff + 800d910: d100 bne.n 800d914 + 800d912: 4770 bx lr + 800d914: b510 push {r4, lr} + 800d916: f811 4b01 ldrb.w r4, [r1], #1 + 800d91a: f803 4f01 strb.w r4, [r3, #1]! + 800d91e: 4291 cmp r1, r2 + 800d920: d1f9 bne.n 800d916 + 800d922: bd10 pop {r4, pc} + +0800d924 : + 800d924: 4402 add r2, r0 + 800d926: 4603 mov r3, r0 + 800d928: 4293 cmp r3, r2 + 800d92a: d100 bne.n 800d92e + 800d92c: 4770 bx lr + 800d92e: f803 1b01 strb.w r1, [r3], #1 + 800d932: e7f9 b.n 800d928 + +0800d934 : + 800d934: 46ec mov ip, sp + 800d936: e8a0 5ff0 stmia.w r0!, {r4, r5, r6, r7, r8, r9, sl, fp, ip, lr} + 800d93a: f04f 0000 mov.w r0, #0 + 800d93e: 4770 bx lr + +0800d940 : + 800d940: e8b0 5ff0 ldmia.w r0!, {r4, r5, r6, r7, r8, r9, sl, fp, ip, lr} + 800d944: 46e5 mov sp, ip + 800d946: 0008 movs r0, r1 + 800d948: bf08 it eq + 800d94a: 2001 moveq r0, #1 + 800d94c: 4770 bx lr + 800d94e: bf00 nop + +0800d950 : + 800d950: b510 push {r4, lr} + 800d952: 460b mov r3, r1 + 800d954: b162 cbz r2, 800d970 + 800d956: 3a01 subs r2, #1 + 800d958: d008 beq.n 800d96c + 800d95a: f813 4b01 ldrb.w r4, [r3], #1 + 800d95e: f800 4b01 strb.w r4, [r0], #1 + 800d962: 2c00 cmp r4, #0 + 800d964: d1f7 bne.n 800d956 + 800d966: 1a58 subs r0, r3, r1 + 800d968: 3801 subs r0, #1 + 800d96a: bd10 pop {r4, pc} + 800d96c: 2200 movs r2, #0 + 800d96e: 7002 strb r2, [r0, #0] + 800d970: f813 2b01 ldrb.w r2, [r3], #1 + 800d974: 2a00 cmp r2, #0 + 800d976: d1fb bne.n 800d970 + 800d978: e7f5 b.n 800d966 + +0800d97a : + 800d97a: 4603 mov r3, r0 + 800d97c: f813 2b01 ldrb.w r2, [r3], #1 + 800d980: 2a00 cmp r2, #0 + 800d982: d1fb bne.n 800d97c + 800d984: 1a18 subs r0, r3, r0 + 800d986: 3801 subs r0, #1 + 800d988: 4770 bx lr + 800d98a: 0000 movs r0, r0 + 800d98c: 0000 movs r0, r0 + ... + +0800d990 <__flash_burn_veneer>: + 800d990: f85f f000 ldr.w pc, [pc] ; 800d994 <__flash_burn_veneer+0x4> + 800d994: 2009e001 .word 0x2009e001 + +0800d998 <__flash_page_erase_veneer>: + 800d998: f85f f000 ldr.w pc, [pc] ; 800d99c <__flash_page_erase_veneer+0x4> + 800d99c: 2009e08d .word 0x2009e08d + 800d9a0: 6f636e69 .word 0x6f636e69 + 800d9a4: 006e .short 0x006e + 800d9a6: 6944 .short 0x6944 + 800d9a8: 44203a65 .word 0x44203a65 + 800d9ac: 44005546 .word 0x44005546 + 800d9b0: 203a6569 .word 0x203a6569 + 800d9b4: 6e776f44 .word 0x6e776f44 + 800d9b8: 64617267 .word 0x64617267 + 800d9bc: 69440065 .word 0x69440065 + 800d9c0: 42203a65 .word 0x42203a65 + 800d9c4: 6b6e616c .word 0x6b6e616c + 800d9c8: 00687369 .word 0x00687369 + 800d9cc: 3a656944 .word 0x3a656944 + 800d9d0: 69724220 .word 0x69724220 + 800d9d4: 42006b63 .word 0x42006b63 + 800d9d8: 32746f6f .word 0x32746f6f + 800d9dc: 00554644 .word 0x00554644 + 800d9e0: 524c .short 0x524c + 800d9e2: 00 .byte 0x00 + 800d9e3: 65 .byte 0x65 + 800d9e4: 7265746e .word 0x7265746e + 800d9e8: 7566645f .word 0x7566645f + 800d9ec: 2928 .short 0x2928 + 800d9ee: 00 .byte 0x00 + 800d9ef: 0d .byte 0x0d + 800d9f0: 31510a0a .word 0x31510a0a + 800d9f4: 6f6f4220 .word 0x6f6f4220 + 800d9f8: 616f6c74 .word 0x616f6c74 + 800d9fc: 3a726564 .word 0x3a726564 + 800da00: 463e0020 .word 0x463e0020 + 800da04: 57455249 .word 0x57455249 + 800da08: 454c4c41 .word 0x454c4c41 + 800da0c: 70003c44 .word 0x70003c44 + 800da10: 2d726961 .word 0x2d726961 + 800da14: 63697262 .word 0x63697262 + 800da18: 0064656b .word 0x0064656b + 800da1c: 69726556 .word 0x69726556 + 800da20: 203a7966 .word 0x203a7966 + 800da24: 00 .byte 0x00 + 800da25: 54 .byte 0x54 + 800da26: 4145 .short 0x4145 + 800da28: 69742052 .word 0x69742052 + 800da2c: 756f656d .word 0x756f656d + 800da30: 00000074 .word 0x00000074 + 800da34: 00000150 .word 0x00000150 + 800da38: 00000011 .word 0x00000011 + 800da3c: 00000001 .word 0x00000001 + 800da40: 00000001 .word 0x00000001 + 800da44: 00000000 .word 0x00000000 + +0800da48 : + 800da48: 0011627f 01001886 22180080 00188600 .b.........".... + 800da58: 18008001 00117d7f .....}... + +0800da61 : + 800da61: 000f577f 07e00182 1e408100 10018600 .W........@..... + 800da71: 01000200 40810003 0186001e 00020008 .......@........ + 800da81: 81000301 82001e40 00030801 00030181 ....@........... + 800da91: 001e4081 5c08018a 08c1010e 1e40071c .@.....\......@. + 800daa1: 08018a00 21020262 c0082210 018a001e ....b..!."...... + 800dab1: 040241f0 10412011 8a001e40 02400801 .A... A.@.....@. + 800dac1: 41400104 001e4010 4004018a c0010402 ..@A.@.....@.... + 800dad1: 1e40107f 04018a00 01040240 40104020 ..@.....@... @.@ + 800dae1: 018a001e 04024004 10401011 8a001e40 .....@....@.@... + 800daf1: 02400801 21082102 001ec008 40f0018a ..@..!.!.......@ + 800db01: 04c10102 7f40071e 00000f7d ......@.}... + +0800db0d : + 800db0d: 0016237f 00270881 00247f81 ff031f81 .#....'...$..... + 800db1d: 0023c081 e081ff04 07810022 e382ff03 ..#....."....... + 800db2d: 860022e0 ff0fff1f 0022f081 03c03f82 ."........"..?.. + 800db3d: 22f08100 04ff8100 21788100 fc018200 ..."......x!.... + 800db4d: 78810004 03820021 810004f0 83002178 ...x!.......x!.. + 800db5d: 030fe007 21788100 800f8700 0000803f ......x!....?... + 800db6d: 870021f8 80ff001f 21f00000 033e8300 .!.........!..>. + 800db7d: 810003ff 830021f0 03f8077c 21e08100 .....!..|......! + 800db8d: 0ff88700 010000c0 870021e0 00801ff0 .........!...... + 800db9d: 20e00100 e0018300 8200033e 0020e001 ... ....>..... . + 800dbad: 7ce00383 01820003 830020e0 04f8c003 ...|..... ...... + 800dbbd: 20e08100 81078300 810004f0 830020e0 ... ......... .. + 800dbcd: 04e08307 20e08100 030f8300 810004c0 ....... ........ + 800dbdd: 830020f0 04c0070f 20f08100 0f1e8300 . ......... .... + 800dbed: 81000480 820020f0 00050f1e 0020f081 ..... ........ . + 800dbfd: 051f1e82 20f08100 1e1e8200 f0810005 ....... ........ + 800dc0d: 1c820020 8100051e 820020f0 00051c3c ........ ..<... + 800dc1d: 0020f081 053c3c82 20f08100 1c3c8200 .. ..<<.... ..<. + 800dc2d: f0810005 3c810020 e0810006 3c810020 .... ..<.... ..< + 800dc3d: 01820005 810020e0 8200053c 0020e001 ..... ..<..... . + 800dc4d: 00053c81 20e00182 053c8100 c0018200 .<..... ..<..... + 800dc5d: 3c810020 03820005 810020c0 8200053c ..<..... ..<... + 800dc6d: 0020c003 00053c81 20800782 051c8100 .. ..<..... .... + 800dc7d: 80078200 1c810020 0f810005 1c810021 .... .......!... + 800dc8d: 1f810005 1e810021 1e810005 1e810021 ....!.......!... + 800dc9d: 3c810005 1e810021 7c810005 1c810021 ..... + 800dcfd: 22e0ffc3 1f1f8200 8081ff03 1f810022 ..."........"... + 800dd0d: fc81ff03 0f810023 e081ff03 03820023 ....#.......#... + 800dd1d: 810027f8 24297f40 f00f8200 03820008 .'..@.)$........ + 800dd2d: 83001cc0 07200008 20048200 0883001c ...... .... .... + 800dd3d: 00082000 001c1081 000a0881 001c1081 . .............. + 800dd4d: e000088c 08c83d5c 00075cf8 8c001c20 ....\=...\.. ... + 800dd5d: 6220c00f 04882822 40800862 088c001c .. b"(..b..@.... + 800dd6d: 22412000 41048828 1c804010 00088b00 . A"(..A.@...... + 800dd7d: 28224020 1040fc88 8b001d41 40200008 @"(..@.A..... @ + 800dd8d: 04892822 1dc11f40 00088a00 25224020 "(..@....... @"% + 800dd9d: 10400451 088a001e 22402000 40045125 Q.@...... @"%Q.@ + 800ddad: 8b001e10 40200008 0c512520 1d410840 ...... @ %Q.@.A. + 800ddbd: 00088b00 22204020 0740f420 0f4b7f81 .... @ " .@...K. + ... + +0800ddcf : + 800ddcf: 0010237f 00272081 00087081 f8e31f83 .#... '..p...... + 800dddf: 7181001c 3f830008 001bfeff 80730e83 ...q...?......s. + 800ddef: 7f830007 001bfeff 80770f83 fc830007 ..........w..... + 800ddff: 001b9fff 08ff0782 3ef08400 001a800f ...........>.... + 800de0f: 078e0382 f0018500 23800700 e0018500 ...........#.... + 800de1f: 1bc00300 e0078200 03850006 c00300c0 ................ + 800de2f: 0183001a 0006e087 00c00385 0019e001 ................ + 800de3f: c403f883 07850007 e0010080 01840018 ................ + 800de4f: 07ee07fc 803f8500 17fc0100 fb7f8500 ......?......... + 800de5f: 07cf0ffe 80ff8500 16ff0000 ff038700 ................ + 800de6f: 871fdfff 82000580 0003ff01 1580ff82 ................ + 800de7f: ff0f8700 03bf8fff 82000580 0003f803 ................ + 800de8f: 15c00f82 ff3f8500 07fe07ff e0038200 ......?......... + 800de9f: 03820003 850015e0 0303807f 820007fc ................ + 800deaf: 0003c003 15e00182 00fe8500 07f80100 ................ + 800debf: c0038200 01820003 820014e0 0003f801 ................ + 800decf: 0007f881 03e00382 c0038200 03820014 ................ + 800dedf: 810003e0 8200077c 0003f803 14c00f82 ....|........... + 800deef: c0078200 3e810003 01870007 0100c0ff .......>........ + 800deff: 001480ff 78800f86 081f0000 15ff0500 .......x........ + 800df0f: 031f8700 0f0000f8 81000780 81ff033f ............?... + 800df1f: 870015fc 00f8071e 07c00700 031f8100 ................ + 800df2f: 15f881ff 0f3c8700 030000f8 850007c0 ......<......... + 800df3f: feff3f1e 87001578 00801f7c 07c00300 .?..x...|....... + 800df4f: 3f1e8500 1578fce7 3e788200 07820003 ...?..x...x>.... + 800df5f: 850007c0 fce33f1e 82001578 00037c78 .....?..x...x|.. + 800df6f: 06800f82 fe038700 7ffcc31f 820014e0 ................ + 800df7f: 000378f0 00071f81 0fff0387 e07ff881 .x.............. + 800df8f: f0820014 81000378 8700071e 0003ff03 ....x........... + 800df9f: 14c0ff40 f0e08200 1e810003 01820007 @............... + 800dfaf: 820003ff 0013c0ff f0e00183 1e810003 ................ + 800dfbf: 01870007 000080ff 0013c0ff f0e00183 ................ + 800dfcf: 0e810003 01870007 0100c0ff 001380ff ................ + 800dfdf: 70e00183 0f810003 ff860008 ff0300c0 ...p............ + 800dfef: 82001380 0004e001 00080f81 00e0ff85 ................ + 800dfff: 0014ff07 04e00182 080f8100 f87f8500 ................ + 800e00f: 14ff0f00 e0018200 0f810004 ff860008 ................ + 800e01f: ff3f00fc 82001380 0004e001 00070f81 ..?............. + 800e02f: ffff0387 c0ffff80 01820013 810004e0 ................ + 800e03f: 8700070f ff3ff007 13e00ffc e0018200 ......?......... + 800e04f: 0f810004 07870007 f8ff1fc0 0013f003 ................ + 800e05f: 04e00182 070e8100 800f8700 00f8ff1f ................ + 800e06f: 810014f8 810004e0 8700071e 3e1f001f ...............> + 800e07f: 14780078 04f08100 071e8100 001e8700 x.x............. + 800e08f: 00f8800f 8100147c 810004f0 8700071e ....|........... + 800e09f: 810f001e 143c00f8 04f08100 073c8100 ......<.......<. + 800e0af: 003c8700 00f8c10f 8100143c 81000478 ..<.....<...x... + 800e0bf: 8700073c c30f003c 141c00f0 047c8100 <...<.........|. + 800e0cf: 07788100 003c8700 00f0c30f 8100141c ..x...<......... + 800e0df: 8100043c 87000778 c30f003c 141e00f0 <...x...<....... + 800e0ef: 043e8100 07f08100 003c8700 00f0c10f ..>.......<..... + 800e0ff: 8100141e 8200031f 0007f001 07003c87 .............<.. + 800e10f: 1e00f0c1 0f860014 03000080 870007e0 ................ + 800e11f: c107003c 141e00f0 c00f8600 c0070000 <............... + 800e12f: 3c870007 f0810700 00141e00 00e00786 ...<............ + 800e13f: 07800f00 003c8700 00e08107 8500141e ......<......... + 800e14f: 0000f003 8700083f 8107003c 141e00e0 ....?...<....... + 800e15f: fc018500 087e0000 003c8700 00e08007 ......~...<..... + 800e16f: 8400151e fc03007f 3c870008 e0800300 ...........<.... + 800e17f: 00151e00 1ff83f84 870008f8 8003003e .....?......>... + 800e18f: 153c00e0 ff0f8400 0008e0ff ff053f81 ..<..........?.. + 800e19f: 0015fc81 ffff0384 81000880 81ff051f ................ + 800e1af: 820016f8 0009fcff ff050f81 0016f081 ................ + 800e1bf: 000a0381 ff050181 297fc081 01820014 ...........).... + 800e1cf: 840006e0 70000004 04810006 01820015 .......p........ + 800e1df: 87000610 88000004 03010000 15048100 ................ + 800e1ef: 08018200 04870006 00040100 00030100 ................ + 800e1ff: 00150481 06040182 00048700 00000401 ................ + 800e20f: 81000301 93001504 173e0401 5c70d001 ..........>...p\ + 800e21f: 00010004 e0870f41 1504f770 04019300 ....A...p....... + 800e22f: 30821801 00046288 10410001 88880041 ...0.b....A.A... + 800e23f: 93001584 10010401 41041144 00010004 ........D..A.... + 800e24f: 01011041 15848804 04019300 1144103f A...........?.D. + 800e25f: 00044004 10410001 88040101 93001584 .@....A......... + 800e26f: 10410401 40fc1144 00010004 01810f41 ..A.D..@....A... + 800e27f: 15848804 04019300 11441041 00004000 ........A.D..@.. + 800e28f: 00410401 88040141 93001580 10410801 ..A.A.........A. + 800e29f: 40003142 04010000 01410041 15808804 B1.@....A.A..... + 800e2af: 10019300 d0411043 00044084 10238800 ....C.A..@....#. + 800e2bf: 80881041 93001584 103de001 40781040 A.........=.@.x@ + 800e2cf: 70000004 e0800f1d 1a848070 26108100 ...p....p......& + 800e2df: 10048200 02820026 82002620 477fc001 ....&... &.....G + 800e2ef: ... + +0800e2f2 : + 800e2f2: 0013247f 26c00382 ffff8200 0c860023 .$.....&....#... + 800e302: ffff0700 860022e0 ff1f001e 0022f8ff ....."........". + 800e312: 7f001e86 22fe7ffe 001e8600 ff0180ff ......."........ + 800e322: 1e870022 0000fc03 0021c03f f0071e87 ".......?.!..... + 800e332: e00f0000 1e870021 0000c00f 0021f003 ....!.........!. + 800e342: 801f1e87 f8010000 1e820021 8100043f ........!...?... + 800e352: 820021fc 00047e1e 00217e81 00fc1e87 .!...~...~!..... + 800e362: 3f00c003 1e870021 c00300f8 00211f00 ...?!.........!. + 800e372: 00f01f88 0f00c003 88002080 0300e01f ......... ...... + 800e382: 800700c0 1f880020 c00300e0 20c00700 .... .......... + 800e392: c01f8800 00c00300 0020c003 fcff1f88 .......... ..... + 800e3a2: 0100c003 880020e0 03feff1f e00100c0 ..... .......... + 800e3b2: 1f880020 c003feff 20f00100 ff1f8800 .......... .... + 800e3c2: 00c003fc 0023f000 00c00385 0023f000 ......#.......#. + 800e3d2: 00c00385 0023f000 00c00385 00237800 ......#......x#. + 800e3e2: 00c00385 00237800 00c00385 00237800 .....x#......x#. + 800e3f2: 00c00385 00237800 00c00385 00237800 .....x#......x#. + 800e402: 00c00385 00237800 00c00385 00237800 .....x#......x#. + 800e412: 00e00385 00237800 00f80385 00247800 .....x#......x$. + 800e422: 0000fc84 84002478 7800007f 3f840024 ....x$.....x$..? + 800e432: 24f00080 c00f8400 0024f000 00e00784 ...$......$..... + 800e442: 840024f0 f001e001 c0830025 0026e001 .$......%.....&. + 800e452: 26e00182 e0038200 07820026 820026c0 ...&....&....&.. + 800e462: 00268007 26800f82 271f8100 273f8100 ..&....&...'..?' + 800e472: 227e8100 04078100 22fc8100 800f8600 ..~".......".... + 800e482: f8010000 0f860022 030000c0 860022f0 ...."........".. + 800e492: 0000f007 0022e00f 00fc0386 23c03f00 ......"......?.# + 800e4a2: 80ff8400 0024ff01 7ffe7f84 840024fe ......$......$.. + 800e4b2: f8ffff1f 07840024 25e0ffff ffff8200 ....$......%.... + 800e4c2: 01820026 212a7f80 08f08100 00088300 &.....*!........ + 800e4d2: 81001c1e 83000888 1c210008 08848100 ..........!..... + 800e4e2: 00088400 001b8000 00088281 00000884 ................ + 800e4f2: 8c001b80 12100e82 072e3ae0 0138e8c0 .........:....8. + 800e502: 828c001c 10131111 21003146 1c024418 ........F1.!.D.. + 800e512: 20828c00 82081291 08228020 001c0482 ... .... ."..... + 800e522: 9120828c 20820812 8208e207 8c001c08 .. .... ........ + 800e532: 12912082 08208208 08fe0822 828b001c . .... ."....... + 800e542: 08a28a20 22082082 001d8008 8a20848b .... ."...... . + 800e552: 204608a2 80082208 888c001d 08a20a11 ..F .".......... + 800e562: 6108203a 1c084218 0ef08c00 02084204 : .a.B.......B.. + 800e572: e8a00720 0021083c 00270281 00278281 ...<.!...'...'. + 800e582: 00274481 477f3881 .D'..8.G... + +0800e58d : + 800e58d: 0013577f 01001c84 850023c0 02002288 .W.......#...".. + 800e59d: 84002320 02002088 88840024 23020020 #... ..$... ..# + 800e5ad: fc038500 23424020 10018500 23424420 .... @B#.... DB# + 800e5bd: 10018600 c04f44fc 01850022 42442010 .....DO.".... DB + 800e5cd: 07850023 424420f8 02850023 822a2020 #.... DB#... *. + 800e5dd: 02850023 822a2020 02850023 822a2020 #... *.#... *. + 800e5ed: 20830025 7d7f0211 %.. ...}... + +0800e5f8 : + 800e5f8: 0002bc7f 0000fe84 82000801 00198007 ................ + 800e608: 18000185 00060100 04001084 85001940 ............@... + 800e618: 000c0001 84000601 20040010 01850019 ........... .... + 800e628: 01000600 10840006 19100400 00019200 ................ + 800e638: 00010003 c141071c 04007e04 075c7010 ......A..~...p\. + 800e648: 01930016 01800100 c2082200 00100421 ........."..!... + 800e658: 62881004 00158008 00000193 410001c0 ...b...........A + 800e668: 04114410 11040010 40104104 01930015 .D.......A.@.... + 800e678: 01e0ff07 44104100 00100411 41041104 .....A.D.......A + 800e688: 00154010 00000193 410001c0 04114410 .@.........A.D.. + 800e698: 11040010 c01f4104 01920015 01800100 .....A.......... + 800e6a8: 44104100 00100411 41041104 92001610 .A.D.......A.... + 800e6b8: 00030001 08410001 100411c4 04210400 ......A.......!. + 800e6c8: 00161041 06000193 22000100 8c204207 A..........".B . + 800e6d8: 40040011 40084188 01930015 01000c00 ...@.A.@........ + 800e6e8: 41001cfc 000e74c0 41708007 00158007 ...A.t....pA.... + 800e6f8: 18000183 40810005 fe810020 10820005 .......@ ....... + 800e708: 82002640 00268008 147f0781 @&....&........ + +0800e717 : + 800e717: 0014577f 00271081 00271081 00272081 .W....'...'.. '. + 800e727: 00272081 00274081 00274081 00258081 . '..@'..@'...%. + 800e737: 81c01f84 810025fc 81002701 81002701 .....%...'...'.. + 800e747: 81002702 81002702 81002704 147c7f04 .'...'...'....|. + ... + +0800e759 : + 800e759: 0003ba7f 0026c081 26c01082 c3308500 ......&....&..0. + 800e769: 06f00100 00078400 001938e0 80c16085 .........8...`.. + 800e779: 00060801 10810884 85001944 0180c040 ........D...@... + 800e789: 84000604 40004110 c0030019 06040182 .....A.@........ + 800e799: 41108400 00194000 40c0808f 201c0401 ...A.@.....@... + 800e7a9: 0070c121 40004110 80850019 040140c0 !.p..A.@.....@.. + 800e7b9: 21872203 41100088 00184000 c0800190 .".!...A.@...... + 800e7c9: 41080160 04112422 e1471000 900018f8 `..A"$....G..... + 800e7d9: 60c08001 2241f001 00001124 40004110 ...`..A"$....A.@ + 800e7e9: 01900018 0160c080 27224100 100000f1 ......`..A"'.... + 800e7f9: 18400041 80019000 00014000 01441541 A.@......@..A.D. + 800e809: 41100000 00194000 4000808f 15410001 ...A.@.....@..A. + 800e819: 00000144 40004110 c08f0019 0001c000 D....A.@........ + 800e829: 11421522 81080000 00194000 8000408f ".B......@...@.. + 800e839: 081c0001 0000e181 40000107 60830019 ...........@...` + 800e849: 00258001 26033082 0c0c8200 07820026 ..%..0.&....&... + 800e859: 24147ff8 ...$.. + +0800e85f : + 800e85f: 000f277f 00052081 ff040181 001c8081 .'... .......... + 800e86f: 00057081 ff040781 001cf081 0005f881 .p.............. + 800e87f: ff040f81 001cf881 0005fc81 ff041f81 ................ + 800e88f: 001cfc81 00057e81 003c1e86 1cfe0700 .....~....<..... + 800e89f: 053f8100 3c1e8600 bf070000 1f82001c ..?....<........ + 800e8af: 87000480 00003c1e 1b809f07 c00f8200 .....<.......... + 800e8bf: 1e870004 0700003c 001bc08f 04e00782 ....<........... + 800e8cf: 3c1e8700 87070000 82001be0 0004f003 ...<............ + 800e8df: 003c1e87 f0830700 0182001b 870004f8 ..<............. + 800e8ef: 00003c1e 1cf88107 04fc8100 3c1e8700 .<.............< + 800e8ff: 80070000 81001cfc 8700047e 00003c1e ........~....<.. + 800e90f: 1c7c8007 043f8100 3c1e8700 80070000 ..|...?....<.... + 800e91f: 82001c3e 0003801f 003c1e87 1e800700 >.........<..... + 800e92f: 0f82001c 820003c0 ff033f1e 1c0e8082 .........?...... + 800e93f: e0078200 1e820003 82ff031f 001c0f00 ................ + 800e94f: 03f00382 1f1e8200 0082ff03 82001c0f ................ + 800e95f: 0003f801 ff0f1e87 0f00feff fc81001d ................ + 800e96f: 1e810003 0f810005 7e81001d 1e810003 ...........~.... + 800e97f: 0f810005 3f81001d 1e810003 0f810005 .......?........ + 800e98f: 1f85001d 1e000080 0f810005 0f85001d ................ + 800e99f: 1e0000c0 0f810005 078b001d 1e0000e0 ................ + 800e9af: 807f0000 00180f00 f08aff06 001e0000 ................ + 800e9bf: 00e0ff01 0600180f 00f88aff 03001e00 ................ + 800e9cf: 0f00f0ff ff060018 0000f08a fb07001e ................ + 800e9df: 180f00f8 057f8100 00e08aff 07001e00 ................ + 800e9ef: 0f007cc0 0f8b001d 1e0000c0 3e800f00 .|.............> + 800e9ff: 001d0f00 00801f8b 0f001e00 0f001e00 ................ + 800ea0f: 3f81001d 1e870003 1e001e00 001d0f00 ...?............ + 800ea1f: 00037e81 1e001e87 0f000e00 fc81001d .~.............. + 800ea2f: 1e870003 0f001e00 001c0f00 03f80182 ................ + 800ea3f: 001e8700 000f001e 82001c0f 0003f003 ................ + 800ea4f: 1e001e87 0f000e00 0782001c 870003e0 ................ + 800ea5f: 001e001e 1c0f001e c00f8200 1e870003 ................ + 800ea6f: 1e000f00 001c0f00 03801f82 001e8700 ................ + 800ea7f: 003e000f 81001c0f 8700043f c007001e ..>.....?....... + 800ea8f: 1c0f007c 047e8100 001e8700 00f8fb07 |.....~......... + 800ea9f: 81001c0f 870004fc ff03001e 1b0f00f0 ................ + 800eaaf: f8018200 1e870004 e0ff0100 001b0f00 ................ + 800eabf: 04f00382 001e8700 00807f00 82001b0f ................ + 800eacf: 0004e007 00051e81 001b0f81 04c00f82 ................ + 800eadf: 051e8100 1b0f8100 801f8200 1e810004 ................ + 800eaef: 0f810005 3f81001b 1e810005 0e810005 .......?........ + 800eaff: 7e81001b 1e810005 1e810005 fc81001b ...~............ + 800eb0f: 1f810005 fe81ff05 f881001b 0f810005 ................ + 800eb1f: fc81ff05 7081001b 07810005 f881ff05 .......p........ + 800eb2f: 2081001b 01810005 e081ff05 00192d7f ... .........-.. + 800eb3f: 07800f82 031c8100 1a048100 05028100 ................ + 800eb4f: 00018400 00032200 001a0481 00050281 .....".......... + 800eb5f: 00000184 81000341 81001a04 84000502 ....A........... + 800eb6f: 41000001 04810003 028e001a 1cf8c005 ...A............ + 800eb7f: 00e00717 c0850f40 8e001a74 04210602 ....@...t.....!. + 800eb8f: 00811822 46004000 001a8c20 1104028e "....@.F ....... + 800eb9f: 41104100 00400000 1a041144 04028e00 .A.A..@.D....... + 800ebaf: 10410011 40000001 0401c40f 028e001a ..A....@........ + 800ebbf: 7ff81004 00000110 01441040 8e001a04 ........@.D..... + 800ebcf: 04100402 00011040 44104100 001a0401 ....@....A.D.... + 800ebdf: 1004028e 01104004 10410000 1a040144 .....@....A.D... + 800ebef: 04028e00 10210411 22001001 8c00c410 ......!....".... + 800ebff: 0f8e001a 1ef81084 00e00010 00440f1c ..............D. + 800ec0f: 0d4b7f74 t.K... + +0800ec15 : + 800ec15: 0010237f 00272081 00087081 f8e31f83 .#... '..p...... + 800ec25: 7181001c 3f830008 001bfeff 80730e83 ...q...?......s. + 800ec35: 7f830007 001bfeff 80770f83 fc830007 ..........w..... + 800ec45: 001b9fff 08ff0782 3ef08400 001a800f ...........>.... + 800ec55: 078e0382 f0018500 23800700 e0018500 ...........#.... + 800ec65: 1bc00300 e0078200 03850006 c00300c0 ................ + 800ec75: 0183001a 0006e087 00c00385 0019e001 ................ + 800ec85: c403f883 07850007 e0010080 01840018 ................ + 800ec95: 07ee07fc 803f8500 17fc0100 fb7f8500 ......?......... + 800eca5: 07cf0ffe 80ff8500 16ff0000 ff038700 ................ + 800ecb5: 871fdfff 82000580 0003ff01 1580ff82 ................ + 800ecc5: ff0f8700 03bf8fff 82000580 0003f803 ................ + 800ecd5: 15c00f82 ff3f8500 07fe07ff e0038200 ......?......... + 800ece5: 03820003 850015e0 0303807f 820007fc ................ + 800ecf5: 0003c003 15e00182 00fe8500 07f80100 ................ + 800ed05: c0038200 01820003 820014e0 0003f801 ................ + 800ed15: 0007f881 03e00382 c0038200 03820014 ................ + 800ed25: 810003e0 8200077c 0003f803 14c00f82 ....|........... + 800ed35: c0078200 3e810003 01870007 0100c0ff .......>........ + 800ed45: 001480ff 78800f86 081f0000 15ff0500 .......x........ + 800ed55: 031f8700 0f0000f8 81000780 81ff033f ............?... + 800ed65: 870015fc 00f8071e 07c00700 031f8100 ................ + 800ed75: 15f881ff 0f3c8700 030000f8 850007c0 ......<......... + 800ed85: feff3f1e 87001578 00801f7c 07c00300 .?..x...|....... + 800ed95: 3f1e8500 1578fce7 3e788200 07820003 ...?..x...x>.... + 800eda5: 850007c0 fce33f1e 82001578 00037c78 .....?..x...x|.. + 800edb5: 06800f82 fe038700 7ffcc31f 820014e0 ................ + 800edc5: 000378f0 00071f81 0fff0387 e07ff881 .x.............. + 800edd5: f0820014 81000378 8700071e 0003ff03 ....x........... + 800ede5: 14c0ff40 f0e08200 1e810003 01820007 @............... + 800edf5: 820003ff 0013c0ff f0e00183 1e810003 ................ + 800ee05: 01870007 000080ff 0013c0ff f0e00183 ................ + 800ee15: 0e810003 01870007 0100c0ff 001380ff ................ + 800ee25: 70e00183 0f810003 ff860008 ff0300c0 ...p............ + 800ee35: 82001380 0004e001 00080f81 00e0ff85 ................ + 800ee45: 0014ff07 04e00182 080f8100 f87f8500 ................ + 800ee55: 14ff0f00 e0018200 0f810004 ff860008 ................ + 800ee65: ff3f00fc 82001380 0004e001 00070f81 ..?............. + 800ee75: ffff0387 c0ffff80 01820013 810004e0 ................ + 800ee85: 8700070f ff3ff007 13e00ffc e0018200 ......?......... + 800ee95: 0f810004 07870007 f8ff1fc0 0013f003 ................ + 800eea5: 04e00182 070e8100 800f8700 00f8ff1f ................ + 800eeb5: 810014f8 810004e0 8700071e 3e1f001f ...............> + 800eec5: 14780078 04f08100 071e8100 001e8700 x.x............. + 800eed5: 00f8800f 8100147c 810004f0 8700071e ....|........... + 800eee5: 810f001e 143c00f8 04f08100 073c8100 ......<.......<. + 800eef5: 003c8700 00f8c10f 8100143c 81000478 ..<.....<...x... + 800ef05: 8700073c c30f003c 141c00f0 047c8100 <...<.........|. + 800ef15: 07788100 003c8700 00f0c30f 8100141c ..x...<......... + 800ef25: 8100043c 87000778 c30f003c 141e00f0 <...x...<....... + 800ef35: 043e8100 07f08100 003c8700 00f0c10f ..>.......<..... + 800ef45: 8100141e 8200031f 0007f001 07003c87 .............<.. + 800ef55: 1e00f0c1 0f860014 03000080 870007e0 ................ + 800ef65: c107003c 141e00f0 c00f8600 c0070000 <............... + 800ef75: 3c870007 f0810700 00141e00 00e00786 ...<............ + 800ef85: 07800f00 003c8700 00e08107 8500141e ......<......... + 800ef95: 0000f003 8700083f 8107003c 141e00e0 ....?...<....... + 800efa5: fc018500 087e0000 003c8700 00e08007 ......~...<..... + 800efb5: 8400151e fc03007f 3c870008 e0800300 ...........<.... + 800efc5: 00151e00 1ff83f84 870008f8 8003003e .....?......>... + 800efd5: 153c00e0 ff0f8400 0008e0ff ff053f81 ..<..........?.. + 800efe5: 0015fc81 ffff0384 81000880 81ff051f ................ + 800eff5: 820016f8 0009fcff ff050f81 0016f081 ................ + 800f005: 000a0381 ff050181 297fc081 3c810014 ...........)...< + 800f015: 80830007 00080e00 00142081 00072281 ......... ...".. + 800f025: 11008083 20820003 81000304 81001420 ....... .... ... + 800f035: 88000721 80200080 04200000 20810003 !..... ... .... + 800f045: 20820014 87000680 80200080 04200000 ... ...... ... . + 800f055: 14208100 87209400 0e3ae0c2 0080800b .. ... ...:..... + 800f065: 08c20720 82031cfc 001420e0 23802094 ........ ... .# + 800f075: 0c114610 20008040 20082200 10430404 .F..@.. .". ..C. + 800f085: 94001420 08228020 20882082 00200080 ... .".. . .. . + 800f095: 04200822 20082208 20940014 8208e287 ". ..". ... .... + 800f0a5: 80008820 e2072000 08042008 14200822 .... ... ..". . + 800f0b5: 88209400 3f820822 00800088 08220820 .. ."..?.... .". + 800f0c5: 22080420 00142008 22882087 08208208 ..". ... .".. . + 800f0d5: 20890003 20082288 08220804 21870015 ... .". .."....! + 800f0e5: 46082208 00030820 22882089 08042008 .".F .... .". .. + 800f0f5: 00150822 62082294 88103a08 11008000 "....".b.:...... + 800f105: 22186108 08420404 94001420 08a2073c .a."..B. ...<... + 800f115: 00080f02 070e0080 041ce8a0 20088203 ............... + 800f125: 02810018 82810027 44810027 38810027 ....'...'..D'..8 + 800f135: 0019477f .G... + +0800f13a : + 800f13a: 0013247f 26f83f82 feff8200 01840025 .$...?.&....%... + 800f14a: 2480ffff f8038400 0024c03f 07e00784 ...$....?.$..... + 800f15a: 840024e0 f001800f 1f840024 24f80000 .$......$......$ + 800f16a: 001e8400 00247800 00003c84 8600227c .....x$..<..|".. + 800f17a: 003c000e 00223c00 78000f88 003c0000 ..<..<"....x..<. + 800f18a: 880020e0 0078800f e0011e00 07880020 . ....x..... ... + 800f19a: 000078c0 20e0031e e0038800 1e000078 .x..... ....x... + 800f1aa: 0020c007 ff060181 00218081 0022ff06 .. .......!...". + 800f1ba: ff047f81 0022fe81 ff047f81 0022fc81 ......".......". + 800f1ca: 00047881 00223c81 00047881 00223c81 .x...<"..x...<". + 800f1da: 00047881 00223c81 00047881 00223c81 .x...<"..x...<". + 800f1ea: 00047881 00223c81 00047881 00223c81 .x...<"..x...<". + 800f1fa: 00047881 00223c81 00047881 00223c81 .x...<"..x...<". + 800f20a: 03007886 223c0080 00788600 3c00c003 .x....<"..x....< + 800f21a: 78860022 00c00300 8600223c c0030078 "..x....<"..x... + 800f22a: 00223c00 03007886 213c00c0 f87f8800 .<"..x....: + 800f3d7: 0013247f 26f83f82 feff8200 01840025 .$...?.&....%... + 800f3e7: 2480ffff f8038400 0024c03f 07e00784 ...$....?.$..... + 800f3f7: 840024e0 f001800f 1f840024 24f80000 .$......$......$ + 800f407: 001e8400 00247800 00003c84 8600227c .....x$..<..|".. + 800f417: 003c000e 00223c00 78000f88 003c0000 ..<..<"....x..<. + 800f427: 880020e0 0078800f e0011e00 07880020 . ....x..... ... + 800f437: 000078c0 20e0031e e0038800 1e000078 .x..... ....x... + 800f447: 0020c007 ff060181 00218081 0022ff06 .. .......!...". + 800f457: ff047f81 0022fe81 ff047f81 0022fc81 ......".......". + 800f467: 00047881 00223c81 00047881 00223c81 .x...<"..x...<". + 800f477: 00047881 00223c81 00047881 00223c81 .x...<"..x...<". + 800f487: 00047881 00223c81 00047881 00223c81 .x...<"..x...<". + 800f497: 00047881 00223c81 00047881 00223c81 .x...<"..x...<". + 800f4a7: 03007886 223c0080 00788600 3c00c003 .x....<"..x....< + 800f4b7: 78860022 00c00300 8600223c c0030078 "..x....<"..x... + 800f4c7: 00223c00 03007886 213c00c0 f87f8800 .<"..x....: + 800f671: 0013247f 26c00182 ffff8200 07840025 .$.....&....%... + 800f681: 24e0ffff ff1f8400 0024f8ff 0ff07f84 ...$......$..... + 800f691: 840024fe ff0000ff 03860023 1f0000f8 .$......#....... + 800f6a1: 860022c0 0000e007 0022e00f 00c00f86 ."........"..... + 800f6b1: 22f00300 031f8100 f8018200 3e810022 ..."........"..> + 800f6c1: 7c810004 7c810022 3e810004 f8860022 ...|"..|...>"... + 800f6d1: 00c00300 8600221f c00300f0 00210f00 ....."........!. + 800f6e1: 00f00188 0f00c003 88002080 0300e001 ......... ...... + 800f6f1: 800700c0 03880020 c00300c0 20c00300 .... .......... + 800f701: c0078800 00c00300 0020c003 00800788 .......... ..... + 800f711: 0100c003 880020e0 03008007 e00100c0 ..... .......... + 800f721: 0f880020 c0030000 20f00000 000f8800 .......... .... + 800f731: 00c00300 0020f000 00000f88 0000c003 ...... ......... + 800f741: 880020f0 0300000e 700000c0 1e880020 . .........p ... + 800f751: c0030000 20780000 001e8800 00c00300 ......x ........ + 800f761: 00207800 00001e88 0000c003 88002078 .x .........x .. + 800f771: 0300001e 780000c0 1e880020 c0030000 .......x ....... + 800f781: 20780000 001e8800 00c00300 00207800 ..x .........x . + 800f791: 00001e88 0000e003 88002078 0300001e ........x ...... + 800f7a1: 780000f0 1e880020 f8030000 20780000 ...x .........x + 800f7b1: 001e8800 00fe0100 00207800 00031e81 .........x ..... + 800f7c1: 00007f84 81002078 8400030e 7000803f ....x ......?..p + 800f7d1: 0f810020 1f840003 20f000e0 030f8100 .......... .... + 800f7e1: e0078400 0020f000 00030f81 00e00384 ...... ......... + 800f7f1: 880020f0 00008007 e001c001 07820020 . .......... ... + 800f801: 82000480 0020e001 04c00782 c0038200 ...... ......... + 800f811: 03820020 820004c0 0020c003 04e00182 ......... ..... + 800f821: 80078200 01820020 820004f0 0021800f .... .........!. + 800f831: 0004f081 00220f81 0004f881 00221e81 ......".......". + 800f841: 00047c81 00223e81 00043e81 00227c81 .|...>"..>...|". + 800f851: 00041f81 0022f881 00c00f86 22f00300 ......"........" + 800f861: e0078600 e0070000 03860022 1f0000f8 ........"....... + 800f871: 840023c0 ff0000ff 7f840024 24fe0ff0 .#......$......$ + 800f881: ff1f8400 0024f8ff ffff0784 820025e0 ......$......%.. + 800f891: 0026ffff 7f800182 8500142a 00f88303 ..&.....*....... + 800f8a1: 8200070e 00090101 09104082 01078300 .........@...... + 800f8b1: 880003c0 00004204 80000011 01860004 .....B.......... + 800f8c1: 00010001 86000480 00104040 00068000 ........@@...... + 800f8d1: 20820883 08880003 20000022 04800080 ... ....".. .... + 800f8e1: 01018600 80000100 40860004 00001040 ...........@@... + 800f8f1: 82000680 00040208 00020888 00002000 ............. .. + 800f901: 82000480 00030101 00058081 00104085 .............@.. + 800f911: 00068000 04020882 0208a400 03200000 .............. . + 800f921: 2e82f083 01010003 f003071f 11100000 ................ + 800f931: 001040c0 2e82f003 3800800b 00040208 .@.........8.... + 800f941: 000204a4 40041000 03318280 00110100 .......@..1..... + 800f951: 00800081 40101100 00001040 0c318280 .......@@.....1. + 800f961: 08440040 a5000402 00f08303 8020080e @.D........... . + 800f971: 00802082 81001101 00008000 40401011 . ............@@ + 800f981: 80000010 20882082 0f3f8200 a30004c0 ..... . ..?..... + 800f991: 01000042 82802008 01008020 00811f11 B.... .. ....... + 800f9a1: 11000080 10404010 82800000 00200820 .....@@..... . . + 800f9b1: 05020882 03228100 e08f9f00 80208280 ......"....... . + 800f9c1: 20290100 00800081 40101100 00001040 ..) .......@@... + 800f9d1: 08208280 08820020 81000502 9f000322 .. . ......."... + 800f9e1: 82800088 00008020 008120aa 0a000080 .... .... ...... + 800f9f1: 104040a0 82800000 00200820 04020882 .@@..... . ..... + 800fa01: 22088a00 88200000 31828000 aa970003 ...".. ....1.... + 800fa11: 80008120 a00a0000 00104040 20828000 .......@@..... + 800fa21: 82002008 00040208 004204ce 20041100 . ........B.... + 800fa31: 032e4688 21440000 30880081 40a00a00 .F....D!...0...@ + 800fa41: 00001040 08204688 08440020 00c00002 @....F . .D..... + 800fa51: f8830300 c0030e00 03203a70 1e440000 ........p: ...D. + 800fa61: 30700081 40400400 00000e38 08203a70 ..p0..@@8...p: . + 800fa71: 08380020 0bc00002 08208100 1e608100 .8....... ...`. + 800fa81: 08208100 1ec08100 27208100 7f208100 .. ....... '.. . + 800fa91: 00001d47 G... + +0800fa95 : + 800fa95: 000e237f 00260881 e0ff0783 1f830025 .#....&.....%... + 800faa5: 0025fcff ffff7f83 01850024 c0ff80ff ..%.....$....... + 800fab5: 1f810005 f881ff03 03850019 e01f00f8 ................ + 800fac5: 7f810005 0019ff04 00e00f85 0005f003 ................ + 800fad5: 8081ff05 1f850018 f8010080 01810004 ................ + 800fae5: c081ff05 3f810018 7c810003 01870004 .......?...|.... + 800faf5: 0000c0e3 0018e07f 00037e81 00043e81 .........~...>.. + 800fb05: c0e30187 f07b0000 78810018 1f810003 ......{....x.... + 800fb15: 01870004 0000c0e3 0018f879 0003f881 ........y....... + 800fb25: 03800f82 e3018700 780000c0 820017fc ...........x.... + 800fb35: 0003f001 03800782 e3018700 780000c0 ...............x + 800fb45: 8200177e 0003e001 03c00382 e3018700 ~............... + 800fb55: 780000c0 8200173f 0003e003 03c00382 ...x?........... + 800fb65: e3018800 780000c0 0016801f 03c00382 .......x........ + 800fb75: e0018200 01880003 0000c0e3 16c00f78 ............x... + 800fb85: c0078200 01820003 880003e0 00c0e301 ................ + 800fb95: c0077800 07820016 81000480 880003f0 .x.............. + 800fba5: 00c0e301 e0037800 07820016 81000480 .....x.......... + 800fbb5: 880003f0 00c0e301 e0017800 07810016 .........x...... + 800fbc5: f0810005 01820003 83ff03e3 16e000f8 ................ + 800fbd5: 050f8100 03708100 e1018200 f083ff03 ......p......... + 800fbe5: 0016f000 00050f81 00037881 03e10182 .........x...... + 800fbf5: 00f083ff 810016f0 8100050f 82000378 ............x... + 800fc05: ff03e001 f000e083 0f810016 78810005 ...............x + 800fc15: 01820003 810005e0 810016f0 8100050f ................ + 800fc25: 82000378 0005e001 0016f081 00050f81 x............... + 800fc35: 00037881 05e00182 16f08100 050f8100 .x.............. + 800fc45: 03788100 e0018200 f0810005 0f810016 ..x............. + 800fc55: 78810005 01820003 810005e0 810016f0 ...x............ + 800fc65: 8100050f 88000370 0700e001 f00000f8 ....p........... + 800fc75: 0f810016 f0810005 01880003 fe1f00e0 ................ + 800fc85: 16f00000 05078100 03f08100 e0018800 ................ + 800fc95: 00ff3f00 0016f000 04800782 03f08100 .?.............. + 800fca5: e0018800 80bf7f00 0016f000 04800782 ................ + 800fcb5: 03f08100 e0018800 c0077c00 0016f000 .........|...... + 800fcc5: 03c00382 e0018200 01880003 03f800e0 ................ + 800fcd5: 16f000e0 c0038200 01820003 880003e0 ................ + 800fce5: f000e001 f000e001 03820016 820003e0 ................ + 800fcf5: 0003c003 01e00188 00e001e0 820016f0 ................ + 800fd05: 0003e001 03c00782 e0018800 e000e001 ................ + 800fd15: 0016f000 03f00182 80078200 01880003 ................ + 800fd25: 00e001e0 17f000f0 03f88100 800f8200 ................ + 800fd35: 01880003 00e001e0 17f000f0 037c8100 ..............|. + 800fd45: 041f8100 e0018800 e000e001 0017f000 ................ + 800fd55: 00033e81 00043e81 01e00188 00e001e0 .>...>.......... + 800fd65: 810017f0 8100033f 8800047f f000e001 ....?........... + 800fd75: f000e001 1f860017 ff0100c0 88000380 ................ + 800fd85: f000e001 f000e003 07860017 f70700e0 ................ + 800fd95: 880003c0 7c00e001 f000c007 03860017 .......|........ + 800fda5: e71f00fc 880003e0 7f00e001 f00080bf ................ + 800fdb5: 01810017 8382ff03 880003f0 3f00e001 ...............? + 800fdc5: f00000ff 7f850018 f801ffff 01880003 ................ + 800fdd5: fe1f00e0 18f00000 ff1f8500 03fc00fc ................ + 800fde5: e0018800 00f80700 0018f000 e0ff0385 ................ + 800fdf5: 00037e00 05e00182 1cf08100 033f8100 .~............?. + 800fe05: e0018200 f0810005 1f86001c 01000080 ................ + 800fe15: 810005e0 86001cf0 0000c00f 0005e001 ................ + 800fe25: 001ce081 00e00786 04e00100 e0018200 ................ + 800fe35: 0385001c 010000f0 e081ff06 0182001c ................ + 800fe45: 060003f8 1dc081ff 03fc8100 057f8100 ................ + 800fe55: 1d8081ff 037e8100 041f8100 1efe81ff ......~......... + 800fe65: 273f8100 271f8100 7f0e8100 8100222a ..?'...'....*".. + 800fe75: 810005e0 82002080 00051001 1f048082 ..... .......... + 800fe85: 08028200 80820005 81001f04 81000602 ................ + 800fe95: 8c002080 1f380002 bce0800b e8800b1c . ....8......... + 800fea5: 018c001c 8c004400 04c21041 1d18410c .....D..A....A.. + 800feb5: 82e08b00 08228800 22080482 8b001d08 ......"....".... + 800fec5: 881f8210 04820002 1d082208 fe088b00 ........."...... + 800fed5: 00028820 22080482 8b001d08 88208008 ......"...... . + 800fee5: 04820002 1c082208 08028c00 02882080 ....."....... .. + 800fef5: 08048208 001c1821 4210018f 10018821 ....!......B!... + 800ff05: 20080482 030c30e8 e08e001a 00881e3c ... .0......<... + 800ff15: 080482e0 0c300820 81002403 82002608 .... .0..$...&.. + 800ff25: 00260802 27100182 7fe08100 00001047 ..&....'....G... + +0800ff35 : + 800ff35: 0001bc7f 00030181 05040182 1c018100 ................ + 800ff45: 00018600 0401c00f 01820005 86001b02 ................ + 800ff55: 40080001 00050401 1b020182 00018600 ...@............ + 800ff65: 0401400c 01810005 0190001c 01400600 .@............@. + 800ff75: 45075c04 0e1df8c0 1874c005 01019000 .\.E......t..... + 800ff85: 0401400f 20c60862 06022304 00188c20 .@..b.. .#.. ... + 800ff95: 99030190 410401c0 04104410 11040241 .......A.D..A... + 800ffa5: 90001804 00f00601 10410401 41fc0044 ..........A.D..A + 800ffb5: 04110402 01900018 0100600c 44104104 .........`...A.D + 800ffc5: 02410401 18041104 08019000 04010000 ..A............. + 800ffd5: 01441041 04024104 00180411 00100190 A.D..A.......... + 800ffe5: 62040100 0401c408 10040241 8100188c ...b....A....... + 800fff5: 8b000401 44075c88 02230c01 18741004 .....\.D..#...t. + 8010005: 04018100 40708b00 f4004400 1004021d ......p@.D...... + 8010015: 81001804 83000501 06400040 18048100 ........@.@..... + 8010025: ff018900 0000e0ff 05401040 04018200 ........@.@..... + 8010035: 4083001e 00068008 001e8881 07074082 ...@.........@.. + 8010045: 7f708100 00001714 ..p..... + +0801004d : + 801004d: 0002b97f 26f80782 0c0c8200 30820026 .......&....&..0 + 801005d: 85002603 01800160 81000404 85001e38 .&..`.......8... + 801006d: 0180c040 84000304 02004480 c003001c @........D...... + 801007d: 03040182 40808400 001c0200 40c08085 .......@.......@ + 801008d: 00040401 001e4081 40c0808f 171c0401 .....@.....@.... + 801009d: 41408003 74c0050e 01900018 0160c080 ..@A...t......`. + 80100ad: 80182204 02414080 188c2006 80019000 ."...@A.. ...... + 80100bd: 040160c0 81401041 040241f8 00180411 .`..A.@..A...... + 80100cd: e0800190 41040160 40800010 11040241 ....`..A...@A... + 80100dd: 8f001904 00403080 00107f88 02414080 .....0@......@A. + 80100ed: 19041104 18808f00 40880040 40800010 ........@..@...@ + 80100fd: 11040241 8f001904 00c000c0 00104050 A...........P@.. + 801010d: 02234080 198c1004 00409300 21500080 .@#.......@...P! + 801011d: 40800010 1004021d 01061874 93001580 ...@....t....... + 801012d: 00800160 00101e20 02014080 18041004 `... ....@...... + 801013d: 15800106 03308200 01810008 04810003 ......0......... + 801014d: 0c820019 8500080c 01000001 82001904 ................ + 801015d: 0008f807 00034281 00238881 00033c81 .....B....#..<.. + 801016d: 147f7081 .p..... + +08010174 : + 8010174: 0014237f 00268081 26c00382 c0038200 .#....&....&.... + 8010184: 03820026 820026c0 0026c003 24c00382 &....&....&....$ + 8010194: c0018500 2303c003 e0038600 c007c003 .......#........ + 80101a4: 07860022 07c003e0 860022e0 c003c00f "........"...... + 80101b4: 0022f003 03001f86 22f800c0 003e8600 .."........"..>. + 80101c4: 7c00c003 7c860022 00c00300 8600223e ...|"..|....>".. + 80101d4: c00300f8 00221f00 0300f086 210f00c0 ......"........! + 80101e4: f0018800 00c00300 0020800f 00e00388 .......... ..... + 80101f4: 0700c003 88002080 0300c003 c00300c0 ..... .......... + 8010204: 07880020 c00300c0 20c00300 80078800 .......... .... + 8010214: 00c00300 0020e001 00800788 0100c003 ...... ......... + 8010224: 880020e0 0300000f f00000c0 0f880020 . .......... ... + 8010234: c0030000 20f00000 000f8800 00c00300 ....... ........ + 8010244: 0020f000 00000e88 0000c003 88002070 .. .........p .. + 8010254: 0300001e 780000c0 1e880020 c0030000 .......x ....... + 8010264: 20780000 001e8800 00c00300 00207800 ..x .........x . + 8010274: 00001e88 0000c003 88002078 0300001e ........x ...... + 8010284: 780000c0 1e880020 c0030000 20780000 ...x .........x + 8010294: 001e8800 00c00300 00207800 00001e88 .........x ..... + 80102a4: 0000c003 88002078 0300001e 780000c0 ....x .........x + 80102b4: 1e810020 78810006 1e810020 78810006 ......x ......x + 80102c4: 1e810020 70810006 0f810020 f0810006 ......p ....... + 80102d4: 0f810020 f0810006 0f810020 f0810006 ....... ....... + 80102e4: 07820020 82000480 0020e001 04800782 ......... ..... + 80102f4: e0018200 07820020 820004c0 0020c003 .... ......... . + 8010304: 04c00382 c0038200 03820020 820004e0 ........ ....... + 8010314: 00208007 04f00182 800f8200 f0810021 .. .........!... + 8010324: 0f810004 f8810022 1f810004 7c810022 ...."......."..| + 8010334: 3e810004 3e810022 7c810004 1f810022 ...>"..>...|"... + 8010344: f8810004 0f860022 030000c0 860022f0 ...."........".. + 8010354: 0000e007 0022e007 00f80386 23c01f00 ......"........# + 8010364: 00ff8400 0024ff00 0ff07f84 840024fe ......$......$.. + 8010374: f8ffff1f 07840024 25e0ffff ffff8200 ....$......%.... + 8010384: 01820026 212a7f80 03388100 00088400 &.....*!..8..... + 8010394: 00044040 001b8081 00034481 40000884 @@.......D.....@ + 80103a4: 81000441 81001b80 84000382 41400008 A.............@A + 80103b4: 80810004 8081001b 08840003 04404000 .............@@. + 80103c4: 1b808100 0e808d00 00e88003 e0024740 ............@G.. + 80103d4: 1b800e38 11408d00 00184104 10034144 8.....@..A..DA.. + 80103e4: 1b801144 20388d00 00082288 08024144 D.....8 ."..DA.. + 80103f4: 1b802082 20048d00 00082288 08024144 . ..... ."..DA.. + 8010404: 1b802082 3f028d00 0008e28f 0802414a . .....?....JA.. + 8010414: 1b8020fe 20028d00 00080208 0802812a . ..... ....*... + 8010424: 1b802080 20828d00 00080208 1003812a . ..... ....*... + 8010434: 1b802080 10448d00 00182184 e0020111 . ....D..!...... + 8010444: 1b801142 0f388d00 00e8c003 00020111 B.....8......... + 8010454: 23800e3c 27028100 27028100 27028100 <..#...'...'...' + 8010464: 7f028100 00001147 65737361 64007472 ....G...assert.d + 8010474: 676e776f 65646172 67697300 69616620 owngrade.sig fai + 8010484: 6f6e006c 72696620 7261776d 61460065 l.no firmware.Fa + 8010494: 726f7463 6f622079 5700746f 3a4e5241 ctory boot.WARN: + 80104a4: 64655220 67696c20 57007468 3a4e5241 Red light.WARN: + 80104b4: 736e5520 656e6769 69662064 61776d72 Unsigned firmwa + 80104c4: 47006572 20646f6f 6d726966 65726177 re.Good firmware + 80104d4: 726f6300 74707572 72696620 7261776d .corrupt firmwar + 80104e4: e. + +080104e6 : + 80104e6: 2641cbb4 f36ce1f7 71b4f28f 0123fb1d ..A&..l....q..#. + 80104f6: 66d6760d 6ca38aa7 f6f9539b 0518587b .v.f...l.S..{X.. + 8010506: e93b0b58 b89fc431 113c0444 470f0896 X.;.1...D.<....G + 8010516: 37ed2581 4a9e237a 3818b7af da0438ba .%.7z#.J...8.8.. + 8010526: 1dc8a2d6 df5e811c 6d290ca6 8d8f57b8 ......^...)m.W.. + 8010536: 9269295e c178d1ce 31d7207b b596a17b ^)i...x.{ .1{... + 8010546: 0c1bef3d c31a79aa c8c45845 ffeb2d8a =....y..EX...-.. + 8010556: 01829bfe bc5e5f87 4fe5a596 9ffe68c7 ....._^....O.h.. + 8010566: 0166ef42 95cfc456 38f0b5f4 c5261164 B.f.V......8d.&. + 8010576: 66c13999 14120632 689c254c bad38c35 .9.f2...L%.h5... + 8010586: 8cde7824 6cdfab52 7809bfb8 3a63bb03 $x..R..l...x..c: + 8010596: 0ed90111 8f737aa4 7f3b18bf c87b0af0 .....zs...;...{. + 80105a6: 56546067 c5ec0c82 0882bc1d ef39c116 g`TV..........9. + 80105b6: 32babff5 e35fce7c d7621e74 4cc5fce9 ...2|._.t.b....L + 80105c6: 8d11e88a 13c2adc3 2a4f2992 a4f8d2ea .........)O*.... + 80105d6: fe7cd5c4 3b450512 07598954 88d7d6da ..|...E;T.Y..... + 80105e6: 37cfb143 1f897cd2 f3acfe5b 95fc33ba C..7.|..[....3.. + 80105f6: dde7d981 14ef9525 bb97efdd a7d8f333 ....%.......3... + 8010606: 977a2b34 73aab3ba 32419de7 17a1fcd8 4+z....s..A2.... + 8010616: fe0bb566 89214063 8e7b92c9 590bdf72 f...c@!...{.r..Y + 8010626: 76dc5cd0 30dd3016 56f180c2 61a85c26 .\.v.0.0...V&\.a + 8010636: 69694fd7 3d57b8e5 582ae235 c69acedd .Oii..W=5.*X.... + 8010646: 2b1ca945 8efc010c 13513fbf 137c7e80 E..+.....?Q..~|. + 8010656: 5e4b4fd5 d59b4c9b e0d81d9e 2246c0ad .OK^.L........F" + 8010666: 20314553 666e6f63 66206769 006c6961 SE1 config fail. + 8010676: 72726f63 20747075 72696170 63657320 corrupt pair sec + 8010686: 75636d00 6c756620 7562006c 66206e72 .mcu full.burn f + 8010696: 3a6c6961 76210020 64696c61 6162003f ail: .!valid?.ba + 80106a6: 61762064 66003f6c 20747361 63697262 d val?.fast bric + 80106b6: 2e2e2e6b 64200020 00656e6f 79706f43 k... . done.Copy + 80106c6: 68676972 30322074 202d3831 43207962 right 2018- by C + 80106d6: 6b6e696f 20657469 2e636e49 206f6e00 oinkite Inc..no + 80106e6: 00726573 66206b77 0016006c 01410800 ser.wk fl.....A. + ... + 8010702: 000000ee 006100e1 218f0000 438f808f ......a....!...C + 8010712: 430080af 20834300 43c343c3 43c343c3 ...C.C. .C.C.C.C + 8010722: 43c343c3 0000438f ffffffff 00000000 .C.C.C.......... + 8010732: ffffffff 00000000 00000000 000000f0 ................ + ... + 801074a: 00001502 003c0000 01bc005c 01bc01fc ......<.\....... + 801075a: 01dc01dc 03dc03d1 03dc03dc 03dc03dc ................ + 801076a: 01dc03dc 0001003c 00120000 00000000 ....<........... + 801077a: 00010000 00080000 02000000 00020000 ................ + 801078a: 00000000 00010000 00070000 .............. + +08010798 : + 8010798: 0d0c0b09 .... + +0801079c : + 801079c: 2e312e31 69742030 323d656d 30353230 1.1.0 time=20250 + 80107ac: 2e353134 36333930 67203133 6d3d7469 415.093631 git=m + 80107bc: 65747361 38324072 61363239 0d006463 aster@28926acd.. + 80107cc: .. + +080107ce : + 80107ce: 33323130 37363534 62613938 66656463 0123456789abcdef + 80107de: 41525350 6166204d 50006c69 203a5253 PSRAM fail.PSR: + 80107ee: 6164616e 52535000 6321203a 6b636568 nada.PSR: !check + 80107fe: 52535000 6576203a 6f697372 fc00006e .PSR: version... + 801080e: 00020000 00000000 00030000 000a0000 ................ + 801081e: 00080000 00100000 6f6c0000 7220676e ..........long r + 801082e: 20646165 6c696166 55464400 72617020 ead fail.DFU par + 801083e: 66206573 006c6961 646f6f67 72696620 se fail.good fir + 801084e: 7261776d 72770065 20676e6f 6c726f77 mware.wrong worl + 801085e: 64730064 64726163 6165735f 3a686372 d.sdcard_search: + 801086e: 64730020 64726163 6f72705f 203a6562 .sdcard_probe: + 801087e: 696e6900 61662074 73006c69 64656570 .init fail.speed + 801088e: 64697700 73620065 3f657a69 006b6f00 .wide.bsize?.ok. + 801089e: 6c696166 61657220 66440064 00655375 fail read.DfuSe. + 80108ae: 6e756f66 20402064 63655200 7265766f found @ .Recover + 80108be: 6f6d2079 002e6564 1f000000 00020000 y mode.......... + 80108ce: 00010000 00030000 000c0000 00040000 ................ + 80108de: 00020000 00010000 00030000 000c0000 ................ + ... + +080108f0 : + 80108f0: 01002008 fffffc2f fffffffe ffffffff . ../........... + 8010900: ffffffff ffffffff ffffffff ffffffff ................ + 8010910: ffffffff d0364141 bfd25e8c af48a03b ....AA6..^..;.H. + 8010920: baaedce6 fffffffe ffffffff ffffffff ................ + 8010930: ffffffff 16f81798 59f2815b 2dce28d9 ........[..Y.(.- + 8010940: 029bfcdb ce870b07 55a06295 f9dcbbac .........b.U.... + 8010950: 79be667e fb10d4b8 9c47d08f a6855419 ~f.y......G..T.. + 8010960: fd17b448 0e1108a8 5da4fbfc 26a3c465 H..........]e..& + 8010970: 483ada77 00000007 00000000 00000000 w.:H............ + ... + 8010994: 0800692d 080061b1 08006387 08005f9d -i...a...c..._.. + +080109a4 : + 80109a4: 01002008 ffffffff ffffffff ffffffff . .............. + ... + 80109c0: 00000001 ffffffff fc632551 f3b9cac2 ........Q%c..... + 80109d0: a7179e84 bce6faad ffffffff ffffffff ................ + 80109e0: 00000000 ffffffff d898c296 f4a13945 ............E9.. + 80109f0: 2deb33a0 77037d81 63a440f2 f8bce6e5 .3.-.}.w.@.c.... + 8010a00: e12c4247 6b17d1f2 37bf51f5 cbb64068 GB,....k.Q.7h@.. + 8010a10: 6b315ece 2bce3357 7c0f9e16 8ee7eb4a .^1kW3.+...|J... + 8010a20: fe1a7f9b 4fe342e2 27d2604b 3bce3c3e .....B.OK`.'><.; + 8010a30: cc53b0f6 651d06b0 769886bc b3ebbd55 ..S....e...vU... + 8010a40: aa3a93e7 5ac635d8 08006a75 080061b1 ..:..5.Zuj...a.. + 8010a50: 08006a1b 08006019 .j...`.. + +08010a58 : + ... + 8010a60: 04030201 09080706 ........ + +08010a68 : + 8010a68: 00000000 04030201 ........ + +08010a70 : + 8010a70: 000186a0 00030d40 00061a80 000c3500 ....@........5.. + 8010a80: 000f4240 001e8480 003d0900 007a1200 @B........=...z. + 8010a90: 00f42400 016e3600 01e84800 02dc6c00 .$...6n..H...l.. + 8010aa0: 20727463 3f746573 00702100 00006000 ctr set?.!p..`.. + 8010ab0: 00000012 00000000 00000003 00000004 ................ + +08010ac0 : + 8010ac0: 00008000 .... + +Disassembly of section .relocate: + +2009e000 : +{ +2009e000: b530 push {r4, r5, lr} + while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)) { +2009e002: 4920 ldr r1, [pc, #128] ; (2009e084 ) +2009e004: 690c ldr r4, [r1, #16] +2009e006: 03e5 lsls r5, r4, #15 +2009e008: d4fc bmi.n 2009e004 + uint32_t error = (FLASH->SR & FLASH_FLAG_SR_ERRORS); +2009e00a: 690d ldr r5, [r1, #16] + if(error) { +2009e00c: 4c1e ldr r4, [pc, #120] ; (2009e088 ) +2009e00e: 4225 tst r5, r4 +2009e010: d104 bne.n 2009e01c + if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP)) { +2009e012: 690c ldr r4, [r1, #16] +2009e014: 07e4 lsls r4, r4, #31 + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP); +2009e016: bf44 itt mi +2009e018: 2401 movmi r4, #1 +2009e01a: 610c strmi r4, [r1, #16] + FLASH->SR = FLASH->SR & FLASH_FLAG_SR_ERRORS; +2009e01c: 4919 ldr r1, [pc, #100] ; (2009e084 ) +2009e01e: 4d1a ldr r5, [pc, #104] ; (2009e088 ) +2009e020: 690c ldr r4, [r1, #16] +2009e022: 402c ands r4, r5 +2009e024: 610c str r4, [r1, #16] + __HAL_FLASH_DATA_CACHE_DISABLE(); +2009e026: 680c ldr r4, [r1, #0] +2009e028: f424 6480 bic.w r4, r4, #1024 ; 0x400 +2009e02c: 600c str r4, [r1, #0] + CLEAR_BIT(FLASH->CR, (FLASH_CR_PG | FLASH_CR_MER1 | FLASH_CR_PER | FLASH_CR_PNB)); // added +2009e02e: 694c ldr r4, [r1, #20] +2009e030: f424 64ff bic.w r4, r4, #2040 ; 0x7f8 +2009e034: f024 0407 bic.w r4, r4, #7 +2009e038: 614c str r4, [r1, #20] + SET_BIT(FLASH->CR, FLASH_CR_PG); +2009e03a: 694c ldr r4, [r1, #20] +2009e03c: f044 0401 orr.w r4, r4, #1 +2009e040: 614c str r4, [r1, #20] + *(__IO uint32_t *)(address) = (uint32_t)val; +2009e042: 6002 str r2, [r0, #0] + __ASM volatile ("isb 0xF":::"memory"); +2009e044: f3bf 8f6f isb sy + *(__IO uint32_t *)(address+4) = (uint32_t)(val >> 32); +2009e048: 6043 str r3, [r0, #4] + while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)) { +2009e04a: 690b ldr r3, [r1, #16] +2009e04c: 03da lsls r2, r3, #15 +2009e04e: d4fc bmi.n 2009e04a + uint32_t error = (FLASH->SR & FLASH_FLAG_SR_ERRORS); +2009e050: 6908 ldr r0, [r1, #16] + if(error) { +2009e052: 4028 ands r0, r5 +2009e054: d104 bne.n 2009e060 + if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP)) { +2009e056: 690b ldr r3, [r1, #16] +2009e058: 07db lsls r3, r3, #31 + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP); +2009e05a: bf44 itt mi +2009e05c: 2301 movmi r3, #1 +2009e05e: 610b strmi r3, [r1, #16] + CLEAR_BIT(FLASH->CR, FLASH_CR_PG); +2009e060: 4b08 ldr r3, [pc, #32] ; (2009e084 ) +2009e062: 695a ldr r2, [r3, #20] +2009e064: f022 0201 bic.w r2, r2, #1 +2009e068: 615a str r2, [r3, #20] + __HAL_FLASH_DATA_CACHE_RESET(); +2009e06a: 681a ldr r2, [r3, #0] +2009e06c: f442 5280 orr.w r2, r2, #4096 ; 0x1000 +2009e070: 601a str r2, [r3, #0] +2009e072: 681a ldr r2, [r3, #0] +2009e074: f422 5280 bic.w r2, r2, #4096 ; 0x1000 +2009e078: 601a str r2, [r3, #0] + __HAL_FLASH_DATA_CACHE_ENABLE(); +2009e07a: 681a ldr r2, [r3, #0] +2009e07c: f442 6280 orr.w r2, r2, #1024 ; 0x400 +2009e080: 601a str r2, [r3, #0] +} +2009e082: bd30 pop {r4, r5, pc} +2009e084: 40022000 .word 0x40022000 +2009e088: 0002c3fa .word 0x0002c3fa + +2009e08c : + if(page_num < ((BL_FLASH_SIZE + BL_NVROM_SIZE) / FLASH_ERASE_SIZE)) { +2009e08c: 4b2d ldr r3, [pc, #180] ; (2009e144 ) +2009e08e: 4003 ands r3, r0 +{ +2009e090: b510 push {r4, lr} + if(page_num < ((BL_FLASH_SIZE + BL_NVROM_SIZE) / FLASH_ERASE_SIZE)) { +2009e092: 2b00 cmp r3, #0 +2009e094: d054 beq.n 2009e140 + while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)) { +2009e096: 4b2c ldr r3, [pc, #176] ; (2009e148 ) + page_num &= 0xff; +2009e098: f3c0 3207 ubfx r2, r0, #12, #8 + while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)) { +2009e09c: 6919 ldr r1, [r3, #16] +2009e09e: 03c9 lsls r1, r1, #15 +2009e0a0: d4fc bmi.n 2009e09c + uint32_t error = (FLASH->SR & FLASH_FLAG_SR_ERRORS); +2009e0a2: 691c ldr r4, [r3, #16] + if(error) { +2009e0a4: 4929 ldr r1, [pc, #164] ; (2009e14c ) +2009e0a6: 420c tst r4, r1 +2009e0a8: d104 bne.n 2009e0b4 + if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP)) { +2009e0aa: 6919 ldr r1, [r3, #16] +2009e0ac: 07cc lsls r4, r1, #31 + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP); +2009e0ae: bf44 itt mi +2009e0b0: 2101 movmi r1, #1 +2009e0b2: 6119 strmi r1, [r3, #16] + FLASH->SR = FLASH->SR & 0xffff; +2009e0b4: 4b24 ldr r3, [pc, #144] ; (2009e148 ) +2009e0b6: 6919 ldr r1, [r3, #16] +2009e0b8: b289 uxth r1, r1 +2009e0ba: 6119 str r1, [r3, #16] + __HAL_FLASH_DATA_CACHE_DISABLE(); +2009e0bc: 6819 ldr r1, [r3, #0] +2009e0be: f421 6180 bic.w r1, r1, #1024 ; 0x400 +2009e0c2: 6019 str r1, [r3, #0] + SET_BIT(FLASH->CR, FLASH_CR_BKER); +2009e0c4: 6959 ldr r1, [r3, #20] + if(bank2) { +2009e0c6: f010 6ffe tst.w r0, #133169152 ; 0x7f00000 + SET_BIT(FLASH->CR, FLASH_CR_BKER); +2009e0ca: bf14 ite ne +2009e0cc: f441 6100 orrne.w r1, r1, #2048 ; 0x800 + CLEAR_BIT(FLASH->CR, FLASH_CR_BKER); +2009e0d0: f421 6100 biceq.w r1, r1, #2048 ; 0x800 +2009e0d4: 6159 str r1, [r3, #20] + MODIFY_REG(FLASH->CR, FLASH_CR_PNB, (page_num << POSITION_VAL(FLASH_CR_PNB))); +2009e0d6: 6959 ldr r1, [r3, #20] + uint32_t result; + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) + __ASM volatile ("rbit %0, %1" : "=r" (result) : "r" (value) ); +2009e0d8: f44f 63ff mov.w r3, #2040 ; 0x7f8 +2009e0dc: f421 61ff bic.w r1, r1, #2040 ; 0x7f8 +2009e0e0: fa93 f3a3 rbit r3, r3 + */ + if (value == 0U) + { + return 32U; + } + return __builtin_clz(value); +2009e0e4: fab3 f383 clz r3, r3 +2009e0e8: 409a lsls r2, r3 +2009e0ea: 4b17 ldr r3, [pc, #92] ; (2009e148 ) +2009e0ec: 430a orrs r2, r1 +2009e0ee: 615a str r2, [r3, #20] + SET_BIT(FLASH->CR, FLASH_CR_PER); +2009e0f0: 695a ldr r2, [r3, #20] +2009e0f2: f042 0202 orr.w r2, r2, #2 +2009e0f6: 615a str r2, [r3, #20] + SET_BIT(FLASH->CR, FLASH_CR_STRT); +2009e0f8: 695a ldr r2, [r3, #20] +2009e0fa: f442 3280 orr.w r2, r2, #65536 ; 0x10000 +2009e0fe: 615a str r2, [r3, #20] + while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)) { +2009e100: 691a ldr r2, [r3, #16] +2009e102: 03d1 lsls r1, r2, #15 +2009e104: d4fc bmi.n 2009e100 + uint32_t error = (FLASH->SR & FLASH_FLAG_SR_ERRORS); +2009e106: 6918 ldr r0, [r3, #16] +2009e108: 4a10 ldr r2, [pc, #64] ; (2009e14c ) + if(error) { +2009e10a: 4010 ands r0, r2 +2009e10c: d104 bne.n 2009e118 + if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP)) { +2009e10e: 691a ldr r2, [r3, #16] +2009e110: 07d2 lsls r2, r2, #31 + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP); +2009e112: bf44 itt mi +2009e114: 2201 movmi r2, #1 +2009e116: 611a strmi r2, [r3, #16] + CLEAR_BIT(FLASH->CR, (FLASH_CR_PER | FLASH_CR_PNB)); +2009e118: 4b0b ldr r3, [pc, #44] ; (2009e148 ) +2009e11a: 695a ldr r2, [r3, #20] +2009e11c: f422 62ff bic.w r2, r2, #2040 ; 0x7f8 +2009e120: f022 0202 bic.w r2, r2, #2 +2009e124: 615a str r2, [r3, #20] + __HAL_FLASH_DATA_CACHE_RESET(); +2009e126: 681a ldr r2, [r3, #0] +2009e128: f442 5280 orr.w r2, r2, #4096 ; 0x1000 +2009e12c: 601a str r2, [r3, #0] +2009e12e: 681a ldr r2, [r3, #0] +2009e130: f422 5280 bic.w r2, r2, #4096 ; 0x1000 +2009e134: 601a str r2, [r3, #0] + __HAL_FLASH_DATA_CACHE_ENABLE(); +2009e136: 681a ldr r2, [r3, #0] +2009e138: f442 6280 orr.w r2, r2, #1024 ; 0x400 +2009e13c: 601a str r2, [r3, #0] +} +2009e13e: bd10 pop {r4, pc} + return 1; +2009e140: 2001 movs r0, #1 +2009e142: e7fc b.n 2009e13e +2009e144: 07fe0000 .word 0x07fe0000 +2009e148: 40022000 .word 0x40022000 +2009e14c: 0002c3fa .word 0x0002c3fa diff --git a/stm32/q1-bootloader/releases/README.md b/stm32/q1-bootloader/releases/README.md index 54dbd3c7..31ae9f0e 100644 --- a/stm32/q1-bootloader/releases/README.md +++ b/stm32/q1-bootloader/releases/README.md @@ -13,3 +13,4 @@ Github is nearly free, so why not capture all the actual bits! - V1.0.2 - bugfix w/ power btn release - V1.0.3 - bugfix to allow (mpy) version numbers < 3.0.0 - V1.0.4 - cleanups and such; final version for first-run of boards. +- V1.1.0 - enable omitted if wrong PIN options & fix "Wipe -> Wallet" trick pin option diff --git a/stm32/q1-bootloader/version.h b/stm32/q1-bootloader/version.h index 6e834330..b6f098a4 100644 --- a/stm32/q1-bootloader/version.h +++ b/stm32/q1-bootloader/version.h @@ -6,7 +6,7 @@ // Public version number for humans. Lots more version data added by Makefile. // - update ../Q1-Makefile BOOTLOADER_VERSION once this is qualified version -#define RELEASE_VERSION "1.0.4" +#define RELEASE_VERSION "1.1.0" extern const char version_string[]; diff --git a/testing/api.py b/testing/api.py index b8bfe1e8..58d7db70 100644 --- a/testing/api.py +++ b/testing/api.py @@ -11,6 +11,10 @@ from ckcc.protocol import CCProtocolPacker def find_bitcoind(): # search for the binary we need # - should be in the path really + env_path = os.environ.get("CC_TEST_BITCOIND", None) + if env_path: + return env_path + easy = shutil.which('bitcoind') if easy: return easy @@ -33,6 +37,7 @@ class Bitcoind: self.userpass = None self.supply_wallet = None self.has_bdb = True + self.version = None def start(self): @@ -51,14 +56,17 @@ class Bitcoind: [ self.bitcoind_path, # needed for newest master - # TODO legacy wallet will be deprecated in 26 + # legacy wallet was deprecated in v29 + # and removed completely in v30 "-deprecatedrpc=create_bdb", "-regtest", f"-datadir={self.datadir}", "-noprinttoconsole", "-fallbackfee=0.0002", "-server=1", + "-listen=0", "-keypool=1", + "-listen=0" f"-port={self.p2p_port}", f"-rpcport={self.rpc_port}" ] @@ -68,8 +76,9 @@ class Bitcoind: # Wait for cookie file to be created cookie_path = os.path.join(self.datadir, "regtest", ".cookie") for i in range(20): - if not os.path.exists(cookie_path): - time.sleep(0.5) + if os.path.exists(cookie_path): + break + time.sleep(0.5) else: RuntimeError("'.cookie' not found. Is bitcoind running?") # Read .cookie file to get user and pass @@ -89,12 +98,14 @@ class Bitcoind: pass assert self.rpc.getblockchaininfo()['chain'] == 'regtest' - assert self.rpc.getnetworkinfo()['version'] >= 220000, "we require >= 22.0 of Core" + self.version = self.rpc.getnetworkinfo()['version'] + assert self.version >= 220000, "we require >= 22.0 of Core" # not descriptors so that we can do dumpwallet try: self.supply_wallet = self.create_wallet(wallet_name="supply", descriptors=False) except JSONRPCException as e: - assert "BDB wallet creation is deprecated" in str(e) + assert "BDB wallet creation is deprecated" in str(e) \ + or "no longer possible to create a legacy wallet" in str(e) # before v30.0 vs v30.0+ self.has_bdb = False self.supply_wallet = self.create_wallet(wallet_name="supply", descriptors=True) @@ -170,8 +181,9 @@ def match_key(bitcoind, set_master_key, reset_seed_words): os.unlink(fn) except JSONRPCException as e: - print(str(e)) - assert "Only legacy wallets are supported by this command" in str(e) + assert "Only legacy wallets are supported by this command" in str(e) \ + or "Method not found" in str(e) # v30.0 + prv_descs = bitcoind.supply_wallet.listdescriptors(True) # True --> show private prv = prv_descs["descriptors"][0]["desc"].replace("pkh(", "").split("/")[0] diff --git a/testing/bip32.py b/testing/bip32.py index d52867dc..57899a39 100644 --- a/testing/bip32.py +++ b/testing/bip32.py @@ -781,5 +781,9 @@ class BIP32Node: def chain_code(self): return self.node.chain_code + def privkey(self): + assert isinstance(self.node, PrvKeyNode) + return bytes(self.node.private_key) + def parent_fingerprint(self): return self.node.parent_fingerprint diff --git a/testing/clone_tests.py b/testing/clone_tests.py index 5f423ec0..f2562cab 100644 --- a/testing/clone_tests.py +++ b/testing/clone_tests.py @@ -5,7 +5,7 @@ from charcodes import KEY_ENTER from core_fixtures import _pick_menu_item, _cap_story, _press_select from core_fixtures import _need_keypress, _cap_menu, _sim_exec from run_sim_tests import ColdcardSimulator, clean_sim_data -from ckcc_protocol.client import ColdcardDevice, CKCC_SIMULATOR_PATH +from ckcc_protocol.client import ColdcardDevice def _clone(source, target): @@ -18,7 +18,7 @@ def _clone(source, target): clean_sim_data() # remove all from previous sim_target = ColdcardSimulator(args=[target_sim_arg, "-l"]) sim_target.start(start_wait=6) - device = ColdcardDevice(sn=CKCC_SIMULATOR_PATH) + device = ColdcardDevice(is_simulator=True) _pick_menu_item(device, target_is_Q, "Import Existing") _pick_menu_item(device, target_is_Q, "Clone Coldcard") time.sleep(.1) @@ -32,11 +32,11 @@ def _clone(source, target): assert f"Bring that card back and press {'ENTER' if target_is_Q else 'OK'} to complete clone process" in story # SOURCE - # clone with multisig wallet + # clone with miniscript wallet sim_source = ColdcardSimulator(args=[source_sim_arg, "--ms", "--p2wsh", "--set", "nfc=1", "--set", "vidsk=1"]) sim_source.start(start_wait=6) - device_source = ColdcardDevice(sn=CKCC_SIMULATOR_PATH) + device_source = ColdcardDevice(is_simulator=True) _pick_menu_item(device_source, source_is_Q, "Advanced/Tools") time.sleep(.1) _pick_menu_item(device_source, source_is_Q, "Backup") @@ -89,12 +89,12 @@ def _clone(source, target): # TARGET again. Killed now - restart and verify settings sim_target = ColdcardSimulator(args=[target_sim_arg]) sim_target.start(start_wait=6) - device = ColdcardDevice(sn=CKCC_SIMULATOR_PATH) + device = ColdcardDevice(is_simulator=True) _pick_menu_item(device, target_is_Q, "Settings") - _pick_menu_item(device, target_is_Q, "Multisig Wallets") + _pick_menu_item(device, target_is_Q, "Miniscript") time.sleep(.1) m = _cap_menu(device) - assert "2/4: P2WSH--2-of-4" in m + assert "P2WSH--2-of-4" in m # check NFC/VDisk after clone - must be disabled # USB enabled as we are on the simulator diff --git a/testing/conftest.py b/testing/conftest.py index 980bd869..fa6555d3 100644 --- a/testing/conftest.py +++ b/testing/conftest.py @@ -1,6 +1,6 @@ # (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # -import pytest, time, sys, random, re, ndef, os, glob, hashlib, json, functools, io, math, bech32, pdb +import pytest, time, sys, random, re, ndef, os, glob, hashlib, json, functools, io, math, bech32, pdb, base64 from subprocess import check_output from ckcc.protocol import CCProtocolPacker from helpers import B2A, U2SAT, hash160, taptweak, addr_from_display_format @@ -13,13 +13,15 @@ from api import bitcoind_d_sim_watch, finalize_v2_v0_convert from binascii import b2a_hex, a2b_hex from constants import * from charcodes import * -from core_fixtures import _need_keypress, _sim_exec, _cap_story, _cap_menu, _cap_screen +from core_fixtures import _need_keypress, _sim_exec, _cap_story, _cap_menu, _cap_screen, _sim_eval from core_fixtures import _press_select, _pick_menu_item, _enter_complex, _dev_hw_label # lock down randomness random.seed(42) +# needs to be run from /testing directory +os.environ["SRC_ROOT"] = os.path.join(os.getcwd().rsplit("/", 1)[0]) if sys.platform == 'darwin': # BUGFIX: my ARM-based MacOS system uses rosetta to run Python in x86 mode # and so I needed this? @@ -31,10 +33,13 @@ def pytest_addoption(parser): default=False, help="run on real dev") parser.addoption("--sim", action="store_true", default=True, help="run on simulator") + parser.addoption("--localhost", action="store_true", + default=False, help="test web stuff against coldcard.com code running on localhost:5070") parser.addoption("--manual", action="store_true", default=False, help="operator must press keys on real CC") parser.addoption("--mk", default=4, help="Assume mark N hardware") + parser.addoption("--sim-socket", "-S", type=str, help="Simulator .socket path", default=None) parser.addoption("--duress", action="store_true", default=False, help="assume logged-in with duress PIN") @@ -77,48 +82,42 @@ def simulator(request): raise pytest.skip('need simulator for this test, have real device') try: - return ColdcardDevice(sn=SIM_PATH) - except: + return ColdcardDevice(sn=request.config.getoption("--sim-socket"), is_simulator=True) + except Exception as e: print("Simulator is required for this test") raise pytest.fail('missing simulator') -@pytest.fixture(scope='module') +@pytest.fixture def sim_exec(dev): - # run code in the simulator's interpretor + # run code in the simulator's interpreter # - can work on real product too, if "debug build" is used. f = functools.partial(_sim_exec, dev) return f -@pytest.fixture(scope='module') +@pytest.fixture def sim_eval(dev): # eval an expression in the simulator's interpretor # - can work on real product too, if "debug build" is used. + f = functools.partial(_sim_eval, dev) + return f - def doit(cmd, timeout=None): - return dev.send_recv(b'EVAL' + cmd.encode('utf-8'), timeout=timeout).decode('utf-8') - - return doit - -@pytest.fixture(scope='module') -def sim_execfile(simulator): +@pytest.fixture +def sim_execfile(simulator, src_root_dir): # run a whole file in the simulator's interpretor # - requires shared filesystem - import os - def doit(fname, timeout=None): - fn = os.path.realpath(fname) - hook = 'execfile("%s")' % fn + hook = 'execfile("%s")' % (src_root_dir + "/testing/" + fname) return simulator.send_recv(b'EXEC' + hook.encode('utf-8'), timeout=timeout).decode('utf-8') return doit -@pytest.fixture(scope='module') +@pytest.fixture def is_simulator(dev): def doit(): return hasattr(dev.dev, 'pipe') return doit -@pytest.fixture(scope='module') +@pytest.fixture def send_ux_abort(simulator): def doit(): @@ -136,7 +135,7 @@ def OK(is_q1): def X(is_q1): return "CANCEL" if is_q1 else "X" -@pytest.fixture(scope='module') +@pytest.fixture def need_keypress(dev, request): def doit(k, timeout=1000): if request.config.getoption("--manual"): @@ -150,7 +149,7 @@ def need_keypress(dev, request): return doit -@pytest.fixture(scope='module') +@pytest.fixture def enter_number(need_keypress, press_select): def doit(number): number = str(number) if not isinstance(number, str) else number @@ -168,7 +167,7 @@ def enter_complex(dev, is_q1): f = functools.partial(_enter_complex, dev, is_q1) return f -@pytest.fixture(scope='module') +@pytest.fixture def enter_hex(need_keypress, enter_text, is_q1): def doit(hex_str): if is_q1: @@ -183,7 +182,7 @@ def enter_hex(need_keypress, enter_text, is_q1): return doit -@pytest.fixture(scope='module') +@pytest.fixture def enter_pin(enter_number, press_select, cap_screen, is_q1): def doit(pin): assert '-' in pin @@ -205,7 +204,7 @@ def enter_pin(enter_number, press_select, cap_screen, is_q1): return doit -@pytest.fixture(scope='module') +@pytest.fixture def do_keypresses(need_keypress): # do a series of keypresses, any kind def doit(value): @@ -215,7 +214,7 @@ def do_keypresses(need_keypress): return doit -@pytest.fixture(scope='module') +@pytest.fixture def enter_text(need_keypress, is_q1): # enter a text value, might be a number or string ... on Q can be multiline def doit(value, multiline=False): @@ -258,14 +257,14 @@ def master_xpub(dev): return r -@pytest.fixture(scope='module') +@pytest.fixture def unit_test(sim_execfile): def doit(filename): rv = sim_execfile(filename) if rv: pytest.fail(rv) return doit -@pytest.fixture(scope='module') +@pytest.fixture def get_settings(sim_execfile): # get all settings def doit(): @@ -276,7 +275,7 @@ def get_settings(sim_execfile): return doit -@pytest.fixture(scope='module') +@pytest.fixture def get_setting(sim_execfile, sim_exec): # get an individual setting def doit(name, default=None): @@ -288,15 +287,15 @@ def get_setting(sim_execfile, sim_exec): return doit -@pytest.fixture(scope='module') +@pytest.fixture def addr_vs_path(master_xpub): - from bip32 import BIP32Node - from ckcc_protocol.constants import AF_CLASSIC, AFC_PUBKEY, AF_P2WPKH, AFC_SCRIPT - from ckcc_protocol.constants import AF_P2WPKH_P2SH, AF_P2SH, AF_P2WSH, AF_P2WSH_P2SH - from bech32 import bech32_decode, convertbits, decode, Encoding - from hashlib import sha256 - def doit(given_addr, path=None, addr_fmt=None, script=None, chain="XTN"): + from bip32 import BIP32Node + from ckcc_protocol.constants import AF_CLASSIC, AFC_PUBKEY, AF_P2WPKH, AFC_SCRIPT + from ckcc_protocol.constants import AF_P2WPKH_P2SH, AF_P2SH, AF_P2WSH, AF_P2WSH_P2SH + from bech32 import bech32_decode, convertbits, decode, Encoding + from hashlib import sha256 + if not script: try: # prefer using xpub if we can @@ -370,13 +369,13 @@ def capture_enabled(sim_eval): # - could be xfail or xskip here assert sim_eval("'sim_display' in sys.modules") == 'True' -@pytest.fixture(scope='module') +@pytest.fixture def cap_menu(dev): "Return menu items as a list" f = functools.partial(_cap_menu, dev) return f -@pytest.fixture(scope='module') +@pytest.fixture def is_ftux_screen(sim_exec): "are we presenting a view from ftux.py??" def doit(): @@ -403,12 +402,12 @@ def expect_ftux(cap_menu, cap_story, press_select, is_ftux_screen): return doit -@pytest.fixture(scope='module') +@pytest.fixture def cap_screen(dev): f = functools.partial(_cap_screen, dev) return f -@pytest.fixture(scope='module') +@pytest.fixture def cap_text_box(cap_screen): # provides text inside a lined box on the screen right now - Q1 only def doit(): @@ -424,15 +423,15 @@ def cap_text_box(cap_screen): return doit -@pytest.fixture(scope='module') +@pytest.fixture def cap_story(dev): # returns (title, body) of whatever story is being actively shown f = functools.partial(_cap_story, dev) return f -@pytest.fixture(scope='module') -def cap_image(request, sim_exec, is_q1, is_headless): +@pytest.fixture +def cap_image(request, sim_exec, is_q1, is_headless, sim_root_dir): def flip(raw): reorg = bytearray(128*64) @@ -452,7 +451,7 @@ def cap_image(request, sim_exec, is_q1, is_headless): if is_headless: raise pytest.skip("headless mode: QR tests disabled") # trigger simulator to capture a snapshot into a named file, read it. - fn = os.path.realpath(f'./debug/snap-{random.randint(int(1E6), int(9E6))}.png') + fn = os.path.realpath(f'{sim_root_dir}/debug/snap-{random.randint(int(1E6), int(9E6))}.png') try: sim_exec(f"from glob import dis; dis.dis.save_snapshot({fn!r})") for _ in range(20): @@ -481,7 +480,7 @@ RV.write(b2a_hex(dis.dis.buffer))''')) QR_HISTORY = [] @pytest.fixture(scope='session') -def qr_quality_check(): +def qr_quality_check(sim_root_dir): # Use this with cap_screen_qr print("QR codes will be captured and shown at end of run.") yield None @@ -530,13 +529,13 @@ def qr_quality_check(): #rv = rv.resize(tuple(c*4 for c in rv.size), resample=Image.NEAREST) - rv.save('debug/all-qrs.png') + rv.save(f'{sim_root_dir}/debug/all-qrs.png') rv.show() -@pytest.fixture(scope='module') -def cap_screen_qr(cap_image): +@pytest.fixture +def cap_screen_qr(cap_image, sim_root_dir): def doit(no_history=False): # NOTE: version=4 QR is pixel doubled to be 66x66 with 2 missing lines at bottom # LATER: not doing that anymore; v={1,2,3} doubled, all higher 1:1 pixels (tiny) @@ -571,7 +570,7 @@ def cap_screen_qr(cap_image): w, h = orig_img.size # 320x240 img = orig_img.crop( (0, 0, w, h-5) ).convert('L') - img.save('debug/last-qr.png') + img.save(f'{sim_root_dir}/debug/last-qr.png') #img.show() # Above usually works @ zoom=1, but not always! @@ -601,9 +600,15 @@ def verify_qr_address(cap_screen_qr, cap_screen, is_q1): # plus text version of address, if any, is right. from ckcc_protocol.constants import AFC_BECH32 - def doit(addr_fmt, expect_addr=None): + def doit(addr_fmt, expect_addr=None, is_change=None): qr = cap_screen_qr().decode('ascii') + if isinstance(addr_fmt, str): + try: + addr_fmt = unmap_addr_fmt[addr_fmt] + except KeyError: + addr_fmt = msg_sign_unmap_addr_fmt[addr_fmt] + if (addr_fmt & AFC_BECH32) or (addr_fmt & AFC_BECH32M): qr = qr.lower() @@ -613,10 +618,36 @@ def verify_qr_address(cap_screen_qr, cap_screen, is_q1): # - skips first line, which on Q shows the index number sometimes # - insists on some spaces full = cap_screen() + full_split = full.split("\n") if is_q1: - txt = ''.join(full.split()[2:]).replace('~', '') + if is_change: + for i, (c, line) in enumerate(zip("XXXXCHANGE", full_split)): + if i > 3: + assert line.startswith(c) + else: + assert not line.startswith(c) + + for i, (c, line) in enumerate(zip("XXXXXXBACK", full_split)): + if i > 5: + assert line.endswith(c) + else: + assert not line.endswith(c) + + elif is_change is False: + for c, line in zip("XXXXCHANGE", full_split): + assert not line.startswith(c) + + for c, line in zip("XXXXXXBACK", full_split): + assert not line.endswith(c) + + txt = None # most of the time there is no address else: - txt = ''.join(full.split()) + if is_change: + assert "CHANGE BACK" in full + elif is_change is False: + assert "CHANGE BACK" not in full + + txt = ''.join(full_split).replace('CHANGE BACK', '') if txt: assert txt == qr @@ -631,7 +662,7 @@ def verify_qr_address(cap_screen_qr, cap_screen, is_q1): return doit -@pytest.fixture(scope='module') +@pytest.fixture def get_pp_sofar(sim_exec): # get entry value for bip39 passphrase def doit(): @@ -641,7 +672,7 @@ def get_pp_sofar(sim_exec): return doit -@pytest.fixture(scope='module') +@pytest.fixture def get_secrets(sim_execfile): # returns big dict based on what we'd normally put into a backup file. def doit(): @@ -667,48 +698,48 @@ def clear_miniscript(unit_test): unit_test('devtest/wipe_miniscript.py') return doit -@pytest.fixture(scope='module') +@pytest.fixture def press_select(dev, has_qwerty): f = functools.partial(_press_select, dev, has_qwerty) return f -@pytest.fixture(scope='module') +@pytest.fixture def press_cancel(need_keypress, has_qwerty): def doit(**kws): need_keypress(KEY_CANCEL if has_qwerty else 'x', **kws) return doit -@pytest.fixture(scope='module') +@pytest.fixture def press_delete(need_keypress, has_qwerty): def doit(**kws): need_keypress(KEY_DELETE if has_qwerty else 'x', **kws) return doit -@pytest.fixture(scope='module') +@pytest.fixture def press_nfc(need_keypress, has_qwerty): def doit(num=3, **kws): need_keypress(KEY_NFC if has_qwerty else str(num), **kws) return doit -@pytest.fixture(scope='module') +@pytest.fixture def press_up(need_keypress, has_qwerty): def doit(**kws): need_keypress(KEY_UP if has_qwerty else "5", **kws) return doit -@pytest.fixture(scope='module') +@pytest.fixture def press_down(need_keypress, has_qwerty): def doit(**kws): need_keypress(KEY_DOWN if has_qwerty else "8", **kws) return doit -@pytest.fixture(scope='module') +@pytest.fixture def press_left(need_keypress, has_qwerty): def doit(**kws): need_keypress(KEY_LEFT if has_qwerty else "7", **kws) return doit -@pytest.fixture(scope='module') +@pytest.fixture def press_right(need_keypress, has_qwerty): def doit(**kws): need_keypress(KEY_RIGHT if has_qwerty else "9", **kws) @@ -750,24 +781,37 @@ def goto_home(cap_menu, press_cancel, press_select, pick_menu_item, cap_screen): return doit -@pytest.fixture(scope="module") +@pytest.fixture def pick_menu_item(dev, has_qwerty): f = functools.partial(_pick_menu_item, dev, has_qwerty) return f -@pytest.fixture(scope='module') -def virtdisk_path(request, is_simulator, needs_virtdisk): +@pytest.fixture(scope='session') +def src_root_dir(): + return os.environ.get("SRC_ROOT") + +@pytest.fixture(scope='session') +def sim_root_dir(dev, request, src_root_dir): + if request.config.getoption("--dev"): + return os.path.join(src_root_dir, "unix/work") + + cmd = f"import ckcc; RV.write(ckcc.get_sim_root_dirs()[0])" + rv = _sim_exec(dev, cmd) + return rv + +@pytest.fixture +def virtdisk_path(request, is_simulator, needs_virtdisk, sim_root_dir): # get a path to indicated filename on emulated/shared dir def doit(fn): - # could use: ckcc.get_sim_root_dirs() here if is_simulator(): get_setting = request.getfixturevalue('get_setting') if not get_setting('vidsk', False): raise pytest.xfail('virtdisk disabled') - assert os.path.isdir('../unix/work/VirtDisk') - return '../unix/work/VirtDisk/' + fn + + return sim_root_dir + '/VirtDisk/' + fn elif sys.platform == 'darwin': + # TODO if not request.config.getoption("--manual"): raise pytest.fail('must use --manual CLI option') @@ -778,7 +822,7 @@ def virtdisk_path(request, is_simulator, needs_virtdisk): return doit -@pytest.fixture(scope='module') +@pytest.fixture def virtdisk_wipe(dev, needs_virtdisk, virtdisk_path): def doit(): for fn in glob.glob(virtdisk_path('*')): @@ -790,13 +834,12 @@ def virtdisk_wipe(dev, needs_virtdisk, virtdisk_path): return doit -@pytest.fixture(scope='module') -def microsd_path(simulator): +@pytest.fixture +def microsd_path(simulator, sim_root_dir): # open a file from the simulated microsd def doit(fn): - # could use: ckcc.get_sim_root_dirs() here - return '../unix/work/MicroSD/' + fn + return sim_root_dir + '/MicroSD/' + fn return doit @@ -811,34 +854,34 @@ def microsd_wipe(microsd_path): os.remove(dir + fname) return doit -@pytest.fixture(scope='module') +@pytest.fixture def open_microsd(simulator, microsd_path): # open a file from the simulated microsd def doit(fn, mode='rb'): + assert fn, 'empty fname' return open(microsd_path(fn), mode) return doit -@pytest.fixture(scope='module') -def settings_path(simulator): +@pytest.fixture +def settings_path(simulator, sim_root_dir): # open a file from the simulated microsd def doit(fn): - # could use: ckcc.get_sim_root_dirs() here - return '../unix/work/settings/' + fn + return sim_root_dir + '/settings/' + fn return doit @pytest.fixture def settings_slots(settings_path): def doit(): - return [fn + return [settings_path(fn) for fn in os.listdir(settings_path("")) if fn.endswith(".aes")] return doit -@pytest.fixture(scope="function") +@pytest.fixture def set_master_key(sim_exec, sim_execfile, simulator, reset_seed_words): # load simulator w/ a specific bip32 master key @@ -862,7 +905,7 @@ def set_master_key(sim_exec, sim_execfile, simulator, reset_seed_words): # - actually need seed words for all tests reset_seed_words() -@pytest.fixture(scope="function") +@pytest.fixture def set_xfp(sim_exec): # set the XFP, without really knowing the private keys # - won't be able to sign, but should accept PSBT for signing @@ -880,7 +923,7 @@ def set_xfp(sim_exec): sim_exec('from main import settings; settings.set("xfp", 0x%x);' % simulator_fixed_xfp) -@pytest.fixture(scope="function") +@pytest.fixture def set_encoded_secret(sim_exec, sim_execfile, simulator, reset_seed_words): # load simulator w/ a specific secret @@ -906,21 +949,21 @@ def set_encoded_secret(sim_exec, sim_execfile, simulator, reset_seed_words): # - actually need seed words for all tests reset_seed_words() -@pytest.fixture(scope="function") +@pytest.fixture def use_mainnet(settings_set): def doit(): settings_set('chain', 'BTC') yield doit settings_set('chain', 'XTN') -@pytest.fixture(scope="function") +@pytest.fixture def use_testnet(settings_set): def doit(do_testnet=True): settings_set('chain', 'XTN' if do_testnet else 'BTC') yield doit settings_set('chain', 'XTN') -@pytest.fixture(scope="function") +@pytest.fixture def use_regtest(request, settings_set): if request.config.getoption("--manual"): def xrt_warn(): @@ -934,8 +977,19 @@ def use_regtest(request, settings_set): settings_set('chain', 'XTN') -@pytest.fixture(scope="function") -def set_seed_words(sim_exec, sim_execfile, simulator, reset_seed_words): +@pytest.fixture +def set_seed_words(change_seed_words, reset_seed_words): + def doit(w): + return change_seed_words(w) + + yield doit + + # Important cleanup: restore normal key, because other tests assume that + + reset_seed_words() + +@pytest.fixture +def change_seed_words(sim_exec, sim_execfile, simulator): # load simulator w/ a specific bip32 master key def doit(words): @@ -950,35 +1004,24 @@ def set_seed_words(sim_exec, sim_execfile, simulator, reset_seed_words): #print("sim xfp: 0x%08x" % simulator.master_fingerprint) return simulator.master_fingerprint - yield doit + return doit - # Important cleanup: restore normal key, because other tests assume that - - reset_seed_words() - -@pytest.fixture() -def reset_seed_words(sim_exec, sim_execfile, simulator): +@pytest.fixture +def reset_seed_words(change_seed_words): # load simulator w/ a specific bip39 seed phrase def doit(): - words = simulator_fixed_words - cmd = 'import main; main.WORDS = %r;' % words.split() - sim_exec(cmd) - rv = sim_execfile('devtest/set_seed.py') - if rv: pytest.fail(rv) - - simulator.start_encryption() - simulator.check_mitm() + new_xfp = change_seed_words(simulator_fixed_words) #print("sim xfp: 0x%08x (reset)" % simulator.master_fingerprint) - assert simulator.master_fingerprint == simulator_fixed_xfp + assert new_xfp == simulator_fixed_xfp - return words + return simulator_fixed_words return doit -@pytest.fixture() +@pytest.fixture def settings_set(sim_exec): def doit(key, val, prelogin=False): @@ -988,7 +1031,7 @@ def settings_set(sim_exec): return doit -@pytest.fixture() +@pytest.fixture def settings_get(sim_exec): def doit(key, def_val=None, prelogin=False): @@ -1000,18 +1043,18 @@ def settings_get(sim_exec): return doit -@pytest.fixture() +@pytest.fixture def master_settings_get(sim_exec): def doit(key): - cmd = f"RV.write(repr(settings.master_get('{key}')))" + cmd = f"RV.write(repr(settings.master_get('{key}', False)))" resp = sim_exec(cmd) assert 'Traceback' not in resp, resp return eval(resp) return doit -@pytest.fixture() +@pytest.fixture def settings_remove(sim_exec): def doit(key): @@ -1020,19 +1063,14 @@ def settings_remove(sim_exec): return doit -@pytest.fixture(scope='module') -def repl(request): - return request.getfixturevalue('mk4_repl') - - -@pytest.fixture(scope='module') -def mk4_repl(sim_eval, sim_exec): +@pytest.fixture(scope='session') +def repl(dev, request): # Provide an interactive connection to the REPL, using the debug build USB commands class Mk4USBRepl: def eval(self, cmd, max_time=3): # send a command, wait for it to finish - resp = sim_eval(cmd) + resp = _sim_eval(dev, cmd) print(f"eval: {cmd} => {resp}") if 'Traceback' in resp: raise RuntimeError(resp) @@ -1040,7 +1078,7 @@ def mk4_repl(sim_eval, sim_exec): def exec(self, cmd, proc_time=1, raw=False): # send a (one line) command and read the one-line response - resp = sim_exec(cmd) + resp = _sim_exec(dev, cmd) print(f"exec: {cmd} => {resp}") if raw: return resp return eval(resp) if resp else None @@ -1141,7 +1179,7 @@ def old_mk_repl(dev=None): return USBRepl() -@pytest.fixture() +@pytest.fixture def decode_with_bitcoind(bitcoind): def doit(raw_txn): @@ -1155,7 +1193,7 @@ def decode_with_bitcoind(bitcoind): return doit -@pytest.fixture() +@pytest.fixture def decode_psbt_with_bitcoind(bitcoind): def doit(raw_psbt): @@ -1170,7 +1208,7 @@ def decode_psbt_with_bitcoind(bitcoind): return doit -@pytest.fixture() +@pytest.fixture def check_against_bitcoind(bitcoind, use_regtest, sim_exec, sim_execfile): def doit(hex_txn, fee, num_warn=0, change_outs=None, dests=[]): @@ -1293,17 +1331,23 @@ def try_sign_microsd(open_microsd, cap_story, pick_menu_item, goto_home, for r in range(10): time.sleep(0.1) title, story = cap_story() - if title == 'PSBT Signed': break + if 'Updated PSBT' in story: break + if 'Finalized transaction' in story: break else: assert False, 'timed out' - txid = None lines = story.split('\n') - if 'Final TXID:' in lines: - txid = lines[-1] - result_fname = lines[-4] - else: - result_fname = lines[-1] + txid = None + if 'TXID:' in lines: + txid = lines[lines.index('TXID:')+1] + + # This is fragile! + # ignore "Press (T) to use Key Teleport to send PSBT to other co-signers" footer + # ignore "Press (0) to save again by..." + # - want the .txn if present, else the .psbt file + t, = [l for l in lines if l.endswith('.txn')] or [None] + p, = [l for l in lines if l.endswith('.psbt')] or [None] + result_fname = t or p result = open_microsd(result_fname, 'rb').read() @@ -1360,16 +1404,18 @@ def try_sign_microsd(open_microsd, cap_story, pick_menu_item, goto_home, @pytest.fixture def try_sign(start_sign, end_sign): - def doit(filename_or_data, accept=True, finalize=False, accept_ms_import=False): - ip = start_sign(filename_or_data, finalize=finalize) - return ip, end_sign(accept, finalize=finalize, accept_ms_import=accept_ms_import) + def doit(filename_or_data, accept=True, finalize=False, accept_ms_import=False, + exit_export_loop=True, miniscript=None): + ip = start_sign(filename_or_data, finalize=finalize, miniscript=miniscript) + return ip, end_sign(accept, finalize=finalize, accept_ms_import=accept_ms_import, + exit_export_loop=exit_export_loop) return doit @pytest.fixture def start_sign(dev): - def doit(filename, finalize=False, stxn_flags=0x0): + def doit(filename, finalize=False, stxn_flags=0x0, miniscript=None): if filename[0:5] == b'psbt\xff': ip = filename filename = 'memory' @@ -1381,36 +1427,38 @@ def start_sign(dev): ll, sha = dev.upload_file(ip) - dev.send_recv(CCProtocolPacker.sign_transaction(ll, sha, finalize, flags=stxn_flags)) + dev.send_recv(CCProtocolPacker.sign_transaction(ll, sha, finalize, flags=stxn_flags, + miniscript_name=miniscript)) return ip return doit @pytest.fixture -def end_sign(dev, need_keypress): +def end_sign(dev, need_keypress, press_cancel): from ckcc_protocol.protocol import CCUserRefused - def doit(accept=True, in_psbt=None, finalize=False, accept_ms_import=False, expect_txn=True): + def doit(accept=True, finalize=False, accept_ms_import=False, expect_txn=True, + exit_export_loop=True): if accept_ms_import: # XXX would be better to do cap_story here, but that would limit test to simulator need_keypress('y', timeout=None) time.sleep(0.050) - if accept != None: + if accept is not None: need_keypress('y' if accept else 'x', timeout=None) - if accept == False: + if accept is False: with pytest.raises(CCUserRefused): done = None - while done == None: + while done is None: time.sleep(0.050) done = dev.send_recv(CCProtocolPacker.get_signed_txn(), timeout=None) return else: done = None - while done == None: + while done is None: time.sleep(0.00) done = dev.send_recv(CCProtocolPacker.get_signed_txn(), timeout=None) @@ -1446,6 +1494,9 @@ def end_sign(dev, need_keypress): for sig in sigs: assert len(sig) <= 71, "overly long signature observed" + if exit_export_loop: + press_cancel() # landed back to export prompt - exit + return psbt_out return doit @@ -1539,7 +1590,7 @@ def has_qwerty(is_q1): return is_q1 @pytest.fixture(scope='module') -def rf_interface(needs_nfc, sim_exec): +def rf_interface(needs_nfc, dev): # provide a read/write connection over NFC # - requires pyscard module and desktop NFC-V reader which doesn't exist raise pytest.xfail('broken NFC-V challenges') @@ -1591,15 +1642,15 @@ def rf_interface(needs_nfc, sim_exec): pass # get the CC into NFC tap mode (but no UX) - sim_exec('glob.NFC.set_rf_disable(0)') + _sim_exec(dev, 'glob.NFC.set_rf_disable(0)') time.sleep(3) yield RFHandler() - sim_exec('glob.NFC.set_rf_disable(1)') + _sim_exec(dev, 'glob.NFC.set_rf_disable(1)') -@pytest.fixture() +@pytest.fixture def nfc_read(request, needs_nfc): # READ data from NFC chip # - perfer to do over NFC reader, but can work over USB too @@ -1617,7 +1668,25 @@ def nfc_read(request, needs_nfc): except: return doit_usb -@pytest.fixture() +@pytest.fixture +def nfc_read_url(nfc_read, press_cancel): + # gives URL from ndef + + def doit(): + contents = nfc_read() + + press_cancel() # exit NFC animation + + # expect a single record, a URL + got, = ndef.message_decoder(contents) + + assert got.type == 'urn:nfc:wkt:U' + + return got.uri + + return doit + +@pytest.fixture def nfc_write(request, needs_nfc, is_q1): # WRITE data into NFC "chip" def doit_usb(ccfile): @@ -1637,20 +1706,26 @@ def nfc_write(request, needs_nfc, is_q1): except: return doit_usb -@pytest.fixture() +@pytest.fixture def enable_nfc(needs_nfc, sim_exec, settings_set): def doit(): settings_set('nfc', 1) sim_exec('import nfc; nfc.NFCHandler.startup()') return doit -@pytest.fixture() -def nfc_disabled(needs_nfc, settings_get): +@pytest.fixture +def nfc_disabled(settings_get): def doit(): return not bool(settings_get('nfc', 0)) return doit -@pytest.fixture() +@pytest.fixture +def vdisk_disabled(settings_get): + def doit(): + return not bool(settings_get('vidsk', 0)) + return doit + +@pytest.fixture def scan_a_qr(sim_exec, is_q1): # simulate a QR being scanned # XXX limitation: our USB protocol can't send a v40 QR, limit is more like 30 or so @@ -1683,14 +1758,14 @@ def ccfile_wrap(recs): return rv -@pytest.fixture() +@pytest.fixture def nfc_write_text(nfc_write): def doit(text): msg = b''.join(ndef.message_encoder([ndef.TextRecord(text), ])) return nfc_write(ccfile_wrap(msg)) return doit -@pytest.fixture() +@pytest.fixture def nfc_read_json(nfc_read): def doit(): import json @@ -1702,7 +1777,7 @@ def nfc_read_json(nfc_read): return doit -@pytest.fixture() +@pytest.fixture def nfc_read_text(nfc_read): def doit(): got = list(ndef.message_decoder(nfc_read())) @@ -1712,7 +1787,43 @@ def nfc_read_text(nfc_read): return got.text return doit -@pytest.fixture() +@pytest.fixture +def nfc_read_txn(nfc_read, press_select): + def doit(txid=None, contents=None): + if contents is None: + contents = nfc_read() + time.sleep(.5) + press_select() + + got_txid = None + got_txn = None + got_psbt = None + got_hash = None + for got in ndef.message_decoder(contents): + if got.type == 'urn:nfc:wkt:T': + assert 'Transaction' in got.text or 'PSBT' in got.text + if 'Transaction' in got.text and txid: + assert b2a_hex(txid).decode() in got.text + elif got.type == 'urn:nfc:ext:bitcoin.org:txid': + got_txid = b2a_hex(got.data).decode('ascii') + elif got.type == 'urn:nfc:ext:bitcoin.org:txn': + got_txn = got.data + elif got.type == 'urn:nfc:ext:bitcoin.org:psbt': + got_psbt = got.data + elif got.type == 'urn:nfc:ext:bitcoin.org:sha256': + got_hash = got.data + else: + raise ValueError(got.type) + + assert got_psbt or got_txn, 'no data?' + assert got_hash + assert got_hash == hashlib.sha256(got_psbt or got_txn).digest() + + return got_txid, got_psbt, got_txn + return doit + + +@pytest.fixture def nfc_block4rf(sim_eval): # wait until RF is enabled and something to read (doesn't read it tho) def doit(timeout=15): @@ -1725,6 +1836,16 @@ def nfc_block4rf(sim_eval): return doit +@pytest.fixture +def nfc_is_enabled(sim_eval): + # NFC is disabled by default in real product, and simulator w/o args + # - but some tests don't need to fail if it's off + # - or maybe your test can use some other method when it's off + # - use this to see if disabled at present and choose the right path + def doit(): + return eval(sim_eval('bool(glob.NFC)')) + return doit + @pytest.fixture def load_shared_mod(): # load indicated file.py as a module @@ -1813,20 +1934,61 @@ def load_export_and_verify_signature(microsd_path, virtdisk_path, verify_detache if is_json: assert fname.endswith(".json") + if addr_fmt == AF_P2TR: + addr_fmt = AF_CLASSIC + contents, address = verify_detached_signature_file([fname], sig_fn, way, addr_fmt) if is_json: - return json.loads(contents), address - return contents, address + return json.loads(contents), address, fname + return contents, address, fname + return doit + +@pytest.fixture +def file_tx_signing_done(virtdisk_path, microsd_path): + def doit(story, encoding="base64", is_vdisk=False): + path_f = virtdisk_path if is_vdisk else microsd_path + enc = "rb" if encoding == "binary" else "r" + _split = story.split("\n\n") + export = None + if 'Updated PSBT is:' == _split[0]: + fname = _split[1] + path = path_f(fname) + with open(path, enc) as f: + export = f.read().strip() + + export_tx = None + if "Finalized transaction (ready for broadcast)" in _split[2]: + fname_tx = _split[3] + path_tx = path_f(fname_tx) + with open(path_tx, enc) as f: + export_tx = f.read().strip() + else: + # just finalized tx + assert "Finalized transaction (ready for broadcast):" == _split[0] + fname_tx = _split[1] + path_tx = path_f(fname_tx) + with open(path_tx, enc) as f: + export_tx = f.read() + + txid = None + for l in _split: + if "TXID" in l: + txid = l.split("\n")[-1].strip() + assert len(txid) == 64, "wrong txid" + break + + return export, export_tx, txid + return doit @pytest.fixture def load_export(need_keypress, cap_story, microsd_path, virtdisk_path, nfc_read_text, nfc_read_json, load_export_and_verify_signature, is_q1, press_cancel, press_select, readback_bbqr, - cap_screen_qr, garbage_collector): + cap_screen_qr, nfc_read_txn, file_tx_signing_done, garbage_collector): def doit(way, label, is_json, sig_check=True, addr_fmt=AF_CLASSIC, ret_sig_addr=False, tail_check=None, sd_key=None, vdisk_key=None, nfc_key=None, ret_fname=False, - fpattern=None, qr_key=None, skip_query=False): + fpattern=None, qr_key=None, is_tx=False, encoding="base64", skip_query=False): s_label = None if label == "Address summary": @@ -1842,7 +2004,8 @@ def load_export(need_keypress, cap_story, microsd_path, virtdisk_path, nfc_read_ time.sleep(0.2) title, story = cap_story() if way == "sd": - if f"({key_map['sd']}) to save {s_label if s_label else label} file to SD Card" in story: + if (f"({key_map['sd']}) to save {s_label if s_label else label} " + f"{'' if is_tx else 'file '}to SD Card") in story: need_keypress(key_map['sd']) elif way == "nfc": @@ -1851,6 +2014,10 @@ def load_export(need_keypress, cap_story, microsd_path, virtdisk_path, nfc_read_ else: need_keypress(key_map['nfc']) time.sleep(0.2) + if is_tx: + nfc_export = nfc_read_txn() + return nfc_export[1:] + if is_json: nfc_export = nfc_read_json() else: @@ -1873,6 +2040,8 @@ def load_export(need_keypress, cap_story, microsd_path, virtdisk_path, nfc_read_ return json.loads(data) elif file_type == "U": return data.decode('utf-8') if not isinstance(data, str) else data + elif file_type in ("P", "T"): + return data else: raise NotImplementedError except: @@ -1890,11 +2059,15 @@ def load_export(need_keypress, cap_story, microsd_path, virtdisk_path, nfc_read_ time.sleep(0.2) title, story = cap_story() + path_f = microsd_path if way == "sd" else virtdisk_path if sig_check: - export, sig_addr = load_export_and_verify_signature(story, way, is_json=is_json, - addr_fmt=addr_fmt, label=label, - tail_check=tail_check, - fpattern=fpattern) + export, sig_addr, fname = load_export_and_verify_signature( + story, way, is_json=is_json, addr_fmt=addr_fmt, + label=label, tail_check=tail_check, fpattern=fpattern + ) + elif is_tx: + export, export_tx, _ = file_tx_signing_done(story, encoding, is_vdisk=(way == "vdisk")) + return export, export_tx else: assert f"{label} file written" in story if tail_check: @@ -1906,10 +2079,8 @@ def load_export(need_keypress, cap_story, microsd_path, virtdisk_path, nfc_read_ assert fpattern in fname if is_json: assert fname.endswith(".json") - if way == "sd": - path = microsd_path(fname) - else: - path = virtdisk_path(fname) + + path = path_f(fname) with open(path, "r") as f: export = f.read() if is_json: @@ -1928,6 +2099,111 @@ def load_export(need_keypress, cap_story, microsd_path, virtdisk_path, nfc_read_ return doit +@pytest.fixture +def signing_artifacts_reexport(cap_story, need_keypress, load_export, press_cancel, is_q1, + settings_get): + + def doit(way, tx_final=False, txid=None, encoding=None, del_after=False, is_usb=False): + label = "Finalized TX ready for broadcast" if tx_final else "Partly Signed PSBT" + def _check_story(the_way): + time.sleep(.2) + title, story = cap_story() + + if the_way in ["qr", "nfc"]: + what = label + " shared via %s." % the_way.upper() + assert what in story + else: + if not del_after: + assert "Updated PSBT is" in story + if tx_final: + assert "Finalized transaction (ready for broadcast)" in story + if txid: + assert txid in story + + to_do = ["sd", "vdisk", "nfc", "qr"] + if not is_usb: + _check_story(way) + to_do.remove(way) # put it as the last item + to_do.append(way) + + if not is_q1: + to_do.remove("qr") + + if not settings_get("nfc", None): + to_do.remove("nfc") + + res = [] + res_tx = [] + for _way in to_do: + try: + rv = load_export(_way, label, is_json=False, sig_check=False, + is_tx=True, encoding=encoding) + if isinstance(rv, tuple): + _psbt, _tx = rv + if _psbt: + res.append(_psbt) + if _tx: + res_tx.append(_tx) + else: + if tx_final: + res_tx.append(rv) + else: + res.append(rv) + if _way in ("qr", "nfc"): + # nfc now needs cancel as it keeps reexporting + # qr needs to go back from qr view + press_cancel() + _check_story(_way) + except BaseException as e: + if _way != "vdisk": + raise + + # check we exported the same - even if in different format + final_res = [] + for x in res: + if x is not None: + x = x.strip() + if isinstance(x, bytearray): + x = bytes(x) + if not isinstance(x, bytes): + try: + # is just a hex string + x = bytes.fromhex(x) + except: + x = base64.b64decode(x) + else: + try: + x = base64.b64decode(x.decode()) + except: pass + + final_res.append(x) + + final_res_tx = [] + for y in res_tx: + if y is not None: + y = y.strip() + try: + y = a2b_hex(y) + except: pass + if isinstance(y, bytearray): + # bytearray is unhashable type + y = bytes(y) + + final_res_tx.append(y) + + if not del_after and final_res: + assert len(set(final_res)) == 1 + + fin_tx = None + if final_res_tx: + assert len(set(final_res_tx)) == 1 + fin_tx = final_res_tx[0] + + return final_res[0] if final_res else None, fin_tx + + return doit + + @pytest.fixture def tapsigner_encrypted_backup(microsd_path, virtdisk_path): def doit(way, testnet=True): @@ -2024,38 +2300,16 @@ def check_and_decrypt_backup(microsd_path): @pytest.fixture -def restore_backup_cs(unit_test, pick_menu_item, cap_story, cap_menu, +def restore_backup_unpacked(unit_test, pick_menu_item, cap_story, cap_menu, press_select, word_menu_entry, get_setting, is_q1, - need_keypress, scan_a_qr, cap_screen): - # restore backup with clear seed as first step - def doit(fn, passphrase, avail_settings=None, pass_way=None): - unit_test('devtest/clear_seed.py') + need_keypress, scan_a_qr, cap_screen, enter_complex): - m = cap_menu() - assert m[0] == 'New Seed Words' - pick_menu_item('Import Existing') - pick_menu_item('Restore Backup') - - time.sleep(.1) - pick_menu_item(fn) - - time.sleep(.1) - if is_q1 and pass_way and pass_way == "qr": - need_keypress(KEY_QR) - time.sleep(.1) - qr = ' '.join(w[:4] for w in passphrase) - scan_a_qr(qr) - for _ in range(20): - scr = cap_screen() - if 'ENTER if all done' in scr: - break - time.sleep(.1) - press_select() - else: - word_menu_entry(passphrase, has_checksum=False) + # check things are right after unpack & install; FTUX shown + def doit(avail_settings=None): time.sleep(.3) title, body = cap_story() + # on simulator Disable USB is always off - so FTUX all the time assert title == 'NO-TITLE' # no Welcome! assert "best security practices" in body @@ -2084,6 +2338,66 @@ def restore_backup_cs(unit_test, pick_menu_item, cap_story, cap_menu, return doit +@pytest.fixture +def restore_backup_cs(unit_test, pick_menu_item, cap_story, cap_menu, press_select, word_menu_entry, + get_setting, is_q1, need_keypress, scan_a_qr, cap_screen, enter_complex, + restore_backup_unpacked, press_cancel): + # restore backup with clear seed as first step + def doit(fn, passphrase, avail_settings=None, pass_way=None, custom_bkpw=False, refuse=False): + unit_test('devtest/clear_seed.py') + + m = cap_menu() + assert m[0] == 'New Seed Words' + if custom_bkpw: + pick_menu_item('Advanced/Tools') + pick_menu_item('I Am Developer.') + pick_menu_item('Restore Bkup') + else: + pick_menu_item('Import Existing') + pick_menu_item('Restore Backup') + + time.sleep(.1) + pick_menu_item(fn) + + time.sleep(.1) + if is_q1 and pass_way and (pass_way == "qr"): + need_keypress(KEY_QR) + time.sleep(.1) + qr = ' '.join(w[:4] for w in passphrase) + scan_a_qr(qr) + for _ in range(20): + scr = cap_screen() + if 'ENTER if all done' in scr: + break + time.sleep(.1) + press_select() + elif custom_bkpw: + enter_complex(passphrase, b39pass=False) + else: + # looking at word entry right now + if is_q1: + scr = cap_screen() + assert fn in scr # backup fname shown at the top + assert "Enter Password for:" in scr + + word_menu_entry(passphrase, has_checksum=False) + + time.sleep(.2) + title, story = cap_story() + assert len(title) == 10 + assert title[0] == "[" + assert title[-1] == "]" + assert "Above is the master fingerprint of the seed stored in the backup." in story + assert f"load backup as master seed" in story + if refuse: + press_cancel() + else: + press_select() + + restore_backup_unpacked(avail_settings=avail_settings) + + return doit + @pytest.fixture def seed_story_to_words(): # Q may display words in a number of different ways to get them all onto the screen, @@ -2166,7 +2480,7 @@ def goto_address_explorer(goto_home, pick_menu_item, need_keypress, return doit @pytest.fixture -def txout_explorer(cap_story, press_cancel, need_keypress, is_q1): +def txout_explorer(cap_story, press_cancel, need_keypress, is_q1, verify_qr_address): def doit(data, chain="XTN"): time.sleep(.1) title, story = cap_story() @@ -2184,11 +2498,26 @@ def txout_explorer(cap_story, press_cancel, need_keypress, is_q1): assert len(ss) == (len(d) * 2) + 1 assert "Press RIGHT to see next group" in ss[-1] if i: - assert " LEFT to go back." in ss[-1] + assert " LEFT to go back" in ss[-1] else: assert "LEFT" not in ss[-1] - for i, (sa, sb, (af, amount, change)) in enumerate(zip(ss[:-1:2], ss[1::2], d), start=i): + if not is_q1: + assert "(4) to show QR code" in ss[-1] + + # collect QR codes first + need_keypress(KEY_QR if is_q1 else "4") + qr_addr_list = [] + for af, amount, change in d: + qr = verify_qr_address(af, is_change=bool(change)) + qr_addr_list.append(qr) + need_keypress(KEY_RIGHT if is_q1 else "9") + time.sleep(.5) + + press_cancel() # QR code on screen - exit + + start = i + for i, (sa, sb, (af, amount, change)) in enumerate(zip(ss[:-1:2], ss[1::2], d), start=start): if change: assert f"Output {i} (change):" == sa else: @@ -2196,6 +2525,9 @@ def txout_explorer(cap_story, press_cancel, need_keypress, is_q1): txt_amount, _, addr = sb.split("\n") addr = addr_from_display_format(addr) + # verify QR matches what is on screen + assert addr == qr_addr_list[i-start] + assert txt_amount == f'{amount / 100000000:.8f} {chain}' if af == "p2pkh": if chain == "BTC": @@ -2277,16 +2609,18 @@ def validate_address(): @pytest.fixture -def skip_if_useless_way(is_q1, nfc_disabled): +def skip_if_useless_way(is_q1, nfc_disabled, vdisk_disabled): # when NFC is disabled, no point trying to do a PSBT via NFC # - important: run_sim_tests.py will enable NFC for complete testing # - similarly: the Mk4 and earlier had no QR scanner, so cannot use that as input def doit(way): if way == "qr" and not is_q1: raise pytest.skip("mk4 QR not supported") - if way == 'nfc' and nfc_disabled(): + elif way == 'nfc' and nfc_disabled(): # runner will test these cases, but fail faster otherwise raise pytest.skip("NFC disabled") + elif way == "vdisk" and vdisk_disabled(): + raise pytest.skip("VirtualDisk disabled") return doit @@ -2330,21 +2664,70 @@ def garbage_collector(): os.remove(pth) except: pass + +@pytest.fixture +def build_test_seed_vault(): + def doit(): + from test_ephemeral import SEEDVAULT_TEST_DATA + sv = [] + for item in SEEDVAULT_TEST_DATA: + xfp, entropy, mnemonic = item + + # build stashed encoded secret + entropy_bytes = bytes.fromhex(entropy) + if mnemonic: + vlen = len(entropy_bytes) + assert vlen in [16, 24, 32] + marker = 0x80 | ((vlen // 8) - 2) + stored_secret = bytes([marker]) + entropy_bytes + else: + stored_secret = entropy_bytes + + sv.append((xfp, stored_secret.hex(), f"[{xfp}]", "meta")) + return sv + return doit + +@pytest.fixture +def get_deltamode(sim_exec): + # get current "deltamode" status: T or F + def doit(): + return eval(sim_exec('RV.write(repr(pa.is_deltamode()))')) + return doit + +@pytest.fixture +def set_deltamode(sim_exec): + # control current "deltamode" status: T or F + def doit(val): + # TC_DELTA_MODE = const(0x0400) + if val: + sim_exec('pa.delay_required |= 0x400') + else: + sim_exec('pa.delay_required &= ~0x400') + + yield doit + + doit(False) + + # useful fixtures from test_backup import backup_system -from test_bbqr import readback_bbqr, render_bbqr, readback_bbqr_ll +from test_bbqr import readback_bbqr, render_bbqr, readback_bbqr_ll, try_sign_bbqr, split_scan_bbqr from test_bip39pw import set_bip39_pw +from test_ccc import get_last_violation from test_drv_entro import derive_bip85_secret, activate_bip85_ephemeral from test_ephemeral import generate_ephemeral_words, import_ephemeral_xprv, goto_eph_seed_menu from test_ephemeral import ephemeral_seed_disabled_ui, restore_main_seed, confirm_tmp_seed from test_ephemeral import verify_ephemeral_secret_ui, get_identity_story, get_seed_value_ux, seed_vault_enable from test_msg import verify_msg_sign_story, sign_msg_from_text, msg_sign_export, sign_msg_from_address -from test_multisig import import_ms_wallet, make_multisig, offer_ms_import, fake_ms_txn -from test_miniscript import offer_minsc_import, get_cc_key, bitcoin_core_signer -from test_multisig import make_ms_address, clear_ms, make_myself_wallet, import_multisig +from test_multisig import import_ms_wallet, make_multisig, fake_ms_txn +from test_miniscript import offer_minsc_import, get_cc_key, bitcoin_core_signer, import_miniscript, usb_miniscript_get, usb_miniscript_addr, create_core_wallet +from test_multisig import make_ms_address, make_myself_wallet +from test_notes import need_some_notes, need_some_passwords +from test_nfc import try_sign_nfc, ndef_parse_txn_psbt from test_se2 import goto_trick_menu, clear_all_tricks, new_trick_pin, se2_gate, new_pin_confirmed from test_seed_xor import restore_seed_xor -from test_ux import pass_word_quiz, word_menu_entry +from test_sign import txid_from_export_prompt +from test_ux import pass_word_quiz, word_menu_entry, enable_hw_ux from txn import fake_txn # EOF diff --git a/testing/constants.py b/testing/constants.py index 517e6774..b972cdaf 100644 --- a/testing/constants.py +++ b/testing/constants.py @@ -1,8 +1,6 @@ # (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # -SIM_PATH = '/tmp/ckcc-simulator.sock' - # Simulator normally powers up with this 'wallet' simulator_fixed_tprv = "tprv8ZgxMBicQKsPeXJHL3vPPgTAEqQ5P2FD9qDeCQT4Cp1EMY5QkwMPWFxHdxHrxZhhcVRJ2m7BNWTz9Xre68y7mX5vCdMJ5qXMUfnrZ2si2X4" simulator_fixed_tpub = "tpubD6NzVbkrYhZ4XzL5Dhayo67Gorv1YMS7j8pRUvVMd5odC2LBPLAygka9p7748JtSq82FNGPppFEz5xxZUdasBRCqJqXvUHq6xpnsMcYJzeh" @@ -43,8 +41,7 @@ addr_fmt_names = { AF_P2WPKH: 'p2wpkh', AF_P2WSH: 'p2wsh', AF_P2WPKH_P2SH: 'p2wpkh-p2sh', - AF_P2WSH_P2SH: 'p2wsh-p2sh', - AF_P2TR: "p2tr", + AF_P2WSH_P2SH: 'p2sh-p2wsh', } @@ -59,6 +56,7 @@ ADDR_STYLES_MS = ['p2sh', 'p2wsh', 'p2wsh-p2sh'] # SIGHASH SIGHASH_MAP = { + "DEFAULT": 0, "ALL": 1, "NONE": 2, "SINGLE": 3, @@ -67,5 +65,7 @@ SIGHASH_MAP = { "SINGLE|ANYONECANPAY": 3 | 0x80, } +SIGHASH_MAP_NON_TAPROOT = {k:v for k, v in SIGHASH_MAP.items() if k != "DEFAULT"} + # (2**31) - 1 --> max unhardened, but we handle hardened via h elsewhere MAX_BIP32_IDX = 2147483647 \ No newline at end of file diff --git a/testing/core_fixtures.py b/testing/core_fixtures.py index c7a8689f..1964bbb0 100644 --- a/testing/core_fixtures.py +++ b/testing/core_fixtures.py @@ -17,6 +17,11 @@ def _sim_exec(device, cmd, binary=False, timeout=60000): # print(f'sim_exec: {cmd!r} -> {s!r}') return s.decode('utf-8') if not isinstance(s, str) else s +def _sim_eval(device, cmd, binary=False, timeout=None): + s = device.send_recv(b'EVAL' + cmd.encode('utf-8'), timeout=timeout) + if binary: return s + return s.decode('utf-8') + def _cap_story(device): cmd = "RV.write('\0'.join(sim_display.story or []))" rv = _sim_exec(device, cmd) @@ -39,6 +44,10 @@ def _press_select(device, is_Q, timeout=None): btn = KEY_ENTER if is_Q else "y" _need_keypress(device, btn, timeout=timeout) +def _press_cancel(device, is_Q, timeout=None): + btn = KEY_CANCEL if is_Q else "x" + _need_keypress(device, btn, timeout=timeout) + def _dev_hw_label(device): # gets a short string that labels product: mk4 / q1, etc v = device.send_recv(CCProtocolPacker.version()).split() @@ -46,7 +55,7 @@ def _dev_hw_label(device): def _pick_menu_item(device, is_Q, text): print(f"PICK menu item: {text}") - WRAP_IF_OVER = 16 # see ../shared/menu.py .. this is larger of 10 or 16 + WRAP_IF_OVER = 10 # see ../shared/menu.py _need_keypress(device, KEY_HOME if is_Q else "0") m = _cap_menu(device) diff --git a/testing/data/migration_640/big_boy.7z b/testing/data/migration_640/big_boy.7z new file mode 100644 index 00000000..a9df2642 Binary files /dev/null and b/testing/data/migration_640/big_boy.7z differ diff --git a/testing/data/migration_640/big_boy_naked.7z b/testing/data/migration_640/big_boy_naked.7z new file mode 100644 index 00000000..5d1996b4 Binary files /dev/null and b/testing/data/migration_640/big_boy_naked.7z differ diff --git a/testing/data/migration_640/bonus101.txt b/testing/data/migration_640/bonus101.txt new file mode 100644 index 00000000..73881043 --- /dev/null +++ b/testing/data/migration_640/bonus101.txt @@ -0,0 +1,29 @@ +# Coldcard backup file! DO NOT CHANGE. + +# Private key details: Bitcoin Testnet 4 +mnemonic = "common firm bus explain pulp assault meat leave donate fade provide loud" +chain = "XTN" +xprv = "tprv8ZgxMBicQKsPerzTfdAMR1kC2UGuVHAvvLrCAjETakn1Z7y1mkHisXnXsssgPjuVcoeThBzgiAB5CDKfK6FaEqfYsJxTMjWMSCQ9ieEfmgs" +xpub = "tpubD6NzVbkrYhZ4YL2FZGpwpRQJbVnqecMqVeSyTFGm12aQPcDnQ97K42QQ4385PZ4KkfTsvqJEbbiykAxMY7hUjktxxQ2J7YrTQUkt2aUNmpN" +raw_secret = "802e6ae87ba84ad61b2283f7410a3ab3c2" +long_secret = "a5fc3fe6fb64388bcf502ee9382fa9a86d8fad8c9aa01aef509323b4cb17c32c856e790e506003a94819a5bdf21e7a223fb928650380b334d6f35d7c5bcfd97e2461ad5a45c421439da5dfa3cf3d3e11b71d85f86c423cb5e85df8c7d7500dc6457ed432f0272e821f3e19d8839867f41d45f69f68b6a906e880f60424f20ed9ec7e7b205c801f0d40da6958c29f6548c8dc15aa83b839eb35c63b9a2d39c2426fba5422727b412241da8386e0da42b175d281705202666d3700b4189b7bdfef09e12214b14d68d3ee77ef23c967d0c7d52e6ecce242a6545264aa37fddfa33a94564db1a5a3aa147965d9583762b735e75bef9cd9c8f29c8e5e93e524dc80514629c5bff06f0e8e6158a4bdffdcbc31d7174d16d9c0d9ecd6dfa07cd81019a156a2fbd449a246b9d89810623d11151c6155670578eda97af93514ae41c7e2d11bba6690cc35d4f9eca089bfdcea240db1f0884d1b2b872d6d5a856306f08f8722579d4e58a07362ec664d1e2000dc74ae25f471150e3d8c2851a36237de595ca65811209828ecd0710c4402c1ded917f2043ded723e6dadc9404e2c4f78557c" + +# Firmware version (informational) +fw_date = "2025-02-19" +fw_version = "6.3.5QX" +fw_timestamp = "250219194002" + +# Coldcard Hardware +serial = "205033774833" +hardware = "q1" + +# User preferences +setting.chain = "XTN" +setting.axi = "Coldcard and Ledger" +setting.vidsk = 2 +setting.ovc = ["2+vxKLCCkrkmKhFOx0S7o1J+PwWKBhE", "2dStVnHaMkR4o85ZgOeWc1wb0KLowvU", "pyQY2wvJ0ubOpnSMpJ3k55c/9qfEVuU", "gbyyxpKqOoA4viPneFibqhudfFG7PP0", "7rfNL1eo79IbRxwsKsCZHpU3s+VKpJc", "WElDKw79eWHA+JyDWNRueGbqfz4fqqY", "Zq711+wOvTcjdy9z7jMnOK1D2p+ZgDE", "vnlrYUXGcRK1bWPDZXamy2o24ooV/b0", "00i9UxxhkKYvewc//jLM2Lalcl2xPk4", "vmQQIfwuZTEfMukfvQ6yNO2LolSPrnk", "r86d6l+7xcBaBXj1bM7M5kCKo3XIyD0", "HF8cFOhQ8sVq1Gt+V8X0FzluwpDcLco", "7T8Froxu1orv5bEN1ED5Y8vTBVdDvcA", "scA9V/CJuUwYw4yv0S3ETNv6gc0jCA4", "hXr9Na/ksibBEDBF/mWRigD9bM+uiqs", "rojMYqIPX7kSY2a9OAJ8GlDxMHwnz0I", "QAdQ3J647TVuFcBcNCh5XzOMJPk7Yb4", "jn5Dpd32fZGf3ZEz0wC7kb15/usrnic", "Pg310c0VaVKl3PGYS8dDpyXDL60bS4Q"] +setting.accts = [[7, 2147483646], [7, 2147483645]] +setting.batt_to = 1800 +setting.miniscript = [["coldcard_new", "wsh(andor(multi(2,@0/**,@1/**,@2/**),or_i(and_v(v:pkh(@3/**),after(1772755200)),thresh(2,pk(@4/**),s:pk(@5/**),s:pk(@6/**),snl:after(1759363200))),and_v(v:thresh(2,pkh(@4/<2;3>/*),a:pkh(@5/<2;3>/*),a:pkh(@6/<2;3>/*)),after(1776643200))))", ["tpubDEA3ba8e1vmGH42xgRBMZKatR649LnNUwSB9wrtrYwdQJ4RbPF5BtxKyVLwWRhBHCNCSPeraKwsjoH613UYZCicmonx4nXerumxgJXNy14J", "tpubDFDtRvv79zVFMkCGC3frybaNtiXryfMQX3hB4U4mZoKdPSSkpJbEohEArV4mb6gkfA9JGTERdExG6Z9rDWwPHYrPp2s8evYCuLk3UN4yoe1", "tpubDFgv4MQCyo8GcEKJbKtPkrURS1uSGQu8pECpPMiKZgsmFZC8krRBoT2EzdkqrjjbYQDEvRLA3jsjfK7BPXS3jkY2GWRy33WDkXpiNdTaa48", "tpubDDvQwemwNy7T6PbQ3Ym2sEMEK8YzpyzSvWqau5hyv8ZJkeY3f6j6pgymd5nPKgLoa7PyQdUqTGzA5sxox9MzsgaBYkDxvu6JieuwNGQy717", "[3d00045d/48h/1h/0h/2h]tpubDEWe62ZwwoJKF2bLf9dy6pw7VRi1GQKNUe2K5tVihD9E6xceLeZXnARkB58cCoEPPFyp3m78ht746LJraSLFMkaquY2A73MFsf853AyjRUY", "[12ab2a99/48h/1h/0h/2h]tpubDEeWrguYhZWQDvuFKBfhCeMfPiRuW5dFfQeqLLUShoxmDCB2cPBruPXndS2xZVHeuSsAZWiiiSuCncodUiy6pkiJmbK58AUp4im7rLKPKBu", "[dc19da0c/48h/1h/0h/2h]tpubDF3HYCjsteTTEVoy9JaY3GcMCABnqbd1WAH5aLVtssp8gY4mvbUEWYebrdGh29rsnamXs7tTkKfg9ciNxnhdHaoYxwBp2x7ghpMRrkDEmbL"], {"ik_u": false, "af": 14, "ct": "XTN"}], ["bbqr", "wsh(andor(multi(2,@0/**,@1/**,@2/**),or_i(and_v(v:pkh(@3/**),after(1773187200)),thresh(2,pk(@4/**),s:pk(@5/**),s:pk(@6/**),snl:after(1759795200))),and_v(v:thresh(2,pkh(@4/<2;3>/*),a:pkh(@5/<2;3>/*),a:pkh(@6/<2;3>/*)),after(1777075200))))", ["tpubDDxm2GDBtg4RZjoYWZoutdtbZ2BFGsTv9ha7i9CrPLKDHE2QVg3fECq1nU2VyDoVozavH4NjpTVKTyoUuLqWZ3bauwcFTvpBwHhiv7EFZjy", "tpubDDz2auawERTfkjFoHm9Dk3m4NnDrw1Xb792tAssf4SWDVVwbHoE59rBKzSU8psFR9u9C7avbRRgS2XCfvk2Cc7WQ9Ndf6JU1qSv3JSSyoUy", "tpubDEgdruGzqmmTUXsuef8YBCWuWa4MfKiLGCtCiipnaHmAynnUhic8o9UgWV9mqrGMktDUrBFbCNdaZdkiRwPBbkTDgFmCL4qoevsVqELSuTm", "tpubDDvQwemwNy7THLKvvHyo2jonUseeGyXBdrWdpvB6nAiQLRV2NGBG7XAC89qf2ge8rnC6UpzjwLGqZncs1D1WqtCW3E8Pn3Yjy9tCKueKZeT", "[3d00045d/48h/1h/0h/2h]tpubDEWe62ZwwoJKF2bLf9dy6pw7VRi1GQKNUe2K5tVihD9E6xceLeZXnARkB58cCoEPPFyp3m78ht746LJraSLFMkaquY2A73MFsf853AyjRUY", "[12ab2a99/48h/1h/0h/2h]tpubDEeWrguYhZWQDvuFKBfhCeMfPiRuW5dFfQeqLLUShoxmDCB2cPBruPXndS2xZVHeuSsAZWiiiSuCncodUiy6pkiJmbK58AUp4im7rLKPKBu", "[dc19da0c/48h/1h/0h/2h]tpubDF3HYCjsteTTEVoy9JaY3GcMCABnqbd1WAH5aLVtssp8gY4mvbUEWYebrdGh29rsnamXs7tTkKfg9ciNxnhdHaoYxwBp2x7ghpMRrkDEmbL"], {"ik_u": false, "af": 14, "ct": "XTN"}], ["Coldcard and Ledger", "wsh(andor(multi(2,@0/**,@1/**,@2/**),or_i(and_v(v:pkh(@3/**),after(1773273600)),thresh(2,pk(@4/**),s:pk(@5/**),s:pk(@6/**),snl:after(1759881600))),and_v(v:thresh(2,pkh(@4/<2;3>/*),a:pkh(@5/<2;3>/*),a:pkh(@6/<2;3>/*)),after(1777161600))))", ["tpubDEqVr77TdusHJb9rTL2CcPUCAVQffsb3QAHaN6vTwZ1SVwAKD3ih7j6if7o5mVgGVdLnas4d4aGWR3nWT38gPEhmyiVKYWEfUh1zT21vVeU", "tpubDFS2NFVDRjfAvstjXFHubA4utbCFyisRVVFTY3GD381XLJmUjZzZa2niFdm2cHz3gjKLm8PYot1F6FUjQeFAHESnd14xGg9wbktS1Bz6LuE", "tpubDFaHA7XNSpnhpCdCgr1Ju9xuCJW7pMTWPK3kr61ZxJZXqUg821dJWzvPkWLHAF7XLZscovkXpZLTsZBhf7riHXAR2mBb7RfKMuq88SZF99C", "tpubDDvQwemwNy7TBUnyxFFWnzh6ZRasucqb4ZyZ6ZkMdsqUESPcNdjtiTRt1d7exQ9dTpDZpSxKsFbfgP38TkVMpRdKsyHGScGNKFxwxAb6pSx", "[3d00045d/48h/1h/0h/2h]tpubDEWe62ZwwoJKF2bLf9dy6pw7VRi1GQKNUe2K5tVihD9E6xceLeZXnARkB58cCoEPPFyp3m78ht746LJraSLFMkaquY2A73MFsf853AyjRUY", "[dc19da0c/48h/1h/0h/2h]tpubDF3HYCjsteTTEVoy9JaY3GcMCABnqbd1WAH5aLVtssp8gY4mvbUEWYebrdGh29rsnamXs7tTkKfg9ciNxnhdHaoYxwBp2x7ghpMRrkDEmbL", "[eda3d606/48h/1h/0h/2h]tpubDEAmqvQkhqP6SbfbSPu3AeRR9kfHLFXYvNDiWashLy7V2zicg1YLg654AqfomsC6kFwTs4MpcnqwxN2AnYAqi5JZeuVDBn3rfZZLTaAuS8Y"], {"ik_u": false, "af": 14, "ct": "XTN"}], ["cc - oct 30 - v1", "wsh(andor(multi(2,@0/**,@1/**,@2/**),or_i(and_v(v:pkh(@3/**),after(1790726400)),thresh(2,pk(@4/**),s:pk(@5/**),s:pk(@6/**),snl:after(1777334400))),and_v(v:thresh(2,pkh(@4/<2;3>/*),a:pkh(@5/<2;3>/*),a:pkh(@6/<2;3>/*)),after(1794614400))))", ["tpubDEH9VodS749EK6AEKQyAKvXWeAKnmPuZDbBstrGqEPQPd3E91UL7KaJia8JqLvr8gmMiCDQjLwLTwobCx55Choidvi43jGKfyS5uDKcSXf1", "tpubDDwMnwg5B5qbbhcjTZPnq21FpBpXKZbNX2xWC7khW44Rt5HnLcvRrGrsF1CXWaCZe4DHLmWCWBmhtawAADvHZZyFy5sJAjo7AcggwstRXpV", "tpubDFQH7Ebm14H8pN3LbZnGWki9YPvAHBTjeFoi3GiguMxdVfTTWyQFAsqCk5zRrNWWKzUao3H6H1rHwss8yQBGpxdQNV5x7wjKunQsqFNbRDA", "tpubDEmyALkSddGqcKnWqe2LcpwkVPK6o62c27saoH9VFT2x3xo4aSeEhBX8AJDxiAmrG1wKF4dvUKLd86pdQCrYfsi1NDVXdVCtDJbjUWXcSwp", "[2b4050d2/48h/1h/7h/2h]tpubDFDhmrJ9Bv2FdN5hJ1WZqXen1JA4nzYJVuKw2L5cPr2XfgmbfT4c7b1RHUs1W9kkuj2nEWxWj5siTFqcYHzQebxRarAZwAgtTsTsbLvBNJ1", "[9d017ded/48h/1h/4h/2h]tpubDFZwAPoqMFCCjfcQ2wzMiAFCqZpCiejxp1UZqjwninwSqhtBsw2YquqqBavkMTgJwd52E7b8ChnJ4N4wUzc6LNQBmKTxH1FVudtTfgTL6w7", "[3d00045d/48h/1h/0h/2h]tpubDEWe62ZwwoJKF2bLf9dy6pw7VRi1GQKNUe2K5tVihD9E6xceLeZXnARkB58cCoEPPFyp3m78ht746LJraSLFMkaquY2A73MFsf853AyjRUY"], {"af": 14, "ct": "XTN"}], ["minsc-Aug 6th coldcard", "XTN", 14, null, ["tpubDEH9VodS749EK6AEKQyAKvXWeAKnmPuZDbBstrGqEPQPd3E91UL7KaJia8JqLvr8gmMiCDQjLwLTwobCx55Choidvi43jGKfyS5uDKcSXf1/<0;1>/*", "tpubDDwMnwg5B5qbbhcjTZPnq21FpBpXKZbNX2xWC7khW44Rt5HnLcvRrGrsF1CXWaCZe4DHLmWCWBmhtawAADvHZZyFy5sJAjo7AcggwstRXpV/<0;1>/*", "tpubDFQH7Ebm14H8pN3LbZnGWki9YPvAHBTjeFoi3GiguMxdVfTTWyQFAsqCk5zRrNWWKzUao3H6H1rHwss8yQBGpxdQNV5x7wjKunQsqFNbRDA/<0;1>/*", "tpubDEmyALkSddGqcKnWqe2LcpwkVPK6o62c27saoH9VFT2x3xo4aSeEhBX8AJDxiAmrG1wKF4dvUKLd86pdQCrYfsi1NDVXdVCtDJbjUWXcSwp/<0;1>/*", "[340e2229/48h/1h/2h/2h]tpubDEQ6R8ei6VZKHkGiYotZythF41bVhudHE4Q9r3sJ5wZM48ohFGFWvSgnmwJCLBjXw3iiLpZcqQsvoCE3JQtBu46XEFYKxuzKUeetgupQhrp/<0;1>/*", "[f2dea0dc/48h/1h/2h/2h]tpubDEnmAnPVRR5wDaSqbxuFBb7zxu92EHz8xa39CznEdNHCvzCuurLfXLLUe3xtG4TtdkvYoi1938dXAAy25JgKjDzhcctYh1AhAd62QRBiQQS/<0;1>/*", "[3d00045d/48h/1h/0h/2h]tpubDEWe62ZwwoJKF2bLf9dy6pw7VRi1GQKNUe2K5tVihD9E6xceLeZXnARkB58cCoEPPFyp3m78ht746LJraSLFMkaquY2A73MFsf853AyjRUY/<0;1>/*", "[340e2229/48h/1h/2h/2h]tpubDEQ6R8ei6VZKHkGiYotZythF41bVhudHE4Q9r3sJ5wZM48ohFGFWvSgnmwJCLBjXw3iiLpZcqQsvoCE3JQtBu46XEFYKxuzKUeetgupQhrp/<2;3>/*", "[f2dea0dc/48h/1h/2h/2h]tpubDEnmAnPVRR5wDaSqbxuFBb7zxu92EHz8xa39CznEdNHCvzCuurLfXLLUe3xtG4TtdkvYoi1938dXAAy25JgKjDzhcctYh1AhAd62QRBiQQS/<2;3>/*", "[3d00045d/48h/1h/0h/2h]tpubDEWe62ZwwoJKF2bLf9dy6pw7VRi1GQKNUe2K5tVihD9E6xceLeZXnARkB58cCoEPPFyp3m78ht746LJraSLFMkaquY2A73MFsf853AyjRUY/<2;3>/*"], "andor(multi(2,@0/<0;1>/*,@1/<0;1>/*,@2/<0;1>/*),or_i(and_v(v:pkh(@3/<0;1>/*),after(1783382400)),thresh(2,pk(@4/<0;1>/*),s:pk(@5/<0;1>/*),s:pk(@6/<0;1>/*),snl:after(1769990400))),and_v(v:thresh(2,pkh(@4/<2;3>/*),a:pkh(@5/<2;3>/*),a:pkh(@6/<2;3>/*)),after(1787270400)))", false, true, false, false], ["minsc-CC test-2", "XTN", 14, null, ["tpubDEH9VodS749EK6AEKQyAKvXWeAKnmPuZDbBstrGqEPQPd3E91UL7KaJia8JqLvr8gmMiCDQjLwLTwobCx55Choidvi43jGKfyS5uDKcSXf1/<0;1>/*", "tpubDDwMnwg5B5qbbhcjTZPnq21FpBpXKZbNX2xWC7khW44Rt5HnLcvRrGrsF1CXWaCZe4DHLmWCWBmhtawAADvHZZyFy5sJAjo7AcggwstRXpV/<0;1>/*", "tpubDFQH7Ebm14H8pN3LbZnGWki9YPvAHBTjeFoi3GiguMxdVfTTWyQFAsqCk5zRrNWWKzUao3H6H1rHwss8yQBGpxdQNV5x7wjKunQsqFNbRDA/<0;1>/*", "tpubDEmyALkSddGqcKnWqe2LcpwkVPK6o62c27saoH9VFT2x3xo4aSeEhBX8AJDxiAmrG1wKF4dvUKLd86pdQCrYfsi1NDVXdVCtDJbjUWXcSwp/<0;1>/*", "[3d00045d/48h/1h/0h/2h]tpubDEWe62ZwwoJKF2bLf9dy6pw7VRi1GQKNUe2K5tVihD9E6xceLeZXnARkB58cCoEPPFyp3m78ht746LJraSLFMkaquY2A73MFsf853AyjRUY/<0;1>/*", "[1da9c2e9/48h/1h/0h/2h]tpubDEfdfM5gUbvkmZazpfQ2PCXLAeZQvZGLkCUSutVpChymZ5r2LWHunidEYfSTHjXaDP7BGNRcFuETg3qU252e3AimLqJfwzt4bqWgoquzrUm/<0;1>/*", "[124b5cb9/48h/1h/0h/2h]tpubDEXKTHXZ5UQxYpehSL3vVphnkE7Qca6BxaizFq8MY5UcXTGnAgYJVymftsqtjoRLCWEgFabDfr7xWCSRmjjf1M7WbDU2gRRned89AaZfGJ6/<0;1>/*", "[3d00045d/48h/1h/0h/2h]tpubDEWe62ZwwoJKF2bLf9dy6pw7VRi1GQKNUe2K5tVihD9E6xceLeZXnARkB58cCoEPPFyp3m78ht746LJraSLFMkaquY2A73MFsf853AyjRUY/<2;3>/*", "[1da9c2e9/48h/1h/0h/2h]tpubDEfdfM5gUbvkmZazpfQ2PCXLAeZQvZGLkCUSutVpChymZ5r2LWHunidEYfSTHjXaDP7BGNRcFuETg3qU252e3AimLqJfwzt4bqWgoquzrUm/<2;3>/*", "[124b5cb9/48h/1h/0h/2h]tpubDEXKTHXZ5UQxYpehSL3vVphnkE7Qca6BxaizFq8MY5UcXTGnAgYJVymftsqtjoRLCWEgFabDfr7xWCSRmjjf1M7WbDU2gRRned89AaZfGJ6/<2;3>/*"], "andor(multi(2,@0/<0;1>/*,@1/<0;1>/*,@2/<0;1>/*),or_i(and_v(v:pkh(@3/<0;1>/*),after(1780876800)),thresh(2,pk(@4/<0;1>/*),s:pk(@5/<0;1>/*),s:pk(@6/<0;1>/*),snl:after(1767484800))),and_v(v:thresh(2,pkh(@4/<2;3>/*),a:pkh(@5/<2;3>/*),a:pkh(@6/<2;3>/*)),after(1784764800)))", false, true, false, false], ["minsc-HEREEEEEEEEEEEEEEEEEEEEEEEEE", "XTN", 14, null, ["tpubDEH9VodS749EK6AEKQyAKvXWeAKnmPuZDbBstrGqEPQPd3E91UL7KaJia8JqLvr8gmMiCDQjLwLTwobCx55Choidvi43jGKfyS5uDKcSXf1/<0;1>/*", "tpubDDwMnwg5B5qbbhcjTZPnq21FpBpXKZbNX2xWC7khW44Rt5HnLcvRrGrsF1CXWaCZe4DHLmWCWBmhtawAADvHZZyFy5sJAjo7AcggwstRXpV/<0;1>/*", "tpubDFQH7Ebm14H8pN3LbZnGWki9YPvAHBTjeFoi3GiguMxdVfTTWyQFAsqCk5zRrNWWKzUao3H6H1rHwss8yQBGpxdQNV5x7wjKunQsqFNbRDA/<0;1>/*", "tpubDEmyALkSddGqcKnWqe2LcpwkVPK6o62c27saoH9VFT2x3xo4aSeEhBX8AJDxiAmrG1wKF4dvUKLd86pdQCrYfsi1NDVXdVCtDJbjUWXcSwp/<0;1>/*", "[3d00045d/48h/1h/0h/2h]tpubDEWe62ZwwoJKF2bLf9dy6pw7VRi1GQKNUe2K5tVihD9E6xceLeZXnARkB58cCoEPPFyp3m78ht746LJraSLFMkaquY2A73MFsf853AyjRUY/<0;1>/*", "[9d5a164b/48h/1h/1h/2h]tpubDEEjQpq11q473oxuSjD7ih1qv4XVWbAkA5imBTT6DyDdbZnqhx41NFRQsvQsfZVWxp9x8cFXQqW8NcHkV6b8sBH5CYPAJE3rGsqgBqKkyZU/<0;1>/*", "[eda3d606/48h/1h/1h/2h]tpubDFFruCeGNRU587SfWR1Y6MRnDULzdbS2pYBr33r7dNJiEcpBEJi7EvXgmjdpzV2wh9V7ZjXZZjmFHcQyp3o3cw2Z2Ce3jteSxzwRxhKZedd/<0;1>/*", "[3d00045d/48h/1h/0h/2h]tpubDEWe62ZwwoJKF2bLf9dy6pw7VRi1GQKNUe2K5tVihD9E6xceLeZXnARkB58cCoEPPFyp3m78ht746LJraSLFMkaquY2A73MFsf853AyjRUY/<2;3>/*", "[9d5a164b/48h/1h/1h/2h]tpubDEEjQpq11q473oxuSjD7ih1qv4XVWbAkA5imBTT6DyDdbZnqhx41NFRQsvQsfZVWxp9x8cFXQqW8NcHkV6b8sBH5CYPAJE3rGsqgBqKkyZU/<2;3>/*", "[eda3d606/48h/1h/1h/2h]tpubDFFruCeGNRU587SfWR1Y6MRnDULzdbS2pYBr33r7dNJiEcpBEJi7EvXgmjdpzV2wh9V7ZjXZZjmFHcQyp3o3cw2Z2Ce3jteSxzwRxhKZedd/<2;3>/*"], "andor(multi(2,@0/<0;1>/*,@1/<0;1>/*,@2/<0;1>/*),or_i(and_v(v:pkh(@3/<0;1>/*),after(1783382400)),thresh(2,pk(@4/<0;1>/*),s:pk(@5/<0;1>/*),s:pk(@6/<0;1>/*),snl:after(1769990400))),and_v(v:thresh(2,pkh(@4/<2;3>/*),a:pkh(@5/<2;3>/*),a:pkh(@6/<2;3>/*)),after(1787270400)))", false, true, false, false], ["minsc-aug 7th cc", "XTN", 14, null, ["tpubDEH9VodS749EK6AEKQyAKvXWeAKnmPuZDbBstrGqEPQPd3E91UL7KaJia8JqLvr8gmMiCDQjLwLTwobCx55Choidvi43jGKfyS5uDKcSXf1/<0;1>/*", "tpubDDwMnwg5B5qbbhcjTZPnq21FpBpXKZbNX2xWC7khW44Rt5HnLcvRrGrsF1CXWaCZe4DHLmWCWBmhtawAADvHZZyFy5sJAjo7AcggwstRXpV/<0;1>/*", "tpubDFQH7Ebm14H8pN3LbZnGWki9YPvAHBTjeFoi3GiguMxdVfTTWyQFAsqCk5zRrNWWKzUao3H6H1rHwss8yQBGpxdQNV5x7wjKunQsqFNbRDA/<0;1>/*", "tpubDEmyALkSddGqcKnWqe2LcpwkVPK6o62c27saoH9VFT2x3xo4aSeEhBX8AJDxiAmrG1wKF4dvUKLd86pdQCrYfsi1NDVXdVCtDJbjUWXcSwp/<0;1>/*", "[3d00045d/48h/1h/0h/2h]tpubDEWe62ZwwoJKF2bLf9dy6pw7VRi1GQKNUe2K5tVihD9E6xceLeZXnARkB58cCoEPPFyp3m78ht746LJraSLFMkaquY2A73MFsf853AyjRUY/<0;1>/*", "[124b5cb9/48h/1h/1h/2h]tpubDFcmEAfJMqEAuX5MhQTaf18D3rf1syukgACgiyzz95Nrx9h8YqsLBKa4Vu8SQ7QG6HafdrYNJwsbox8EAn2NK2pTN46MYrmQRdX2uCmdGT9/<0;1>/*", "[3526b934/48h/1h/1h/2h]tpubDETAAYNjfXMcZVppE3YzUAYcto7zXH1sZMm2dDw9KT56rQoeih8hA7xFVWFs6PHRhei3M2nKTfaeZvDsxovK2QgLcixPyXGKQTJ8aXXKFar/<0;1>/*", "[3d00045d/48h/1h/0h/2h]tpubDEWe62ZwwoJKF2bLf9dy6pw7VRi1GQKNUe2K5tVihD9E6xceLeZXnARkB58cCoEPPFyp3m78ht746LJraSLFMkaquY2A73MFsf853AyjRUY/<2;3>/*", "[124b5cb9/48h/1h/1h/2h]tpubDFcmEAfJMqEAuX5MhQTaf18D3rf1syukgACgiyzz95Nrx9h8YqsLBKa4Vu8SQ7QG6HafdrYNJwsbox8EAn2NK2pTN46MYrmQRdX2uCmdGT9/<2;3>/*", "[3526b934/48h/1h/1h/2h]tpubDETAAYNjfXMcZVppE3YzUAYcto7zXH1sZMm2dDw9KT56rQoeih8hA7xFVWFs6PHRhei3M2nKTfaeZvDsxovK2QgLcixPyXGKQTJ8aXXKFar/<2;3>/*"], "andor(multi(2,@0/<0;1>/*,@1/<0;1>/*,@2/<0;1>/*),or_i(and_v(v:pkh(@3/<0;1>/*),after(1783468800)),thresh(2,pk(@4/<0;1>/*),s:pk(@5/<0;1>/*),s:pk(@6/<0;1>/*),snl:after(1770076800))),and_v(v:thresh(2,pkh(@4/<2;3>/*),a:pkh(@5/<2;3>/*),a:pkh(@6/<2;3>/*)),after(1787356800)))", false, true, false, false], ["minsc-cc test", "XTN", 14, null, ["tpubDEH9VodS749EK6AEKQyAKvXWeAKnmPuZDbBstrGqEPQPd3E91UL7KaJia8JqLvr8gmMiCDQjLwLTwobCx55Choidvi43jGKfyS5uDKcSXf1/<0;1>/*", "tpubDDwMnwg5B5qbbhcjTZPnq21FpBpXKZbNX2xWC7khW44Rt5HnLcvRrGrsF1CXWaCZe4DHLmWCWBmhtawAADvHZZyFy5sJAjo7AcggwstRXpV/<0;1>/*", "tpubDFQH7Ebm14H8pN3LbZnGWki9YPvAHBTjeFoi3GiguMxdVfTTWyQFAsqCk5zRrNWWKzUao3H6H1rHwss8yQBGpxdQNV5x7wjKunQsqFNbRDA/<0;1>/*", "tpubDEmyALkSddGqcKnWqe2LcpwkVPK6o62c27saoH9VFT2x3xo4aSeEhBX8AJDxiAmrG1wKF4dvUKLd86pdQCrYfsi1NDVXdVCtDJbjUWXcSwp/<0;1>/*", "[3d00045d/48h/1h/0h/2h]tpubDEWe62ZwwoJKF2bLf9dy6pw7VRi1GQKNUe2K5tVihD9E6xceLeZXnARkB58cCoEPPFyp3m78ht746LJraSLFMkaquY2A73MFsf853AyjRUY/<0;1>/*", "[dc7f959a/48h/1h/0h/2h]tpubDDvasTj1PH4nMxAVbXw3MVd28sy7diMP6JXumzYKZK1tEg5vDRg98VfK9Et21JbJyUR5HTnDN4V4ti9UdMvrDVWBCqxknxxXmePzoRApUr5/<0;1>/*", "[b9f957e9/48h/1h/0h/2h]tpubDFS15gqmwz5MyctfhuLtpHbDnzxJuSYsVDT9PRsEPcudzMRe5xQCGdanzJvdqDpzqbZ5vaBpK7NPBMQicUSmvwnMbT5FfnQDD3xrJxsTAxY/<0;1>/*", "[3d00045d/48h/1h/0h/2h]tpubDEWe62ZwwoJKF2bLf9dy6pw7VRi1GQKNUe2K5tVihD9E6xceLeZXnARkB58cCoEPPFyp3m78ht746LJraSLFMkaquY2A73MFsf853AyjRUY/<2;3>/*", "[dc7f959a/48h/1h/0h/2h]tpubDDvasTj1PH4nMxAVbXw3MVd28sy7diMP6JXumzYKZK1tEg5vDRg98VfK9Et21JbJyUR5HTnDN4V4ti9UdMvrDVWBCqxknxxXmePzoRApUr5/<2;3>/*", "[b9f957e9/48h/1h/0h/2h]tpubDFS15gqmwz5MyctfhuLtpHbDnzxJuSYsVDT9PRsEPcudzMRe5xQCGdanzJvdqDpzqbZ5vaBpK7NPBMQicUSmvwnMbT5FfnQDD3xrJxsTAxY/<2;3>/*"], "andor(multi(2,@0/<0;1>/*,@1/<0;1>/*,@2/<0;1>/*),or_i(and_v(v:pkh(@3/<0;1>/*),after(1782259200)),thresh(2,pk(@4/<0;1>/*),s:pk(@5/<0;1>/*),s:pk(@6/<0;1>/*),snl:after(1768867200))),and_v(v:thresh(2,pkh(@4/<2;3>/*),a:pkh(@5/<2;3>/*),a:pkh(@6/<2;3>/*)),after(1786147200)))", false, true, false, false], ["minsc-july 28th", "XTN", 14, null, ["tpubDEH9VodS749EK6AEKQyAKvXWeAKnmPuZDbBstrGqEPQPd3E91UL7KaJia8JqLvr8gmMiCDQjLwLTwobCx55Choidvi43jGKfyS5uDKcSXf1/<0;1>/*", "tpubDDwMnwg5B5qbbhcjTZPnq21FpBpXKZbNX2xWC7khW44Rt5HnLcvRrGrsF1CXWaCZe4DHLmWCWBmhtawAADvHZZyFy5sJAjo7AcggwstRXpV/<0;1>/*", "tpubDFQH7Ebm14H8pN3LbZnGWki9YPvAHBTjeFoi3GiguMxdVfTTWyQFAsqCk5zRrNWWKzUao3H6H1rHwss8yQBGpxdQNV5x7wjKunQsqFNbRDA/<0;1>/*", "tpubDEmyALkSddGqcKnWqe2LcpwkVPK6o62c27saoH9VFT2x3xo4aSeEhBX8AJDxiAmrG1wKF4dvUKLd86pdQCrYfsi1NDVXdVCtDJbjUWXcSwp/<0;1>/*", "[f2dea0dc/48h/1h/1h/2h]tpubDEjCL7gG119Yjo8wHYSzeiFjJJYYRJH42DXewXsAEESM4AGwyGJ3ahZtiXtuTVy7F98v6SZsANKpspBN8H89FWP5P2g1kstKfVDnBya1BG4/<0;1>/*", "[340e2229/48h/1h/1h/2h]tpubDFHUR9kVAJpUkbsRjGjHEGJdpT68dYWgnunzZkmPmFXJSojZP4SmBaNRbV44ikqJH2uy1pRzBCA9DYauAtyQ3fd7Cum9pBfigpvVtDQFTtB/<0;1>/*", "[3d00045d/48h/1h/0h/2h]tpubDEWe62ZwwoJKF2bLf9dy6pw7VRi1GQKNUe2K5tVihD9E6xceLeZXnARkB58cCoEPPFyp3m78ht746LJraSLFMkaquY2A73MFsf853AyjRUY/<0;1>/*", "[f2dea0dc/48h/1h/1h/2h]tpubDEjCL7gG119Yjo8wHYSzeiFjJJYYRJH42DXewXsAEESM4AGwyGJ3ahZtiXtuTVy7F98v6SZsANKpspBN8H89FWP5P2g1kstKfVDnBya1BG4/<2;3>/*", "[340e2229/48h/1h/1h/2h]tpubDFHUR9kVAJpUkbsRjGjHEGJdpT68dYWgnunzZkmPmFXJSojZP4SmBaNRbV44ikqJH2uy1pRzBCA9DYauAtyQ3fd7Cum9pBfigpvVtDQFTtB/<2;3>/*", "[3d00045d/48h/1h/0h/2h]tpubDEWe62ZwwoJKF2bLf9dy6pw7VRi1GQKNUe2K5tVihD9E6xceLeZXnARkB58cCoEPPFyp3m78ht746LJraSLFMkaquY2A73MFsf853AyjRUY/<2;3>/*"], "andor(multi(2,@0/<0;1>/*,@1/<0;1>/*,@2/<0;1>/*),or_i(and_v(v:pkh(@3/<0;1>/*),after(1782604800)),thresh(2,pk(@4/<0;1>/*),s:pk(@5/<0;1>/*),s:pk(@6/<0;1>/*),snl:after(1769212800))),and_v(v:thresh(2,pkh(@4/<2;3>/*),a:pkh(@5/<2;3>/*),a:pkh(@6/<2;3>/*)),after(1786492800)))", false, true, false, false], ["minsc-real cc test", "XTN", 14, null, ["tpubDEH9VodS749EK6AEKQyAKvXWeAKnmPuZDbBstrGqEPQPd3E91UL7KaJia8JqLvr8gmMiCDQjLwLTwobCx55Choidvi43jGKfyS5uDKcSXf1/<0;1>/*", "tpubDDwMnwg5B5qbbhcjTZPnq21FpBpXKZbNX2xWC7khW44Rt5HnLcvRrGrsF1CXWaCZe4DHLmWCWBmhtawAADvHZZyFy5sJAjo7AcggwstRXpV/<0;1>/*", "tpubDFQH7Ebm14H8pN3LbZnGWki9YPvAHBTjeFoi3GiguMxdVfTTWyQFAsqCk5zRrNWWKzUao3H6H1rHwss8yQBGpxdQNV5x7wjKunQsqFNbRDA/<0;1>/*", "tpubDEmyALkSddGqcKnWqe2LcpwkVPK6o62c27saoH9VFT2x3xo4aSeEhBX8AJDxiAmrG1wKF4dvUKLd86pdQCrYfsi1NDVXdVCtDJbjUWXcSwp/<0;1>/*", "[3d00045d/48h/1h/0h/2h]tpubDEWe62ZwwoJKF2bLf9dy6pw7VRi1GQKNUe2K5tVihD9E6xceLeZXnARkB58cCoEPPFyp3m78ht746LJraSLFMkaquY2A73MFsf853AyjRUY/<0;1>/*", "[3526b934/48h/1h/0h/2h]tpubDESiT13HcKofR5yqwn3LE2LLj9wBRG4d6K3tkowsX7mxnx78WcxBBd6gvcb5N7uqoX7ezsJtAujZ8T66MvumJ25QM2cCiy7Wo9SB2gGf2Ly/<0;1>/*", "[f40f5987/48h/1h/0h/2h]tpubDFHmNY1WuvAk4BmfbyqvU8QaqsXCAx5ezUAhcjXXNRPip5CzRpW4JT6CKySrSb9HLdVTMA3PQUzHBCjztNjy2tkGvBU6XhTQrnwkCHGfzZn/<0;1>/*", "[3d00045d/48h/1h/0h/2h]tpubDEWe62ZwwoJKF2bLf9dy6pw7VRi1GQKNUe2K5tVihD9E6xceLeZXnARkB58cCoEPPFyp3m78ht746LJraSLFMkaquY2A73MFsf853AyjRUY/<2;3>/*", "[3526b934/48h/1h/0h/2h]tpubDESiT13HcKofR5yqwn3LE2LLj9wBRG4d6K3tkowsX7mxnx78WcxBBd6gvcb5N7uqoX7ezsJtAujZ8T66MvumJ25QM2cCiy7Wo9SB2gGf2Ly/<2;3>/*", "[f40f5987/48h/1h/0h/2h]tpubDFHmNY1WuvAk4BmfbyqvU8QaqsXCAx5ezUAhcjXXNRPip5CzRpW4JT6CKySrSb9HLdVTMA3PQUzHBCjztNjy2tkGvBU6XhTQrnwkCHGfzZn/<2;3>/*"], "andor(multi(2,@0/<0;1>/*,@1/<0;1>/*,@2/<0;1>/*),or_i(and_v(v:pkh(@3/<0;1>/*),after(1780876800)),thresh(2,pk(@4/<0;1>/*),s:pk(@5/<0;1>/*),s:pk(@6/<0;1>/*),snl:after(1767484800))),and_v(v:thresh(2,pkh(@4/<2;3>/*),a:pkh(@5/<2;3>/*),a:pkh(@6/<2;3>/*)),after(1784764800)))", false, true, false, false]] + +# EOF diff --git a/testing/debug/.gitignore b/testing/debug/.gitignore deleted file mode 100644 index c81791f8..00000000 --- a/testing/debug/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -*.psbt -*.txn -*.txt -*.json -*.png diff --git a/testing/descriptor.py b/testing/descriptor.py index 34d7cb6b..9dde4c3d 100644 --- a/testing/descriptor.py +++ b/testing/descriptor.py @@ -115,23 +115,6 @@ def parse_desc_str(string): return res -def multisig_descriptor_template(xpub, path, xfp, addr_fmt): - key_exp = "[%s%s]%s/0/*" % (xfp.lower(), path.replace("m", ''), xpub) - if addr_fmt == AF_P2WSH_P2SH: - descriptor_template = "sh(wsh(sortedmulti(M,%s,...)))" - elif addr_fmt == AF_P2WSH: - descriptor_template = "wsh(sortedmulti(M,%s,...))" - elif addr_fmt == AF_P2SH: - descriptor_template = "sh(sortedmulti(M,%s,...))" - elif addr_fmt == AF_P2TR: - # provably unspendable BIP-0341 - descriptor_template = "tr(" + PROVABLY_UNSPENDABLE + ",sortedmulti_a(M,%s,...))" - else: - return None - descriptor_template = descriptor_template % key_exp - return descriptor_template - - class Descriptor: __slots__ = ( "keys", @@ -158,7 +141,6 @@ class Descriptor: @staticmethod def parse_key_orig_info(key: str): - # key origin info is required for our MultisigWallet close_index = key.find("]") if key[0] != "[" or close_index == -1: raise ValueError("Key origin info is required for %s" % (key)) diff --git a/testing/devtest/check_decode.py b/testing/devtest/check_decode.py index 91b3ece8..6d14ba90 100644 --- a/testing/devtest/check_decode.py +++ b/testing/devtest/check_decode.py @@ -34,7 +34,7 @@ for fn in ['had_witness', 'num_inputs', 'num_outputs', if 'destinations' in expect: for (val, addr), (idx, txo) in zip(expect['destinations'], p.output_iter()): assert val == txo.nValue - txt = active_request.render_output(txo) + txt, _ = active_request.render_output(txo) # normalize from display format address = txt.split("\n")[-2] assert address[0] == "\x02" diff --git a/testing/devtest/menu_dump.py b/testing/devtest/menu_dump.py index a0835fb8..d10be3c7 100644 --- a/testing/devtest/menu_dump.py +++ b/testing/devtest/menu_dump.py @@ -10,12 +10,13 @@ async def doit(): import version async def dump_menu(fd, m, label, indent, menu_item=None, menu_idx=0, whs=False): from menu import MenuItem, ToggleMenuItem, MenuSystem, NonDefaultMenuItem - from seed import WordNestMenu, EphemeralSeedMenu, SeedVaultMenu + from seed import WordNestMenu, EphemeralSeedMenu, SeedVaultMenu, not_hobbled_mode from trick_pins import TrickPinMenu from users import UsersMenu from flow import has_secrets, nfc_enabled, vdisk_enabled, word_based_seed from flow import hsm_policy_available, is_not_tmp, has_real_secret - from flow import has_se_secrets, hsm_available + from flow import has_se_secrets, hsm_available, qr_and_has_secrets, has_pushtx_url + from flow import sssp_related_keys, sssp_allow_passphrase, sssp_allow_notes, sssp_allow_vault print("%s%s"% (indent, label), file=fd) @@ -24,7 +25,7 @@ async def doit(): m = [] # recursing into functions that do stuff doesn't work well, skip - avoid = {'Clone Coldcard', 'Debug Functions', 'Migrate COLDCARD'} + avoid = {'Clone Coldcard', 'Debug Functions', 'Migrate Coldcard'} if any(label.startswith(a) for a in avoid): return @@ -32,8 +33,9 @@ async def doit(): if version.has_qwerty and m.__name__ == "start_seed_import": print('%s[SEED WORD ENTRY]' % indent, file=fd) return - if m.__name__ == "make_custom": + if m.__name__ in ("make_custom", "bkpw_override"): # address explorer custom path menu + # bkpw override = dev thing return print("Calling: %r (%s)" % (m.__name__, label)) @@ -65,11 +67,11 @@ async def doit(): # trick pins are not available in EmptyWallet continue - pred = getattr(mi, 'predicate', None) + pred = getattr(mi, '_predicate', None) if pred in (True, False): if here in ("NFC Tools", "Import via NFC", "NFC File Share"): here += ' [IF NFC ENABLED]' - if "QR" in here and "Scan" in here: + if "QR" in here or "Scan" in here or "BBQr" in here: here += ' [IF QR SCANNER]' if "battery" in here: here += ' [IF BATTERIES]' @@ -97,9 +99,26 @@ async def doit(): here += ' [IF SECRET AND NOT TMP SEED]' elif pred == hsm_available: here += ' [IF HSM AND SECRET]' + elif pred == qr_and_has_secrets: + here += ' [IF QR AND SECRET]' + # do nothing, only in NormalOps menu, but SSSP has different menu dump + elif pred == not_hobbled_mode: pass + # here += ' [IF SSSP DISABLED]' + elif pred == has_pushtx_url: + here += ' [IF PUSHTX ENABLED]' + elif pred == sssp_related_keys: + here += ' [IF SSSP RELATED KEYS ENABLED]' + elif pred == sssp_allow_passphrase: + here += ' [IF WORD BASED SEED & SSSP RELATED KEYS ENABLED]' + elif pred == sssp_allow_notes: + here += '[IF ENABLED & SSSP ALLOW NOTES]' + elif pred == sssp_allow_vault: + here += '[IF ENABLED & SSSP RELATED KEYS ENABLED]' elif pred: - if here == "Secure Notes & Passwords": + if here in ("Secure Notes & Passwords", "Push Transaction"): here += ' [IF ENBALED]' + if here == "Secure Logout": + here += ' [IF NOT BATTERIES]' else: here += ' [MAYBE]' @@ -131,15 +150,29 @@ async def doit(): print('%s%s' % (indent, here), file=fd) - from flow import EmptyWallet, NormalSystem, FactoryMenu, VirginSystem + from flow import EmptyWallet, NormalSystem, FactoryMenu, VirginSystem, HobbledTopMenu from glob import settings # need these to supress warnings and info messages # that need user interaction nad/or show hidden items settings.put("seedvault", 1) + settings.put("seeds", [["7126EB3C", "808ae37a2d3d3d0f9db5ca98c8300e3818", "[7126EB3C]", "TRNG Words"], + ["CCEE13B9", "018d669ed0fddccd7f34ef6dac86864e75fc4036d7dd3992c985ba0e625d8da83ac33b64d371a6d0d1a4a5200f00080ef5e2b341251b30a8b665be42c43fb4c5f3", "[CCEE13B9]", "BIP-39 Passphrase on [0F056943]"], + ["03EE9989", "01a00f4ecbfb55b186bae4486e0e292a34e1afb0c1f64ad4a9a3f378bdeefb7296abce50461838f76979a695d6b4f6ac329661c227f1137400520cbbb1294333a7", "[03EE9989]", "BIP85 Derived from [0F056943], index=543"]]) + settings.put("secnap", 1) + settings.put("notes", [{"misc": "some random notes", "title": "note0"}, + {"password": "AnnounceHalf+~^99891", "site": "abc.org", "misc": "never disclose!!!!!", "user": "satoshi", "title": "secret-PWD"}]) settings.put("axskip", 1) settings.put("b39skip", 1) settings.put("sd2fa", ["a"]) + settings.put("ptxurl", 'https://coldcard.com/pushtx#') + settings.put("multisig", [["CC-2-of-4", [2, 4], [[1130956047, "tpubDF2rnouQaaYrXF4noGTv6rQYmx87cQ4GrUdhpvXkhtChwQPbdGTi8GA88NUaSrwZBwNsTkC9bFkkC8vDyGBVVAQTZ2AS6gs68RQXtXcCvkP"], [3503269483, "tpubDFcrvj5n7gyaxWQkoX69k2Zij4vthiAwvN2uhYjDrE6wktKoQaE7gKVZRiTbYdrAYH1UFPGdzdtWJc6WfR2gFMq6XpxA12gCdQmoQNU9mgm"], [2389277556, "tpubDExj5FnaUnPAn7sHGUeBqD3buoNH5dqmjAT6884vbDpH1iDYWigb7kFo2cA97dc8EHb54u13TRcZxC4kgRS9gc3Ey2xc8c5urytEzTcp3ac"], [3190206587, "tpubDFiuHYSJhNbHcbLJoxWdbjtUcbKR6PvLq53qC1Xq6t93CrRx78W3wcng8vJyQnY3giMJZEgNCRVzTojLb8RqPFpW5Ms2dYpjcJYofN1joyu"]], {"pp": "m/48h/1h/0h/2h", "ch": "XTN", "ft": 14}]]) + settings.put("tp", {"11-11": [0, 16384, 0], "333-3334": [1, 4096, 1001], "!p": [2, 33280, 3]}) + + + # saved passphrase on MicroSD + with open("MicroSD/.tmp.tmp", "wb") as f: + f.write(b'\xf0\xc9\xff\x00\xf37c\xdd\x8bz\xfa\x0b\xd9\x16;g8\xf8S0\xa5\x129\x99\xd4\xa2=\n\x01\xf9q$w\xb2sb,\xa7\xf9') with open('menudump.txt', 'wt') as fd: for nm, m in [ @@ -147,8 +180,13 @@ async def doit(): ('[IF BLANK WALLET]', EmptyWallet), ('[NORMAL OPERATION]', NormalSystem), ('[FACTORY MODE]', FactoryMenu), + ('[SSSP]', HobbledTopMenu), ]: - await dump_menu(fd, m, nm, '', whs=(m == NormalSystem)) + if "SSSP" in nm: + from pincodes import pa + pa.hobbled_mode = True + + await dump_menu(fd, m, nm, '', whs=(m in (NormalSystem,HobbledTopMenu))) print('---\n', file=fd) print("DONE: check menudump.txt file") diff --git a/testing/devtest/set_encoded_secret.py b/testing/devtest/set_encoded_secret.py index f10080ad..f9b56c76 100644 --- a/testing/devtest/set_encoded_secret.py +++ b/testing/devtest/set_encoded_secret.py @@ -16,6 +16,6 @@ raw = main.ENCODED_SECRET pa.change(new_secret=raw) pa.new_main_secret(raw) -print("New key in effect: %s" % settings.get('xpub', 'MISSING')) -print("Fingerprint: %s" % xfp2str(settings.get('xfp', 0))) +print("New key in effect (encoded): %s" % settings.get('xpub', 'MISSING')) +print(".. w/ XFP= %s" % xfp2str(settings.get('xfp', 0))) diff --git a/testing/devtest/set_seed.py b/testing/devtest/set_seed.py index 6b2be19b..acb6255e 100644 --- a/testing/devtest/set_seed.py +++ b/testing/devtest/set_seed.py @@ -1,6 +1,7 @@ # (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # -# load up the simulator w/ indicated list of seed words +# Load up the simulator w/ indicated list of seed words +# from sim_settings import sim_defaults import stash, chains from pincodes import pa @@ -11,7 +12,6 @@ from utils import xfp2str from actions import goto_top_menu from nvstore import SettingsObject - tn = chains.BitcoinTestnet stash.bip39_passphrase = '' @@ -23,14 +23,16 @@ PassphraseMenu.pp_sofar = '' SettingsObject.master_sv_data = {} SettingsObject.master_nvram_key = None set_seed_value(main.WORDS) +stash.SensitiveValues.clear_cache() settings.set('chain', 'XTN') settings.set('words', len(main.WORDS)) settings.set('terms_ok', True) settings.set('idle_to', 0) -print("New key in effect: %s" % settings.get('xpub', 'MISSING')) -print("Fingerprint: %s" % xfp2str(settings.get('xfp', 0))) +print("TESTING: New key in effect [%s]: %s..%s = %s" % ( + xfp2str(settings.get('xfp', 0)), main.WORDS[0], main.WORDS[-1], + settings.get('xpub', 'MISSING'))) # impt: if going from xprv => seed words, main menu needs updating goto_top_menu() diff --git a/testing/devtest/set_tprv.py b/testing/devtest/set_tprv.py index f0d7cbae..69369fec 100644 --- a/testing/devtest/set_tprv.py +++ b/testing/devtest/set_tprv.py @@ -1,6 +1,7 @@ # (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # -# load up the simulator w/ indicated test master key +# load up the simulator w/ indicated test master key in TPRV format. +# import main, ngu from sim_settings import sim_defaults import stash, chains @@ -34,8 +35,9 @@ pa.change(new_secret=raw) pa.new_main_secret(raw) settings.set('words', False) -print("New key in effect: %s" % settings.get('xpub', 'MISSING')) -print("Fingerprint: %s" % xfp2str(settings.get('xfp', 0))) - assert settings.get('xfp', 0) == swab32(node.my_fp()) +print("TESTING: New tprv in effect [%s]: %s" % ( + settings.get('xpub', 'MISSING'), + xfp2str(settings.get('xfp', 0)))) + diff --git a/testing/devtest/unit_addrs.py b/testing/devtest/unit_addrs.py index 299d7c21..a4db6473 100644 --- a/testing/devtest/unit_addrs.py +++ b/testing/devtest/unit_addrs.py @@ -4,44 +4,51 @@ from h import a2b_hex, b2a_hex from serializations import CTxOut from uio import BytesIO +from public_constants import AF_CLASSIC, AF_P2WPKH, AF_P2SH cases = [ # TxOut, type, is_segwit, hash160/pubkey, - ( 'c4f33d0000000000160014ad46a001d55bd55d157e716bf17c02f8964b5a19', - 'p2pkh', True, - 'ad46a001d55bd55d157e716bf17c02f8964b5a19' ), - ( '202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac', - 'p2pkh', False, - '8280b37df378db99f66f85c95a783a76ac7a6d59' ), - + ( + 'c4f33d0000000000160014ad46a001d55bd55d157e716bf17c02f8964b5a19', + AF_P2WPKH, + 'ad46a001d55bd55d157e716bf17c02f8964b5a19' + ), + ( + '202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac', + AF_CLASSIC, + '8280b37df378db99f66f85c95a783a76ac7a6d59' + ), # from legendary txid: 40eee3ae1760e3a8532263678cdf64569e6ad06abc133af64f735e52562bccc8 - ( '301b0f000000000017a914e9c3dd0c07aac76179ebc76a6c78d4d67c6c160a87', - 'p2sh', False, - 'e9c3dd0c07aac76179ebc76a6c78d4d67c6c160a'), - + ( + '301b0f000000000017a914e9c3dd0c07aac76179ebc76a6c78d4d67c6c160a87', + AF_P2SH, + 'e9c3dd0c07aac76179ebc76a6c78d4d67c6c160a' + ), # from testnet: a4c89e0ffb84d06a1e62f0f9f0f5974db250878caa1f71f9992a1f865b8ff2fa # via - ( 'b88201000000000017a914f0ca58dc8e539421a3cb4a9c22c059973075287c87', - 'p2sh', False, - 'f0ca58dc8e539421a3cb4a9c22c059973075287c'), - + ( + 'b88201000000000017a914f0ca58dc8e539421a3cb4a9c22c059973075287c87', + AF_P2SH, + 'f0ca58dc8e539421a3cb4a9c22c059973075287c' + ), # XXX missing: P2SH segwit, 1of1 and N of M - ( 'd0f13d0000000000160014f2369bac6d24ed11313fa65adda1971d10e17bff', - 'p2pkh', True, - 'f2369bac6d24ed11313fa65adda1971d10e17bff') + ( + 'd0f13d0000000000160014f2369bac6d24ed11313fa65adda1971d10e17bff', + AF_P2WPKH, + 'f2369bac6d24ed11313fa65adda1971d10e17bff' + ) ] -for raw_txo, expect_type, expect_sw, expect_hash in cases: +for raw_txo, expect_type, expect_hash in cases: expect_hash = a2b_hex(expect_hash) out = CTxOut() out.deserialize(BytesIO(a2b_hex(raw_txo))) print("Case: %s... " % raw_txo[0:30]) - addr_type, addr_or_pubkey, is_segwit = out.get_address() + addr_type, addr_or_pubkey = out.get_address() - assert is_segwit == expect_sw, 'wrong segwit' assert addr_or_pubkey == expect_hash, 'wrong pubkey/addr' assert addr_type == expect_type, addr_type diff --git a/testing/devtest/unit_bip32.py b/testing/devtest/unit_bip32.py new file mode 100644 index 00000000..7ab29575 --- /dev/null +++ b/testing/devtest/unit_bip32.py @@ -0,0 +1,47 @@ +# (c) Copyright 2024 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# +# Invalid Extended Keys test +# https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-5 +from desc_utils import Key +from seed import xprv_to_encoded_secret +from glob import settings + +TO_CHECK_PUB = [ + "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6LBpB85b3D2yc8sfvZU521AAwdZafEz7mnzBBsz4wKY5fTtTQBm", #(pubkey version / prvkey mismatch) + "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6Txnt3siSujt9RCVYsx4qHZGc62TG4McvMGcAUjeuwZdduYEvFn", #(invalid pubkey prefix 04) + "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6N8ZMMXctdiCjxTNq964yKkwrkBJJwpzZS4HS2fxvyYUA4q2Xe4", #(invalid pubkey prefix 01) + # blinded keys allowed + # "xpub661no6RGEX3uJkY4bNnPcw4URcQTrSibUZ4NqJEw5eBkv7ovTwgiT91XX27VbEXGENhYRCf7hyEbWrR3FewATdCEebj6znwMfQkhRYHRLpJ", # (zero depth with non - zero parent fingerprint) + # "xpub661MyMwAuDcm6CRQ5N4qiHKrJ39Xe1R1NyfouMKTTWcguwVcfrZJaNvhpebzGerh7gucBvzEQWRugZDuDXjNDRmXzSZe4c7mnTK97pTvGS8", # (zero depth with non - zero index) + "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6Q5JXayek4PRsn35jii4veMimro1xefsM58PgBMrvdYre8QyULY", # (invalid pubkey 020000000000000000000000000000000000000000000000000000000000000007) + "DMwo58pR1QLEFihHiXPVykYB6fJmsTeHvyTp7hRThAtCX8CvYzgPcn8XnmdfHPmHJiEDXkTiJTVV9rHEBUem2mwVbbNfvT2MTcAqj3nesx8uBf9", # unknown version +] + +TO_CHECK_PRV = [ + "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFGTQQD3dC4H2D5GBj7vWvSQaaBv5cxi9gafk7NF3pnBju6dwKvH", # (prvkey version / pubkey mismatch) + "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFGpWnsj83BHtEy5Zt8CcDr1UiRXuWCmTQLxEK9vbz5gPstX92JQ", # (invalid prvkey prefix 04) + "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFAzHGBP2UuGCqWLTAPLcMtD9y5gkZ6Eq3Rjuahrv17fEQ3Qen6J", # (invalid prvkey prefix 01) + # "xprv9s2SPatNQ9Vc6GTbVMFPFo7jsaZySyzk7L8n2uqKXJen3KUmvQNTuLh3fhZMBoG3G4ZW1N2kZuHEPY53qmbZzCHshoQnNf4GvELZfqTUrcv", # (zero depth with non - zero parent fingerprint) + # "xprv9s21ZrQH4r4TsiLvyLXqM9P7k1K3EYhA1kkD6xuquB5i39AU8KF42acDyL3qsDbU9NmZn6MsGSUYZEsuoePmjzsB3eFKSUEh3Gu1N3cqVUN", # (zero depth with non - zero index) + "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzF93Y5wvzdUayhgkkFoicQZcP3y52uPPxFnfoLZB21Teqt1VvEHx", # (private key 0 not in 1..n - 1) + "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFAzHGBP2UuGCqWLTAPLcMtD5SDKr24z3aiUvKr9bJpdrcLg1y3G", # (private key n not in 1..n - 1) + "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHL", # (invalid checksum) + "DMwo58pR1QLEFihHiXPVykYB6fJmsTeHvyTp7hRThAtCX8CvYzgPcn8XnmdfHGMQzT7ayAmfo4z3gY5KfbrZWZ6St24UVf2Qgo6oujFktLHdHY4", # (unknown version) +] + +settings.set('chain', "BTC") +for i, ek in enumerate(TO_CHECK_PUB): + try: + Key.from_string(ek).validate(None) + raise RuntimeError + except (AssertionError, ValueError) as e: + print("exc", e) + +for i, ek in enumerate(TO_CHECK_PRV): + try: + xprv_to_encoded_secret(ek) + raise AttributeError + except (ValueError, RuntimeError, AssertionError) as e: + print("exc", e) + +# EOF \ No newline at end of file diff --git a/testing/devtest/unit_bip388.py b/testing/devtest/unit_bip388.py new file mode 100644 index 00000000..64014632 --- /dev/null +++ b/testing/devtest/unit_bip388.py @@ -0,0 +1,145 @@ +# (c) Copyright 2025 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# +# BIP-0388 vectors https://github.com/bitcoin/bips/blob/master/bip-0388.mediawiki + +valid = [ + ( + "pkh(@0/**)", + ["[6738736c/44'/0'/0']xpub6Br37sWxruYfT8ASpCjVHKGwgdnYFEn98DwiN76i2oyY6fgH1LAPmmDcF46xjxJr22gw4jmVjTE2E3URMnRPEPYyo1zoPSUba563ESMXCeb"], + "pkh([6738736c/44'/0'/0']xpub6Br37sWxruYfT8ASpCjVHKGwgdnYFEn98DwiN76i2oyY6fgH1LAPmmDcF46xjxJr22gw4jmVjTE2E3URMnRPEPYyo1zoPSUba563ESMXCeb/<0;1>/*)", + ), + ( + "sh(wpkh(@0/**))", + ["[6738736c/49'/0'/1']xpub6Bex1CHWGXNNwGVKHLqNC7kcV348FxkCxpZXyCWp1k27kin8sRPayjZUKDjyQeZzGUdyeAj2emoW5zStFFUAHRgd5w8iVVbLgZ7PmjAKAm9"], + "sh(wpkh([6738736c/49'/0'/1']xpub6Bex1CHWGXNNwGVKHLqNC7kcV348FxkCxpZXyCWp1k27kin8sRPayjZUKDjyQeZzGUdyeAj2emoW5zStFFUAHRgd5w8iVVbLgZ7PmjAKAm9/<0;1>/*))", + ), + ( + "wpkh(@0/**)", + ["[6738736c/84'/0'/2']xpub6CRQzb8u9dmMcq5XAwwRn9gcoYCjndJkhKgD11WKzbVGd932UmrExWFxCAvRnDN3ez6ZujLmMvmLBaSWdfWVn75L83Qxu1qSX4fJNrJg2Gt"], + "wpkh([6738736c/84'/0'/2']xpub6CRQzb8u9dmMcq5XAwwRn9gcoYCjndJkhKgD11WKzbVGd932UmrExWFxCAvRnDN3ez6ZujLmMvmLBaSWdfWVn75L83Qxu1qSX4fJNrJg2Gt/<0;1>/*)", + ), + ( + "tr(@0/**)", + ["[6738736c/86'/0'/0']xpub6CryUDWPS28eR2cDyojB8G354izmx294BdjeSvH469Ty3o2E6Tq5VjBJCn8rWBgesvTJnyXNAJ3QpLFGuNwqFXNt3gn612raffLWfdHNkYL"], + "tr([6738736c/86'/0'/0']xpub6CryUDWPS28eR2cDyojB8G354izmx294BdjeSvH469Ty3o2E6Tq5VjBJCn8rWBgesvTJnyXNAJ3QpLFGuNwqFXNt3gn612raffLWfdHNkYL/<0;1>/*)", + ), + ( + "wsh(sortedmulti(2,@0/**,@1/**))", + ["[6738736c/48'/0'/0'/2']xpub6FC1fXFP1GXLX5TKtcjHGT4q89SDRehkQLtbKJ2PzWcvbBHtyDsJPLtpLtkGqYNYZdVVAjRQ5kug9CsapegmmeRutpP7PW4u4wVF9JfkDhw", + "[b2b1f0cf/48'/0'/0'/2']xpub6EWhjpPa6FqrcaPBuGBZRJVjzGJ1ZsMygRF26RwN932Vfkn1gyCiTbECVitBjRCkexEvetLdiqzTcYimmzYxyR1BZ79KNevgt61PDcukmC7"], + "wsh(sortedmulti(2,[6738736c/48'/0'/0'/2']xpub6FC1fXFP1GXLX5TKtcjHGT4q89SDRehkQLtbKJ2PzWcvbBHtyDsJPLtpLtkGqYNYZdVVAjRQ5kug9CsapegmmeRutpP7PW4u4wVF9JfkDhw/<0;1>/*,[b2b1f0cf/48'/0'/0'/2']xpub6EWhjpPa6FqrcaPBuGBZRJVjzGJ1ZsMygRF26RwN932Vfkn1gyCiTbECVitBjRCkexEvetLdiqzTcYimmzYxyR1BZ79KNevgt61PDcukmC7/<0;1>/*))", + ), + ( + "wsh(thresh(3,pk(@0/**),s:pk(@1/**),s:pk(@2/**),sln:older(12960)))", + ["[6738736c/48'/0'/0'/100']xpub6FC1fXFP1GXQpyRFfSE1vzzySqs3Vg63bzimYLeqtNUYbzA87kMNTcuy9ubr7MmavGRjW2FRYHP4WGKjwutbf1ghgkUW9H7e3ceaPLRcVwa", + "[b2b1f0cf/44'/0'/0'/100']xpub6EYajCJHe2CK53RLVXrN14uWoEttZgrRSaRztujsXg7yRhGtHmLBt9ot9Pd5ugfwWEu6eWyJYKSshyvZFKDXiNbBcoK42KRZbxwjRQpm5Js", + "[a666a867/44'/0'/0'/100']xpub6Dgsze3ujLi1EiHoCtHFMS9VLS1UheVqxrHGfP7sBJ2DBfChEUHV4MDwmxAXR2ayeytpwm3zJEU3H3pjCR6q6U5sP2p2qzAD71x9z5QShK2"], + "wsh(thresh(3,pk([6738736c/48'/0'/0'/100']xpub6FC1fXFP1GXQpyRFfSE1vzzySqs3Vg63bzimYLeqtNUYbzA87kMNTcuy9ubr7MmavGRjW2FRYHP4WGKjwutbf1ghgkUW9H7e3ceaPLRcVwa/<0;1>/*),s:pk([b2b1f0cf/44'/0'/0'/100']xpub6EYajCJHe2CK53RLVXrN14uWoEttZgrRSaRztujsXg7yRhGtHmLBt9ot9Pd5ugfwWEu6eWyJYKSshyvZFKDXiNbBcoK42KRZbxwjRQpm5Js/<0;1>/*),s:pk([a666a867/44'/0'/0'/100']xpub6Dgsze3ujLi1EiHoCtHFMS9VLS1UheVqxrHGfP7sBJ2DBfChEUHV4MDwmxAXR2ayeytpwm3zJEU3H3pjCR6q6U5sP2p2qzAD71x9z5QShK2/<0;1>/*),sln:older(12960)))", + ), + ( + "wsh(or_d(pk(@0/**),and_v(v:multi(2,@1/**,@2/**,@3/**),older(65535))))", + ["[6738736c/48'/0'/0'/100']xpub6FC1fXFP1GXQpyRFfSE1vzzySqs3Vg63bzimYLeqtNUYbzA87kMNTcuy9ubr7MmavGRjW2FRYHP4WGKjwutbf1ghgkUW9H7e3ceaPLRcVwa", + "[b2b1f0cf/44'/0'/0'/100']xpub6EYajCJHe2CK53RLVXrN14uWoEttZgrRSaRztujsXg7yRhGtHmLBt9ot9Pd5ugfwWEu6eWyJYKSshyvZFKDXiNbBcoK42KRZbxwjRQpm5Js", + "[a666a867/44'/0'/0'/100']xpub6Dgsze3ujLi1EiHoCtHFMS9VLS1UheVqxrHGfP7sBJ2DBfChEUHV4MDwmxAXR2ayeytpwm3zJEU3H3pjCR6q6U5sP2p2qzAD71x9z5QShK2", + "[bb641298/44'/0'/0'/100']xpub6Dz8PHFmXkYkykQ83ySkruky567XtJb9N69uXScJZqweYiQn6FyieajdiyjCvWzRZ2GoLHMRE1cwDfuJZ6461YvNRGVBJNnLA35cZrQKSRJ"], + "wsh(or_d(pk([6738736c/48'/0'/0'/100']xpub6FC1fXFP1GXQpyRFfSE1vzzySqs3Vg63bzimYLeqtNUYbzA87kMNTcuy9ubr7MmavGRjW2FRYHP4WGKjwutbf1ghgkUW9H7e3ceaPLRcVwa/<0;1>/*),and_v(v:multi(2,[b2b1f0cf/44'/0'/0'/100']xpub6EYajCJHe2CK53RLVXrN14uWoEttZgrRSaRztujsXg7yRhGtHmLBt9ot9Pd5ugfwWEu6eWyJYKSshyvZFKDXiNbBcoK42KRZbxwjRQpm5Js/<0;1>/*,[a666a867/44'/0'/0'/100']xpub6Dgsze3ujLi1EiHoCtHFMS9VLS1UheVqxrHGfP7sBJ2DBfChEUHV4MDwmxAXR2ayeytpwm3zJEU3H3pjCR6q6U5sP2p2qzAD71x9z5QShK2/<0;1>/*,[bb641298/44'/0'/0'/100']xpub6Dz8PHFmXkYkykQ83ySkruky567XtJb9N69uXScJZqweYiQn6FyieajdiyjCvWzRZ2GoLHMRE1cwDfuJZ6461YvNRGVBJNnLA35cZrQKSRJ/<0;1>/*),older(65535))))", + ), + ( + "tr(@0/**,{sortedmulti_a(1,@0/<2;3>/*,@1/**),or_b(pk(@2/**),s:pk(@3/**))})", + ["[6738736c/48'/0'/0'/100']xpub6FC1fXFP1GXQpyRFfSE1vzzySqs3Vg63bzimYLeqtNUYbzA87kMNTcuy9ubr7MmavGRjW2FRYHP4WGKjwutbf1ghgkUW9H7e3ceaPLRcVwa", + "xpub6Fc2TRaCWNgfT49nRGG2G78d1dPnjhW66gEXi7oYZML7qEFN8e21b2DLDipTZZnfV6V7ivrMkvh4VbnHY2ChHTS9qM3XVLJiAgcfagYQk6K", + "xpub6GxHB9kRdFfTqYka8tgtX9Gh3Td3A9XS8uakUGVcJ9NGZ1uLrGZrRVr67DjpMNCHprZmVmceFTY4X4wWfksy8nVwPiNvzJ5pjLxzPtpnfEM", + "xpub6GjFUVVYewLj5no5uoNKCWuyWhQ1rKGvV8DgXBG9Uc6DvAKxt2dhrj1EZFrTNB5qxAoBkVW3wF8uCS3q1ri9fueAa6y7heFTcf27Q4gyeh6"], + "tr([6738736c/48'/0'/0'/100']xpub6FC1fXFP1GXQpyRFfSE1vzzySqs3Vg63bzimYLeqtNUYbzA87kMNTcuy9ubr7MmavGRjW2FRYHP4WGKjwutbf1ghgkUW9H7e3ceaPLRcVwa/<0;1>/*,{sortedmulti_a(1,[6738736c/48'/0'/0'/100']xpub6FC1fXFP1GXQpyRFfSE1vzzySqs3Vg63bzimYLeqtNUYbzA87kMNTcuy9ubr7MmavGRjW2FRYHP4WGKjwutbf1ghgkUW9H7e3ceaPLRcVwa/<2;3>/*,xpub6Fc2TRaCWNgfT49nRGG2G78d1dPnjhW66gEXi7oYZML7qEFN8e21b2DLDipTZZnfV6V7ivrMkvh4VbnHY2ChHTS9qM3XVLJiAgcfagYQk6K/<0;1>/*),or_b(pk(xpub6GxHB9kRdFfTqYka8tgtX9Gh3Td3A9XS8uakUGVcJ9NGZ1uLrGZrRVr67DjpMNCHprZmVmceFTY4X4wWfksy8nVwPiNvzJ5pjLxzPtpnfEM/<0;1>/*),s:pk(xpub6GjFUVVYewLj5no5uoNKCWuyWhQ1rKGvV8DgXBG9Uc6DvAKxt2dhrj1EZFrTNB5qxAoBkVW3wF8uCS3q1ri9fueAa6y7heFTcf27Q4gyeh6/<0;1>/*))})", + ), + # ( + # "tr(musig(@0,@1,@2)/**,{and_v(v:pk(musig(@0,@1)/**),older(12960)),{and_v(v:pk(musig(@0,@2)/**),older(12960)),and_v(v:pk(musig(@1,@2)/**),older(12960))}})", + # ["[6738736c/48'/0'/0'/100']xpub6FC1fXFP1GXQpyRFfSE1vzzySqs3Vg63bzimYLeqtNUYbzA87kMNTcuy9ubr7MmavGRjW2FRYHP4WGKjwutbf1ghgkUW9H7e3ceaPLRcVwa", + # "[b2b1f0cf/44'/0'/0'/100']xpub6EYajCJHe2CK53RLVXrN14uWoEttZgrRSaRztujsXg7yRhGtHmLBt9ot9Pd5ugfwWEu6eWyJYKSshyvZFKDXiNbBcoK42KRZbxwjRQpm5Js", + # "[a666a867/44'/0'/0'/100']xpub6Dgsze3ujLi1EiHoCtHFMS9VLS1UheVqxrHGfP7sBJ2DBfChEUHV4MDwmxAXR2ayeytpwm3zJEU3H3pjCR6q6U5sP2p2qzAD71x9z5QShK2"], + # "tr(musig([6738736c/48'/0'/0'/100']xpub6FC1fXFP1GXQpyRFfSE1vzzySqs3Vg63bzimYLeqtNUYbzA87kMNTcuy9ubr7MmavGRjW2FRYHP4WGKjwutbf1ghgkUW9H7e3ceaPLRcVwa,[b2b1f0cf/44'/0'/0'/100']xpub6EYajCJHe2CK53RLVXrN14uWoEttZgrRSaRztujsXg7yRhGtHmLBt9ot9Pd5ugfwWEu6eWyJYKSshyvZFKDXiNbBcoK42KRZbxwjRQpm5Js,[a666a867/44'/0'/0'/100']xpub6Dgsze3ujLi1EiHoCtHFMS9VLS1UheVqxrHGfP7sBJ2DBfChEUHV4MDwmxAXR2ayeytpwm3zJEU3H3pjCR6q6U5sP2p2qzAD71x9z5QShK2)/<0;1>/*,{and_v(v:pk(musig([6738736c/48'/0'/0'/100']xpub6FC1fXFP1GXQpyRFfSE1vzzySqs3Vg63bzimYLeqtNUYbzA87kMNTcuy9ubr7MmavGRjW2FRYHP4WGKjwutbf1ghgkUW9H7e3ceaPLRcVwa,[b2b1f0cf/44'/0'/0'/100']xpub6EYajCJHe2CK53RLVXrN14uWoEttZgrRSaRztujsXg7yRhGtHmLBt9ot9Pd5ugfwWEu6eWyJYKSshyvZFKDXiNbBcoK42KRZbxwjRQpm5Js)/<0;1>/*),older(12960)),{and_v(v:pk(musig([6738736c/48'/0'/0'/100']xpub6FC1fXFP1GXQpyRFfSE1vzzySqs3Vg63bzimYLeqtNUYbzA87kMNTcuy9ubr7MmavGRjW2FRYHP4WGKjwutbf1ghgkUW9H7e3ceaPLRcVwa,[a666a867/44'/0'/0'/100']xpub6Dgsze3ujLi1EiHoCtHFMS9VLS1UheVqxrHGfP7sBJ2DBfChEUHV4MDwmxAXR2ayeytpwm3zJEU3H3pjCR6q6U5sP2p2qzAD71x9z5QShK2)/<0;1>/*),older(12960)),and_v(v:pk(musig([b2b1f0cf/44'/0'/0'/100']xpub6EYajCJHe2CK53RLVXrN14uWoEttZgrRSaRztujsXg7yRhGtHmLBt9ot9Pd5ugfwWEu6eWyJYKSshyvZFKDXiNbBcoK42KRZbxwjRQpm5Js,[a666a867/44'/0'/0'/100']xpub6Dgsze3ujLi1EiHoCtHFMS9VLS1UheVqxrHGfP7sBJ2DBfChEUHV4MDwmxAXR2ayeytpwm3zJEU3H3pjCR6q6U5sP2p2qzAD71x9z5QShK2)/<0;1>/*),older(12960))}})", + # ), +] + +invalid = [ + ( + # Key placeholder with no path following it + "key derivation missing", + "pkh(@0)", + ["[0f056943/99h/0h/0h]xpub6DMjVrmtVxXyn5hBuLScBtHeQ9X3ws6uasj7mWRu7ay7mQrX5suQKwYgNZBJYnWKugRk1KrgmTHtgwGvB7QcgELYCuacE3oA25SGMQZTiRg"], + ), + ( + # Key placeholder with an explicit path present + "need multipath", + "pkh(@0/0/**)", + ["[0f056943/99h/0h/0h]xpub6DMjVrmtVxXyn5hBuLScBtHeQ9X3ws6uasj7mWRu7ay7mQrX5suQKwYgNZBJYnWKugRk1KrgmTHtgwGvB7QcgELYCuacE3oA25SGMQZTiRg"], + ), + ( + # Key placeholders out of order + "Out of order", + "sh(multi(1,@1/**,@0/**))", + ["[0f056943/99h/0h/0h]xpub6DMjVrmtVxXyn5hBuLScBtHeQ9X3ws6uasj7mWRu7ay7mQrX5suQKwYgNZBJYnWKugRk1KrgmTHtgwGvB7QcgELYCuacE3oA25SGMQZTiRg", + "[6738736c/44'/0'/0']xpub6Br37sWxruYfT8ASpCjVHKGwgdnYFEn98DwiN76i2oyY6fgH1LAPmmDcF46xjxJr22gw4jmVjTE2E3URMnRPEPYyo1zoPSUba563ESMXCeb"], + ), + ( + # Skipped key placeholder @1 + "Out of order", + "sh(multi(1,@0/**,@2/**))", + ["[0f056943/99h/0h/0h]xpub6DMjVrmtVxXyn5hBuLScBtHeQ9X3ws6uasj7mWRu7ay7mQrX5suQKwYgNZBJYnWKugRk1KrgmTHtgwGvB7QcgELYCuacE3oA25SGMQZTiRg", + "[6738736c/44'/0'/0']xpub6Br37sWxruYfT8ASpCjVHKGwgdnYFEn98DwiN76i2oyY6fgH1LAPmmDcF46xjxJr22gw4jmVjTE2E3URMnRPEPYyo1zoPSUba563ESMXCeb"], + ), + ( + # Repeated keys with the same path expression + "Insane", + "sh(multi(1,@0/**,@0/**))", + ["[0f056943/99h/0h/0h]xpub6DMjVrmtVxXyn5hBuLScBtHeQ9X3ws6uasj7mWRu7ay7mQrX5suQKwYgNZBJYnWKugRk1KrgmTHtgwGvB7QcgELYCuacE3oA25SGMQZTiRg"], + ), + ( + # Non-disjoint multipath expressions (@0/1/* appears twice) + "Non-disjoint multipath", + "sh(multi(1,@0/<0;1>/*,@0/<1;2>/*))", + ["[0f056943/99h/0h/0h]xpub6DMjVrmtVxXyn5hBuLScBtHeQ9X3ws6uasj7mWRu7ay7mQrX5suQKwYgNZBJYnWKugRk1KrgmTHtgwGvB7QcgELYCuacE3oA25SGMQZTiRg"], + ), + ( + # Taproot non-disjoint multipath expressions (@0/1/* appears twice in tapscript) + "Non-disjoint multipath", + "tr(@0/<5;6>/*,multi_a(1,@0/<0;1>/*,@0/<1;2>/*))", + ["[0f056943/99h/0h/0h]xpub6DMjVrmtVxXyn5hBuLScBtHeQ9X3ws6uasj7mWRu7ay7mQrX5suQKwYgNZBJYnWKugRk1KrgmTHtgwGvB7QcgELYCuacE3oA25SGMQZTiRg"], + ), + ( + # Taproot non-disjoint multipath expressions (@0/1/* appears twice as internal key and tapscript key) + "Non-disjoint multipath", + "tr(@0/<0;1>/*,multi_a(1,@0/<5;6>/*,@0/<1;2>/*))", + ["[0f056943/99h/0h/0h]xpub6DMjVrmtVxXyn5hBuLScBtHeQ9X3ws6uasj7mWRu7ay7mQrX5suQKwYgNZBJYnWKugRk1KrgmTHtgwGvB7QcgELYCuacE3oA25SGMQZTiRg"], + ), + ( + # solved cardinality > 2 + "Solved cardinality > 2", + "pkh(@0/<0;1;2>/*)", + ["[0f056943/99h/0h/0h]xpub6DMjVrmtVxXyn5hBuLScBtHeQ9X3ws6uasj7mWRu7ay7mQrX5suQKwYgNZBJYnWKugRk1KrgmTHtgwGvB7QcgELYCuacE3oA25SGMQZTiRg"], + ) +] + +import glob +from glob import settings +from descriptor import Descriptor +from wallet import MiniScriptWallet + +settings.set('chain', "BTC") + +# valid vectors +for policy, keys_info, desc in valid: + d = Descriptor.from_string(desc) + pol, ki = d.bip388_wallet_policy() + assert pol == policy, "\n" + pol + "\n" + policy + assert keys_info == keys_info + +# invalid vectors +for err, policy, keys_info in invalid: + glob.DESC_CACHE = {} + try: + msc = MiniScriptWallet.from_bip388_wallet_policy("random_name", policy, keys_info) + assert False, "succeeded, but must have failed!" + except BaseException as e: + if err not in str(e): + raise diff --git a/testing/devtest/unit_multisig.py b/testing/devtest/unit_multisig.py deleted file mode 100644 index 8270aa0b..00000000 --- a/testing/devtest/unit_multisig.py +++ /dev/null @@ -1,61 +0,0 @@ -# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. -# -# unit test for address decoding for multisig -from h import a2b_hex, b2a_hex -from chains import BitcoinMain, BitcoinTestnet, BitcoinRegtest -from multisig import disassemble_multisig -from public_constants import AF_CLASSIC, AF_P2SH, AF_P2WPKH, AF_P2WSH, AF_P2WPKH_P2SH, AF_P2WSH_P2SH -from public_constants import AFC_PUBKEY, AFC_SEGWIT, AFC_BECH32, AFC_SCRIPT, AFC_WRAPPED - -if 1: - - pk = a2b_hex('0202c68b0228cb577123c2f41275dadf8f4958890d3daf3728e38492f4913077dc') - script = a2b_hex('52210202c68b0228cb577123c2f41275dadf8f4958890d3daf3728e38492f4913077dc2102316dfd8d084a2b645061423013b52f513846e80c10816f66330f5609c8f6e7e221025328ece688cdc37d679b3af650f5d51487c1fe2fbd733b38cbfb58a9588a2155210288eb170b0661a6e86d1f1ab53a1099970d1b4d4cdd44d503d926effeec1e20842102fc3285261cccf4e7a44219758ee0383d25133b19a9fa14441ecb6ce9f3a4a52821038d00b6b4752dbba6afe6dcc00ef4b1fb0c212695f28a7908256808c2c201c43521038d5bcc32c89e363d181a08eb1c7613c0ba9aa02643d04cf00ae2cfea4192c9722103a11fd11e66e3d50818e3826a9b157245e6b361e32db9036768b54b4bc09adf092103d357b96bf98bcd5705d0f4745c2557d452d46a7cb9a6b193521de4516790f1182103f5bf5e00104c8956127ff926c0c5dd74690f8e67a21898cecb256dda34428a795aae') - - M, N, pubkeys = disassemble_multisig(script) - - assert M == 2 - assert N == 10 - assert pubkeys[0] == pk - -# assert keys == ['mpsMLTNqBNrsQuYNmZPj7ifqqMTSnZMMWH', 'mjoj9a1cFNPhvFkbrwzNPTBCWxhteAJHE5', -# 'mkjqteuKMDApEzsZbdphtufvVPmCFafLhM', 'mvRSS7xmYBjDUEQsxvNefXLbwQHpwm76wb', -# 'mhGBcrA9xDuBWttQLZFGRBJHcGEZyQpT3b', 'mkYFhxXQY6mMZbKxcuk6j6FD2Ff1gX6zgC', -# 'mmgkFCdHKxCHuTMcJ9CPncRMA2UPainW6j', 'mg5fNCy7TJiZ8L4uxU3XerW2twNYAY3hmU', -# 'myY1Xmhx6CdvFn6uzdUDo5EM2HxmsPXPJB', 'mozpwp3z32g9vBZxbpN6ySxx7A5EWw4Zfi'] - - addr = BitcoinMain.p2sh_address(AF_P2SH, script) - assert addr[0] == '3' - assert addr == '3Kt6KxjirrFS7GexJiXLLhmuaMzSbjp275' - - addr = BitcoinTestnet.p2sh_address(AF_P2SH, script) - assert addr[0] == '2' - assert addr == '2NBSJPhfkUJknK4HVyr9CxemAniCcRfhqp4' - - addr = BitcoinRegtest.p2sh_address(AF_P2SH, script) - assert addr[0] == '2' - assert addr == '2NBSJPhfkUJknK4HVyr9CxemAniCcRfhqp4' - - addr = BitcoinMain.p2sh_address(AF_P2WSH, script) - assert addr[0:4] == 'bc1q', addr - assert len(addr) >= 62 - assert addr == 'bc1qnjw7wy4e9tf4kkqaf43n2cyjwug0ystugum08c5j5hwhfncc4mkqftu4jr' - - addr = BitcoinTestnet.p2sh_address(AF_P2WSH, script) - assert addr[0:4] == 'tb1q', addr - assert len(addr) >= 62 - assert addr == 'tb1qnjw7wy4e9tf4kkqaf43n2cyjwug0ystugum08c5j5hwhfncc4mkq7r26gv' - - addr = BitcoinRegtest.p2sh_address(AF_P2WSH, script) - print(addr) - assert addr[0:6] == 'bcrt1q', addr - assert len(addr) >= 64 - assert addr == 'bcrt1qnjw7wy4e9tf4kkqaf43n2cyjwug0ystugum08c5j5hwhfncc4mkqn6quak' - - -if 1: - from utils import xfp2str, str2xfp - - assert xfp2str(0x10203040) == '40302010' - for i in 0, 1, 0x12345678: - assert str2xfp(xfp2str(i)) == i diff --git a/testing/devtest/unit_script.py b/testing/devtest/unit_script.py new file mode 100644 index 00000000..a5af2512 --- /dev/null +++ b/testing/devtest/unit_script.py @@ -0,0 +1,53 @@ +# (c) Copyright 2025 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# +from uio import BytesIO +from serializations import ser_push_data, ser_string_vector, deser_string_vector +from serializations import ser_compact_size, deser_compact_size, disassemble + +test_data = [ + # data, result + (55*b"a", b'7aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'), + (75*b"a", b'Kaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'), + (76*b"a", b'LLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'), + (77*b"a", b'LMaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'), + (254*b"a", b'L\xfe' + (254 * b"a")), + (255*b"a", b'L\xff' + (255 * b"a")), + (256*b"a", b'M\x00\x01' + (256 * b"a")), + (500*b"a", b'M\xf4\x01' + (500 * b"a")), + (65535*b"a", b'M\xff\xff' + (65535 * b"a")), +] + +for i, (data, result) in enumerate(test_data): + assert ser_push_data(data) == result, i + d, _ = list(disassemble(result))[0] + assert d == data + +try: + # PUSHDATA 4 not implemented + ser_push_data(65536 * b"a") + raise RuntimeError +except AssertionError: pass + +# test serialization/deserialization +# all M/N combinations +V = range(1, 16) +for i, v1 in enumerate(V): + for j in range(i+1, len(V)): + M, N = v1, V[j] + # number of pubkeys times 1 pushdata + 33 pubkey = 34 * N + # +1 M + # +1 N + # +1 OP_CHECKMULTISIG + ms_script_len = (34 * N) + 1 + 1 + 1 + vec = [b"\x00"] + (M * [71*b"s"]) + [ms_script_len*b"w"] + assert vec == deser_string_vector(BytesIO(ser_string_vector(vec))) + + +for i in [253, 0x10000, 0x100000000]: + for j in [-1, 0, 1]: + num = i + j + x = ser_compact_size(num) + + assert num == deser_compact_size(BytesIO(x)) + +# EOF diff --git a/testing/devtest/wipe_ms.py b/testing/devtest/wipe_ms.py deleted file mode 100644 index 293b6125..00000000 --- a/testing/devtest/wipe_ms.py +++ /dev/null @@ -1,13 +0,0 @@ -# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. -# -# quickly clear all multisig wallets installed -from glob import settings -from ux import restore_menu - -if settings.get('multisig'): - del settings.current['multisig'] - settings.save() - - print("cleared multisigs") - -restore_menu() diff --git a/testing/helpers.py b/testing/helpers.py index eaf5443d..578fb34b 100644 --- a/testing/helpers.py +++ b/testing/helpers.py @@ -45,7 +45,7 @@ def fake_dest_addr(style='p2pkh'): if style == 'p2wsh': return bytes([0, 32]) + prandom(32) - if style in ['p2sh', 'p2wsh-p2sh', 'p2wpkh-p2sh']: + if style in ['p2sh', 'p2wsh-p2sh', 'p2sh-p2wsh', 'p2wpkh-p2sh', 'p2sh-p2wpkh']: # all equally bogus P2SH outputs return bytes([0xa9, 0x14]) + prandom(20) + bytes([0x87]) @@ -79,7 +79,7 @@ def make_change_addr(wallet, style): is_segwit = False elif style == 'p2wpkh': redeem_scr = bytes([0, 20]) + target - elif style == 'p2wpkh-p2sh': + elif style in ('p2wpkh-p2sh', 'p2sh-p2wpkh'): redeem_scr = bytes([0, 20]) + target actual_scr = bytes([0xa9, 0x14]) + hash160(redeem_scr) + bytes([0x87]) elif style == 'p2tr': @@ -103,6 +103,11 @@ def xfp2str(xfp): from struct import pack return b2a_hex(pack(' 3xUP, 3xDOWN, DOWN + for _ in range(3): + _need_keypress(device, "5") + _press_select(device, is_Q) + time.sleep(.1) + + for _ in range(3): + _need_keypress(device, "8") + _press_select(device, is_Q) + time.sleep(.1) + + _need_keypress(device, "8") + _press_select(device, is_Q) + + time.sleep(.1) + # abandon -> 3xOK + for _ in range(3): + _press_select(device, is_Q) + + time.sleep(.1) + title, story = _cap_story(device) + assert "Sorry, those words are incorrect" in story + _press_select(device, is_Q) + time.sleep(.1) + # now insert correct words + if is_Q: + # just because of auto-fil feature + _enter_complex(device, is_Q, "wif") + _enter_complex(device, is_Q, "clar") + else: + # wife -> 3xUP, 3xDOWN, DOWN + for _ in range(3): + _need_keypress(device, "5") + _press_select(device, is_Q) + time.sleep(.1) + + for _ in range(3): + _need_keypress(device, "8") + _press_select(device, is_Q) + time.sleep(.1) + + _need_keypress(device, "8") + _press_select(device, is_Q) + + # clarify 2xDOWN, 4xDOWN, 2xDOWN + for _ in range(2): + _need_keypress(device, "8") + _press_select(device, is_Q) + time.sleep(.1) + + for _ in range(4): + _need_keypress(device, "8") + _press_select(device, is_Q) + time.sleep(.1) + + for _ in range(2): + _need_keypress(device, "8") + _press_select(device, is_Q) + time.sleep(.1) + + menu = _cap_menu(device) + assert "Settings" in menu # not in SSSP + + sim.stop() + + +def test_sssp_login_countdown(request): + bypass_pin = "236-156" + is_Q = request.config.getoption('--Q') + clean_sim_data() # remove all from previous + sim = ColdcardSimulator(args=["--q1"] if is_Q else []) + sim.start(start_wait=6) + device = ColdcardDevice(is_simulator=True) + + _pick_menu_item(device, is_Q, "Settings") + _pick_menu_item(device, is_Q, "Login Settings") + _set_login_countdown(device, is_Q, " 5 minutes") + + time.sleep(.2) + for _ in range(2): # go back + _press_cancel(device, is_Q) + + time.sleep(.1) + _pick_menu_item(device, is_Q, "Advanced/Tools") + _pick_menu_item(device, is_Q, "Spending Policy") + _pick_menu_item(device, is_Q, "Single-Signer") + _press_select(device, is_Q) # confirm story + # now create bypass PIN + # 1st entry + time.sleep(.1) + _login(device, is_Q, bypass_pin) + # 2nd confirmation entry + _login(device, is_Q, bypass_pin) + + time.sleep(2) + sim.stop() # power off + + sim = ColdcardSimulator(args=["--q1" if is_Q else "", "--pin", "22-22", "--early-usb"]) + sim.start(start_wait=6) + device = ColdcardDevice(is_simulator=True) + secs = 5 + + _login(device, is_Q, bypass_pin) + time.sleep(.1) + title, story = _cap_story(device) + assert "Spending Policy Unlock" in story + _press_select(device, is_Q) + time.sleep(.1) + _login(device, is_Q, "22-22") + + time.sleep(.15) + scr = " ".join(_cap_screen(device).split("\n")) + assert "Login countdown in effect" in scr + assert "Must wait:" in scr + assert f"{secs}s" in scr + time.sleep(secs + 1) + _login(device, is_Q, "22-22") + time.sleep(3) + m = _cap_menu(device) + assert "Ready To Sign" in m + sim.stop() + + +def test_sssp_trick_pins(request): + # only testing countdown TP + ct_pin = "89-89" + bypass_pin = "15-16" + is_Q = request.config.getoption('--Q') + clean_sim_data() # remove all from previous + sim = ColdcardSimulator(args=["--q1" if is_Q else "", "--pin", "22-22", "--early-usb"]) + sim.start(start_wait=6) + device = ColdcardDevice(is_simulator=True) + _login(device, is_Q, "22-22") + + _pick_menu_item(device, is_Q, "Settings") + _pick_menu_item(device, is_Q, "Login Settings") + _pick_menu_item(device, is_Q, "Trick PINs") + + # now countdown TP + _pick_menu_item(device, is_Q, "Add New Trick") + time.sleep(.1) + + for ch in ct_pin[:2]: + _need_keypress(device, ch) + time.sleep(.1) + _press_select(device, is_Q) + + if not is_Q: + # anti-phishing words + _press_select(device, is_Q) + + for ch in ct_pin[-2:]: + _need_keypress(device, ch) + time.sleep(.1) + _press_select(device, is_Q) + + _pick_menu_item(device, is_Q, "Login Countdown") + _press_select(device, is_Q) + time.sleep(.1) + + _pick_menu_item(device, is_Q, "Just Countdown") + for _ in range(2): + _press_select(device, is_Q) + time.sleep(.1) + + # adjust countdown to lowest possible value + _pick_menu_item(device, is_Q, f'↳{ct_pin}') + _pick_menu_item(device, is_Q, '↳Countdown') + _need_keypress(device, "4") + _pick_menu_item(device, is_Q, " 5 minutes") + + for _ in range(10): + _press_cancel(device, is_Q) + + time.sleep(.1) + _pick_menu_item(device, is_Q, "Advanced/Tools") + _pick_menu_item(device, is_Q, "Spending Policy") + _pick_menu_item(device, is_Q, "Single-Signer") + _press_select(device, is_Q) # confirm story + # now create bypass PIN + # 1st entry + time.sleep(.1) + _login(device, is_Q, bypass_pin) + # 2nd confirmation entry + _login(device, is_Q, bypass_pin) + + time.sleep(2) + sim.stop() + + sim = ColdcardSimulator(args=["--q1" if is_Q else "", "--pin", "22-22", "--early-usb"]) + sim.start(start_wait=6) + device = ColdcardDevice(is_simulator=True) + + _login(device, is_Q, bypass_pin) + time.sleep(.1) + title, story = _cap_story(device) + assert "Spending Policy Unlock" in story + _press_select(device, is_Q) + time.sleep(.1) + # try to log in with countdown TP instead of main + # send you directly into countdown + _login(device, is_Q, ct_pin) + time.sleep(.15) + scr = " ".join(_cap_screen(device).split("\n")) + assert "Login countdown in effect" in scr + assert "Must wait:" in scr + assert "5s" in scr + time.sleep(6) + + sim.stop() # EOF diff --git a/testing/pytest.ini b/testing/pytest.ini index 5c80ecdd..a56b54e9 100644 --- a/testing/pytest.ini +++ b/testing/pytest.ini @@ -1,7 +1,7 @@ [pytest] -addopts = -vvx --disable-warnings +;addopts = -vvx --disable-warnings # you need to comment above and uncomment below to use run_sim_tests.py -#addopts = -vv --disable-warnings +addopts = -vv --disable-warnings markers = bitcoind: indicates local bitcoind (testnet) will be needed onetime: test cant be combined with any others, likely needs board reset diff --git a/testing/requirements.txt b/testing/requirements.txt index e0e1a6ff..920c4b4b 100644 --- a/testing/requirements.txt +++ b/testing/requirements.txt @@ -23,3 +23,5 @@ git+https://github.com/coinkite/bsms-bitcoin-secure-multisig-setup.git@master#eg # BBQr library git+https://github.com/coinkite/BBQr.git@master#egg=bbqr&subdirectory=python +# for backend testing +requests==2.32.4 diff --git a/testing/run_sim_tests.py b/testing/run_sim_tests.py index d5fb9797..d54a1d46 100644 --- a/testing/run_sim_tests.py +++ b/testing/run_sim_tests.py @@ -30,16 +30,82 @@ python run_sim_tests.py --collect veryslow # just print all python run_sim_tests.py --collect manual # just print all manual tests to stdout Make sure to run manual test if you want to state that your changes passed all the tests. + +Testing on multiple simulators in parallel + +python run_sim_tests.py --q1 --multiproc # to run all Q tests in parallel (default num-proc=14 simulators) +python run_sim_tests.py --multiproc --num-proc 6 # to run all Mk4 tests in parallel max 6 simulators at once +python run_sim_tests.py -m test_addr.py -m test_bbqr.py --multiproc # just desired test +python run_sim_tests.py --q1 -m test_sign.py --multiproc # just desired test +python run_sim_tests --multiproc --turbo # turbo causes both Mk4 & Q tests to run simultaneously (turbo doubles num-procs) +python run_sim_tests --multiproc --turbo # all Mk4 & Q tests run in 60 minutes total!! +python run_sim_tests --multiproc --turbo -m test_addr.py -m test_ux.py # will spawn 4 simulators: one Q and one Mk4 for address tests & one Q and one Mk4 for ux tests + +Console output has some useful info: +* when job is started it will print its PID +* when job is done you'll get elapsed time from start (test duration) +* when all is done - complete test session duration + +``` +$ python run_sim_tests.py -m test_addr.py -m test_drv_entro.py -m test_usb.py --multiproc --turbo +started: Mk4 test_addr.py 38824 +started: Q test_addr.py 38935 +started: Mk4 test_drv_entro.py 39042 +started: Q test_drv_entro.py 39150 +started: Mk4 test_usb.py 39257 +started: Q test_usb.py 39364 +done: Mk4 test_usb.py 0:00:06.043072 +done: Q test_usb.py 0:00:06.081147 +done: Mk4 test_addr.py 0:00:51.141250 +done: Q test_addr.py 0:01:03.185571 +done: Mk4 test_drv_entro.py 0:03:24.234521 +done: Q test_drv_entro.py 0:03:30.278795 + + +elapsed: 0:03:50.308146 +``` + +After jobs are finished, or even during execution you can inspect `/tmp/cc-simulators` directory: +* contains simulator work directories named as of specific simulator +* log directories where pytest output is piped + * mk4_logs + * q1_logs + +``` +$ pwd +/tmp/cc-simulators +$ ls +38824 38935 39042 39150 39257 39364 mk4_logs q1_logs +$ ls 39042/* +39042/debug: +last-qr.png + +39042/MicroSD: +drv-hex-idx0-2.txt drv-pw-idx0.txt drv-words-idx0-2.txt drv-words-idx0.txt +drv-hex-idx0.txt drv-wif-idx0.txt drv-words-idx0-3.txt drv-xprv-idx0.txt + +39042/settings: + +39042/VirtDisk: +README.md +$ ls mk4_logs/ +test_addr.py.log test_drv_entro.py.log test_usb.py.log +``` + +To parse only failures use below cmd in {mk4,q1}_logs directory: +``` +for f in $(ls); do x=`grep -n "short test summary info" $f | grep -Eo '^[^:]+'`; if [ -n "$x" ];then tail -n +"$x" $f | grep -E '^FAILED|^ERROR';fi ;done +``` """ -import os, time, glob, json, pytest, atexit, signal, argparse, subprocess, contextlib +import os, time, glob, json, pytest, atexit, signal, argparse, subprocess, contextlib, shutil +from datetime import timedelta from typing import List - from pytest import ExitCode SIM_INIT_WAIT = 2 # 2 seconds, can be tweaked via cmdline arguments ( -w 6 ) - +DEFAULT_PYTEST_MARKS = "not onetime and not veryslow and not manual" @contextlib.contextmanager def pushd(new_dir): @@ -50,13 +116,17 @@ def pushd(new_dir): finally: os.chdir(previous_dir) +def clean_directory(pth): + for root, dirs, files in os.walk(pth): + for f in files: + os.unlink(os.path.join(root, f)) + for d in dirs: + shutil.rmtree(os.path.join(root, d)) -def remove_client_sockets(): +def remove_all_client_sockets(): with pushd("/tmp"): for fn in glob.glob("ckcc-client*.sock"): os.remove(fn) - print("Removed all client sockets") - def remove_cautious(fpath: str) -> None: if os.path.basename(fpath) in ["README.md", ".gitignore"]: @@ -99,7 +169,7 @@ def is_ok(ec: ExitCode) -> bool: def _run_pytest_tests(test_module: str, pytest_marks: str, pytest_k: str, pdb: bool, - failed_first: bool, psbt2=False, is_Q=False, headless=False) -> ExitCode: + failed_first: bool, psbt2=False, is_Q=False, headless=False, sim_socket=None) -> ExitCode: cmd_list = [ "--cache-clear", "-m", pytest_marks, "--sim", test_module if test_module is not None else "" @@ -116,42 +186,50 @@ def _run_pytest_tests(test_module: str, pytest_marks: str, pytest_k: str, pdb: b cmd_list.insert(0, "--Q") # only changes behavior in login_settings_test if headless: cmd_list.append("--headless") + if sim_socket: + cmd_list.append("--sim-socket") + cmd_list.append(sim_socket) return pytest.main(cmd_list) -def _run_coldcard_tests(test_module: str, simulator_args: List[str], pytest_marks: str, +def _run_coldcard_tests(test_module: str, simulator_args: List[str], pytest_k: str, pdb: bool, failed_first: bool, psbt2=False, - is_Q=False, headless=False) -> ExitCode: + is_Q=False, headless=False, pytest_marks: str = DEFAULT_PYTEST_MARKS, + sim_segregate=False) -> ExitCode: + sock_path = None if simulator_args is not None: - sim = ColdcardSimulator(args=simulator_args, headless=headless) + sim = ColdcardSimulator(args=simulator_args, headless=headless, segregate=sim_segregate) sim.start() time.sleep(1) + sock_path = sim.socket exit_code = _run_pytest_tests(test_module, pytest_marks, pytest_k, pdb, - failed_first, psbt2, is_Q, headless) + failed_first, psbt2, is_Q, headless, sock_path) if simulator_args is not None: sim.stop() time.sleep(1) clean_sim_data() + remove_all_client_sockets() + return exit_code def run_coldcard_tests(test_module=None, simulator_args=None, pytest_k=None, pdb=False, failed_first=False, psbt2=False, is_Q=False, headless=False, - pytest_marks="not onetime and not veryslow and not manual"): + pytest_marks=DEFAULT_PYTEST_MARKS): failed = [] - exit_code = _run_coldcard_tests(test_module, simulator_args, pytest_marks, pytest_k, - pdb, failed_first, psbt2, is_Q, headless) + exit_code = _run_coldcard_tests(test_module, simulator_args, pytest_k, + pdb, failed_first, psbt2, is_Q, headless, pytest_marks) if not is_ok(exit_code): # no success, no nothing - give failed another try, each alone with its own simulator last_failed = get_last_failed() print("Running failed from last run", last_failed) exit_codes = [] for failed_test in last_failed: - exit_code_2 = _run_coldcard_tests(failed_test, simulator_args, pytest_marks, + exit_code_2 = _run_coldcard_tests(failed_test, simulator_args, pytest_k, pdb, failed_first, psbt2, is_Q, - headless) + headless, pytest_marks) exit_codes.append(exit_code_2) if not is_ok(exit_code_2): failed.append(failed_test) @@ -173,11 +251,12 @@ class PytestCollectMarked: class ColdcardSimulator: - def __init__(self, path=None, args=None, headless=False): + def __init__(self,args=None, headless=False, segregate=False): self.proc = None self.args = args - self.path = "/tmp/ckcc-simulator.sock" if path is None else path self.headless = headless + self.segregate = segregate + self.socket = "/tmp/ckcc-simulator.sock" def start(self, start_wait=None): # here we are in testing directory @@ -188,14 +267,20 @@ class ColdcardSimulator: cmd_list.extend(self.args) if self.headless: cmd_list.append("--headless") + if self.segregate: + cmd_list.append("--segregate") self.proc = subprocess.Popen( cmd_list, # this needs to be in firmware/unix - expected to be run from firmware/testing cwd="../unix", - preexec_fn=os.setsid + preexec_fn=os.setsid, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, ) time.sleep(start_wait or SIM_INIT_WAIT) + if self.segregate: + self.socket = "/tmp/ckcc-simulator-%d.sock" % self.proc.pid atexit.register(self.stop) def stop(self): @@ -205,7 +290,6 @@ class ColdcardSimulator: os.waitpid(os.getpgid(self.proc.pid), 0) atexit.unregister(self.stop) - remove_client_sockets() def main(): @@ -233,6 +317,12 @@ def main(): help="only run tests which match the given substring expression") parser.add_argument("--headless", action="store_true", default=False, help="run simulator instance in headless mode") + parser.add_argument("--multiproc", action="store_true", default=False, + help="Run tests & simulators in parallel") + parser.add_argument("--num-proc", type=int, default=16, + help="How many executors/simulators to run in parallel in --multiproc mode") + parser.add_argument("--turbo", action="store_true", default=False, + help="Both Mk4 and Q at the same time") args = parser.parse_args() if args.sim_init_wait: @@ -258,46 +348,167 @@ def main(): if args.module is None: test_modules = [] elif len(args.module) == 1 and args.module[0].lower() == "all": - test_modules = sorted(glob.glob("test_*.py")) + test_modules = glob.glob("test_*.py") assert test_modules, "please run in ../testing subdir" else: for fn in args.module: if not os.path.exists(fn): raise RuntimeError(f"{fn} does not exist") - test_modules = sorted(args.module) + test_modules = args.module - result = [] - for test_module in test_modules: - test_args = DEFAULT_SIMULATOR_ARGS - if test_module in ["test_rng.py", "test_pincodes.py", "test_rolls.py"]: - # test_pincodes.py can only be run against real device - # test_rng.py not needed when using simulator - # test_rolls.py should be run alone as it does not need simulator - print("Skipped", test_module) - continue + # test_pincodes.py can only be run against real device + # test_rng.py not needed when using simulator + # test_rolls.py should be run alone as it does not need simulator + # set diff + test_modules = set(test_modules) - {"test_rng.py", "test_pincodes.py", "test_rolls.py"} - print("Started", test_module) + module_args = [] + for test_module in sorted(list(test_modules)): + sim_args = DEFAULT_SIMULATOR_ARGS if test_module in ["test_bsms.py", "test_address_explorer.py", "test_export.py", "test_multisig.py", "test_ux.py"]: - test_args = DEFAULT_SIMULATOR_ARGS + ["--set", "vidsk=1"] + sim_args = DEFAULT_SIMULATOR_ARGS + ["--set", "vidsk=1"] if test_module == "test_vdisk.py": - test_args = ["--eject"] + DEFAULT_SIMULATOR_ARGS + ["--set", "vidsk=1"] + sim_args = ["--eject"] + DEFAULT_SIMULATOR_ARGS + ["--set", "vidsk=1"] if test_module == "test_bip39pw.py": - test_args = [] - if test_module in ["test_unit.py", "test_se2.py", "test_backup.py"]: + sim_args = [] + if test_module in ["test_unit.py", "test_se2.py", "test_backup.py", "test_teleport.py", + "test_hobble.py", "test_sssp.py"]: # test_nvram_mk4 needs to run without --eff # se2 duress wallet activated as ephemeral seed requires proper `settings.load` - test_args = ["--set", "nfc=1"] - if test_module in ["test_ephemeral.py", "test_notes.py"]: - test_args = ["--set", "nfc=1", "--set", "vidsk=1"] + sim_args = ["--set", "nfc=1"] + if test_module in ["test_ephemeral.py", "test_notes.py", "test_ccc.py"]: + # proper `settings.load` _ virtual disk + sim_args = ["--set", "nfc=1", "--set", "vidsk=1"] - if args.q1 and '--q1' not in test_args: - test_args.append('--q1') + if args.q1 and '--q1' not in sim_args: + sim_args.append('--q1') - ec, failed_tests = run_coldcard_tests(test_module, simulator_args=test_args, - pytest_k=args.pytest_k, pdb=args.pdb, - failed_first=args.ff, psbt2=args.psbt2, - headless=args.headless) + module_args.append((test_module, sim_args, args.pytest_k, args.pdb, + args.ff, args.psbt2, args.q1, args.headless)) + + if args.multiproc: + start_time = time.time() + def add_to_queue(module_name, simulator_args, queue): + if module_name == "test_miniscript.py": + queue.append((2, [module_name, simulator_args, "not liana_miniscripts_simple and not test_tapscript and not test_bitcoind_tapscript_address and not test_minitapscript", ""])) + queue.append((0, [module_name, simulator_args, "liana_miniscripts_simple", "-sep1"])) + queue.append((2, [module_name, simulator_args, "test_tapscript", "-sep2"])) + queue.append((0, [module_name, simulator_args, "test_bitcoind_tapscript_address", "-sep3"])) + queue.append((0, [module_name, simulator_args, "test_minitapscript", "-sep4"])) + + elif module_name == "test_multisig.py": + # split takes too much time + queue.append((0, [module_name, simulator_args, "not tutorial and not airgapped and not ms_address and not descriptor_export", ""])) + queue.append((0, [module_name, simulator_args, "airgapped", "-sep1"])) + queue.append((0, [module_name, simulator_args, "tutorial", "-sep2"])) + queue.append((0, [module_name, simulator_args, "ms_address", "-sep3"])) + queue.append((0, [module_name, simulator_args, "descriptor_export", "-sep4"])) + + elif module_name == "test_seed_xor.py": + # split takes too much time + queue.append((0, [module_name, simulator_args, "test_import_xor", "-sep1"])) + queue.append((0, [module_name, simulator_args, "not test_import_xor", ""])) + + elif module_name in ["test_export.py", "test_ephemeral.py", "test_sign.py", "test_msg.py", + "test_backup.py", "test_bsms.py"]: + # higher priority + queue.append((1, [module_name, simulator_args, None, ""])) + + else: + # standard priority + queue.append((2, [module_name, simulator_args, None, ""])) + + # will clear everything there from previous runs + tmp_dir = "/tmp/cc-simulators" + clean_directory(tmp_dir) # clean it + mk4_log_dir = f"{tmp_dir}/mk4_logs" + q1_log_dir = f"{tmp_dir}/q1_logs" + os.makedirs(mk4_log_dir, exist_ok=True) + os.makedirs(q1_log_dir, exist_ok=True) + + q = [] # build priority queue + for mod_name, sim_args, *_ in module_args: + if args.turbo: + if "--q1" in sim_args: + add_to_queue(mod_name, sim_args, q) + add_to_queue(mod_name, [i for i in sim_args if i == "--q1"], q) + else: + add_to_queue(mod_name, sim_args, q) + add_to_queue(mod_name, sim_args + ["--q1"], q) + + else: + add_to_queue(mod_name, sim_args, q) + + # sort queue by priority, highest priority elements at the end + q = [i[1] for i in sorted(q, reverse=True)] + + num_proc = args.num_proc + if args.turbo: + # double num-proc + num_proc *= 2 + + procs = [] + while True: + # create as many processes as allowed by --num-proc (default=14) + if q and (len(procs) < num_proc): + # start simulators first + q_chunks = [] + for _ in range (num_proc - len(procs)): + try: + mn, sim_args, k, mod_add = q.pop() # remove element + except IndexError: + # priority queue is empty + break + sim = ColdcardSimulator(sim_args, segregate=True) + sim.start(start_wait=0) + ld = q1_log_dir if "--q1" in sim_args else mk4_log_dir + q_chunks.append((sim, mn, mod_add, k, ld)) + + time.sleep(5) + for sim, mn, mod_add, k, log_dir in q_chunks: + assert sim.socket + out_log_path = f"{log_dir}/%s.log" % (mn + mod_add) + out_fd = open(out_log_path, "w") + cmd_list = ["pytest", "--cache-clear", "-m", DEFAULT_PYTEST_MARKS, "--sim", + mn, "--sim-socket", sim.socket] + if k: + cmd_list.extend(["-k", k]) + p = subprocess.Popen(cmd_list, preexec_fn=os.setsid, stdout=out_fd, stderr=out_fd) + mark = "Q" if "q1" in log_dir else "Mk4" + procs.append((mn+mod_add, p, out_fd, sim, mark, time.time())) + print(f'started: {mark:<6}{mn+mod_add:<30}{sim.socket.split("-")[-1].split(".")[0]:<10}') + + if not procs and not q: + # done + break + + i = 0 + while i < len(procs): + mn, p, out_fd, sim, mark, st = procs[i] + if p.poll() is None: + # still running + i += 1 + continue + else: + # done + p.communicate() + out_fd.close() + sim.stop() + del procs[i] + print(f"done: {mark:<6}{mn:<30}{str(timedelta(seconds=time.time()-st)):<15}") + + time.sleep(3) + + # multiprocess done + print(f"\n\nelapsed: {str(timedelta(seconds=time.time()-start_time))}") + return + + result = [] + for arguments in module_args: + test_module = arguments[0] + print("Started", test_module) + ec, failed_tests = run_coldcard_tests(*arguments) result.append((test_module, ec, failed_tests)) print("Done", test_module) print(80 * "=") @@ -362,5 +573,8 @@ def main(): if __name__ == "__main__": main() - + # sim = ColdcardSimulator(args=["--eff", "--segregate"]) + # sim.start() + # import pdb;pdb.set_trace() + # x = 5 # EOF diff --git a/testing/seedless_tests.py b/testing/seedless_tests.py index 05555e5d..4920bb84 100644 --- a/testing/seedless_tests.py +++ b/testing/seedless_tests.py @@ -3,9 +3,9 @@ import pytest, pdb, time, random, os from charcodes import KEY_CANCEL from core_fixtures import _pick_menu_item, _press_select -from core_fixtures import _need_keypress, _cap_screen, _sim_exec +from core_fixtures import _need_keypress, _sim_exec from run_sim_tests import ColdcardSimulator, clean_sim_data -from ckcc_protocol.client import ColdcardDevice, CKCC_SIMULATOR_PATH +from ckcc_protocol.client import ColdcardDevice def test_status_bar_rewrite_after_restore_master(request): @@ -13,7 +13,7 @@ def test_status_bar_rewrite_after_restore_master(request): clean_sim_data() # remove all from previous sim = ColdcardSimulator(args=["--q1", "-l"]) sim.start(start_wait=3) - device = ColdcardDevice(sn=CKCC_SIMULATOR_PATH) + device = ColdcardDevice(is_simulator=True) _pick_menu_item(device, True, "Advanced/Tools") _pick_menu_item(device, True, "Temporary Seed") diff --git a/testing/teleport_cli.py b/testing/teleport_cli.py new file mode 100644 index 00000000..636310ce --- /dev/null +++ b/testing/teleport_cli.py @@ -0,0 +1,138 @@ +# (c) Copyright 2025 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# +# Key Teleport protocol re-implementation: CLI for humans (testing purposes only). +# +import click, pyqrcode, json +from bbqr import split_qrs +from pysecp256k1.extrakeys import keypair_create, keypair_sec +from teleport_protocol import (receiver_step1, sender_step1, txt_grouper, stash_encode_secret, + stash_decode_secret, receiver_step2) + + +def show_payload(payload, type_code, title, msg): + vers, parts = split_qrs(payload, type_code, max_version=5) + qs = [pyqrcode.create(part, error='L', version=vers, mode='alphanumeric') + for part in parts] + + for q in qs: + click.echo(q.terminal()) + + click.echo("\nBBQr payload:") + for p in parts: + click.echo(p) + + click.echo() + click.echo(title) + click.echo(msg) + +def show_received(dtype, data): + if dtype == 's': + # words / bip 32 master / xprv, etc + noun, decoded = stash_decode_secret(data) + print(f"Received {noun} via teleport:\n", decoded) + + elif dtype == 'x': + # TODO seems can be removed + # it's an XPRV, but in binary.. some extra data we throw away here; sigh + # XXX no way to send this .. but was thinking of address explorer + raise NotImplementedError + + elif dtype == 'p': + # raw PSBT -- much bigger more complex + raise NotImplementedError + + elif dtype == 'b': + # full system backup, including master: text lines + print("Received backup via Teleport:\n") + for ln in data.decode().split('\n'): + if not ln: continue + print(ln) + + elif dtype == 'v': + # one key export from a seed vault + # - watch for incompatibility here if we ever change VaultEntry + print("Received Seed Vault entry via Teleport:\n", json.loads(data)) + elif dtype == 'n': + # import secure note(s) + print("Received secure note(s) via Teleport:\n", json.loads(data)) + else: + raise ValueError("Unknown type", dtype) + +@click.group() +def main(): + pass + +@main.command('recv_init') +@click.option('--secret', '-k', type=str, default=None, + help='Ephemeral private key used to create shared ECDH key') +def recv_init(secret): + number_pass, enc_pubkey, kp_receiver = receiver_step1(secret=secret) + msg = (f'To receive sensitive data from another COLDCARD,' + f'share this Receiver Password with sender:\n\t{number_pass}' + f' = {txt_grouper(number_pass)}') + + show_payload(enc_pubkey, "R", 'Key Teleport: Receive', msg) + if secret is None: + # if user haven't specified secret for ECDH keypair dump it to stdout + # it is needed as second arguemnt to "recv" cmd + click.echo("Picked ephemeral ECDH key: " + keypair_sec(kp_receiver).hex()) + + click.echo() + # encrypted pubkey payload is first argument to "send" cmd + click.echo("Encrypted pubkey (payload): " + enc_pubkey.hex()) + + +@main.command('send') +@click.argument('payload', type=str) +@click.option('--secret', '-k', type=str, default=None, + help='Ephemeral private key used to create shared ECDH key') +@click.option('--password', prompt=True, required=True) +@click.option('--mnemonic', type=str, default=None) +@click.option('--xprv', type=str, default=None) +@click.option('--text', type=str, default=None) +@click.option('--backup', type=click.Path(exists=True), default=None) +def send(payload, secret, password, mnemonic, xprv, text, backup): + if mnemonic: + cleartext = b"s" + stash_encode_secret(words=mnemonic) + elif xprv: + cleartext = b"s" + stash_encode_secret(xprv=xprv) + elif text: + cleartext = b"n" + json.dumps([{"title": "Quick Note", "misc":text}]).encode() + else: + assert backup + out = [] + with open(backup, "r") as f: # this needs to be cleartext backup + for ln in f.readlines(): + if not ln: continue + if ln[0] == '#': continue + out.append(ln.encode()) + + cleartext = b"b" + b'\n'.join(ln for ln in out) + + noid_txt, encrypted_payload, kp_sender, pk_rec = sender_step1( + password, bytes.fromhex(payload), cleartext, secret=secret + ) + msg = ("Share this password with the receiver, via some different channel:" + "\n\n\t%s = %s" % (noid_txt, txt_grouper(noid_txt))) + show_payload(encrypted_payload, "S", 'Teleport Password', msg) + + click.echo() + # encrypted payload is first arguemnt to "recv" cmd + click.echo("Encrypted payload: " + encrypted_payload.hex()) + + +@main.command('recv') +@click.argument('payload', type=str) +@click.argument('secret', type=str) +@click.option('--password', prompt=True, required=True) +def recv(payload, secret, password): + dtype, received = receiver_step2(password.upper(), bytes.fromhex(payload), + keypair_create(bytes.fromhex(secret))) + click.echo() + show_received(dtype, received) + + +if __name__ == "__main__": + main() + +# EOF diff --git a/testing/teleport_protocol.py b/testing/teleport_protocol.py new file mode 100644 index 00000000..0bfebe52 --- /dev/null +++ b/testing/teleport_protocol.py @@ -0,0 +1,256 @@ +# (c) Copyright 2025 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# +# Key Teleport protocol re-implementation. +# +import os, pyaes, hashlib, base64 +from bip32 import BIP32Node, PrvKeyNode +from mnemonic import Mnemonic +from pysecp256k1 import ec_seckey_verify, ec_pubkey_serialize, ec_pubkey_parse +from pysecp256k1.extrakeys import keypair_create, keypair_sec, keypair_pub +from pysecp256k1.ecdh import ecdh, ECDH_HASHFP_CLS + + +wordlist = Mnemonic('english').wordlist + +def py_ckcc_hashfp(output, x, y, data=None): + try: + m = hashlib.sha256() + m.update(x.contents.raw) + m.update(y.contents.raw) + output.contents.raw = m.digest() + return 1 + except: + return 0 + +ckcc_hashfp = ECDH_HASHFP_CLS(py_ckcc_hashfp) + + +def txt_grouper(txt): + # split into 2-char groups and add spaces -- to make it easier to read/remember + return ' '.join(txt[n:n+2] for n in range(0, len(txt), 2)) + +def stash_encode_secret(words=None, xprv=None): + nv = bytearray(72) + if words: + wlen = len(words.split(" ")) + assert wlen in [12, 18, 24] + entropy = Mnemonic('english').to_entropy(words) + nv[0] = (0x80 | ((len(entropy) // 8) - 2)) + nv[1:1 + wlen] = entropy + + elif xprv: + node = BIP32Node.from_wallet_key(xprv) + nv[0] = 0x01 + nv[1:33] = node.chain_code() + nv[33:65] = node.privkey() + + # trim zeros + while nv[-1] == 0: + nv = nv[0:-1] + + return nv + +def stash_decode_secret(secret_bytes): + marker = secret_bytes[0] + + if marker == 0x01: + ch, pk = secret_bytes[1:33], secret_bytes[33:65] + n = PrvKeyNode(pk, ch) + node = BIP32Node(netcode='BTC', node=n) + return "xprv", node.hwif(as_private=True) + + elif marker & 0x80: + # seed phrase + ll = ((marker & 0x3) + 2) * 8 + assert ll in [16, 24, 32] + + # make master secret, using the memonic words, and passphrase (or empty string) + seed_bits = secret_bytes[1:1 + ll] + + return "words", Mnemonic('english').to_mnemonic(seed_bits) + + +def generate_rx_code(kp): + # Receiver-side password: given a pubkey (33 bytes, compressed format) + # - construct an 8-digit decimal "password" + # - it's an AES key, but only 26 bits worth + pubkey = bytearray(ec_pubkey_serialize(keypair_pub(kp), compressed=True)) + + # - want the code to be deterministic, but I also don't want to save it + # - double sha256 TODO why ? single sha is imo enough and twice as fast + nk = hashlib.sha256(hashlib.sha256(keypair_sec(kp) + b'COLCARD4EVER').digest()).digest() + + # first byte will be 0x02 or 0x03 (Y coord) -- remove those known 7 bits + pubkey[0] ^= nk[20] & 0xfe + + num = '%08d' % (int.from_bytes(nk[4:8], 'big') % 1_0000_0000) + + # encryption after baby key stretch + kk = hashlib.sha256(num.encode()).digest() + + enc = pyaes.AESModeOfOperationCTR(kk, pyaes.Counter(0)).encrypt + ciphertext = enc(bytes(pubkey)) + + return num, ciphertext + + +def decrypt_rx_pubkey(code, payload): + # given an 8-digit numeric code, make the key and then decrypt/checksum check + # - every value works, there is no fail. + kk = hashlib.sha256(code.encode()).digest() + dec = pyaes.AESModeOfOperationCTR(kk, pyaes.Counter(0)).decrypt + rx_pubkey = bytearray(dec(payload)) + + # first byte will be 0x02 or 0x03 but other 7 bits are noise + rx_pubkey[0] &= 0x01 + rx_pubkey[0] |= 0x02 + + pubkey = bytes(rx_pubkey) + + # validate that it's on the curve... otherwise the code is wrong + try: + ec_pubkey_parse(pubkey) + return pubkey + except: + return None + + +def pick_noid_key(): + # pick an 40 bit password, shown as base32 + # - on rx, libngu base32 decoder will convert '018' into 'OLB' + # - but a little tempted to removed vowels here? + # TODO what about base64.b32encode + k = os.urandom(5) + txt = base64.b32encode(k).decode() + return k, txt + + +def noid_stretch(session_key, noid_key): + return hashlib.pbkdf2_hmac('sha512', session_key, noid_key, 5000)[0:32] + + +def encode_payload(my_keypair, his_pubkey, noid_key, body, for_psbt=False): + assert len(his_pubkey) == 33 + assert len(noid_key) == 5 + + session_key = ecdh(keypair_sec(my_keypair), ec_pubkey_parse(his_pubkey), hashfp=ckcc_hashfp) + + # stretch noid key out -- will be slow + pk = noid_stretch(session_key, noid_key) + + enc = pyaes.AESModeOfOperationCTR(pk, pyaes.Counter(0)).encrypt + b1 = enc(body) + b1 += hashlib.sha256(body).digest()[-2:] + + enc = pyaes.AESModeOfOperationCTR(session_key, pyaes.Counter(0)).encrypt + b2 = enc(b1) + b2 += hashlib.sha256(b1).digest()[-2:] + + if for_psbt: + # no need to share pubkey for PSBT files + return b2 + + return ec_pubkey_serialize(keypair_pub(my_keypair)) + b2 + +def decode_step1(my_keypair, his_pubkey, body): + # Do ECDH and remove top layer of encryption + try: + session_key = ecdh(keypair_sec(my_keypair), ec_pubkey_parse(his_pubkey), hashfp=ckcc_hashfp) + dec = pyaes.AESModeOfOperationCTR(session_key, pyaes.Counter(0)).decrypt + rv = dec(body[:-2]) + chk = hashlib.sha256(rv).digest()[-2:] + assert chk == body[-2:] # likely means wrong rx key, or truncation + except: + return None, None + + return session_key, rv + +def decode_step2(session_key, noid_key, body): + assert len(noid_key) == 5 + pk = noid_stretch(session_key, noid_key) + dec = pyaes.AESModeOfOperationCTR(pk, pyaes.Counter(0)).decrypt + msg = dec(body[:-2]) + chk = hashlib.sha256(msg).digest()[-2:] + return msg if chk == body[-2:] else None + +def receiver_step1(secret=None): + if secret is None: + secret = os.urandom(32) + ec_seckey_verify(secret) + kpr = keypair_create(secret) + num, payload = generate_rx_code(kpr) + return num, payload, kpr + +def sender_step1(num_pwd, encrypted_pubkey, to_send, secret=None): + pkr = decrypt_rx_pubkey(num_pwd, encrypted_pubkey) + + # Pick and show noid key to sender + noid_key, noid_txt = pick_noid_key() + + if secret is None: + secret = os.urandom(32) + + ec_seckey_verify(secret) + kps = keypair_create(secret) + + # "to_send" has to be properly encoded (dtype + what) + payload = encode_payload(kps, pkr, noid_key, to_send) + return noid_txt, payload, kps, pkr + +def receiver_step2(teleport_pwd, payload, keypair): + assert len(teleport_pwd) == 8 + noid_key = base64.b32decode(teleport_pwd) + his_pubkey = payload[0:33] + body = payload[33:] + + session_key, body = decode_step1(keypair, his_pubkey, body) + final = decode_step2(session_key, noid_key, body) + if final: + return chr(final[0]), final[1:] + else: + return None, None + + +def selftest(): + # WORDS + # RECEIVER INIT + number_pass, enc_pubkey, kp_receiver = receiver_step1() + + # SENDER + # what are we sending ? + words = "talk retire wisdom poet actress hood goose case amateur zebra analyst radar" + cleartext = b"s" + stash_encode_secret(words=words) + noid_txt, encrypted_payload, kp_sender, pk_rec = sender_step1(number_pass, enc_pubkey, cleartext) + + # check we properly decrypted receiver pubkey + assert pk_rec == ec_pubkey_serialize(keypair_pub(kp_receiver)) + + # RECEIVER STEP2 + _, received = receiver_step2(noid_txt, encrypted_payload, kp_receiver) + assert words == stash_decode_secret(received)[1] + # === + + # XPRV + # RECEIVER INIT + number_pass, enc_pubkey, kp_receiver = receiver_step1() + + # SENDER + # what are we sending ? + xprv = "xprv9s21ZrQH143K4BwRCYKSEPwcAMYweWkfKLURabnnv2GLNhJN1LSCgDQyGWyNcat72najQKwyshCBXWfHHVbcdxPAZPqByMyWDbWp5SjCfEa" + cleartext = b"s" + stash_encode_secret(xprv=xprv) + noid_txt, encrypted_payload, kp_sender, pk_rec = sender_step1(number_pass, enc_pubkey, cleartext) + + # check we properly decrypted receiver pubkey + assert pk_rec == ec_pubkey_serialize(keypair_pub(kp_receiver)) + + # RECEIVER STEP2 + _, received = receiver_step2(noid_txt, encrypted_payload, kp_receiver) + assert xprv == stash_decode_secret(received)[1] + # === + + print("Selftest passed.") + +if __name__ == "__main__": + selftest() + +# EOF diff --git a/testing/test_640_migrations.py b/testing/test_640_migrations.py new file mode 100644 index 00000000..f6e8a596 --- /dev/null +++ b/testing/test_640_migrations.py @@ -0,0 +1,545 @@ +import pytest, time, base64, shutil + + +msc0 = ('msc0', 'XTN', 14, None, + ['[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<0;1>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<2;3>/*'], + 'or_d(pk(@0/<0;1>/*),and_v(v:pkh(@0/<2;3>/*),older(5)))', + False, True, False, False) +psbt0 = 'cHNidP8BAIkCAAAAAZUEvRkqYPrqNKdvyfg7NQopNrWECJgMNqjca1IcEIVTAQAAAAD9////ApQuGh4BAAAAIgAgGjlJEPeLTybA3gHmfxuqEd7X1+PQZN31PiCG5GIfo5QA4fUFAAAAACIAIBO/Xj1D55iB+2Vdhp0jRls7TMrYi3kDWrSGbF07PwfHAAAAAAABAH0CAAAAAXB5YpRHvulXzMx3Gb+uCMYBCG3m4huSm9AAc8OoWQ70AAAAAAD9////AgzV9QUAAAAAFgAUOG3K9ZXBYY3cvxmqFWXyHewk/K0AERAkAQAAACIAIGdWKDqhxwBgKRV7QF+tYv516km5iOKZw8CktnFKO6VmZQAAAAEBKwARECQBAAAAIgAgZ1YoOqHHAGApFXtAX61i/nXqSbmI4pnDwKS2cUo7pWYBBUEhAv4uHbVQEQkVrUThtBx6BnGlZJcyVHMKOYaJoBpEjQJyrHNkdqkUM+9pq+yldgqOn/1x/0rqPEMVp86IrVWyaCIGAv4uHbVQEQkVrUThtBx6BnGlZJcyVHMKOYaJoBpEjQJyGA8FaUNUAACAAQAAgAAAAIAAAAAAAAAAACIGA2e65FIqxSTkQqvwsotxrrWTyaY1q47lIMO19ZaZ8D9zGA8FaUNUAACAAQAAgAAAAIACAAAAAAAAAAABAUEhAv4IiIHn01IKyw4lEaIxhArVyFqGABpomkhcTjULKKv7rHNkdqkUqOoqpzlXZR4XRJ8ozXFV3QTy8bCIrVWyaCICAt97v3uk5Jw1GcvpwazScC2ZRQPNOI7QqwAO7GYhQFJ7GA8FaUNUAACAAQAAgAAAAIADAAAAAAAAACICAv4IiIHn01IKyw4lEaIxhArVyFqGABpomkhcTjULKKv7GA8FaUNUAACAAQAAgAAAAIABAAAAAAAAAAABAUEhA4/rg1i66LDEfY+O55hN2NoI/I/DlwP21VPYbrGIoWiMrHNkdqkUxeG8e0VP5VXSyTnAGNyZJdSljFSIrVWyaCICAxtQTXbpjMrxg7OlwJvsVHMO0LcUtasy4ofc4KsG7lMaGA8FaUNUAACAAQAAgAAAAIACAAAAAQAAACICA4/rg1i66LDEfY+O55hN2NoI/I/DlwP21VPYbrGIoWiMGA8FaUNUAACAAQAAgAAAAIAAAAAAAQAAAAA=' + +msc1 = ('msc1', 'XTN', 14, None, + ['[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<2147483646;2147483647>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<100;101>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<26;27>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<4;5>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<20;21>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<104;105>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<22;23>/*'], + 'or_i(and_v(v:pkh(@0/<2147483646;2147483647>/*),older(10)),or_d(multi(3,@0/<100;101>/*,@0/<26;27>/*,@0/<4;5>/*),and_v(v:thresh(2,pkh(@0/<20;21>/*),a:pkh(@0/<104;105>/*),a:pkh(@0/<22;23>/*)),older(5))))', + False, True, False, False) +psbt1 = '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' + +msc2 = ('msc2', 'XTN', 35, + 'tpubD6NzVbkrYhZ4WhUnV3cPSoRWGf9AUdG2dvNpsXPiYzuTnxzAxemnbajrATDBWhaAVreZSzoGSe3YbbkY2K267tK3TrRmNiLH2pRBpo8yaWm/<2;3>/*', + ['[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<0;1>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<2;3>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<2147483646;2147483647>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<100;101>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<26;27>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<4;5>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<20;21>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<104;105>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<22;23>/*'], + '{or_d(pk(@0/<0;1>/*),and_v(v:pkh(@0/<2;3>/*),older(5))),or_i(and_v(v:pkh(@0/<2147483646;2147483647>/*),older(10)),or_d(multi_a(3,@0/<100;101>/*,@0/<26;27>/*,@0/<4;5>/*),and_v(v:thresh(2,pkh(@0/<20;21>/*),a:pkh(@0/<104;105>/*),a:pkh(@0/<22;23>/*)),older(5))))}', + False, False, False, True) +psbt2 = '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' + +msc3 = ('msc3', 'XTN', 35, + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<66;67>/*', + ['[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<0;1>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<2;3>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<2147483646;2147483647>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<100;101>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<26;27>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<4;5>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<20;21>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<104;105>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<22;23>/*'], + '{or_d(pk(@0/<0;1>/*),and_v(v:pkh(@0/<2;3>/*),older(5))),or_i(and_v(v:pkh(@0/<2147483646;2147483647>/*),older(10)),or_d(multi_a(3,@0/<100;101>/*,@0/<26;27>/*,@0/<4;5>/*),and_v(v:thresh(2,pkh(@0/<20;21>/*),a:pkh(@0/<104;105>/*),a:pkh(@0/<22;23>/*)),older(5))))}', + False, False, False, True) +psbt3 = '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' + +msc4 = ('msc4', 'XTN', 35, + 'unspend(eaa76f06a330102de2653adda09522b704868d1e5ec63b6eadf35906d5ef47a8)/<2;3>/*', + ['[5baa3998/44h/1h/0h]tpubDC8cZY4a6nmoa9DDumkEayC7Sn6sMXjwTPYbYb91KH5GoT8G9nHFpLSaWe7xcHXARepk3q5h1vLsJgpeSzcggFVdhGpKkqK1Ujv8KFBbv9K/<0;1>/*', + '[0f056943/86h/1h/0h]tpubDCeEX49avtiXrBTv3JWTtco99Ka499jXdZHBRtm7va2gkMAui11ctZjqNAT9dLVNaEozt2C1kfTM88cnvZCXsWLJN2p4viGvsyGjtKVV7A1/<4;5>/*', + '[0f056943/86h/1h/0h]tpubDCeEX49avtiXrBTv3JWTtco99Ka499jXdZHBRtm7va2gkMAui11ctZjqNAT9dLVNaEozt2C1kfTM88cnvZCXsWLJN2p4viGvsyGjtKVV7A1/<6;7>/*'], + '{or_d(pk(@0/<0;1>/*),and_v(v:pkh(@1/<4;5>/*),older(5))),pk(@1/<6;7>/*)}', + False, False, False, True) +psbt4 = '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' + +msc5 = ('msc5', 'XTN', 35, + 'tpubD6NzVbkrYhZ4WeQCEoPi88B5FpWsnGfBmm76EUtexSg17KaNVAPeGwYWJ4aD1YDrFZ9P6pNAZEpWZHtBczPryBDKXQnhn1VPWAiSE5AzgSc/<0;1>/*', + ['[c65b017a/44h/1h/0h]tpubDD1b2M82BJ2PWbC2KyUaTEgFiUsYrd9QU8dMTbcXTRZA9rBMnbMQLB1ZU1icGSBZwd8KNm7oD3GceMMW7y1t27xmVLUaSChGxtyM3NoxLi2/<0;1>/*', + '[0f056943/86h/1h/0h]tpubDCeEX49avtiXrBTv3JWTtco99Ka499jXdZHBRtm7va2gkMAui11ctZjqNAT9dLVNaEozt2C1kfTM88cnvZCXsWLJN2p4viGvsyGjtKVV7A1/<0;1>/*', + '[ff12824b/44h/1h/0h]tpubDDcx2UWrF6LRNdGGYoLFkfZZuahG63yBN4BuNiuSEfFfhCAGJU81QKw1zbQVM8sn1NomMa1LSZLh7mzK8gxfpuRHbXhykg4wXK6dg56pnti/<0;1>/*', + '[b69b3715/44h/1h/0h]tpubDDRVW8LtH1wB2JrSEGf8eixM1HrjZVJCx6NNbxNpyZ775CGFMVLQ3dppmK7b75Ze3uZeAKiV1RDWotMXU2ns2mcUEmdZosaSfCg6QwJsRnH/<0;1>/*'], + '{pk(@0/<0;1>/*),or_d(multi_a(2,@1/<0;1>/*,@2/<0;1>/*),and_v(v:pkh(@3/<0;1>/*),older(5)))}', + False, False, False, True) +psbt5 = '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' + +msc6 = ('msc6', 'XTN', 14, None, + ['[22da0343/44h/1h/0h]tpubDDTfrYcgqkLoq79TNkVThZ9nqW4VWJRY3zCWkQnNkXzoraF5GMENKPJM1dMQascfTBNJstMLkmJLJ3k4b1k9rAjf3dgNMhYMfHJSUcM4hgL/<0;1>/*', + '[0f056943/84h/0h/0h]tpubDCx8y86cKonoPyTtj3f9NZLpBYoBNkbAzUdafMHhggjxkhF8Dny2aekWfDafywEMZEQaQjkK9Gxn7aN7usLRUQdYbvDgcnmYRf72khPEouL/<0;1>/*'], + 'or_d(pk(@0/<0;1>/*),and_v(v:pkh(@1/<0;1>/*),older(5)))', + False, True, False, False) +psbt6 = 'cHNidP8BAIkCAAAAAZ+qJdb0lqGAEMPMICKWzLnUyZliwuofNPuaoUXOdEeyAQAAAAAFAAAAAgDh9QUAAAAAIgAgeZUP3ag3Z9LPoDX/lgAjY4rVzLqCGWvH80nX61Ri3S3IIRoeAQAAACIAIAVYxCfKPiVyBGJlO00OLCd2WF3l/2GIKn1QmzW57W9BAAAAAAABAH0CAAAAAZ2QKy6wW7VGwLcuoMi8VF1lwZasFgPRiFjsgYvBBcU6AAAAAAD9////AgzV9QUAAAAAFgAU5QE7LsYrtnlIArQ3lTiyZt3RpdMAERAkAQAAACIAICxBuCUbPghtGArbOkNpOP+fezN7K2cnLIZl13CsXHeNZQAAAAEBKwARECQBAAAAIgAgLEG4JRs+CG0YCts6Q2k4/597M3srZycshmXXcKxcd40BBUEhA9u0i9ZASI19YAJbZ/7VTcyi+Xp/P1y2kGWIK7KwZhY0rHNkdqkUwlbbAR/7nTxMoBnCUFuf0H4/YzqIrVWyaCIGAm6bjASKZuCeW7cfyV8nBfPu8dy/m21Jul2/3o7pZPSqGA8FaUNUAACAAAAAgAAAAIAAAAAAAAAAACIGA9u0i9ZASI19YAJbZ/7VTcyi+Xp/P1y2kGWIK7KwZhY0GCLaA0MsAACAAQAAgAAAAIAAAAAAAAAAAAABAUEhA0fM+aMLp/bIHqWfZNEJQQSSgVjBM7BitpHTmnAVojhKrHNkdqkUD5Z+eTYp3lim2aGwAcgbWLMQ/FSIrVWyaCICAzJ8UTRtnTziGrKZsdRtCDYI2jQ0Vk3XCCHGKWdC/8g5GA8FaUNUAACAAAAAgAAAAIABAAAAAAAAACICA0fM+aMLp/bIHqWfZNEJQQSSgVjBM7BitpHTmnAVojhKGCLaA0MsAACAAQAAgAAAAIABAAAAAAAAAAABAUEhA1JLXehw3jTSBY949/rYqUbK0RH0CzOEDBRnJ3G0X7bRrHNkdqkUSehqo5gEBUUX2Bqe5BRy3GENV46IrVWyaCICAvakK3+5GsKevk86P0vPv5oJAQKOrNs4wjrwfBciK/GiGA8FaUNUAACAAAAAgAAAAIAAAAAAAQAAACICA1JLXehw3jTSBY949/rYqUbK0RH0CzOEDBRnJ3G0X7bRGCLaA0MsAACAAQAAgAAAAIAAAAAAAQAAAAA=' + +msc7 = ('msc7', + 'XTN', + 26, + None, + ['[0f056943/84h/0h/0h]tpubDCx8y86cKonoPyTtj3f9NZLpBYoBNkbAzUdafMHhggjxkhF8Dny2aekWfDafywEMZEQaQjkK9Gxn7aN7usLRUQdYbvDgcnmYRf72khPEouL/<0;1>/*', + '[15ace8ea/44h/1h/0h]tpubDDu2UQkKM2qC4PbeeF6QLjpa2zLhzqNTEMCvR4tcvsNLDSFU71LhE2iuu4n4r6EpcMiRqWefkPFvqXbpEPrLbu845kLzvomc9TLcU6MFRnz/<0;1>/*', + '[f6d171f3/44h/1h/0h]tpubDCHEhsb2A6wPTSMfehSyAz1A2e2KLTRsxP6esPFcWaDHMB34KypYx9ghUfjP4yvEHwpQVhq3rMPk5NNpF7f9TXLBMYjHsbi97oY2MKwpdqr/<0;1>/*'], + 'or_d(pk(@0/<0;1>/*),and_v(v:multi(2,@1/<0;1>/*,@2/<0;1>/*),after(105)))', + True, + True, + False, + False) +psbt7 = 'cHNidP8BAHMCAAAAAee9+U9VlOKIxxnS8lU1B2UAxG4rBr7b19E1x3+rdFyuAQAAAAD9////AgDh9QUAAAAAF6kUuKH4qKblAE+rGF/umyLErOfKj82HIB8aHgEAAAAXqRQMj2DqZNf+8oPXrt6ESCCkV7vUn4cAAAAAAAEAcwIAAAABrDsI989CKpOYTdwsKuoLwj2TWtZCKP8O7cBkGsZDMMUAAAAAAP3///8C1NX1BQAAAAAXqRQ/2fGSLgsGlZ8IOlwomAfdAFNiIYcAERAkAQAAABepFDqmHpfbOn965Rg2xIIyaA2+KHITh2UAAAABASAAERAkAQAAABepFDqmHpfbOn965Rg2xIIyaA2+KHIThwEEIgAgKGcMdKaBlKaEzA74l8+lK0tNJTNbGTOCxCjnU8Wt/fUBBXAhAm6bjASKZuCeW7cfyV8nBfPu8dy/m21Jul2/3o7pZPSqrHNkUiEC50cc+7+DxrUum7kBSYahPUCXtgXNXy6jdM9pbJutnschAq6mTi6CHG7QC9b9Gi8ndfdf6pN3vblmyZG1GIRNJKpXUq8BabFoIgYCbpuMBIpm4J5btx/JXycF8+7x3L+bbUm6Xb/ejulk9KoYDwVpQ1QAAIAAAACAAAAAgAAAAAAAAAAAIgYCrqZOLoIcbtAL1v0aLyd191/qk3e9uWbJkbUYhE0kqlcY9tFx8ywAAIABAACAAAAAgAAAAAAAAAAAIgYC50cc+7+DxrUum7kBSYahPUCXtgXNXy6jdM9pbJutnscYFazo6iwAAIABAACAAAAAgAAAAAAAAAAAAAEAIgAgvXK/OfnmRlAu7Y1ppZ57P+DZc1Bwr1tFX/ZPLrKfDi8BAXAhAzJ8UTRtnTziGrKZsdRtCDYI2jQ0Vk3XCCHGKWdC/8g5rHNkUiEDozCTNehsgXKb9Zwv4lETze2cKVWBM9dwVPc2fjsxyrshA2CZXftGOd/e7wQjorqvhpk8BbqKBf7oez4H7l1auk4rUq8BabFoIgIDMnxRNG2dPOIaspmx1G0INgjaNDRWTdcIIcYpZ0L/yDkYDwVpQ1QAAIAAAACAAAAAgAEAAAAAAAAAIgIDYJld+0Y5397vBCOiuq+GmTwFuooF/uh7PgfuXVq6TisY9tFx8ywAAIABAACAAAAAgAEAAAAAAAAAIgIDozCTNehsgXKb9Zwv4lETze2cKVWBM9dwVPc2fjsxyrsYFazo6iwAAIABAACAAAAAgAEAAAAAAAAAAAEAIgAgmGa1T5b553Ej/m9XtZFGytZlEX7JE/ByRkJb3Hr3E5ABAXAhAvakK3+5GsKevk86P0vPv5oJAQKOrNs4wjrwfBciK/GirHNkUiEDDQt6gVVSrSzNggc3rBNVSWs0kj01zqAgRJeYzzGWZm8hAjOaWesJtTs7s635NUHEmtenezqS63t3fQSufcp4BNoOUq8BabFoIgICM5pZ6wm1Ozuzrfk1QcSa16d7OpLre3d9BK59yngE2g4Y9tFx8ywAAIABAACAAAAAgAAAAAABAAAAIgIC9qQrf7kawp6+Tzo/S8+/mgkBAo6s2zjCOvB8FyIr8aIYDwVpQ1QAAIAAAACAAAAAgAAAAAABAAAAIgIDDQt6gVVSrSzNggc3rBNVSWs0kj01zqAgRJeYzzGWZm8YFazo6iwAAIABAACAAAAAgAAAAAABAAAAAA==' + +msc8 = ('msc8', + 'XTN', + 14, + None, + ['[01d03393/44h/1h/0h]tpubDDAF9jGCaBw7dJ6DLnPH2mzq1RJcDuf11hQYv68yB9h54mJ3SH9HqcPPewekxeYRr5dYCUVyjwyBCCuDQjooFjJAJkcmwBPKJT5GB9dYhX4/<0;1>/*', + '[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<0;1>/*', + '[36007fa0/44h/1h/0h]tpubDDH4Qq4JEWcqGZ6quCxMsq5qJrbQkSEx4bRoTn7XUt3kgnwuSrvCA1gehroD6T2HWHBcV7XEDDYxVDkpV342htHxRJ4PQc7RcHxdwkrbCy8/<0;1>/*', + '[2ef62e5b/44h/1h/0h]tpubDCRSQVsy1ueB34k4G3GyWgFGKfRLNksBeGgEwUZiZYGhvnVUsP4CWHPeyy8ryGkjtV1YjLBMWTbRnGaEqEETnJXj7XP8Y2pYa2WY2mFT9bn/<0;1>/*', + '[f8dc2d63/44h/1h/0h]tpubDDrqVehtKQ53gHAwXhxo3M1ZwwEXhraA5xdPR5JWDviFLnuPECUttAWYpFKF9UTGqg6rzXKfujyrUyUuVXVdk6gxt2tZaz8qoMVTHA26e4o/<0;1>/*', + '[185ec28a/44h/1h/0h]tpubDCGy13DqjMd4gTWhmobGtpP3TKzHySci2CQBBU2ypDKLuGUyNLqctYeypXWS56EVizni2FqP9YD8tsXDWzs76YW7epABV9ad3dKU52GAAbz/<0;1>/*', + '[d8a8170c/44h/1h/0h]tpubDDcSLWkXynTZ2h4dGgybHmE9pPHkURy1QbDQBES6v5vjRRgrNU5vD9DzpjeiQewpPsAz6ZptPBpa44qw5Aczx1CA8zyGrHVCbnXeyHeqbvJ/<0;1>/*'], + 'or_i(and_v(v:pkh(@0/<0;1>/*),older(10)),or_d(multi(3,@1/<0;1>/*,@2/<0;1>/*,@3/<0;1>/*),and_v(v:thresh(2,pkh(@4/<0;1>/*),a:pkh(@5/<0;1>/*),a:pkh(@6/<0;1>/*)),older(5))))', + False, + True, + False, + False) +psbt8 = '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' + +msc9 = ('msc9', + 'XTN', + 35, + 'tpubD6NzVbkrYhZ4WMCcYXEgDrM1AFATSGmrFyMnA2Dgx1Y551VueaE3iemHhQBxhKWjepG76Cy5QmXv8z4KwN6ARTnZ5hVuShfxL129NVGXZuE/<0;1>/*', + ['[0f056943/48h/1h/0h/3h]tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/<0;1>/*', + '[73c99def/44h/1h/0h]tpubDDU2nuesHbwsZdZcjSXaLSYLpMmkRq6DSxVsGyyM3Zftojb8xEr7RGcjUMLL84YYzkvrMD6SiRBJgo2BXfXsYVAve667Hu1S3noWNDjA342/<0;1>/*', + '[843a20d6/44h/1h/0h]tpubDDgVgV5xoaEr2Qn4SACCtG8wjwHU5mdMkAkr5xhqRkn51cNmmQiDSDCP9wzXm2cKKJ9enoqQ3wrZ2WEoS1Lcs9MVW3kRh8MvBG7WXe2pY2U/<0;1>/*', + '[327c93bb/44h/1h/0h]tpubDD61Z1UQmq5uzfDY6rZHHatCsVGjL5fEmgfq6weAeNSt1o1nz5FguJM8RgfWRRSiTQVknLJqTqpCcYg918bPtF9HcntvUtPz1h1xd9azxZs/<0;1>/*', + '[110d8beb/44h/1h/0h]tpubDDgM8tY3G7wByVp3Gjk6KCnF9qD5mFRhUyzRXLaKyuhAGFm1961dHG5NKNGDZuPwJyxkbE8TrbVXDcArx6UwHr61LC95u1RXjXckBD3a8h4/<0;1>/*', + '[f34034e3/44h/1h/0h]tpubDC9vBBKf193c5NGz2JgW15NkaahrdAbhfKdTKse4K1SRGpsoWCr4BVDVmTq7aZBzcLLye5EbSgq8FbVVKjCjkoTC1Yj3x9fmmtvXQ5xfFqZ/<0;1>/*', + '[0f056943/86h/1h/1000h]tpubDCeEX49avtjHpPSsvyzvtLw3XdPLZD1FKwXa6oRDfWzV3tQFgA8qAzS1SLRFZtyEjkedCHbEx82ABzoqUH97hkFFN4UY9ob38X9XoAz5MD5/<0;1>/*'], + '{{sortedmulti_a(5,@0/<0;1>/*,@1/<0;1>/*,@2/<0;1>/*,@3/<0;1>/*,@4/<0;1>/*),{sortedmulti_a(5,@0/<0;1>/*,@1/<0;1>/*,@2/<0;1>/*,@3/<0;1>/*,@5/<0;1>/*),sortedmulti_a(5,@0/<0;1>/*,@1/<0;1>/*,@2/<0;1>/*,@4/<0;1>/*,@5/<0;1>/*)}},{sortedmulti_a(5,@0/<0;1>/*,@1/<0;1>/*,@3/<0;1>/*,@4/<0;1>/*,@5/<0;1>/*),{sortedmulti_a(5,@0/<0;1>/*,@2/<0;1>/*,@3/<0;1>/*,@4/<0;1>/*,@5/<0;1>/*),{sortedmulti_a(5,@1/<0;1>/*,@2/<0;1>/*,@3/<0;1>/*,@4/<0;1>/*,@5/<0;1>/*),pk(@6/<0;1>/*)}}}}', + False, + False, + False, + True) +psbt9 = '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' + +msc10 = ('msc10', + 'XTN', + 35, + '[8eca7947/44h/1h/0h]tpubDDMb4yomGjaFLfw7H5Vf5hg9NX6gYPbufimrPPJiujBRkkTAM6KLjVapsgg4jiZWFpUESFfnum5uqHW1LoHrwvvhVKGDJyZAxmdWfkLdZzg/<0;1>/*', + ['[0f056943/86h/0h/100h]tpubDCrr3F1M4TwdzHNLh6bKhxKAxY56MSdF65ziwC5uni3ozDUfsYVA2GDGSSwrAKdmgZeZBvBFYsb3pwC7baN7DY7y6QSNka93itxZqSUfED9/<0;1>/*', + '[9ad7aaf5/44h/1h/0h]tpubDCbQqRCKRkhmsVuNNFtkMW2k5w8MoWfWcZdSNEgyrSLFf3X9KL3F5N2DkVU7YPEaZ7mHUngHFkmJTEhz7BS4ixXsav68FMXWfXq4btqHqVo/<0;1>/*', + '[7d6611a0/44h/1h/0h]tpubDCRFv9sR4cmGD59CgjYWgqXZwCwH8ce7UmpTc5cihMyb5NGHhGQta5EPAcuQjbsBH4qmkSicTL1qRzzycrdEbEP2bMwCPcwviGaPE1AdPgN/<0;1>/*', + '[948dc473/44h/1h/0h]tpubDCLRovrtFZ99FW6PqAsHpYThgUFVhDohRgq4dKciFDTTkVjaDttDUfjDKEFt9n8vWoDYgoTqaZJhyLsFiSf2SH7Ns4uEY3SoLjXE56AP9me/<0;1>/*', + '[24e307f7/44h/1h/0h]tpubDCv3JZrbaza97d68DsGD864qwfosuLNm9amJ3jNKqjEcfgKN7Xytnfkgmm9JDJuVwVyPyKMyM853h2M1E8QyY8FPuGzbgHwGZKFocHxqxwZ/<0;1>/*', + '[fd503bd6/44h/1h/0h]tpubDDLCDAXYMkfBM9dK3SyF5rVCBnxpxS3uJj22Qk29JYVRxcywEdLyADp6gtjYFC93pCXUS76D1pKHutDmEktm8TXGD3A8q4XsebnMukXJnWw/<0;1>/*', + '[b7076d9e/44h/1h/0h]tpubDCvBpiqp4FjBtG5BPSyJzDRf44QDuGzPVrbpjH7yp2TnW5r1noong1pDv826hvD5nZitq7PXn5mjkiwgBUPuynNvZqkf28QY1ZL8F9ms8tj/<0;1>/*', + '[2366936b/44h/1h/0h]tpubDCEZPU51TzpzMjEYm41qDZLwGCtmhtEbamgAvLyUHK99vpxExCF1up8c8739HYJXHZnybcvsjT5XNLH47pfAgbscDq21zUjxPUwS7BbZgm1/<0;1>/*'], + '{{{pk(@0/<0;1>/*),pk(@1/<0;1>/*)},{pk(@2/<0;1>/*),pk(@3/<0;1>/*)}},{{pk(@4/<0;1>/*),pk(@5/<0;1>/*)},{pk(@6/<0;1>/*),pk(@7/<0;1>/*)}}}', + False, + False, + False, + True) +psbt10 = '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' + +msc11 = ('msc11', + 'XTN', + 14, + None, + ['[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<0;1>/*', + '[0f056943/84h/1h/9h]tpubDC7jGaaSE66QBAcX8TUD3JKWari1zmGH4gNyKZcrfq6NwCofKujNF2kyeVXgKshotxw5Yib8UxLrmmCmWd8NVPVTAL8rGfMdc7TsAKqsy6y/<0;1>/*'], + 'or_d(pk(@0/<0;1>/*),and_v(v:pkh(@1/<0;1>/*),older(5)))', + False, + True, + False, + False) +psbt11 = 'cHNidP8BAIkCAAAAAeajJP7NnniNTc0ijFoXLSLtb7PO2fnQ8jbl8C+DVxdsAQAAAAD9////ApQuGh4BAAAAIgAgYQyLpJkO9kBVeWXDYdxaXSvS7QQnOoi4FD+PamMH/X4A4fUFAAAAACIAIBWoIlvyWbWTvKnqtnPqHQPvHp0zOuzSxZykLf6o39JAAAAAAAABAH0CAAAAAQ8q09oG5iqNoaLh+d+wnJx8ZmSV6stHDXD168XsKpa1AAAAAAD9////AgzV9QUAAAAAFgAUK/ucYCV98CDUd+ad9FhOyNOVF3QAERAkAQAAACIAILDk63Iobkx0I4JV4PBNdXfwdQYWXsogF9IUgV6VAbSlYgAAAAEBKwARECQBAAAAIgAgsOTrcihuTHQjglXg8E11d/B1BhZeyiAX0hSBXpUBtKUBBUEhAv4uHbVQEQkVrUThtBx6BnGlZJcyVHMKOYaJoBpEjQJyrHNkdqkUHjL11qZ7EjPWsWmzAEK9NtBwWT6IrVWyaCIGAtH+84GMHyKHtjE4maikoSEkG/eMCQak6oo4yNI+EbPUGA8FaUNUAACAAQAAgAkAAIAAAAAAAAAAACIGAv4uHbVQEQkVrUThtBx6BnGlZJcyVHMKOYaJoBpEjQJyGA8FaUNUAACAAQAAgAAAAIAAAAAAAAAAAAABAUEhAv4IiIHn01IKyw4lEaIxhArVyFqGABpomkhcTjULKKv7rHNkdqkUd5gurNTUtMrZ7ZiTL4iKDnmlpeyIrVWyaCICAkSD3BVCWHBK+5zkCAFC8SHxd5FDK8kqVUabscA1eUONGA8FaUNUAACAAQAAgAkAAIABAAAAAAAAACICAv4IiIHn01IKyw4lEaIxhArVyFqGABpomkhcTjULKKv7GA8FaUNUAACAAQAAgAAAAIABAAAAAAAAAAABAUEhA4/rg1i66LDEfY+O55hN2NoI/I/DlwP21VPYbrGIoWiMrHNkdqkUSB+Xtanv3jBJzKRXZWA12VyS99KIrVWyaCICA0w19Yw7qJXx92jmtN1wbu7fMoSAhE84tUWxTQnpFIGlGA8FaUNUAACAAQAAgAkAAIAAAAAAAQAAACICA4/rg1i66LDEfY+O55hN2NoI/I/DlwP21VPYbrGIoWiMGA8FaUNUAACAAQAAgAAAAIAAAAAAAQAAAAA=' + +msc12 = ('msc12', + 'XTN', + 35, + 'tpubD6NzVbkrYhZ4WMCcYXEgDrM1AFATSGmrFyMnA2Dgx1Y551VueaE3iemHhQBxhKWjepG76Cy5QmXv8z4KwN6ARTnZ5hVuShfxL129NVGXZuE/<0;1>/*', + ['[0f056943/86h/1h/0h]tpubDCeEX49avtiXrBTv3JWTtco99Ka499jXdZHBRtm7va2gkMAui11ctZjqNAT9dLVNaEozt2C1kfTM88cnvZCXsWLJN2p4viGvsyGjtKVV7A1/<0;1>/*', + '[c6cf0772/44h/1h/0h]tpubDDpU5jGokiDTkDwh9buZtwHZtzFdt1ieJUo9wTZJbQjKPoDqwkbRbgLAjcudTFckERECg62Po3TpYaJEDo2rKGGHHHNLNATx1rVoXkjp8Af/<0;1>/*', + '[4632a5b7/44h/1h/0h]tpubDCd5ZhLsPEtgobKPyu6UCi4fZTN1GW9Cv8vPyYV7D9PB7EQpUG72yF42uYPE2gYKs4Y7GLSCcsibf8h4TLEyg6MLoKLgH6yNVEWAHMZ8Guh/<0;1>/*'], + 'thresh(3,c:pk_k(@0/<0;1>/*),sc:pk_k(@1/<0;1>/*),sc:pk_k(@2/<0;1>/*),sdv:older(5))', + False, + False, + False, + True) +psbt12 = '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' + +msc14 = ('msc14', + 'XTN', + 14, + None, + ['[0f056943/86h/1h/0h]tpubDCeEX49avtiXrBTv3JWTtco99Ka499jXdZHBRtm7va2gkMAui11ctZjqNAT9dLVNaEozt2C1kfTM88cnvZCXsWLJN2p4viGvsyGjtKVV7A1/<0;1>/*', + '[868f806d/44h/1h/0h]tpubDDg3avkJTE6FpMMMcZW4diGGvPv4UdnkRCsHiyuwkuQQx59CRErNoju5veGZJtj4n78cFRQsCexWNQg1xdxapsfGUU58uHDo9b1Mk81PNEq/<0;1>/*', + '[0f056943/86h/1h/0h]tpubDCeEX49avtiXrBTv3JWTtco99Ka499jXdZHBRtm7va2gkMAui11ctZjqNAT9dLVNaEozt2C1kfTM88cnvZCXsWLJN2p4viGvsyGjtKVV7A1/<2;3>/*', + '[868f806d/44h/1h/0h]tpubDDg3avkJTE6FpMMMcZW4diGGvPv4UdnkRCsHiyuwkuQQx59CRErNoju5veGZJtj4n78cFRQsCexWNQg1xdxapsfGUU58uHDo9b1Mk81PNEq/<2;3>/*', + '[8ee3999f/44h/1h/0h]tpubDCyWeEF2pHfsQQPMXp6dVKAVBHpmDKEpMRGUZDKocwE7Ts8HvvrxmEJwdRd9ctDc8ikL7KHRCywbLbkQmkpTS6xZNj5SKSmTE9SyNWSx7sA/<0;1>/*'], + 'or_d(multi(2,@0/<0;1>/*,@1/<0;1>/*),and_v(v:thresh(2,pkh(@0/<2;3>/*),a:pkh(@1/<2;3>/*),a:pkh(@2/<0;1>/*)),older(10)))', + False, + True, + False, + False) +psbt14 = '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' + +msc15 = ('msc15', + 'XTN', + 35, + 'tpubD6NzVbkrYhZ4WbzhCs1gLUM8s8LAwTh68xVh1a3nRQyA3tbAJFSE2FEaH2CEGJTKmzcBagpyG35Kjv3UGpTEWbc7qSCX6mswrLQVVPgXECd/<0;1>/*', + ['[0f056943/86h/1h/0h]tpubDCeEX49avtiXrBTv3JWTtco99Ka499jXdZHBRtm7va2gkMAui11ctZjqNAT9dLVNaEozt2C1kfTM88cnvZCXsWLJN2p4viGvsyGjtKVV7A1/<2;3>/*', + '[607d04ba/44h/1h/0h]tpubDCpjTp9e7txGnMp2jmNGDjtyvBgznTFnD51TxNW1uvpZQS7HDKQKhkYAHcZA9jBRcXY6S4pD6xkJmD7JbBfdzZptRmgwfyj8vKBrkf8F4bA/<2;3>/*', + '[aa29a974/44h/1h/0h]tpubDDHGzw6SUa25Wx9SJohiSA319YRVakSqaXngLbUnnmVUxses7T9fiLp2bpcAT3gJMFs7aYvbfyREYv21oiXXNMNVnNjw9ZkohPgBXe1NRC2/<0;1>/*', + '[eb64e281/44h/1h/0h]tpubDCpbWyRPLE4oZSvng2vA8LXGKZFxuuSTgDrxFbvxZRtgMFjhJM2F6H7gjQrykHmqXShWXmXJwrpjtQhEgWNvprf9k8QYRjxmL2JeumUEK97/<0;1>/*', + '[0f056943/86h/1h/0h]tpubDCeEX49avtiXrBTv3JWTtco99Ka499jXdZHBRtm7va2gkMAui11ctZjqNAT9dLVNaEozt2C1kfTM88cnvZCXsWLJN2p4viGvsyGjtKVV7A1/<0;1>/*', + '[607d04ba/44h/1h/0h]tpubDCpjTp9e7txGnMp2jmNGDjtyvBgznTFnD51TxNW1uvpZQS7HDKQKhkYAHcZA9jBRcXY6S4pD6xkJmD7JbBfdzZptRmgwfyj8vKBrkf8F4bA/<0;1>/*'], + '{and_v(v:multi_a(2,@0/<2;3>/*,@1/<2;3>/*,@2/<0;1>/*,@3/<0;1>/*),older(10)),multi_a(2,@0/<0;1>/*,@1/<0;1>/*)}', + False, + False, + False, + True) +psbt15 = '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' + +msc16 = ('msc16', + 'XTN', + 14, + None, + ['[0f056943/99h/0h/0h]tpubDDjN26baDEVS3st3MXRhPod1jGchwFby8WKR84V3TVj1WhXEA6kVUPDWcbG65HTZhaxecuNZJZ7wP7mXZyFrZfnqGWKuuaTPc32g7Nuhf65/<0;1>/*'], + 'and_v(v:pk(@0/<0;1>/*),older(10))', + False, + True, + False, + False) +psbt16 = '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' + +msc17 = ('msc17', + 'XTN', + 35, + 'tpubD6NzVbkrYhZ4XgXS51CV3bhoP5dJeQqPhEyhKPDXBgEs64VdSyAfku99gtDXQzY6HEXY5Dqdw8Qud1fYiyewDmYjKe9gGJeDx7x936ur4Ju/<0;1>/*', + ['[0f056943/99h/0h/0h]tpubDDjN26baDEVS3st3MXRhPod1jGchwFby8WKR84V3TVj1WhXEA6kVUPDWcbG65HTZhaxecuNZJZ7wP7mXZyFrZfnqGWKuuaTPc32g7Nuhf65/<0;1>/*'], + 'and_v(v:pk(@0/<0;1>/*),older(10))', + False, + False, + False, + True) +psbt17 = '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' + +msc18 = ('msc18', + 'XTN', + 14, + None, + ['[0f056943/84h/1h/0h]tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<0;1>/*', + 'tpubDCxa9ZSg31K2um9qcMogpVDK2YbAbMn7XqaDyBeKtFSBzHEFAJYtnXDUwBitg39d8TtucYxyKsbWJoKzxmsJbdXruxxdh6zG2LXQuBiRSCp/<0;1>/*'], + 'or_d(pk(@0/<0;1>/*),and_v(v:pkh(@1/<0;1>/*),older(100)))', + False, + True, + False, + False) +psbt18 = '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' + +msc19 = ('msc19', + 'XTN', + 14, + None, + ['[0f056943/86h/1h/0h]tpubDCeEX49avtiXrBTv3JWTtco99Ka499jXdZHBRtm7va2gkMAui11ctZjqNAT9dLVNaEozt2C1kfTM88cnvZCXsWLJN2p4viGvsyGjtKVV7A1/<0;1>/*', + '[e0fa0d67/44h/1h/0h]tpubDCgP2uAUWT1mNJrSmjDuDcWoKz5A1irJLZ8NYLEmNoEKfWhr7v7EwNRFjTgYbyU12HnD2DwQBGMUimB4M5N1Rb1qJCbgUhk6ZyB2pFzz1ye/<0;1>/*', + '[e0fa0d67/44h/1h/0h]tpubDCgP2uAUWT1mNJrSmjDuDcWoKz5A1irJLZ8NYLEmNoEKfWhr7v7EwNRFjTgYbyU12HnD2DwQBGMUimB4M5N1Rb1qJCbgUhk6ZyB2pFzz1ye/<2;3>/*', + '[0f056943/86h/1h/0h]tpubDCeEX49avtiXrBTv3JWTtco99Ka499jXdZHBRtm7va2gkMAui11ctZjqNAT9dLVNaEozt2C1kfTM88cnvZCXsWLJN2p4viGvsyGjtKVV7A1/<2;3>/*', + '[136d22cf/44h/1h/0h]tpubDDfNoDCpdfQNuBt1VaT9VEgdMMGgdJ8xKycXedazyHwAAvBU7Fr7M5HE1RtuWuAwzs79XKxXaMz87cCQjv1zVghcDsZmo96cihzt1Zkwc6t/<0;1>/*'], + 'or_d(multi(2,@0/<0;1>/*,@1/<0;1>/*),and_v(v:thresh(2,pkh(@1/<2;3>/*),a:pkh(@0/<2;3>/*),a:pkh(@2/<0;1>/*)),older(10)))', + False, + True, + False, + False) +psbt19 = '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' + +msc20 = ('msc20', + 'XTN', + 35, + '[0f056943/86h/1h/0h]tpubDCeEX49avtiXrBTv3JWTtco99Ka499jXdZHBRtm7va2gkMAui11ctZjqNAT9dLVNaEozt2C1kfTM88cnvZCXsWLJN2p4viGvsyGjtKVV7A1/<0;1>/*', + ['[0f056943/86h/1h/0h]tpubDCeEX49avtiXrBTv3JWTtco99Ka499jXdZHBRtm7va2gkMAui11ctZjqNAT9dLVNaEozt2C1kfTM88cnvZCXsWLJN2p4viGvsyGjtKVV7A1/<2;3>/*', + '[758ce887/44h/1h/0h]tpubDCmTGaAGyukMjeL1cv5CMByjuaNULHrF5iemnVAEdQAGeNdGqqxcsyDY5Tef3HfRC6DRR8nA82Tsw51aeNdNeAieLg5vUgAWyNbKDCNTg39/<2;3>/*', + '[80f987dd/44h/1h/0h]tpubDDCEzMY1oAUdp3MHNgrEA2Y67AsLdeaS1gJ529kbkto9NAVB76KpgxyiUQV4uiMLUK79rj67N3oSmKAwhHrxUEYFQEATEcas6jARA5Do2t6/<2;3>/*', + '[cff263dc/44h/1h/0h]tpubDCcXPLhk177GnGXuAV5rYcxbGQHH58ddBZWk5yqyT5Syp6UX875WoXuZn3XxTkpmBp2PCUdixHuDznTom2YtcqKLtX8ksvqwvFCNKr4cgJi/<0;1>/*', + '[758ce887/44h/1h/0h]tpubDCmTGaAGyukMjeL1cv5CMByjuaNULHrF5iemnVAEdQAGeNdGqqxcsyDY5Tef3HfRC6DRR8nA82Tsw51aeNdNeAieLg5vUgAWyNbKDCNTg39/<0;1>/*', + '[80f987dd/44h/1h/0h]tpubDDCEzMY1oAUdp3MHNgrEA2Y67AsLdeaS1gJ529kbkto9NAVB76KpgxyiUQV4uiMLUK79rj67N3oSmKAwhHrxUEYFQEATEcas6jARA5Do2t6/<0;1>/*'], + '{and_v(v:multi_a(2,@0/<2;3>/*,@1/<2;3>/*,@2/<2;3>/*,@3/<0;1>/*),older(10)),multi_a(2,@1/<0;1>/*,@2/<0;1>/*)}', + False, + False, + False, + True) +psbt20 = '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' + +# MULTISIGS +ms0 = ['ms0', (2, 2), [(1130956047, 1, 'tpubDF2rnouQaaYrXF4noGTv6rQYmx87cQ4GrUdhpvXkhtChwQPbdGTi8GA88NUaSrwZBwNsTkC9bFkkC8vDyGBVVAQTZ2AS6gs68RQXtXcCvkP'), (4118082990, 0, 'tpubDDX85PzueTZjod816TDBdJPk8vWhqyZkSAXJ5xUjvSd1PyuEKnjt5UxiinKJSZzTTFVGSsSEm57LtpxQGdmSjQJtBmz1KUKtA9H63EzZmbA')], {'d': ['m/44h/1h/0h', 'm/48h/1h/0h/2h'], 'ch': 'XTN', 'ft': 14}, 0] +ms_psbt0 = 'cHNidP8BAgQCAAAAAQMEAAAAAAEEAQEBBQEBAfsEAgAAAAABAJACAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////wMBZgD/////AgDyBSoBAAAAIgAgmpn9BiIVcQF8SNxOBdxHZnr4zV50wqEfgao3H2nXwQYAAAAAAAAAACZqJKohqe3i9hw/cdHe/T+pmd+jaVN1XGkGiXmZYrSL69g2l06M+QAAAAABASsA8gUqAQAAACIAIJqZ/QYiFXEBfEjcTgXcR2Z6+M1edMKhH4GqNx9p18EGAQVHUiEDpu0LHSZwTffTfIc4jmXAz2wEHnpdj8wqeEmXnjhsLmQhA2TIP6eApQSJp8iL+LUKERNbAllqpwd359L99FBGOPdtUq4iAgNkyD+ngKUEiafIi/i1ChETWwJZaqcHd+fS/fRQRjj3bUcwRAIgWd1qBvLJ3w7BCnKnf/lqC2NWx+k2ZckyogR7jvIa6Z0CIEGD4eI8QB34FHub2MqS6+V4pKbAVPW9Yb2f3e+3u6uhAQEDBAEAAAAiBgNkyD+ngKUEiafIi/i1ChETWwJZaqcHd+fS/fRQRjj3bRiu9XT1LAAAgAEAAIAAAACAAAAAAAAAAAAiBgOm7QsdJnBN99N8hziOZcDPbAQeel2PzCp4SZeeOGwuZBwPBWlDMAAAgAEAAIAAAACAAgAAgAAAAAAAAAAAAQ4g4ufuvyFOaMtZDSxF3z96nMBVdUModjxZLZnWC+AJdMwBDwQAAAAAARAE/f///wABAUdSIQOjp2xvvj06HYuo4Nu5+DDkWJK2g6Nw3I4z0U645qLW+iEDHguZsfImfX5ke8u+ZPYHqIQ2OchLKxSdQ9O+uL1qfSZSriICAx4LmbHyJn1+ZHvLvmT2B6iENjnISysUnUPTvri9an0mGK71dPUsAACAAQAAgAAAAIAAAAAAAQAAACICA6OnbG++PTodi6jg27n4MORYkraDo3DcjjPRTrjmotb6HA8FaUMwAACAAQAAgAAAAIACAACAAAAAAAEAAAABBCIAIA6r03dk/6wErujg+YtRD4AykJKKhjg6az38chGPiG2OAQMISOYFKgEAAAAA' + +ms1 = ['ms1', (2, 2), [(1130956047, 1, 'tpubDF2rnouQaaYrXF4noGTv6rQYmx87cQ4GrUdhpvXkhtChwQPbdGTi8GA88NUaSrwZBwNsTkC9bFkkC8vDyGBVVAQTZ2AS6gs68RQXtXcCvkP'), (642592534, 0, 'tpubDCRchFK4N5fkmpD19kfdVBTPcRbcG321XpZc9EF5y9uH2d6DZdiYsVWvuZ6mTQpfqNuTVjqgb4ye33bFGHdhdS1eNwqrdbVQAwSwsftTCGZ')], {'d': ['m/44h/1h/0h', 'm/48h/1h/0h/2h'], 'ch': 'XTN', 'ft': 14}] +ms_psbt1 = 'cHNidP8BAgQCAAAAAQMEAAAAAAEEAQEBBQEBAfsEAgAAAAABAJACAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////wMBZgD/////AgDyBSoBAAAAIgAgO7Et1Pc0tJ02+BhzSyIaAyUnI0+XDeJSG1+9yVYYKhQAAAAAAAAAACZqJKohqe3i9hw/cdHe/T+pmd+jaVN1XGkGiXmZYrSL69g2l06M+QAAAAABASsA8gUqAQAAACIAIDuxLdT3NLSdNvgYc0siGgMlJyNPlw3iUhtfvclWGCoUAQVHUiEDgwkO0ZNeLYTc0jARk0ubSvJSVLUeWXbOJI5gspAixFghA6btCx0mcE3303yHOI5lwM9sBB56XY/MKnhJl544bC5kUq4iAgODCQ7Rk14thNzSMBGTS5tK8lJUtR5Zds4kjmCykCLEWEcwRAIgI2cs69L4CIcU83erd/vww+0gfITnEDGSVTfCl55d33ICIDujRu9l8AUSkHUaz7syn5mJwnP81D3pxUYIBvoVmX30AQEDBAEAAAAiBgODCQ7Rk14thNzSMBGTS5tK8lJUtR5Zds4kjmCykCLEWBgWL00mLAAAgAEAAIAAAACAAAAAAAAAAAAiBgOm7QsdJnBN99N8hziOZcDPbAQeel2PzCp4SZeeOGwuZBwPBWlDMAAAgAEAAIAAAACAAgAAgAAAAAAAAAAAAQ4g1dxbBflVNuLZ2Ul1HWuYv3YvB+1WVb8try3mMtNWnpEBDwQAAAAAARAE/f///wABAUdSIQI1DhBwGxC7cQhnJ80CPFsg5dA/8ZVi447B1hj12FYq8yEDo6dsb749Oh2LqODbufgw5FiStoOjcNyOM9FOuOai1vpSriICAjUOEHAbELtxCGcnzQI8WyDl0D/xlWLjjsHWGPXYVirzGBYvTSYsAACAAQAAgAAAAIAAAAAAAQAAACICA6OnbG++PTodi6jg27n4MORYkraDo3DcjjPRTrjmotb6HA8FaUMwAACAAQAAgAAAAIACAACAAAAAAAEAAAABBCIAIBzbGbUkOtQUlU758Be6etJ319rIzQhJ2CMnsdGC4PFQAQMISOYFKgEAAAAA' + +ms2 = ['ms2', (2, 2), [(1130956047, 1, 'tpubDF2rnouQaaYrUEy2JM1YD3RFzew4onawGM4X2Re67gguTf5CbHonBRiFGe3Xjz7DK88dxBFGf2i7K1hef3PM4cFKyUjcbJXddaY9F5tJBoP'), (2783214288, 0, 'tpubDCqWSUR4xtNPhMrVjQ2h5rdN2BACCHfviVnUrAynei9WaqvuykcjGyvGcbY9hJfpeovM4xVy5E3jMPw1tUc19PeqpVT9LxiTvgS9bZT5ceE')], {'d': ['m/44h/1h/0h', 'm/48h/1h/0h/1h'], 'ch': 'XTN', 'ft': 26}] +ms_psbt2 = 'cHNidP8BAgQCAAAAAQMEAAAAAAEEAQEBBQEBAfsEAgAAAAABAIUCAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////wMBZgD/////AgDyBSoBAAAAF6kUb91OzriEjIgsWsSckPDC0Q+Jg6SHAAAAAAAAAAAmaiSqIant4vYcP3HR3v0/qZnfo2lTdVxpBol5mWK0i+vYNpdOjPkAAAAAAQEgAPIFKgEAAAAXqRRv3U7OuISMiCxaxJyQ8MLRD4mDpIcBBCIAIAtFYt0+m5ogPeAsF0wFYNUBTIr8zh9b3qyzA/GacXm0AQVHUiECOW8/hX0o1kO8nwuxBxbuW4vBfkcUSC7HQfJzbz2kUU0hA0AM5GQodaOUjCy0igI+AveDhgmkPzUR7Uq5tMXXqdTRUq4iAgI5bz+FfSjWQ7yfC7EHFu5bi8F+RxRILsdB8nNvPaRRTUcwRAIgYAx0HVnw1ptPsDxwA8LO/btP44LaPvKneUUYHY7hyG8CIEk1IDl6R5zJDHqGYkXoBwmLamUuHQ0XR814wPo1JYjUAQEDBAEAAAAiBgI5bz+FfSjWQ7yfC7EHFu5bi8F+RxRILsdB8nNvPaRRTRjQeuSlLAAAgAEAAIAAAACAAAAAAAAAAAAiBgNADORkKHWjlIwstIoCPgL3g4YJpD81Ee1KubTF16nU0RwPBWlDMAAAgAEAAIAAAACAAQAAgAAAAAAAAAAAAQ4gui/D81PS/KT/SauPldOYn71xRmcYZ0Kj2dxDPpRW0ZABDwQAAAAAARAE/f///wABACIAIEB0TJfmwXDzSb/VIr0lxfWIilZ4/9NxxZIw1ckjnQuxAQFHUiEDSK842mj16CcwA8Oxafwy+HR4T9vgB3S6eLdqeeAcetchA4mgQByfozPkgmIIhTWOPBs3dPU0X6FoXoJSvAM0VIHJUq4iAgNIrzjaaPXoJzADw7Fp/DL4dHhP2+AHdLp4t2p54Bx61xjQeuSlLAAAgAEAAIAAAACAAAAAAAEAAAAiAgOJoEAcn6Mz5IJiCIU1jjwbN3T1NF+haF6CUrwDNFSByRwPBWlDMAAAgAEAAIAAAACAAQAAgAAAAAABAAAAAQQXqRSPvHXlyB6V3gbZGQNf3pn0ajFr2IcBAwho5AUqAQAAAAA=' + +# originless key +ms3 = ['ms3', (2, 2), [(1130956047, 1, 'tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r'), (2267113793, 0, 'tpubDCGx6bNmE4zRFgfeV2PbGfcuhg6aeqtLYgNEGZ2pghgFiarh8j2yVruetVWUd6ykfkxaGgB8GhEkaGva1jXvqJrLXC3LboxsQTHqqCZD5Jj')], {'ch': 'XTN', 'd': ['m', 'm/84h/1h/0h'], 'ft': 14}] +ms_psbt3 = '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' + + +@pytest.fixture +def settings_append(sim_exec): + def doit(key, val): + x = sim_exec("x=settings.get('%s',[])\nx.append(%r)\nsettings.set('%s', x)" % (key, val, key)) + assert x == '' + return doit + + +def test_miniscript(settings_get, settings_set, clear_miniscript, goto_home, pick_menu_item, + cap_menu, try_sign): + + # try one by one + for msc, psbt in [(msc0, psbt0), (msc1, psbt1), (msc2, psbt2), (msc3, psbt3), (msc4, psbt4), + (msc5, psbt5), (msc6, psbt6), (msc7, psbt7), (msc8, psbt8),(msc9, psbt9), + (msc10, psbt10), (msc11, psbt11), (msc12, psbt12), (msc14, psbt14), + (msc15, psbt15), (msc16, psbt16), (msc17, psbt17), (msc18, psbt18), + (msc19, psbt19), (msc20, psbt20)]: + + clear_miniscript() + name = msc[0] + print(name) # debug in case of failure + settings_set("miniscript", [msc]) + goto_home() + pick_menu_item("Settings") + pick_menu_item("Miniscript") # migration happens here as we start deserializing the wallets + time.sleep(.1) + assert name in cap_menu() + res = settings_get("miniscript") + assert len(res) == 1 + assert len(res[0]) == 4 # new format (name, policy, keys, opts) + assert res[0][0] == name + try_sign(base64.b64decode(psbt)) + + +def test_multisig(settings_set, settings_get, try_sign, goto_home, pick_menu_item, cap_menu, + clear_miniscript): + # try one by one + for ms, psbt in [(ms0, ms_psbt0), (ms1, ms_psbt1), (ms2, ms_psbt2), (ms3, ms_psbt3)]: + clear_miniscript() + name = ms[0] + settings_set("multisig", [ms]) + goto_home() + pick_menu_item("Settings") + pick_menu_item("Miniscript") # migration happens here + time.sleep(.1) + assert name in cap_menu() + assert settings_get("multisig", None) is None + msc = settings_get("miniscript") + assert len(msc) == 1 + assert len(msc[0]) == 4 # new format (name, policy, keys, opts) + assert msc[0][0] == name + try_sign(base64.b64decode(psbt)) + + # now try bulk migration + clear_miniscript() + settings_set("multisig", [ms0, ms1, ms2, ms3]) + goto_home() + pick_menu_item("Settings") + pick_menu_item("Miniscript") # migration happens here + menu = cap_menu() + for name in ["ms0", "ms1", "ms2", "ms3"]: + assert name in menu + + assert settings_get("multisig", None) is None + msc = settings_get("miniscript") + assert len(msc) == 4 + for x in msc: + assert len(x) == 4 # new format (name, policy, keys, opts) + + for i, psbt in enumerate([ms_psbt0, ms_psbt1, ms_psbt2, ms_psbt3]): + try_sign(base64.b64decode(psbt), miniscript="ms%d" % i) + + +def test_multisig_derivation_path_migration(start_sign, end_sign, settings_set, goto_home, clear_miniscript, + pick_menu_item, cap_story, cap_menu, press_cancel, settings_get): + clear_miniscript() + multisigs = [ + ['ms1', (2, 3), [(2718032886, 0, 'tpubDGThxU1AibvJnWta5ghydVz3WDMAKFEe2mAP8vtoYfUXkgoYisuk5heGfrqgrE18RUPvEVhUWfZHCH3EVi2sBEQyLFMx9JVyNvWa7zQtRaC'), (3913158354, 1, 'tpubDGauoqnAp5SEYQHYrasWkfWNoh1SD3izdfPtHRXQXp2YWhnJ5pPQEFsxe696c6iuuqA9SfaJcenv4ZLmXFfRavQDAnKKky7QTPxznp3vUUQ'), (1130956047, 2, 'tpubDH8ECUKZYchtZF1RmJ3oBGWKtroMxyUyd6iQKJx2JWoezuethw6PHSewUgbC3vWkihaFuKUVmLAYMVdxq3iMo9AV7beRceQGQzHYq9UhgBR')], {'d': ["m/48'/1'/0'/2'/0", "m/48'/1'/0'/2'/1", "m/48'/1'/0'/2'/2"], 'ch': 'XTN', 'ft': 14}], + ['ms2', (3, 5), [(2044885442, 'tpubD9h2yEghZWRp4Mvi4MPhyP7ZN8GDqYVRMk6rNf5omds7WTjmRZiok8xgwEP3uXLVbpxVrqnjm4bNXL6tLwHtYF9J7uVSG9u95Yid38fX9dT'), (3035660899, 'tpubD8zYsexbkYEiCbTso12bUsE8Y1CUn3WHjLER3fWqc8mcP7FhDK1Rc6Tixr6v3SQ4XBi5d4bbTskUCxe4eZujkL2cQ3enCDENtBYJYzYuUaR'), (3343279201, 'tpubD8yeTfF4L8aCEaQbuPjjzNeyPs2WGJPNWcBMDuDP7NP2VjLBCB5afvfhAg3oTytxvnLXZbMBWyEhs2nt3wmduwSCMotB8RHcxxkvMRtZHrq'), (1010565321, 'tpubD9jpJX26AjUzTjCuZb9PfWmKjrSjFzXfNjBFwMY6ckt9qw3m9rpYw3NGD2yZut6UbFuQZm2xttchgchzGjJn26Fu1uZp1tveV1WcmUaXpay'), (1130956047, 'tpubD8NXmKsmWp3a3DXhbihAYbYLGaRNVdTnr6JoSxxfXYQcmwVtW2hv8QoDwng6JtEonmJoL3cNEwfd2cLXMpGezwZ2vL2dQ7259bueNKj9C8n')], {'pp': "m/45'", 'ch': 'XTN', 'ft': 26}], + ('ms', (2, 2), [(2285969762, 0, 'tpubDEy2hd2VTrqbBS8cS2svq12UmjGM2j7FHmocjHzAXfVhmJdhBFVVbmAi13humi49esaAuSmz36NEJ6GL3u58RzNuUkExP9vL4d81PM3s8u6'), (1130956047, 1, 'tpubDEFX3QojMWh7x4vSAHN17wpsywpP78aSs2t6nyELHuq1k34gub9mQ7QiaHNCBAYjSQ4UCMMpfBkf5np1cTQaStrvvRCxwxZ7kZaGHqYxUv3')], {'ch': 'XTN', 'ft': 14, 'd': ["m/48'/0'/99'/2'", "m/48'/0'/33'/2'"]}) + ] + + settings_set("multisig", multisigs) + + # psbt from nunchuk, with global xpubs belonging to above ms wallet + b64_psbt = "cHNidP8BAF4CAAAAAfkDjXlS32gzOjVhSRArKxvkAecMTnp1g8wwMJTtq74/AAAAAAD9////AekaAAAAAAAAIgAgzs2e4h4vctbFvvauK+QVFAPzCFnMi1H9hTacH7498P8AAAAATwEENYfPBC7g3O2AAAACLvzTgnL7V0DNOnISJdvOgq/6Pw6DAtkPflmZ+Hc04qwC5CShG0rDIlh8gu7gH2NMBLfrIzYSzoSomnVHeMxtxVQUDwVpQzAAAIAAAACAIQAAgAIAAIBPAQQ1h88EkEB8moAAAALv/1L+Cfeg2EPc01pS00f18DIdU5BOeExlGsXyEFOKGwL71tcAiRuL4Bs+uT1JJjU6AbR3j3X60/rI+rTMJmnOgRRiIUGIMAAAgAAAAIBjAACAAgAAgAABAIkCAAAAAZ5Im3CxbYDyByyrr4luss5vr+s0r7Vt8pK+OvicPLO7AAAAAAD9////AnM2AAAAAAAAIgAgvZi0zfKCeBasTet1hNKm73GA4MEkwiSVwCB9cN0/EnTmvqUXAAAAACJRIJF/VcIeZ3E4f+ZEjwiUl5AUUxBJgoaEaPaHHJecq18lq+4qAAEBK3M2AAAAAAAAIgAgvZi0zfKCeBasTet1hNKm73GA4MEkwiSVwCB9cN0/EnQiAgNRdmGxEwsP88xu9rl/tGAXq7kPm/730yTyQ6XHQL/D3kcwRAIgHNmbk4J9wu4ljq6UouY132eX1i/2jWvJjuuWWyLRFScCIBPyPCuZ/Hmd06h9KtVkSropBonIuqIc/BK8JZ50YKp/AQEDBAEAAAABBUdSIQMBr34TVHrqSk8K6505//5YTOkHmHqF83J8iUURtL/ptCEDUXZhsRMLD/PMbva5f7RgF6u5D5v+99Mk8kOlx0C/w95SriIGAwGvfhNUeupKTwrrnTn//lhM6QeYeoXzcnyJRRG0v+m0HA8FaUMwAACAAAAAgCEAAIACAACAAAAAAAAAAAAiBgNRdmGxEwsP88xu9rl/tGAXq7kPm/730yTyQ6XHQL/D3hxiIUGIMAAAgAAAAIBjAACAAgAAgAAAAAAAAAAAAAEBR1IhAscIZVvBcy3Q0GKO4UqR3gDB3pm/tWas8siH3Ej8MmuCIQN8lTj0MMTpT+Dlk2MbMdAaL93hezzNP3WDsRn/gwlVQlKuIgICxwhlW8FzLdDQYo7hSpHeAMHemb+1ZqzyyIfcSPwya4IcYiFBiDAAAIAAAACAYwAAgAIAAIAAAAAAAQAAACICA3yVOPQwxOlP4OWTYxsx0Bov3eF7PM0/dYOxGf+DCVVCHA8FaUMwAACAAAAAgCEAAIACAACAAAAAAAEAAAAA" + + goto_home() + pick_menu_item("Settings") + pick_menu_item("Miniscript") # migration happens here + time.sleep(.1) + + names = ["ms", "ms1", "ms2"] + menu = cap_menu() + for n in names: + assert n in menu + + assert settings_get("multisig", None) is None + msc = settings_get("miniscript") + assert len(msc) == 3 + for w in msc: + assert len(w) == 4 # new format (name, policy, keys, opts) + + # in time of creatin of PSBT, lopp was making testnet3 unusable... + settings_set("fee_limit", -1) + start_sign(base64.b64decode(b64_psbt)) + title, story = cap_story() + assert title == "OK TO SEND?" + end_sign() + settings_set("fee_limit", 10) # rollback + pick_menu_item("Settings") + pick_menu_item("Miniscript") + for msi in names: # three wallets imported + pick_menu_item(msi) + pick_menu_item("View Details") + time.sleep(.1) + _, story = cap_story() + assert "'" not in story + press_cancel() + press_cancel() + + +def test_big_guys(microsd_path, src_root_dir, goto_home, pick_menu_item, need_keypress, + set_seed_words, microsd_wipe, enter_complex, press_select, cap_story, + settings_get, press_cancel): + # unable to import via settings_set (USB max size) + # so good place to test migration via backup + # + fname0 = "big_boy_naked.7z" + psbt0 = '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' + + fname1 = "big_boy.7z" + psbt1 = 'cHNidP8BAP0rAgIAAAABs5srdV6r4A+1Rex64Pdn2OFcsfQ3hm7ubX6lWtsqHHABAAAAAP3///8MSX3XFwAAAAAiUSCsE0UdC+0kRaOgtbalQ6pqYg2Bs/NZGkyxqJM4HeE2dwCE1xcAAAAAIlEgW1uZ5PJSBcKlfCev/ltIAJoVOoUZTqBNMIgLWFFIX3UAhNcXAAAAACJRIOi5FO3/yJfw8lrKggHH/QpwheUA2Ic86OKrWR6A3A6FAITXFwAAAAAiUSBYub7o2MiDnudZoMcVDrmNLUk2cD0cxLEPD7Ti53glzACE1xcAAAAAIlEgzmtrd22FInSRjf/STCgKptcwuAWDGZAnjQwe1SY3Ct4AhNcXAAAAACJRIM53mqALeY8iN9qWZUZvaqP+o415VtQPCffh2piI5mcTAITXFwAAAAAiUSD48mVVc8w8ubKEDBafiwuiWoooxNZ444Qmaf3+HAFI7wCE1xcAAAAAIlEgnG7lDhf2qIfv9/PQDLWQtulNShqNzhUyLHCiXmydw+sAhNcXAAAAACJRIBEh+lyLL4FWWJscpR2+++forE7N1MxG9FFyqDlYffxqAITXFwAAAAAiUSCEqO2mb1bi8+lcGlNIJeQmqagY7r9CDYK4eyxNfmH2TgCE1xcAAAAAIlEg5ppxcFZfHDm4X7JnQ5Mt38JbFJ+XVZ8o2kph2L4IA8wAZc0dAAAAABYAFDTA+oL+2EloufkRTH1jsf2I8YblAAAAAAABASsAERAkAQAAACJRIGBIpCQEVrE/Dej8+SZE7+/cWAB1EpKBZzAGk0HoKza5ohXBbwdUjurWhFW2F5cH9kdJ8rIGSPalUmfTcXPmF4hZSnHPnN2Nb20D/ACwcmPwynrQuNMT68YlAfwC7SeSI5GgfbP3LPgxiTTYdG+lmNHYcJnHSXCJWGNy6VdZrPdBoiS9sCmM1ox7cFY7btdrDSj42Ic/7QBA3C1Xg26fUKuzqNxMUf1BDIbFHHdLlwlz2knKM9LaxGAGUWJwF0f51kD7lo8gFRPvk/VvT0y0JL7bTA//lM5ZWG9ELc5t+0HofN89mKWsILC41DB8/QRjgZdX9mcJGrgjSXGNXi7KAK/rZw60NZBPuiBxizGMSqTleQ3ESPYs16hokXrgtDg8YKpXBIcQAokBDrogVgNtUMYQhoA4WILiar5f+02musF0h635Hki4hmTFzYq6U50C6AOywEIVwW8HVI7q1oRVtheXB/ZHSfKyBkj2pVJn03Fz5heIWUpx4yJzvjzHesdz9TM4IFYcsK6SD+ugpUzAOuY6OKBVKlnPIBlF9+AFotrtZpLBI+ShPaPAzyOnFTd0JdaXjWOR7J4NrCCAyYcKDFhdCwAzSqnrBWQqw9W3ImjYv82BFyR5OEVNp7ogtANPvPKPgOm/6CYUHyR1KjWkI4tzap+neKt/Q2HWydi6IMVUdfA/IIestZnFYi38+MR8U1x+amsuTnhCCvXU6xeRuiCXr0cDmG1tqgI44mPy8NPstdSIGVUnL0+tn9nUifMmYLogLLi5dAlxJ/+ae055SCdDbEztz+A4pseGXnJHZzj+m0m6VpzAohXBbwdUjurWhFW2F5cH9kdJ8rIGSPalUmfTcXPmF4hZSnFXRhOAgoYEZ9a0CWknIDKRQF+dlVVGyoG+kBeJmqGwbLP3LPgxiTTYdG+lmNHYcJnHSXCJWGNy6VdZrPdBoiS9sCmM1ox7cFY7btdrDSj42Ic/7QBA3C1Xg26fUKuzqNxMUf1BDIbFHHdLlwlz2knKM9LaxGAGUWJwF0f51kD7lmwgXzFOClwYCUtomfNgC2kisvqGdTDkWq+yDYV7KN/nCiysIK2KMo9bdQP+KL+tP2XH/PEVb8Xg+jGczqIV9Ki+w+XwuiBhKl4oEMqyqAx/0st8vEdC+/cbawwlHbjQemSe+pQqFLpSnQF4ssCiFcFvB1SO6taEVbYXlwf2R0nysgZI9qVSZ9Nxc+YXiFlKcRJX/rQAgkaX0oZk3OV8xJhPdfXwa5vlZ8hG6ro3XCHY2oRKoQLTMz0TdSuXu7bbDqzT9XwApuszbRPGNs/vfZKwKYzWjHtwVjtu12sNKPjYhz/tAEDcLVeDbp9Qq7Oo3ExR/UEMhsUcd0uXCXPaScoz0trEYAZRYnAXR/nWQPuW0iBzLutIoJ86aeqbGxSl+ofivg5pWR2F0X13KTmUrmKqcawgjQg/gAaTtAWtC+eezdlv+1m1yLwRYu+OzRUoJAmfBUe6IOKhM3WHy4totA22m6aysw0TXW0qZtVv7u8fJO767q+vuiAWiIBd9WMj1TJz0OwixMGEe2VWNe4GC1nQLREtNcM6D7ogogZEBKqTbl9nWERS0y2uW2GsV0iQ3aTM6J6pC2bfqXG6IFW0yPbRHpilSMS+1Y+sSaeBFT1zal9088UTuWbYSPfWulWdARSywIIVwW8HVI7q1oRVtheXB/ZHSfKyBkj2pVJn03Fz5heIWUpxGpRDFreNOIJjOgNmiDX4qaXWa7M6YeFwkuPF6HHO4tdw3wQy8EIsovcEiNNMPpUK6PPM33H6O5VNUTp+0KLN8ExR/UEMhsUcd0uXCXPaScoz0trEYAZRYnAXR/nWQPuWjyC43t/QJX39kQ+EhqJCLRaxpsC6o3ztftJ+oNZcVzHnFqwga1AKxU9FQk+Kl1JECYTJv1aQIYc8bvrb7iCXGWo/ndS6IKWgraH3SyQ413RNixpL+wTMdFnOxBJwZ9wqYq+3SwlruiBQp8UDkzuzHHQLK/IhYCa5WFRESsf0zKQqN6bW01eLHbpTnQLoA7LAghXBbwdUjurWhFW2F5cH9kdJ8rIGSPalUmfTcXPmF4hZSnGiEnslIVoLgqVfbxaMOvU+ftQEI18h1peLpGN6jLggcnDfBDLwQiyi9wSI00w+lQro88zfcfo7lU1ROn7Qos3wTFH9QQyGxRx3S5cJc9pJyjPS2sRgBlFicBdH+dZA+5aPIMop1+hl084FbmEQ+8ddoIAcvihPtg47QtoCRo5owNAzrCAgxQM+LerxPLANTyyrslh6qZFXnmTADE/sTpa5azdA3LogtM47lX9x2XYk1IijH0+SNzrQkk1xKw4YPGDNIvhjXTS6ID/rQHOezLMA6HhUImVrdvXtitADlCjXikJwRUZ6oS3bulOdAugDssCiFcFvB1SO6taEVbYXlwf2R0nysgZI9qVSZ9Nxc+YXiFlKce9HPeFiw92zQH3JKF4N4QnWbFTQifZmyDSoLTxBPsjI2oRKoQLTMz0TdSuXu7bbDqzT9XwApuszbRPGNs/vfZKwKYzWjHtwVjtu12sNKPjYhz/tAEDcLVeDbp9Qq7Oo3ExR/UEMhsUcd0uXCXPaScoz0trEYAZRYnAXR/nWQPuW0iD2vVmmdQEbpebohQ+SibK8VPnYId3camLA503bDiQsJawgrnrAhNNCxzM9qvzPT2KHmRnZByeziwWvwzaii8zj6626IB8K+eS3gjZgMNJtzAV/2gNw+TaVsIAF5pOenapchV8JuiCU0R2sLo3+l+XslaaUCDh3QhXkHEz5On/JdJLhR2d5XrogQPQzBHFehAqg3RhHsRsw/dwnaeg+qOB4kogwRezZDEe6INw9GYcGvankdaDJUiasIof0WwBPBAf40djguVyREOebulSdATyywCEWFRPvk/VvT0y0JL7bTA//lM5ZWG9ELc5t+0HofN89mKU5AVdGE4CChgRn1rQJaScgMpFAX52VVUbKgb6QF4maobBs1qc/5SwAAIABAACAAAAAgAgAAAAAAAAAIRYWiIBd9WMj1TJz0OwixMGEe2VWNe4GC1nQLREtNcM6DzkB70c94WLD3bNAfckoXg3hCdZsVNCJ9mbINKgtPEE+yMhNiFgrLAAAgAEAAIAAAACAAgAAAAAAAAAhFhlF9+AFotrtZpLBI+ShPaPAzyOnFTd0JdaXjWOR7J4NOQFMUf1BDIbFHHdLlwlz2knKM9LaxGAGUWJwF0f51kD7lk2IWCssAACAAQAAgAAAAIAAAAAAAAAAACEWHwr55LeCNmAw0m3MBX/aA3D5NpWwgAXmk56dqlyFXwk5ARJX/rQAgkaX0oZk3OV8xJhPdfXwa5vlZ8hG6ro3XCHYDwVpQ1YAAIABAACAAAAAgAQAAAAAAAAAIRYgxQM+LerxPLANTyyrslh6qZFXnmTADE/sTpa5azdA3DkBGpRDFreNOIJjOgNmiDX4qaXWa7M6YeFwkuPF6HHO4tdNiFgrLAAAgAEAAIAAAACACgAAAAAAAAAhFiy4uXQJcSf/mntOeUgnQ2xM7c/gOKbHhl5yR2c4/ptJOQFMUf1BDIbFHHdLlwlz2knKM9LaxGAGUWJwF0f51kD7lg8FaUNWAACAAQAAgAAAAIAAAAAAAAAAACEWP+tAc57MswDoeFQiZWt29e2K0AOUKNeKQnBFRnqhLds5ARqUQxa3jTiCYzoDZog1+Kml1muzOmHhcJLjxehxzuLXBWA3+SwAAIABAACAAAAAgAoAAAAAAAAAIRZA9DMEcV6ECqDdGEexGzD93Cdp6D6o4HiSiDBF7NkMRzkBElf+tACCRpfShmTc5XzEmE919fBrm+VnyEbqujdcIdh/0Tc9LAAAgAEAAIAAAACABAAAAAAAAAAhFlCnxQOTO7McdAsr8iFgJrlYVERKx/TMpCo3ptbTV4sdOQGiEnslIVoLgqVfbxaMOvU+ftQEI18h1peLpGN6jLggcgVgN/ksAACAAQAAgAAAAIAIAAAAAAAAACEWVbTI9tEemKVIxL7Vj6xJp4EVPXNqX3TzxRO5ZthI99Y5Ae9HPeFiw92zQH3JKF4N4QnWbFTQifZmyDSoLTxBPsjIBWA3+SwAAIABAACAAAAAgAIAAAAAAAAAIRZWA21QxhCGgDhYguJqvl/7Taa6wXSHrfkeSLiGZMXNijkBV0YTgIKGBGfWtAlpJyAykUBfnZVVRsqBvpAXiZqhsGwFYDf5LAAAgAEAAIAAAACABgAAAAAAAAAhFl8xTgpcGAlLaJnzYAtpIrL6hnUw5Fqvsg2Feyjf5wosOQHPnN2Nb20D/ACwcmPwynrQuNMT68YlAfwC7SeSI5GgfdanP+UsAACAAQAAgAAAAIAGAAAAAAAAACEWYSpeKBDKsqgMf9LLfLxHQvv3G2sMJR240HpknvqUKhQ5Ac+c3Y1vbQP8ALByY/DKetC40xPrxiUB/ALtJ5IjkaB9DwVpQ1YAAIABAACAAAAAgAYAAAAAAAAAIRZrUArFT0VCT4qXUkQJhMm/VpAhhzxu+tvuIJcZaj+d1DkBohJ7JSFaC4KlX28WjDr1Pn7UBCNfIdaXi6Rjeoy4IHJNiFgrLAAAgAEAAIAAAACACAAAAAAAAAAhFm8HVI7q1oRVtheXB/ZHSfKyBkj2pVJn03Fz5heIWUpxDQB8Rh5dAAAAAAAAAAAhFnGLMYxKpOV5DcRI9izXqGiReuC0ODxgqlcEhxACiQEOOQFXRhOAgoYEZ9a0CWknIDKRQF+dlVVGyoG+kBeJmqGwbH/RNz0sAACAAQAAgAAAAIAGAAAAAAAAACEWcy7rSKCfOmnqmxsUpfqH4r4OaVkdhdF9dyk5lK5iqnE5Ae9HPeFiw92zQH3JKF4N4QnWbFTQifZmyDSoLTxBPsjI1qc/5SwAAIABAACAAAAAgAIAAAAAAAAAIRaAyYcKDFhdCwAzSqnrBWQqw9W3ImjYv82BFyR5OEVNpzkBTFH9QQyGxRx3S5cJc9pJyjPS2sRgBlFicBdH+dZA+5Z/0Tc9LAAAgAEAAIAAAACAAAAAAAAAAAAhFo0IP4AGk7QFrQvnns3Zb/tZtci8EWLvjs0VKCQJnwVHOQHvRz3hYsPds0B9ySheDeEJ1mxU0In2Zsg0qC08QT7IyOaS5TEsAACAAQAAgAAAAIACAAAAAAAAACEWlNEdrC6N/pfl7JWmlAg4d0IV5BxM+Tp/yXSS4UdneV45ARJX/rQAgkaX0oZk3OV8xJhPdfXwa5vlZ8hG6ro3XCHYTYhYKywAAIABAACAAAAAgAQAAAAAAAAAIRaXr0cDmG1tqgI44mPy8NPstdSIGVUnL0+tn9nUifMmYDkBTFH9QQyGxRx3S5cJc9pJyjPS2sRgBlFicBdH+dZA+5bmkuUxLAAAgAEAAIAAAACAAAAAAAAAAAAhFqIGRASqk25fZ1hEUtMtrlthrFdIkN2kzOieqQtm36lxOQHvRz3hYsPds0B9ySheDeEJ1mxU0In2Zsg0qC08QT7IyH/RNz0sAACAAQAAgAAAAIACAAAAAAAAACEWpaCtofdLJDjXdE2LGkv7BMx0Wc7EEnBn3Cpir7dLCWs5AaISeyUhWguCpV9vFow69T5+1AQjXyHWl4ukY3qMuCByf9E3PSwAAIABAACAAAAAgAgAAAAAAAAAIRatijKPW3UD/ii/rT9lx/zxFW/F4PoxnM6iFfSovsPl8DkBz5zdjW9tA/wAsHJj8Mp60LjTE+vGJQH8Au0nkiORoH3mkuUxLAAAgAEAAIAAAACABgAAAAAAAAAhFq56wITTQsczPar8z09ih5kZ2Qcns4sFr8M2oovM4+utOQESV/60AIJGl9KGZNzlfMSYT3X18Gub5WfIRuq6N1wh2OaS5TEsAACAAQAAgAAAAIAEAAAAAAAAACEWsLjUMHz9BGOBl1f2ZwkauCNJcY1eLsoAr+tnDrQ1kE85AVdGE4CChgRn1rQJaScgMpFAX52VVUbKgb6QF4maobBsTYhYKywAAIABAACAAAAAgAYAAAAAAAAAIRa0A0+88o+A6b/oJhQfJHUqNaQji3Nqn6d4q39DYdbJ2DkBTFH9QQyGxRx3S5cJc9pJyjPS2sRgBlFicBdH+dZA+5YFYDf5LAAAgAEAAIAAAACAAAAAAAAAAAAhFrTOO5V/cdl2JNSIox9Pkjc60JJNcSsOGDxgzSL4Y100OQEalEMWt404gmM6A2aINfippdZrszph4XCS48Xocc7i13/RNz0sAACAAQAAgAAAAIAKAAAAAAAAACEWuN7f0CV9/ZEPhIaiQi0WsabAuqN87X7SfqDWXFcx5xY5AaISeyUhWguCpV9vFow69T5+1AQjXyHWl4ukY3qMuCBy5pLlMSwAAIABAACAAAAAgAgAAAAAAAAAIRbFVHXwPyCHrLWZxWIt/PjEfFNcfmprLk54Qgr11OsXkTkBTFH9QQyGxRx3S5cJc9pJyjPS2sRgBlFicBdH+dZA+5bWpz/lLAAAgAEAAIAAAACAAAAAAAAAAAAhFsop1+hl084FbmEQ+8ddoIAcvihPtg47QtoCRo5owNAzOQEalEMWt404gmM6A2aINfippdZrszph4XCS48Xocc7i1w8FaUNWAACAAQAAgAAAAIAIAAAAAAAAACEW3D0Zhwa9qeR1oMlSJqwih/RbAE8EB/jR2OC5XJEQ55s5ARJX/rQAgkaX0oZk3OV8xJhPdfXwa5vlZ8hG6ro3XCHYBWA3+SwAAIABAACAAAAAgAQAAAAAAAAAIRbioTN1h8uLaLQNtpumsrMNE11tKmbVb+7vHyTu+u6vrzkB70c94WLD3bNAfckoXg3hCdZsVNCJ9mbINKgtPEE+yMgPBWlDVgAAgAEAAIAAAACAAgAAAAAAAAAhFva9WaZ1ARul5uiFD5KJsrxU+dgh3dxqYsDnTdsOJCwlOQESV/60AIJGl9KGZNzlfMSYT3X18Gub5WfIRuq6N1wh2NanP+UsAACAAQAAgAAAAIAEAAAAAAAAAAEXIG8HVI7q1oRVtheXB/ZHSfKyBkj2pVJn03Fz5heIWUpxARggB48FHJL6bRmtkJlduXHAEJDCGoWgyWBFPwRdjiDRI/0AAQUgmHqCI+qVZzd5EnS8QN+t4MTBUbEgr+MxHBZq8CGaJ70BBv2aBAHAziCdMbv+dySw4BiJ30kcbA2SCwOdk7cHltKt/eAcCq+wSawgCz0S/bwWyKNsp07NcRyam6d6a8bPU4jlVB6ChuMdKki6IMqS1dOtrHCYfMlDLmwDLpfAvOnrLaGlSaM3TsI7yTaNuiCKIBnp4CGe/4Z369ev+/UjTa973UzbuTU5NT2jpw4YsrogeIV0Zd0uHAjzeTqq+SGVaF5SScHBnZmVFdoq6EE8JxO6IPEG2EybxcvLdxuaY3ygMyswgy/EDOm/1gRDUJkq69CTulacBMCOIFxdbPRe2SaJIlmVkRrpoM0YRZJ01gQfE2PCLsfGnO4NrCCLeyI4ZD3Ped7dSsbDVowE4fY3kU3QAKeQB43BhTK697oggl7kTubqHZBjr97clMrn5GtDit42VdUwyQyWfLOKQi66INlkyAKhB8de+IX1kB16IWncgGXyU4qJkgwp6KNgIon+ulOdAugDsgTAayD1yL2DPO4JSQEzf/07IdRhBOmArve1WIHYzGS8xgLB56wgNIZgbtPoJ+9pLm7Z8XADxtMx1trdt/P80wBCQS6hHd+6IFOAAMms4iGGfmiqFo1YiQSQd0TKxR2uaJoPL2/nQewAulKdAXiyBMDRIA25uqU0s7IfW4FrcDfNHnuvPfgTEY6ntdAXo/PQgxX+rCAUkMAjUqCmCB9GssxYANcWfVp8jT+JujxF0XebmZrs7roguBu9tpwE70lD3RX2/aGxHugN9QwXJIBqqNGIUFw8gF+6IB4tD3t/0KbOubfvHCbBPE1/08cLhPfq3ewv0cWwsoa0uiALsYwX+UEXD2fIqQM+8r3o/QuTz+gTZNUAwKB1xhfb67ogTVcC6on3sB4ELN5UGgdazf2NTf1DgWtxb7vve/1oCgO6VJ0BPLIEwNEgW0FS1RvKNRX2AIcnIHx3+SFUvzSwjP91CPwp3phRynmsIGIru9YN9gw/gbkw65U+EU713SvuYi81Lo2BmDYAh+sRuiBRCNdh0SOA6+5I5pWXTWHeO7RUb7bsYBJaxxprSFvtbbogisP7d+itm2Pn/t5392h2o/iaTWRedAqo40zXtzfZ5LC6IJ4BmML3kxe4Q3YQDpQUmnTAVBkewbxRej98Vx6kUxCEuiAhdNyS/t3hra0gKbsBGPA0g8WhfujnARNxdQYgQ9laerpVnQEUsgPAjiDwhdtBZnHToRjtjlz0hucmpbkJCr7jx91mGsUAVQunuKwgzd2iwFAHgNwfTfabe/0BTyx0iXJDfh8PFi+Z3wgsiYS6IJpI0yHAWxxH9TMZu2Wd8Mnbbpqh1JhKVocIK4pYmfmcuiDgs/VJf0T+8eVE6JbKL+oJy/J22W2JmkqWSFHYYLJOJrpTnQLoA7IDwI4guzV4hZbq88ak0rUYhXa778mxuleRvo7V6qqber9IgRWsINS4ZL1iqzbn8OLrG3rCxaaGKrMqye3eYBfO5dmB4DVIuiAEm3TqDaHUxt0Bpg8NDLuhycs69sACxIq9w5w8Uod4Yrog8UHR4no7C7i42wbdBlWZnC9Vf+zh/WlqYMPKCjVRzjS6U50C6AOyIQcEm3TqDaHUxt0Bpg8NDLuhycs69sACxIq9w5w8Uod4YjkBWM1rAcnOxk6TB73TdHvy95rBN/9pMXdj8qZxh07COap/0Tc9LAAAgAEAAIAAAACACAAAAAEAAAAhBws9Ev28FsijbKdOzXEcmpunemvGz1OI5VQegobjHSpIOQF84JsKayTuxgCE0gxcaGGaAimm5ZDxhOhF+/qHUtbAb3/RNz0sAACAAQAAgAAAAIAAAAAAAQAAACEHC7GMF/lBFw9nyKkDPvK96P0Lk8/oE2TVAMCgdcYX2+s5AZxVkMryZmYDTlCW8YXVcqcEkhr0M3Y30LnqgMtSP3nXf9E3PSwAAIABAACAAAAAgAQAAAABAAAAIQcNubqlNLOyH1uBa3A3zR57rz34ExGOp7XQF6Pz0IMV/jkBnFWQyvJmZgNOUJbxhdVypwSSGvQzdjfQueqAy1I/edfWpz/lLAAAgAEAAIAAAACABAAAAAEAAAAhBxSQwCNSoKYIH0ayzFgA1xZ9WnyNP4m6PEXRd5uZmuzuOQGcVZDK8mZmA05QlvGF1XKnBJIa9DN2N9C56oDLUj951+aS5TEsAACAAQAAgAAAAIAEAAAAAQAAACEHHi0Pe3/Qps65t+8cJsE8TX/TxwuE9+rd7C/RxbCyhrQ5AZxVkMryZmYDTlCW8YXVcqcEkhr0M3Y30LnqgMtSP3nXTYhYKywAAIABAACAAAAAgAQAAAABAAAAIQchdNyS/t3hra0gKbsBGPA0g8WhfujnARNxdQYgQ9laejkBKO5qIL/1d/RHBJHcEJQLRs6Zrp7TUTMbCuQcVgfi+O4FYDf5LAAAgAEAAIAAAACAAgAAAAEAAAAhBzSGYG7T6CfvaS5u2fFwA8bTMdba3bfz/NMAQkEuoR3fOQGN+Lpb6xiGGLlSr+VA7d3Ev28ldOl45n6BYXDL4TE1bOaS5TEsAACAAQAAgAAAAIAGAAAAAQAAACEHTVcC6on3sB4ELN5UGgdazf2NTf1DgWtxb7vve/1oCgM5AZxVkMryZmYDTlCW8YXVcqcEkhr0M3Y30LnqgMtSP3nXBWA3+SwAAIABAACAAAAAgAQAAAABAAAAIQdRCNdh0SOA6+5I5pWXTWHeO7RUb7bsYBJaxxprSFvtbTkBKO5qIL/1d/RHBJHcEJQLRs6Zrp7TUTMbCuQcVgfi+O4PBWlDVgAAgAEAAIAAAACAAgAAAAEAAAAhB1OAAMms4iGGfmiqFo1YiQSQd0TKxR2uaJoPL2/nQewAOQGN+Lpb6xiGGLlSr+VA7d3Ev28ldOl45n6BYXDL4TE1bA8FaUNWAACAAQAAgAAAAIAGAAAAAQAAACEHW0FS1RvKNRX2AIcnIHx3+SFUvzSwjP91CPwp3phRynk5ASjuaiC/9Xf0RwSR3BCUC0bOma6e01EzGwrkHFYH4vju1qc/5SwAAIABAACAAAAAgAIAAAABAAAAIQdcXWz0XtkmiSJZlZEa6aDNGEWSdNYEHxNjwi7HxpzuDTkBTaqzeIwFD7CFV7idEKECseIHOHnEl0+qByp6tv3FY4HWpz/lLAAAgAEAAIAAAACACAAAAAEAAAAhB2Iru9YN9gw/gbkw65U+EU713SvuYi81Lo2BmDYAh+sROQEo7mogv/V39EcEkdwQlAtGzpmuntNRMxsK5BxWB+L47uaS5TEsAACAAQAAgAAAAIACAAAAAQAAACEHeIV0Zd0uHAjzeTqq+SGVaF5SScHBnZmVFdoq6EE8JxM5AXzgmwprJO7GAITSDFxoYZoCKablkPGE6EX7+odS1sBv5pLlMSwAAIABAACAAAAAgAAAAAABAAAAIQeCXuRO5uodkGOv3tyUyufka0OK3jZV1TDJDJZ8s4pCLjkBTaqzeIwFD7CFV7idEKECseIHOHnEl0+qByp6tv3FY4F/0Tc9LAAAgAEAAIAAAACABgAAAAEAAAAhB4ogGengIZ7/hnfr16/79SNNr3vdTNu5NTk1PaOnDhiyOQF84JsKayTuxgCE0gxcaGGaAimm5ZDxhOhF+/qHUtbAb9anP+UsAACAAQAAgAAAAIAAAAAAAQAAACEHisP7d+itm2Pn/t5392h2o/iaTWRedAqo40zXtzfZ5LA5ASjuaiC/9Xf0RwSR3BCUC0bOma6e01EzGwrkHFYH4vjuTYhYKywAAIABAACAAAAAgAIAAAABAAAAIQeLeyI4ZD3Ped7dSsbDVowE4fY3kU3QAKeQB43BhTK69zkBTaqzeIwFD7CFV7idEKECseIHOHnEl0+qByp6tv3FY4FNiFgrLAAAgAEAAIAAAACABgAAAAEAAAAhB5h6giPqlWc3eRJ0vEDfreDEwVGxIK/jMRwWavAhmie9DQB8Rh5dAAAAAAEAAAAhB5pI0yHAWxxH9TMZu2Wd8Mnbbpqh1JhKVocIK4pYmfmcOQEQ6ylJeKGCp+lSUCpzPF6ynWp3ZInsr6SgjneOfWaA1H/RNz0sAACAAQAAgAAAAIAKAAAAAQAAACEHnTG7/ncksOAYid9JHGwNkgsDnZO3B5bSrf3gHAqvsEk5AXzgmwprJO7GAITSDFxoYZoCKablkPGE6EX7+odS1sBvTYhYKywAAIABAACAAAAAgAAAAAABAAAAIQeeAZjC95MXuEN2EA6UFJp0wFQZHsG8UXo/fFcepFMQhDkBKO5qIL/1d/RHBJHcEJQLRs6Zrp7TUTMbCuQcVgfi+O5/0Tc9LAAAgAEAAIAAAACAAgAAAAEAAAAhB7gbvbacBO9JQ90V9v2hsR7oDfUMFySAaqjRiFBcPIBfOQGcVZDK8mZmA05QlvGF1XKnBJIa9DN2N9C56oDLUj951w8FaUNWAACAAQAAgAAAAIAEAAAAAQAAACEHuzV4hZbq88ak0rUYhXa778mxuleRvo7V6qqber9IgRU5AVjNawHJzsZOkwe903R78veawTf/aTF3Y/KmcYdOwjmq5pLlMSwAAIABAACAAAAAgAgAAAABAAAAIQfKktXTraxwmHzJQy5sAy6XwLzp6y2hpUmjN07CO8k2jTkBfOCbCmsk7sYAhNIMXGhhmgIppuWQ8YToRfv6h1LWwG8FYDf5LAAAgAEAAIAAAACAAAAAAAEAAAAhB83dosBQB4DcH032m3v9AU8sdIlyQ34fDxYvmd8ILImEOQEQ6ylJeKGCp+lSUCpzPF6ynWp3ZInsr6SgjneOfWaA1E2IWCssAACAAQAAgAAAAIAKAAAAAQAAACEH1LhkvWKrNufw4usbesLFpoYqsyrJ7d5gF87l2YHgNUg5AVjNawHJzsZOkwe903R78veawTf/aTF3Y/KmcYdOwjmqTYhYKywAAIABAACAAAAAgAgAAAABAAAAIQfZZMgCoQfHXviF9ZAdeiFp3IBl8lOKiZIMKeijYCKJ/jkBTaqzeIwFD7CFV7idEKECseIHOHnEl0+qByp6tv3FY4EFYDf5LAAAgAEAAIAAAACABgAAAAEAAAAhB+Cz9Ul/RP7x5UTolsov6gnL8nbZbYmaSpZIUdhgsk4mOQEQ6ylJeKGCp+lSUCpzPF6ynWp3ZInsr6SgjneOfWaA1AVgN/ksAACAAQAAgAAAAIAKAAAAAQAAACEH8IXbQWZx06EY7Y5c9IbnJqW5CQq+48fdZhrFAFULp7g5ARDrKUl4oYKn6VJQKnM8XrKdandkieyvpKCOd459ZoDUDwVpQ1YAAIABAACAAAAAgAgAAAABAAAAIQfxBthMm8XLy3cbmmN8oDMrMIMvxAzpv9YEQ1CZKuvQkzkBfOCbCmsk7sYAhNIMXGhhmgIppuWQ8YToRfv6h1LWwG8PBWlDVgAAgAEAAIAAAACAAAAAAAEAAAAhB/FB0eJ6Owu4uNsG3QZVmZwvVX/s4f1pamDDygo1Uc40OQFYzWsByc7GTpMHvdN0e/L3msE3/2kxd2PypnGHTsI5qgVgN/ksAACAAQAAgAAAAIAIAAAAAQAAACEH9ci9gzzuCUkBM3/9OyHUYQTpgK73tViB2MxkvMYCwec5AY34ulvrGIYYuVKv5UDt3cS/byV06XjmfoFhcMvhMTVs1qc/5SwAAIABAACAAAAAgAYAAAABAAAAAAEFIKyCMw/+O3k85vdhHbFf0rn7bzQqZJxYJvGCQCxm7H3uAQb9mgQBwM4gcF1eXxDzFxivMSsnnBis86TDEbcPO9urMMqK2tgHhJ+sINCHbVYxR9EkWIrWhfZNNhn2XXm6uCqIpKsxEegJ+UKNuiB0yGTKZidpUScQy6wxObJysDlHpx6yo6MTMbFCciUwxbogsE+QZdjgB7wAaQd4hWI0NFeBO5pgmggfjR9G2xU9aDS6IAS8F6X08yVYAI7YSoH7tj+GAS3YczGuDuSrHXQFjqGDuiAu5rQkEJWkY8srfBaWoLFi3q3BmFoLyor1KTrqGYWqbbpWnATAjiCuO0VUyhn9pko5+SSkg1YXBXoTe+iBJ4F+pbl57ZEJd6wg5fZyXLWqSOybtoj0wYygG+X1/2Ro9jecG/V52QTuy2y6IIdWpstHgeM+0o+XM2foH1nmpqt+eV88Y/vALi8uiOP8uiCx/FXB/3LJaTNk/8nCv7fbxdII1N3FHp/eFjOz897JLbpTnQLoA7IEwGsgpAmWuk1ba7ELcRhG7vjNJggTr7R8BhL7Y7HR0IqcDl6sIPirs/oVzsc3YNzy0CWB/V32N/xjYGsrq84Q8DFYkagduiAbCzyDoUZsKUBxcWSldXoi5AledioefVoTS0Fphlfv0LpSnQF4sgTA0SBzAPmt9riuiatQjiHt2VJ/8IDeGna3/aHU2Bl5JFXv0Kwg4Yt5bFOk7n1B9qied41g3AjFgrgJLpivuncE6JjTLBq6IJPMTCYog6Fk8Tsx/tpw3jfYyKE0PE3IXbnrje8761T4uiAC9p/orIZxgHRwoC0NbByAhEJQBovkAryrWEbKKpsHuLogno59TRLerKdR+pxxOyMELC3Uh5P1Bv1ZH0yh5elvfsG6IIqWtMAhIG8SMb+6cx2F3CMIEQKdgg4Nz57I7hw9xMxAulSdATyyBMDRINyJ1PLqrd0ALMXV0ADFzlftK9gFPEn2Ie6Gmqzr6ps3rCCo0XVv1L8N+U3vdSRqCG6oiC0Q8VRX2ZqJnHlOoQRbProgDuJ1FIEu0O24MyW0YjOuMUpTDtZG1s2dI99FW34y4TC6INXxOcybhQFzullHuZAblodw/IyzjuCn+tHcP9BjaiJwuiAUfExcBBBojUDZTdlIS/bBSL5jG8RToad8eQP6MmUcArogXZnJhV7yGECdWqIqE1t020uM2rO1xNyqNxDuj1nXskK6VZ0BFLIDwI4gMs8GyjytpKX+Z1+ShKDtTslFQrCrGqjz24tFuwpfT4CsIDWtm9Z2SzIKeh0pJKfLD1LP0GMlTYN520UUUwc5whI0uiBNpQv5ecaVCT1Q3KJM3JpGC9njCNkyHFd+zHDRl+RZIbognXHQEtOQOhD2i7La4S2SUbuB/ZMEdeHXZjFJcdSTWfu6U50C6AOyA8COIIKoVp0+voYlC3sHpXnM1FzcwnuhK1aL9KHNcfXrKSTGrCD8dYYENiEDIYVQx3KHjr1MY2/euCZG8/2cL7RH6WIyj7og8eLLMPMLnkezEjcHiM1FMU4u0btIU8unTpBadhfeHey6IIFdsvaWglN71jbPEijzNlorTIH+ljHy5ecGiknZ5Y/IulOdAugDsiEHAvaf6KyGcYB0cKAtDWwcgIRCUAaL5AK8q1hGyiqbB7g5AVYp30t8jCgP1tH4GiRvcRWZSZi40GfrLcX8hk4v61WpTYhYKywAAIABAACAAAAAgAQAAAACAAAAIQcEvBel9PMlWACO2EqB+7Y/hgEt2HMxrg7kqx10BY6hgzkBGeWekZoyURRdEjkKWflVOA75Fxa0WlI/H8ZiGj1ME7PmkuUxLAAAgAEAAIAAAACAAAAAAAIAAAAhBw7idRSBLtDtuDMltGIzrjFKUw7WRtbNnSPfRVt+MuEwOQGB9zRSosxzD71p7VO5Y3tBwNoMg4eKydnwBerZWIclfg8FaUNWAACAAQAAgAAAAIACAAAAAgAAACEHFHxMXAQQaI1A2U3ZSEv2wUi+YxvEU6GnfHkD+jJlHAI5AYH3NFKizHMPvWntU7lje0HA2gyDh4rJ2fAF6tlYhyV+f9E3PSwAAIABAACAAAAAgAIAAAACAAAAIQcbCzyDoUZsKUBxcWSldXoi5AledioefVoTS0Fphlfv0DkBe0nW2wTojSrb24mVe+kySwXg/6NvU1frMq1GuqLM31cPBWlDVgAAgAEAAIAAAACABgAAAAIAAAAhBy7mtCQQlaRjyyt8FpagsWLercGYWgvKivUpOuoZhaptOQEZ5Z6RmjJRFF0SOQpZ+VU4DvkXFrRaUj8fxmIaPUwTsw8FaUNWAACAAQAAgAAAAIAAAAAAAgAAACEHMs8GyjytpKX+Z1+ShKDtTslFQrCrGqjz24tFuwpfT4A5AW2Ni9+fG1wIMt0e4rouEC8oORpJCZuilu2U3alGAPE8DwVpQ1YAAIABAACAAAAAgAgAAAACAAAAIQc1rZvWdksyCnodKSSnyw9Sz9BjJU2DedtFFFMHOcISNDkBbY2L358bXAgy3R7iui4QLyg5GkkJm6KW7ZTdqUYA8TxNiFgrLAAAgAEAAIAAAACACgAAAAIAAAAhB02lC/l5xpUJPVDcokzcmkYL2eMI2TIcV37McNGX5FkhOQFtjYvfnxtcCDLdHuK6LhAvKDkaSQmbopbtlN2pRgDxPH/RNz0sAACAAQAAgAAAAIAKAAAAAgAAACEHXZnJhV7yGECdWqIqE1t020uM2rO1xNyqNxDuj1nXskI5AYH3NFKizHMPvWntU7lje0HA2gyDh4rJ2fAF6tlYhyV+BWA3+SwAAIABAACAAAAAgAIAAAACAAAAIQdwXV5fEPMXGK8xKyecGKzzpMMRtw8726swyora2AeEnzkBGeWekZoyURRdEjkKWflVOA75Fxa0WlI/H8ZiGj1ME7NNiFgrLAAAgAEAAIAAAACAAAAAAAIAAAAhB3MA+a32uK6Jq1COIe3ZUn/wgN4adrf9odTYGXkkVe/QOQFWKd9LfIwoD9bR+Bokb3EVmUmYuNBn6y3F/IZOL+tVqdanP+UsAACAAQAAgAAAAIAEAAAAAgAAACEHdMhkymYnaVEnEMusMTmycrA5R6cesqOjEzGxQnIlMMU5ARnlnpGaMlEUXRI5Cln5VTgO+RcWtFpSPx/GYho9TBOzBWA3+SwAAIABAACAAAAAgAAAAAACAAAAIQeBXbL2loJTe9Y2zxIo8zZaK0yB/pYx8uXnBopJ2eWPyDkBO4mPdFxGgt9hpHnxr9qoXSbL9jbyKIIXSgDivxndgsMFYDf5LAAAgAEAAIAAAACACAAAAAIAAAAhB4KoVp0+voYlC3sHpXnM1FzcwnuhK1aL9KHNcfXrKSTGOQE7iY90XEaC32GkefGv2qhdJsv2NvIoghdKAOK/Gd2Cw+aS5TEsAACAAQAAgAAAAIAIAAAAAgAAACEHh1amy0eB4z7Sj5czZ+gfWeamq355Xzxj+8AuLy6I4/w5AbuzRDO2UlVCow7Kk0uSw752HtqbgC0Alcn77jaYAyNIf9E3PSwAAIABAACAAAAAgAYAAAACAAAAIQeKlrTAISBvEjG/unMdhdwjCBECnYIODc+eyO4cPcTMQDkBVinfS3yMKA/W0fgaJG9xFZlJmLjQZ+stxfyGTi/rVakFYDf5LAAAgAEAAIAAAACABAAAAAIAAAAhB5PMTCYog6Fk8Tsx/tpw3jfYyKE0PE3IXbnrje8761T4OQFWKd9LfIwoD9bR+Bokb3EVmUmYuNBn6y3F/IZOL+tVqQ8FaUNWAACAAQAAgAAAAIAEAAAAAgAAACEHnXHQEtOQOhD2i7La4S2SUbuB/ZMEdeHXZjFJcdSTWfs5AW2Ni9+fG1wIMt0e4rouEC8oORpJCZuilu2U3alGAPE8BWA3+SwAAIABAACAAAAAgAoAAAACAAAAIQeejn1NEt6sp1H6nHE7IwQsLdSHk/UG/VkfTKHl6W9+wTkBVinfS3yMKA/W0fgaJG9xFZlJmLjQZ+stxfyGTi/rVal/0Tc9LAAAgAEAAIAAAACABAAAAAIAAAAhB6QJlrpNW2uxC3EYRu74zSYIE6+0fAYS+2Ox0dCKnA5eOQF7SdbbBOiNKtvbiZV76TJLBeD/o29TV+syrUa6oszfV9anP+UsAACAAQAAgAAAAIAGAAAAAgAAACEHqNF1b9S/DflN73UkaghuqIgtEPFUV9maiZx5TqEEWz45AYH3NFKizHMPvWntU7lje0HA2gyDh4rJ2fAF6tlYhyV+5pLlMSwAAIABAACAAAAAgAIAAAACAAAAIQesgjMP/jt5POb3YR2xX9K5+280KmScWCbxgkAsZux97g0AfEYeXQAAAAACAAAAIQeuO0VUyhn9pko5+SSkg1YXBXoTe+iBJ4F+pbl57ZEJdzkBu7NEM7ZSVUKjDsqTS5LDvnYe2puALQCVyfvuNpgDI0jWpz/lLAAAgAEAAIAAAACACAAAAAIAAAAhB7BPkGXY4Ae8AGkHeIViNDRXgTuaYJoIH40fRtsVPWg0OQEZ5Z6RmjJRFF0SOQpZ+VU4DvkXFrRaUj8fxmIaPUwTs9anP+UsAACAAQAAgAAAAIAAAAAAAgAAACEHsfxVwf9yyWkzZP/Jwr+328XSCNTdxR6f3hYzs/PeyS05AbuzRDO2UlVCow7Kk0uSw752HtqbgC0Alcn77jaYAyNIBWA3+SwAAIABAACAAAAAgAYAAAACAAAAIQfQh21WMUfRJFiK1oX2TTYZ9l15urgqiKSrMRHoCflCjTkBGeWekZoyURRdEjkKWflVOA75Fxa0WlI/H8ZiGj1ME7N/0Tc9LAAAgAEAAIAAAACAAAAAAAIAAAAhB9XxOcybhQFzullHuZAblodw/IyzjuCn+tHcP9BjaiJwOQGB9zRSosxzD71p7VO5Y3tBwNoMg4eKydnwBerZWIclfk2IWCssAACAAQAAgAAAAIACAAAAAgAAACEH3InU8uqt3QAsxdXQAMXOV+0r2AU8SfYh7oaarOvqmzc5AYH3NFKizHMPvWntU7lje0HA2gyDh4rJ2fAF6tlYhyV+1qc/5SwAAIABAACAAAAAgAIAAAACAAAAIQfhi3lsU6TufUH2qJ53jWDcCMWCuAkumK+6dwTomNMsGjkBVinfS3yMKA/W0fgaJG9xFZlJmLjQZ+stxfyGTi/rVanmkuUxLAAAgAEAAIAAAACABAAAAAIAAAAhB+X2cly1qkjsm7aI9MGMoBvl9f9kaPY3nBv1edkE7stsOQG7s0QztlJVQqMOypNLksO+dh7am4AtAJXJ++42mAMjSE2IWCssAACAAQAAgAAAAIAGAAAAAgAAACEH8eLLMPMLnkezEjcHiM1FMU4u0btIU8unTpBadhfeHew5ATuJj3RcRoLfYaR58a/aqF0my/Y28iiCF0oA4r8Z3YLDf9E3PSwAAIABAACAAAAAgAgAAAACAAAAIQf4q7P6Fc7HN2Dc8tAlgf1d9jf8Y2BrK6vOEPAxWJGoHTkBe0nW2wTojSrb24mVe+kySwXg/6NvU1frMq1GuqLM31fmkuUxLAAAgAEAAIAAAACABgAAAAIAAAAhB/x1hgQ2IQMhhVDHcoeOvUxjb964Jkbz/ZwvtEfpYjKPOQE7iY90XEaC32GkefGv2qhdJsv2NvIoghdKAOK/Gd2Cw02IWCssAACAAQAAgAAAAIAIAAAAAgAAAAABBSA/UUI8yjswr20zs9UrVLTs7wy1YrQGdoB679DYf0lU2QEG/ZoEAcDOIEEHd+ghZbgXzxXbUK/kItOWo0QY1B8WKrMU8jUlwx9/rCBpU/pH2dKGd9IT9QWqzAbMJangHNbKFrqmom3+wjqWcrogWXCfi7O6F4MAmvB1wn3x5lXB6yg6b2TqIt8CxnwdR5+6IGNdiSF0fMBX4GsGvvCxCg7QPUKfIR7P4O9qMBC5OeJ+uiBQdyxeLyY7uiG8GXyLx0eVhQIHXxvmRruGk9PnYiPTg7og2thrJ8obWTgFysZHX73SCpnyez38srpRpkcAR32YUXi6VpwEwI4gCG1IkaoiArMtJHEebqTzG9q6TAWDQSrkZI+32WTMzjKsICIKZthNXcCCQ50MjojvMhlEA10jE2VvC0SUGGudYBA4uiB4qG1Bb96pjURfyWk6y95hrqSaElXqjV7U7L8tojhST7ogsipKTzM6oIVIsxSSxBTqlZPX8jkceh/gh0o1sMhAr+G6U50C6AOyBMBrIODRuDgfYQgKmTrwIrDJVrbmCBY53csSxfCekOBsn70crCAFRpc2P+vp/zMEc13/TQxE9FjxhbslbETEP8mFdW+mirogZNhduzpwUWZHdI/uEyUPervPzeQPc7JarjLPhLNkS566Up0BeLIEwNEgZxbfBUNRyDPVwJ5em1wZKNIfCZO//06/fGFo/lbBtlSsIISO4YgEr8lVhiF13vSeELTAYE1Q3Z8Mj9SGu7qufADKuiCKkY41ZAf609cxpRCS0MKO5LgW70wBc9J+QBZwjjBtwLogmS9bB6DOdJIax6Ft1Zf2pgTUDpVTms4AOITkw/Ezduu6IAtWe9aRtNIb9HXH5v9/2XDa+tFTChSP0/BAN+/si4GxuiBH5jGe8TjJC9M/qtIPkb7dggswkhOSHU6Y3IKh4SOuwrpUnQE8sgTA0SA+4zaR5soREzFHrnz9v4zNBQoiKWLxaP9/GnaeZ7FA26wgxp7Yo07uSpWE6sKeyLCZzlENCjTZp21/D+eSc7MR4JW6II7cLDpjaJdRFL9c+GgpQaRf8Jllin6ySaAAazgFgSyouiAsRwhCIOHajsw7485AI6Lt7a6sNAH97vFY9BESw2X8uLogy1WvzIpI/YbvtD4zwbeCHb/4ac3JVjhcyJjYsS1apvG6IJEy2GP1vbkkjWv7ymWTtEZm7AEjPhJnjA3h0EgPcFGzulWdARSyA8COIIaKzhm0SpO386iY+GSRhbA7+/GnVyqw4EBA6UgUFMYErCAv+JF/NX78fXHM94nxtON8fSZVVtT3vcjdnElFEKEgXLogq/SK8h5VBUegMLDXc9H41sMbGquYN9/QH9tAWhU4+hi6IEaawhwOA6+Qnz907L0B8RPzZ8PqIV92xsYlkVtO4jN7ulOdAugDsgPAjiDP/W3FlMUKIC2hthduMbShA+5XkV9HEba1nw5MaHlzSqwg8mtIWFn1ObND1qgf0FWw5cF5tePvVz0pBIw16cyFp9G6IF3m1Y3HT+AF46xabUNXWttvZABqMuTxUGCbFiRgXGBRuiCkfAe0Kwr3dyw8HUkDPg1NCtaR94GIKgrNrxDQb1n5EbpTnQLoA7IhBwVGlzY/6+n/MwRzXf9NDET0WPGFuyVsRMQ/yYV1b6aKOQHxf1eo//sxIeekvKfmlrDzfaz0ZRNPgrKQN2OQ/dCz+eaS5TEsAACAAQAAgAAAAIAGAAAAAwAAACEHCG1IkaoiArMtJHEebqTzG9q6TAWDQSrkZI+32WTMzjI5AVLEpOhsWJOeX78sMyTiNCwLvHEANCASn64lhXAGzGBj1qc/5SwAAIABAACAAAAAgAgAAAADAAAAIQcLVnvWkbTSG/R1x+b/f9lw2vrRUwoUj9PwQDfv7IuBsTkBWoSc70COzTSVf8WwmVPR7SBqZmvaKvmL7HGRilL8haZ/0Tc9LAAAgAEAAIAAAACABAAAAAMAAAAhByIKZthNXcCCQ50MjojvMhlEA10jE2VvC0SUGGudYBA4OQFSxKTobFiTnl+/LDMk4jQsC7xxADQgEp+uJYVwBsxgY02IWCssAACAAQAAgAAAAIAGAAAAAwAAACEHLEcIQiDh2o7MO+POQCOi7e2urDQB/e7xWPQREsNl/Lg5AQ/J9BPtRxQJwvovgKEMjCW+XpWB2PFrppKi9dzXNO74TYhYKywAAIABAACAAAAAgAIAAAADAAAAIQcv+JF/NX78fXHM94nxtON8fSZVVtT3vcjdnElFEKEgXDkB+Yx0Z3c/Vb7f69YU4Ci7YAx76cmfq1ePTxaGHowTMfhNiFgrLAAAgAEAAIAAAACACgAAAAMAAAAhBz7jNpHmyhETMUeufP2/jM0FCiIpYvFo/38adp5nsUDbOQEPyfQT7UcUCcL6L4ChDIwlvl6Vgdjxa6aSovXc1zTu+NanP+UsAACAAQAAgAAAAIACAAAAAwAAACEHP1FCPMo7MK9tM7PVK1S07O8MtWK0BnaAeu/Q2H9JVNkNAHxGHl0AAAAAAwAAACEHQQd36CFluBfPFdtQr+Qi05ajRBjUHxYqsxTyNSXDH385AYSZz6hp3mEuk3XN8MIskoI+nlf9v8+e0/prpXTgms5OTYhYKywAAIABAACAAAAAgAAAAAADAAAAIQdGmsIcDgOvkJ8/dOy9AfET82fD6iFfdsbGJZFbTuIzezkB+Yx0Z3c/Vb7f69YU4Ci7YAx76cmfq1ePTxaGHowTMfgFYDf5LAAAgAEAAIAAAACACgAAAAMAAAAhB0fmMZ7xOMkL0z+q0g+Rvt2CCzCSE5IdTpjcgqHhI67COQFahJzvQI7NNJV/xbCZU9HtIGpma9oq+YvscZGKUvyFpgVgN/ksAACAAQAAgAAAAIAEAAAAAwAAACEHUHcsXi8mO7ohvBl8i8dHlYUCB18b5ka7hpPT52Ij04M5AYSZz6hp3mEuk3XN8MIskoI+nlf9v8+e0/prpXTgms5O5pLlMSwAAIABAACAAAAAgAAAAAADAAAAIQdZcJ+Ls7oXgwCa8HXCffHmVcHrKDpvZOoi3wLGfB1HnzkBhJnPqGneYS6Tdc3wwiySgj6eV/2/z57T+muldOCazk4FYDf5LAAAgAEAAIAAAACAAAAAAAMAAAAhB13m1Y3HT+AF46xabUNXWttvZABqMuTxUGCbFiRgXGBROQGeIUgTrZ0dIeuCYbGrMveETfs3GIlr7iRh1/9wE3C/B3/RNz0sAACAAQAAgAAAAIAIAAAAAwAAACEHY12JIXR8wFfgawa+8LEKDtA9Qp8hHs/g72owELk54n45AYSZz6hp3mEuk3XN8MIskoI+nlf9v8+e0/prpXTgms5O1qc/5SwAAIABAACAAAAAgAAAAAADAAAAIQdk2F27OnBRZkd0j+4TJQ96u8/N5A9zslquMs+Es2RLnjkB8X9XqP/7MSHnpLyn5paw832s9GUTT4KykDdjkP3Qs/kPBWlDVgAAgAEAAIAAAACABgAAAAMAAAAhB2cW3wVDUcgz1cCeXptcGSjSHwmTv/9Ov3xhaP5WwbZUOQFahJzvQI7NNJV/xbCZU9HtIGpma9oq+YvscZGKUvyFptanP+UsAACAAQAAgAAAAIAEAAAAAwAAACEHaVP6R9nShnfSE/UFqswGzCWp4BzWyha6pqJt/sI6lnI5AYSZz6hp3mEuk3XN8MIskoI+nlf9v8+e0/prpXTgms5Of9E3PSwAAIABAACAAAAAgAAAAAADAAAAIQd4qG1Bb96pjURfyWk6y95hrqSaElXqjV7U7L8tojhSTzkBUsSk6GxYk55fvywzJOI0LAu8cQA0IBKfriWFcAbMYGN/0Tc9LAAAgAEAAIAAAACABgAAAAMAAAAhB4SO4YgEr8lVhiF13vSeELTAYE1Q3Z8Mj9SGu7qufADKOQFahJzvQI7NNJV/xbCZU9HtIGpma9oq+YvscZGKUvyFpuaS5TEsAACAAQAAgAAAAIAEAAAAAwAAACEHhorOGbRKk7fzqJj4ZJGFsDv78adXKrDgQEDpSBQUxgQ5AfmMdGd3P1W+3+vWFOAou2AMe+nJn6tXj08Whh6MEzH4DwVpQ1YAAIABAACAAAAAgAgAAAADAAAAIQeKkY41ZAf609cxpRCS0MKO5LgW70wBc9J+QBZwjjBtwDkBWoSc70COzTSVf8WwmVPR7SBqZmvaKvmL7HGRilL8haYPBWlDVgAAgAEAAIAAAACABAAAAAMAAAAhB47cLDpjaJdRFL9c+GgpQaRf8Jllin6ySaAAazgFgSyoOQEPyfQT7UcUCcL6L4ChDIwlvl6Vgdjxa6aSovXc1zTu+A8FaUNWAACAAQAAgAAAAIACAAAAAwAAACEHkTLYY/W9uSSNa/vKZZO0RmbsASM+EmeMDeHQSA9wUbM5AQ/J9BPtRxQJwvovgKEMjCW+XpWB2PFrppKi9dzXNO74BWA3+SwAAIABAACAAAAAgAIAAAADAAAAIQeZL1sHoM50khrHoW3Vl/amBNQOlVOazgA4hOTD8TN26zkBWoSc70COzTSVf8WwmVPR7SBqZmvaKvmL7HGRilL8haZNiFgrLAAAgAEAAIAAAACABAAAAAMAAAAhB6R8B7QrCvd3LDwdSQM+DU0K1pH3gYgqCs2vENBvWfkROQGeIUgTrZ0dIeuCYbGrMveETfs3GIlr7iRh1/9wE3C/BwVgN/ksAACAAQAAgAAAAIAIAAAAAwAAACEHq/SK8h5VBUegMLDXc9H41sMbGquYN9/QH9tAWhU4+hg5AfmMdGd3P1W+3+vWFOAou2AMe+nJn6tXj08Whh6MEzH4f9E3PSwAAIABAACAAAAAgAoAAAADAAAAIQeyKkpPMzqghUizFJLEFOqVk9fyORx6H+CHSjWwyECv4TkBUsSk6GxYk55fvywzJOI0LAu8cQA0IBKfriWFcAbMYGMFYDf5LAAAgAEAAIAAAACABgAAAAMAAAAhB8ae2KNO7kqVhOrCnsiwmc5RDQo02adtfw/nknOzEeCVOQEPyfQT7UcUCcL6L4ChDIwlvl6Vgdjxa6aSovXc1zTu+OaS5TEsAACAAQAAgAAAAIACAAAAAwAAACEHy1WvzIpI/YbvtD4zwbeCHb/4ac3JVjhcyJjYsS1apvE5AQ/J9BPtRxQJwvovgKEMjCW+XpWB2PFrppKi9dzXNO74f9E3PSwAAIABAACAAAAAgAIAAAADAAAAIQfP/W3FlMUKIC2hthduMbShA+5XkV9HEba1nw5MaHlzSjkBniFIE62dHSHrgmGxqzL3hE37NxiJa+4kYdf/cBNwvwfmkuUxLAAAgAEAAIAAAACACAAAAAMAAAAhB9rYayfKG1k4BcrGR1+90gqZ8ns9/LK6UaZHAEd9mFF4OQGEmc+oad5hLpN1zfDCLJKCPp5X/b/PntP6a6V04JrOTg8FaUNWAACAAQAAgAAAAIAAAAAAAwAAACEH4NG4OB9hCAqZOvAisMlWtuYIFjndyxLF8J6Q4GyfvRw5AfF/V6j/+zEh56S8p+aWsPN9rPRlE0+CspA3Y5D90LP51qc/5SwAAIABAACAAAAAgAYAAAADAAAAIQfya0hYWfU5s0PWqB/QVbDlwXm14+9XPSkEjDXpzIWn0TkBniFIE62dHSHrgmGxqzL3hE37NxiJa+4kYdf/cBNwvwdNiFgrLAAAgAEAAIAAAACACAAAAAMAAAAAAQUg7kcvUj4CdJOKqn4nFJ2dLQMHjTfGrXwTpiRHMDmBz1oBBv2aBAHAziDcR/Kc1YvAYUIjepBRnJitJpgMhtJOEIKvrdFRgvM3LKwghUjpvkMmgOu5y2Ox0odv2BX2HKa62r6uNTa9c4nLuEC6IHjx+nVy1xvKzYiZzskytf8jFmjHHyUatmG82MuZiJ4luiClSi+iRE86zm85NmNP3BwCXyLoaEIZ5CI6HLx5zID+2boglmtMyl7if1gVF4SlN9xB1JyruUBS0wnNr/KUVCM2f2a6ID7TNKXxWZJYdDBPuQC1hCpz8hQsO2KTUHMKL01Rm1BCulacBMCOIHmgEwlX8IwF2EPKryHiaGrVli0M3e8HpjLNMLMRB5GRrCBJnIok2U6yA2t08CUdduT3L5iis7JxUYYXs31opD6Edbogvq87nv9WP6t3NTmyc8RyvlsLP5Ls4fWXdNn2RVSolQe6IKHviLsgwakiU4jYEcJTr7LZD2WOydosuQL88/O8beVhulOdAugDsgTAayDypFD+1sR+j9iAYzTuKUTbaPRuUVR2dhtZ7fz3h19S0Kwg5a9qOK54lzTJIXuq6nk4riAOP9SDPk9GNzbb2fuJ9Uy6IK0Bm423e7D8e7IR+kHIrhQot3hy5o9YRnvuz5nzglcXulKdAXiyBMDRIIVmzwidx33Q26tHIq9AjSrUcPpGWSAmH4cR94zBvilirCB5oocj5MbN0ZeYYn328CmoY2CNVfgIDkXFRTxQY5iH2boghl5w+h5fAsx3tJbf33vOBXXMcVUAbrkGISp4fXj07YW6IOEKCqz5qqoZXQiqOfLV5NBGbGz2c/jAe12OQ32T0qfouiBelapQSJe39msjDGPLC9kQJfbdRoVIDVFyvs7v1r8Ch7ogf3WsZhgtIF2IVh99UcrCoJ11MNLVgAxmG79Q0qUIxtW6VJ0BPLIEwNEg5JRp+ufZhnt1FcHVCcIzL8H//ne1//dQtShpqzdmwuusIGyHkEH+rWqwATTzUqddQ3Jx+xt0e0vx0dkmEtGxCsrxuiAiB+uH6jmD97dua29ngHPNqO/et+XbvU57hZGidW4dfrogdgZIGvf709hrzJmXeQd+Azq4t7zC9Kc16TZGZ8AumKG6IBjOf3B4/QnbqmcumiX1MnQbvYSQ1dPX58z+RAbxdyYcuiC9iXoJHEaW1tqAVLD2tx51wsk53hLKEhZG/fcxiaUHc7pVnQEUsgPAjiCqf2fOr+RfnbrsjjS/M2S9oJdQT2H9zHpQGnoK+9YUF6wgQwr0PUCH/FB62biyc+yJfkInbEYmjfWMVy5ovNmvX1K6IODqYzjXrQdBsG2UJlPBVGBRSvF/RdAcm1alfUzyK6ISuiA3rCzZnKWQHC5kz+XzPYEfGZkJ07aNLB0l1Nu+i/l9ibpTnQLoA7IDwI4gMsx76AX4x/sfk23EkMoqZVeDaoiPbAu+gXTQdnxA6JqsIGU4A661k4zVx2UQuoZpBXHgOVp3v4A0195YybfAvEhtuiAfpvAgmH5TlSZ0WNL781/W6HOT87ks7+b58DV1wILPebogAGqMoMQTt/Zx6VkqeAa26jolbAq+DPnINPJbvubc7AC6U50C6AOyIQcAaoygxBO39nHpWSp4BrbqOiVsCr4M+cg08lu+5tzsADkBtmQXXfTfIVhNdQ0shshAzryflJP2PR7LacYxyy1pi4IFYDf5LAAAgAEAAIAAAACACAAAAAQAAAAhBxjOf3B4/QnbqmcumiX1MnQbvYSQ1dPX58z+RAbxdyYcOQEDbni8A19KdQuiKc5DjCXE9eaYncyhGCXrW6519SWuQH/RNz0sAACAAQAAgAAAAIACAAAABAAAACEHH6bwIJh+U5UmdFjS+/Nf1uhzk/O5LO/m+fA1dcCCz3k5AbZkF1303yFYTXUNLIbIQM68n5ST9j0ey2nGMcstaYuCf9E3PSwAAIABAACAAAAAgAgAAAAEAAAAIQciB+uH6jmD97dua29ngHPNqO/et+XbvU57hZGidW4dfjkBA254vANfSnULoinOQ4wlxPXmmJ3MoRgl61uudfUlrkAPBWlDVgAAgAEAAIAAAACAAgAAAAQAAAAhBzLMe+gF+Mf7H5NtxJDKKmVXg2qIj2wLvoF00HZ8QOiaOQG2ZBdd9N8hWE11DSyGyEDOvJ+Uk/Y9HstpxjHLLWmLguaS5TEsAACAAQAAgAAAAIAIAAAABAAAACEHN6ws2ZylkBwuZM/l8z2BHxmZCdO2jSwdJdTbvov5fYk5AZTqaY0mG6WzssyqfkeoqFGp+SLnBZcH2p2YIjMoIGdJBWA3+SwAAIABAACAAAAAgAoAAAAEAAAAIQc+0zSl8VmSWHQwT7kAtYQqc/IULDtik1BzCi9NUZtQQjkBlsRhScK/XBq3UjegLL6FX9a1Ng4K9P8ZHyIugV1JX1MPBWlDVgAAgAEAAIAAAACAAAAAAAQAAAAhB0MK9D1Ah/xQetm4snPsiX5CJ2xGJo31jFcuaLzZr19SOQGU6mmNJhuls7LMqn5HqKhRqfki5wWXB9qdmCIzKCBnSU2IWCssAACAAQAAgAAAAIAKAAAABAAAACEHSZyKJNlOsgNrdPAlHXbk9y+YorOycVGGF7N9aKQ+hHU5AVoSP6rbJUDh84ZtTmZRGrCVrQ4qUzkrfvO9uDppI0jjTYhYKywAAIABAACAAAAAgAYAAAAEAAAAIQdelapQSJe39msjDGPLC9kQJfbdRoVIDVFyvs7v1r8ChzkB6ISXLIissm1GzsHlona1u7Xy/QQ8qgsba+Jgtle8SzN/0Tc9LAAAgAEAAIAAAACABAAAAAQAAAAhB2U4A661k4zVx2UQuoZpBXHgOVp3v4A0195YybfAvEhtOQG2ZBdd9N8hWE11DSyGyEDOvJ+Uk/Y9HstpxjHLLWmLgk2IWCssAACAAQAAgAAAAIAIAAAABAAAACEHbIeQQf6tarABNPNSp11DcnH7G3R7S/HR2SYS0bEKyvE5AQNueLwDX0p1C6IpzkOMJcT15pidzKEYJetbrnX1Ja5A5pLlMSwAAIABAACAAAAAgAIAAAAEAAAAIQd2Bkga9/vT2GvMmZd5B34DOri3vML0pzXpNkZnwC6YoTkBA254vANfSnULoinOQ4wlxPXmmJ3MoRgl61uudfUlrkBNiFgrLAAAgAEAAIAAAACAAgAAAAQAAAAhB3jx+nVy1xvKzYiZzskytf8jFmjHHyUatmG82MuZiJ4lOQGWxGFJwr9cGrdSN6AsvoVf1rU2Dgr0/xkfIi6BXUlfUwVgN/ksAACAAQAAgAAAAIAAAAAABAAAACEHeaATCVfwjAXYQ8qvIeJoatWWLQzd7wemMs0wsxEHkZE5AVoSP6rbJUDh84ZtTmZRGrCVrQ4qUzkrfvO9uDppI0jj1qc/5SwAAIABAACAAAAAgAgAAAAEAAAAIQd5oocj5MbN0ZeYYn328CmoY2CNVfgIDkXFRTxQY5iH2TkB6ISXLIissm1GzsHlona1u7Xy/QQ8qgsba+Jgtle8SzPmkuUxLAAAgAEAAIAAAACABAAAAAQAAAAhB391rGYYLSBdiFYffVHKwqCddTDS1YAMZhu/UNKlCMbVOQHohJcsiKyybUbOweWidrW7tfL9BDyqCxtr4mC2V7xLMwVgN/ksAACAAQAAgAAAAIAEAAAABAAAACEHhUjpvkMmgOu5y2Ox0odv2BX2HKa62r6uNTa9c4nLuEA5AZbEYUnCv1wat1I3oCy+hV/WtTYOCvT/GR8iLoFdSV9Tf9E3PSwAAIABAACAAAAAgAAAAAAEAAAAIQeFZs8Incd90NurRyKvQI0q1HD6RlkgJh+HEfeMwb4pYjkB6ISXLIissm1GzsHlona1u7Xy/QQ8qgsba+Jgtle8SzPWpz/lLAAAgAEAAIAAAACABAAAAAQAAAAhB4ZecPoeXwLMd7SW3997zgV1zHFVAG65BiEqeH149O2FOQHohJcsiKyybUbOweWidrW7tfL9BDyqCxtr4mC2V7xLMw8FaUNWAACAAQAAgAAAAIAEAAAABAAAACEHlmtMyl7if1gVF4SlN9xB1JyruUBS0wnNr/KUVCM2f2Y5AZbEYUnCv1wat1I3oCy+hV/WtTYOCvT/GR8iLoFdSV9T5pLlMSwAAIABAACAAAAAgAAAAAAEAAAAIQeh74i7IMGpIlOI2BHCU6+y2Q9ljsnaLLkC/PPzvG3lYTkBWhI/qtslQOHzhm1OZlEasJWtDipTOSt+8724OmkjSOMFYDf5LAAAgAEAAIAAAACABgAAAAQAAAAhB6VKL6JETzrObzk2Y0/cHAJfIuhoQhnkIjocvHnMgP7ZOQGWxGFJwr9cGrdSN6AsvoVf1rU2Dgr0/xkfIi6BXUlfU9anP+UsAACAAQAAgAAAAIAAAAAABAAAACEHqn9nzq/kX5267I40vzNkvaCXUE9h/cx6UBp6CvvWFBc5AZTqaY0mG6WzssyqfkeoqFGp+SLnBZcH2p2YIjMoIGdJDwVpQ1YAAIABAACAAAAAgAgAAAAEAAAAIQetAZuNt3uw/HuyEfpByK4UKLd4cuaPWEZ77s+Z84JXFzkBEgQrYblWKeIV8kB1sOaIjE/920VrufumAbJ9xln7NxcPBWlDVgAAgAEAAIAAAACABgAAAAQAAAAhB72JegkcRpbW2oBUsPa3HnXCyTneEsoSFkb99zGJpQdzOQEDbni8A19KdQuiKc5DjCXE9eaYncyhGCXrW6519SWuQAVgN/ksAACAAQAAgAAAAIACAAAABAAAACEHvq87nv9WP6t3NTmyc8RyvlsLP5Ls4fWXdNn2RVSolQc5AVoSP6rbJUDh84ZtTmZRGrCVrQ4qUzkrfvO9uDppI0jjf9E3PSwAAIABAACAAAAAgAYAAAAEAAAAIQfcR/Kc1YvAYUIjepBRnJitJpgMhtJOEIKvrdFRgvM3LDkBlsRhScK/XBq3UjegLL6FX9a1Ng4K9P8ZHyIugV1JX1NNiFgrLAAAgAEAAIAAAACAAAAAAAQAAAAhB+DqYzjXrQdBsG2UJlPBVGBRSvF/RdAcm1alfUzyK6ISOQGU6mmNJhuls7LMqn5HqKhRqfki5wWXB9qdmCIzKCBnSX/RNz0sAACAAQAAgAAAAIAKAAAABAAAACEH4QoKrPmqqhldCKo58tXk0EZsbPZz+MB7XY5DfZPSp+g5AeiElyyIrLJtRs7B5aJ2tbu18v0EPKoLG2viYLZXvEszTYhYKywAAIABAACAAAAAgAQAAAAEAAAAIQfklGn659mGe3UVwdUJwjMvwf/+d7X/91C1KGmrN2bC6zkBA254vANfSnULoinOQ4wlxPXmmJ3MoRgl61uudfUlrkDWpz/lLAAAgAEAAIAAAACAAgAAAAQAAAAhB+WvajiueJc0ySF7qup5OK4gDj/Ugz5PRjc229n7ifVMOQESBCthuVYp4hXyQHWw5oiMT/3bRWu5+6YBsn3GWfs3F+aS5TEsAACAAQAAgAAAAIAGAAAABAAAACEH7kcvUj4CdJOKqn4nFJ2dLQMHjTfGrXwTpiRHMDmBz1oNAHxGHl0AAAAABAAAACEH8qRQ/tbEfo/YgGM07ilE22j0blFUdnYbWe3894dfUtA5ARIEK2G5ViniFfJAdbDmiIxP/dtFa7n7pgGyfcZZ+zcX1qc/5SwAAIABAACAAAAAgAYAAAAEAAAAAAEFIAY4B+R8tEehp/MamKlHalMAYs1ZdCoKHo2yMEpZsJg1AQb9mgQBwM4gzC7nd+Hh6RIlHckGo7XXU59IEasl/cbR06MKkRGYfhusILxEuySb8UTOnZ1lsbx18q58ITVwsCZl2Mpoa0TOsW/JuiD6c2sjlcNyWax9tirF7GWFczr04uv7eWkqTAP3So8s4bogO4bPwj04gndbfi6MLBjkjIqLUagZQwPEedJnfYXTTIS6IE42FJrs5ScuHw/OyLgUIsooKbeKIVQfiaGDQVOzKFrGuiAr1evudQ9sepn6aXlfQloya94b2pFbF+Bmv77T+qqGXrpWnATAjiD/Qpim63wcV9eU2/k9pwK5zVecDBgo1WMR57ieDOiPS6wg8XmxekAFYmwv1xRrFlndX9tIWn34lweyrx9mU4+y6Ju6IHKaJ49ajCWgAnEPALN8oDsltTyZUoQ7o0n+Kso/x45vuiB7hgN8w7LByKVl2l+yG4qmrd/6BNYdoAkDS2WvC9zXrrpTnQLoA7IEwGsg1fQzh+xY72r9AolIWrlgKIKO9swfz+mjeDVog3Cj8sysIBZYpwqo6INlzaTU3C3sU+IYfoXaL7Law6xQvQanEijPuiDFIgX/nj//j1hOez774r+BBbrOigGbfF7UQrXSOaYzOLpSnQF4sgTA0SCTgEJbm419XC4ZQJxq1appKxb8DlXV5v0iR7DJ6GnbZKwg3iunyXKf2/4o9hzdo5ktwNXao8y/IZNqyClkJMxpmJK6IHoRVpUc5yrIRCiQwJU05ezqWu28fXyFI1okb/UibLJauiDYHekjWo4oHd8bntYkOny9V7bPJSwvzA/FzCLQkugb47ogjmgBiounO+PKkk4M67ulZVYdvME/8vgBfN345aBE9xe6IIBt+6JtgK9aOxz22yqKLpJFKArRpLkb4mxj9vSpFO0AulSdATyyBMDRIAgIzclDvd9wbPYHXq+jjk0K71pSejJ+2qIjLZTSr1NUrCAQ7qaybtmMEQ4AwLFpW468Jk2PxhIPPBZm1EiZjZRe/7ogV0MIbeZX4bYAWx95M1hJ0aK9AbTCsb4ol6uOFV+uMd+6IGEt5akrdJHq4Y2+1ZMWinBGORm4FqfwiU1hQ6gjG21ruiCXF34QL756O2nFqmWnA5Bz4ziHyNMJ2TtMhhUGPV7mnLog/VncgE/+6f92NkWjesDMmvkJYUcGTTsZL/H1CoQt77u6VZ0BFLIDwI4g/Jr0bkNGmh3/Zq7FO22ZvGVivqmv8aP/rEwdz2BSd6+sIOy00HvaAs7h0Iq1aB65NAG/Z+EJIt2QczMGspyWnYwbuiA96TnBCeQ8DPZzWMrqY2Nu3mDdBlwbn25q0RHLru7Q6rogZQzaasytzRZ+c8D1rE2NRAkvVaeUAmF5vbkQcJrrscC6U50C6AOyA8COIDp4ewlORXdlplLLR2b2V/b4nW2sxM2u3dIqbk/zbBhNrCDTISq3LjlZoKNFmYD9kS+j/jZKPLXm5uLMD3ls4EECa7og4JmhWpHTbAmXzu2zbRMfkLfXuV6DKbGTIIgdMWTLDM66IBIU9cvuSkMZ0d8zJzH0lIQMZ0JRg34QJFKqtKOFS0ZbulOdAugDsiEHBjgH5Hy0R6Gn8xqYqUdqUwBizVl0KgoejbIwSlmwmDUNAHxGHl0AAAAABQAAACEHCAjNyUO933Bs9gder6OOTQrvWlJ6Mn7aoiMtlNKvU1Q5Ab5QRVu958CxE78dkr1/nRKSomuXR/lfbwf8ygGdE0H31qc/5SwAAIABAACAAAAAgAIAAAAFAAAAIQcQ7qaybtmMEQ4AwLFpW468Jk2PxhIPPBZm1EiZjZRe/zkBvlBFW73nwLETvx2SvX+dEpKia5dH+V9vB/zKAZ0TQffmkuUxLAAAgAEAAIAAAACAAgAAAAUAAAAhBxIU9cvuSkMZ0d8zJzH0lIQMZ0JRg34QJFKqtKOFS0ZbOQFSaLLtYjZy7adnibHsh7h+u9yb5cZ6po0O/4lLM/sbiQVgN/ksAACAAQAAgAAAAIAIAAAABQAAACEHFlinCqjog2XNpNTcLexT4hh+hdovstrDrFC9BqcSKM85AYOOFJCdzc6rC9v48jKlm5Hm/Naxqidodne9wjhMqfeb5pLlMSwAAIABAACAAAAAgAYAAAAFAAAAIQcr1evudQ9sepn6aXlfQloya94b2pFbF+Bmv77T+qqGXjkB83OZou5dqe9wZh7L5Av0OQlcYOQkybs+tbRKKx5htHIPBWlDVgAAgAEAAIAAAACAAAAAAAUAAAAhBzp4ewlORXdlplLLR2b2V/b4nW2sxM2u3dIqbk/zbBhNOQFSaLLtYjZy7adnibHsh7h+u9yb5cZ6po0O/4lLM/sbieaS5TEsAACAAQAAgAAAAIAIAAAABQAAACEHO4bPwj04gndbfi6MLBjkjIqLUagZQwPEedJnfYXTTIQ5AfNzmaLuXanvcGYey+QL9DkJXGDkJMm7PrW0SiseYbRy1qc/5SwAAIABAACAAAAAgAAAAAAFAAAAIQc96TnBCeQ8DPZzWMrqY2Nu3mDdBlwbn25q0RHLru7Q6jkBG5tfJGwn9eQ2NLoWFl/eLz7xxFnjFKz8pmSN2bvn7fd/0Tc9LAAAgAEAAIAAAACACgAAAAUAAAAhB042FJrs5ScuHw/OyLgUIsooKbeKIVQfiaGDQVOzKFrGOQHzc5mi7l2p73BmHsvkC/Q5CVxg5CTJuz61tEorHmG0cuaS5TEsAACAAQAAgAAAAIAAAAAABQAAACEHV0MIbeZX4bYAWx95M1hJ0aK9AbTCsb4ol6uOFV+uMd85Ab5QRVu958CxE78dkr1/nRKSomuXR/lfbwf8ygGdE0H3DwVpQ1YAAIABAACAAAAAgAIAAAAFAAAAIQdhLeWpK3SR6uGNvtWTFopwRjkZuBan8IlNYUOoIxttazkBvlBFW73nwLETvx2SvX+dEpKia5dH+V9vB/zKAZ0TQfdNiFgrLAAAgAEAAIAAAACAAgAAAAUAAAAhB2UM2mrMrc0WfnPA9axNjUQJL1WnlAJheb25EHCa67HAOQEbm18kbCf15DY0uhYWX94vPvHEWeMUrPymZI3Zu+ft9wVgN/ksAACAAQAAgAAAAIAKAAAABQAAACEHcponj1qMJaACcQ8As3ygOyW1PJlShDujSf4qyj/Hjm85Ac7OXrzZSfJCpI5Tf+GIgCKKhIRXMY67tM5sYqk9mqylf9E3PSwAAIABAACAAAAAgAYAAAAFAAAAIQd6EVaVHOcqyEQokMCVNOXs6lrtvH18hSNaJG/1ImyyWjkBpf9/6NLePIEXw46EPMWzbxbNhwvoPCs3+4KJ7Ib+aXAPBWlDVgAAgAEAAIAAAACABAAAAAUAAAAhB3uGA3zDssHIpWXaX7Ibiqat3/oE1h2gCQNLZa8L3NeuOQHOzl682UnyQqSOU3/hiIAiioSEVzGOu7TObGKpPZqspQVgN/ksAACAAQAAgAAAAIAGAAAABQAAACEHgG37om2Ar1o7HPbbKooukkUoCtGkuRvibGP29KkU7QA5AaX/f+jS3jyBF8OOhDzFs28WzYcL6DwrN/uCieyG/mlwBWA3+SwAAIABAACAAAAAgAQAAAAFAAAAIQeOaAGKi6c748qSTgzru6VlVh28wT/y+AF83fjloET3FzkBpf9/6NLePIEXw46EPMWzbxbNhwvoPCs3+4KJ7Ib+aXB/0Tc9LAAAgAEAAIAAAACABAAAAAUAAAAhB5OAQlubjX1cLhlAnGrVqmkrFvwOVdXm/SJHsMnoadtkOQGl/3/o0t48gRfDjoQ8xbNvFs2HC+g8Kzf7gonshv5pcNanP+UsAACAAQAAgAAAAIAEAAAABQAAACEHlxd+EC++ejtpxaplpwOQc+M4h8jTCdk7TIYVBj1e5pw5Ab5QRVu958CxE78dkr1/nRKSomuXR/lfbwf8ygGdE0H3f9E3PSwAAIABAACAAAAAgAIAAAAFAAAAIQe8RLskm/FEzp2dZbG8dfKufCE1cLAmZdjKaGtEzrFvyTkB83OZou5dqe9wZh7L5Av0OQlcYOQkybs+tbRKKx5htHJ/0Tc9LAAAgAEAAIAAAACAAAAAAAUAAAAhB8UiBf+eP/+PWE57Pvviv4EFus6KAZt8XtRCtdI5pjM4OQGDjhSQnc3Oqwvb+PIypZuR5vzWsaonaHZ3vcI4TKn3mw8FaUNWAACAAQAAgAAAAIAGAAAABQAAACEHzC7nd+Hh6RIlHckGo7XXU59IEasl/cbR06MKkRGYfhs5AfNzmaLuXanvcGYey+QL9DkJXGDkJMm7PrW0SiseYbRyTYhYKywAAIABAACAAAAAgAAAAAAFAAAAIQfTISq3LjlZoKNFmYD9kS+j/jZKPLXm5uLMD3ls4EECazkBUmiy7WI2cu2nZ4mx7Ie4frvcm+XGeqaNDv+JSzP7G4lNiFgrLAAAgAEAAIAAAACACAAAAAUAAAAhB9X0M4fsWO9q/QKJSFq5YCiCjvbMH8/po3g1aINwo/LMOQGDjhSQnc3Oqwvb+PIypZuR5vzWsaonaHZ3vcI4TKn3m9anP+UsAACAAQAAgAAAAIAGAAAABQAAACEH2B3pI1qOKB3fG57WJDp8vVe2zyUsL8wPxcwi0JLoG+M5AaX/f+jS3jyBF8OOhDzFs28WzYcL6DwrN/uCieyG/mlwTYhYKywAAIABAACAAAAAgAQAAAAFAAAAIQfeK6fJcp/b/ij2HN2jmS3A1dqjzL8hk2rIKWQkzGmYkjkBpf9/6NLePIEXw46EPMWzbxbNhwvoPCs3+4KJ7Ib+aXDmkuUxLAAAgAEAAIAAAACABAAAAAUAAAAhB+CZoVqR02wJl87ts20TH5C317legymxkyCIHTFkywzOOQFSaLLtYjZy7adnibHsh7h+u9yb5cZ6po0O/4lLM/sbiX/RNz0sAACAAQAAgAAAAIAIAAAABQAAACEH7LTQe9oCzuHQirVoHrk0Ab9n4Qki3ZBzMwaynJadjBs5ARubXyRsJ/XkNjS6FhZf3i8+8cRZ4xSs/KZkjdm75+33TYhYKywAAIABAACAAAAAgAoAAAAFAAAAIQfxebF6QAVibC/XFGsWWd1f20haffiXB7KvH2ZTj7LomzkBzs5evNlJ8kKkjlN/4YiAIoqEhFcxjru0zmxiqT2arKVNiFgrLAAAgAEAAIAAAACABgAAAAUAAAAhB/pzayOVw3JZrH22KsXsZYVzOvTi6/t5aSpMA/dKjyzhOQHzc5mi7l2p73BmHsvkC/Q5CVxg5CTJuz61tEorHmG0cgVgN/ksAACAAQAAgAAAAIAAAAAABQAAACEH/Jr0bkNGmh3/Zq7FO22ZvGVivqmv8aP/rEwdz2BSd685ARubXyRsJ/XkNjS6FhZf3i8+8cRZ4xSs/KZkjdm75+33DwVpQ1YAAIABAACAAAAAgAgAAAAFAAAAIQf9WdyAT/7p/3Y2RaN6wMya+QlhRwZNOxkv8fUKhC3vuzkBvlBFW73nwLETvx2SvX+dEpKia5dH+V9vB/zKAZ0TQfcFYDf5LAAAgAEAAIAAAACAAgAAAAUAAAAhB/9CmKbrfBxX15Tb+T2nArnNV5wMGCjVYxHnuJ4M6I9LOQHOzl682UnyQqSOU3/hiIAiioSEVzGOu7TObGKpPZqspdanP+UsAACAAQAAgAAAAIAIAAAABQAAAAABBSCjabh1e0bW/GWTAmzMhbpKkARx5Y2IKtll07EJyIWKnQEG/ZoEAcDOIOPLbmagUCCHP0WmcH3eRnORoheNQJiEsaS07WtA2EjxrCDyBbHseOMRxDgcmVtpA/OLvagm4SUAPVBEIAR1ts/Eubogu3exGxIJ4ZQ7tIVnnI7mEeqoE6ThOusdVmsRQOf0lSu6IIevcqU+LKMQiiPWVf+gDE+BiesOCadXA+mjqPLdpwrquiBRN+nJr//ULVLubTKOQzMNMFhcGW4l/Og8dzkJHXloI7og8OzNXtHOQ7zC/Amf7DvcxHq4K1E+3qvgmyea7kmW3ky6VpwEwI4gfqUMvj4HR6B+7DVSvyZ3OSwEUlxuilGIDlQhYSNrZFesIEM68FnwaQafgGnJM6UcSY5Q89Sobcujesr1FppPYJypuiC2MTJ8k5rv67jzMWKLsA+JcYlU6EyOhnSQw3QcSWvMxLog3/5x/SS7C4WTWsrgY1nWEf0nOGdulebIsv7dtXaCszW6U50C6AOyBMBrICwVb1O6tNNT3LkGBRqQfVioPMWcLz1Ros2EqLJqGewBrCB6TabsaITIMuO2biVcYSbygo6uMT2qXAJUSlaROnxAlLogps51HGdbHkG2e3g3JA7tXF8M9wjkHxvOEqzWAsDFPwC6Up0BeLIEwNEgqYar/nRK7CcGlT4WlJIuxqs/HDxtqHGvIiDBYeXGcemsIDWnOBrusLJfq8d2uCEM61KpGVhk2+mkyV0CrJfy1ud4uiBqj9zNaj+u6ulpGkASiZnc5JubOTpV7bcPjz4d5pC7P7ogLLKBmcG8IRFOdHeY/o2zY0xYFPBDrlUtUKGY6pEANV+6IPYU3Y76HDAM1MZPaAsd1T11Cdm5qv7nO4twoMaEhGuJuiBLTSci4q9rzLAigwK7u1nko2AXvVITqo/Wyr9xtoPOs7pUnQE8sgTA0SBDFJOOp7ktbewYmMU2fMJUhr0+T+H75y4hKUba/oSDy6wg/elWX+HFtQh8EdAZp/lgAK7vv02iurjqpnoLNzoVFaq6IH4Rl2y5v5vYl+XSomE/qxLu5jwnSeCmemP0AHWICJ4quiD5hr8z2VdboBvCGO7B6EzFofn/TcdeojIuVj52OgXM7bogyuMajTyS1tzdrOFXvuvprwMac6y6HDSflvnPOjc3gsG6IB1fAABKAphZV2ndZS5lIXeuDCrg2zPm/fylapb+T2+JulWdARSyA8COIK3rLylWDrmTO5V9boe226/UNx+99FLBxAuJjKXOSowerCAuQ5IHCwQ/5wgC8XOtd3ySBYo+gAx0R1qe+HBpS195grogioFPZ/4fOlhCiKSlTy9q5N36pF/VdX5L3x9+NhukvVW6ILKrPx9hejLOXTRbIAUwugKidbCBMa/zOpjWEFG5B3EXulOdAugDsgPAjiAhW7kJBNeWHdJ4CFCm/M8Z4SmJrxObRe/5ydeGz0IPKKwgx6NCcP2MyXpYz6b0AWZJfqD2pKdHNBfu5Yu92Qm4g0K6IAb4V09LQFixxKXXjVtP19dXgexFjGskGcmCZG4ZsMafuiA9dIzmfrFtVzwygYY0B3OTdx+PX/mMHeUgFImmWSaHj7pTnQLoA7IhBwb4V09LQFixxKXXjVtP19dXgexFjGskGcmCZG4ZsMafOQGl0T2p3e5SkGq5rVZLhZN32n4KeXFwUHdJE31hMayqCX/RNz0sAACAAQAAgAAAAIAIAAAABgAAACEHHV8AAEoCmFlXad1lLmUhd64MKuDbM+b9/KVqlv5Pb4k5AZGXg5QJlj3rb4xYXOkRQZYsZUMGukk9qdbHXZ6syeb/BWA3+SwAAIABAACAAAAAgAIAAAAGAAAAIQchW7kJBNeWHdJ4CFCm/M8Z4SmJrxObRe/5ydeGz0IPKDkBpdE9qd3uUpBqua1WS4WTd9p+CnlxcFB3SRN9YTGsqgnmkuUxLAAAgAEAAIAAAACACAAAAAYAAAAhBywVb1O6tNNT3LkGBRqQfVioPMWcLz1Ros2EqLJqGewBOQFtF/j4tHjJ/vhNNUsAVdzPegKLil5Fei1ErCopnsJo3NanP+UsAACAAQAAgAAAAIAGAAAABgAAACEHLLKBmcG8IRFOdHeY/o2zY0xYFPBDrlUtUKGY6pEANV85ASUxf800GBNXqs56KhFDILPg6XZq43fUhHLDMJzOtdlBTYhYKywAAIABAACAAAAAgAQAAAAGAAAAIQcuQ5IHCwQ/5wgC8XOtd3ySBYo+gAx0R1qe+HBpS195gjkBTUauK27WNMCDVl9AHX6cMIGgM9KCsjyZnJVlLoAvYYdNiFgrLAAAgAEAAIAAAACACgAAAAYAAAAhBzWnOBrusLJfq8d2uCEM61KpGVhk2+mkyV0CrJfy1ud4OQElMX/NNBgTV6rOeioRQyCz4Ol2auN31IRywzCczrXZQeaS5TEsAACAAQAAgAAAAIAEAAAABgAAACEHPXSM5n6xbVc8MoGGNAdzk3cfj1/5jB3lIBSJplkmh485AaXRPand7lKQarmtVkuFk3fafgp5cXBQd0kTfWExrKoJBWA3+SwAAIABAACAAAAAgAgAAAAGAAAAIQdDFJOOp7ktbewYmMU2fMJUhr0+T+H75y4hKUba/oSDyzkBkZeDlAmWPetvjFhc6RFBlixlQwa6ST2p1sddnqzJ5v/Wpz/lLAAAgAEAAIAAAACAAgAAAAYAAAAhB0M68FnwaQafgGnJM6UcSY5Q89Sobcujesr1FppPYJypOQGkOrkLL+3bMLvPojlXmEobN7V8ZD929JynODAF0WjSzE2IWCssAACAAQAAgAAAAIAGAAAABgAAACEHS00nIuKva8ywIoMCu7tZ5KNgF71SE6qP1sq/cbaDzrM5ASUxf800GBNXqs56KhFDILPg6XZq43fUhHLDMJzOtdlBBWA3+SwAAIABAACAAAAAgAQAAAAGAAAAIQdRN+nJr//ULVLubTKOQzMNMFhcGW4l/Og8dzkJHXloIzkB5nD4fkSz5K5ghHzsosNRD7JmZjFEKQDGj7bWTHlOyVDmkuUxLAAAgAEAAIAAAACAAAAAAAYAAAAhB2qP3M1qP67q6WkaQBKJmdzkm5s5OlXttw+PPh3mkLs/OQElMX/NNBgTV6rOeioRQyCz4Ol2auN31IRywzCczrXZQQ8FaUNWAACAAQAAgAAAAIAEAAAABgAAACEHek2m7GiEyDLjtm4lXGEm8oKOrjE9qlwCVEpWkTp8QJQ5AW0X+Pi0eMn++E01SwBV3M96AouKXkV6LUSsKimewmjc5pLlMSwAAIABAACAAAAAgAYAAAAGAAAAIQd+EZdsub+b2Jfl0qJhP6sS7uY8J0ngpnpj9AB1iAieKjkBkZeDlAmWPetvjFhc6RFBlixlQwa6ST2p1sddnqzJ5v8PBWlDVgAAgAEAAIAAAACAAgAAAAYAAAAhB36lDL4+B0egfuw1Ur8mdzksBFJcbopRiA5UIWEja2RXOQGkOrkLL+3bMLvPojlXmEobN7V8ZD929JynODAF0WjSzNanP+UsAACAAQAAgAAAAIAIAAAABgAAACEHh69ypT4soxCKI9ZV/6AMT4GJ6w4Jp1cD6aOo8t2nCuo5AeZw+H5Es+SuYIR87KLDUQ+yZmYxRCkAxo+21kx5TslQ1qc/5SwAAIABAACAAAAAgAAAAAAGAAAAIQeKgU9n/h86WEKIpKVPL2rk3fqkX9V1fkvfH342G6S9VTkBTUauK27WNMCDVl9AHX6cMIGgM9KCsjyZnJVlLoAvYYd/0Tc9LAAAgAEAAIAAAACACgAAAAYAAAAhB6NpuHV7Rtb8ZZMCbMyFukqQBHHljYgq2WXTsQnIhYqdDQB8Rh5dAAAAAAYAAAAhB6bOdRxnWx5Btnt4NyQO7VxfDPcI5B8bzhKs1gLAxT8AOQFtF/j4tHjJ/vhNNUsAVdzPegKLil5Fei1ErCopnsJo3A8FaUNWAACAAQAAgAAAAIAGAAAABgAAACEHqYar/nRK7CcGlT4WlJIuxqs/HDxtqHGvIiDBYeXGcek5ASUxf800GBNXqs56KhFDILPg6XZq43fUhHLDMJzOtdlB1qc/5SwAAIABAACAAAAAgAQAAAAGAAAAIQet6y8pVg65kzuVfW6Httuv1DcfvfRSwcQLiYylzkqMHjkBTUauK27WNMCDVl9AHX6cMIGgM9KCsjyZnJVlLoAvYYcPBWlDVgAAgAEAAIAAAACACAAAAAYAAAAhB7KrPx9hejLOXTRbIAUwugKidbCBMa/zOpjWEFG5B3EXOQFNRq4rbtY0wINWX0AdfpwwgaAz0oKyPJmclWUugC9hhwVgN/ksAACAAQAAgAAAAIAKAAAABgAAACEHtjEyfJOa7+u48zFii7APiXGJVOhMjoZ0kMN0HElrzMQ5AaQ6uQsv7dswu8+iOVeYShs3tXxkP3b0nKc4MAXRaNLMf9E3PSwAAIABAACAAAAAgAYAAAAGAAAAIQe7d7EbEgnhlDu0hWecjuYR6qgTpOE66x1WaxFA5/SVKzkB5nD4fkSz5K5ghHzsosNRD7JmZjFEKQDGj7bWTHlOyVAFYDf5LAAAgAEAAIAAAACAAAAAAAYAAAAhB8ejQnD9jMl6WM+m9AFmSX6g9qSnRzQX7uWLvdkJuINCOQGl0T2p3e5SkGq5rVZLhZN32n4KeXFwUHdJE31hMayqCU2IWCssAACAAQAAgAAAAIAIAAAABgAAACEHyuMajTyS1tzdrOFXvuvprwMac6y6HDSflvnPOjc3gsE5AZGXg5QJlj3rb4xYXOkRQZYsZUMGukk9qdbHXZ6syeb/f9E3PSwAAIABAACAAAAAgAIAAAAGAAAAIQff/nH9JLsLhZNayuBjWdYR/Sc4Z26V5siy/t21doKzNTkBpDq5Cy/t2zC7z6I5V5hKGze1fGQ/dvScpzgwBdFo0swFYDf5LAAAgAEAAIAAAACABgAAAAYAAAAhB+PLbmagUCCHP0WmcH3eRnORoheNQJiEsaS07WtA2EjxOQHmcPh+RLPkrmCEfOyiw1EPsmZmMUQpAMaPttZMeU7JUE2IWCssAACAAQAAgAAAAIAAAAAABgAAACEH8OzNXtHOQ7zC/Amf7DvcxHq4K1E+3qvgmyea7kmW3kw5AeZw+H5Es+SuYIR87KLDUQ+yZmYxRCkAxo+21kx5TslQDwVpQ1YAAIABAACAAAAAgAAAAAAGAAAAIQfyBbHseOMRxDgcmVtpA/OLvagm4SUAPVBEIAR1ts/EuTkB5nD4fkSz5K5ghHzsosNRD7JmZjFEKQDGj7bWTHlOyVB/0Tc9LAAAgAEAAIAAAACAAAAAAAYAAAAhB/YU3Y76HDAM1MZPaAsd1T11Cdm5qv7nO4twoMaEhGuJOQElMX/NNBgTV6rOeioRQyCz4Ol2auN31IRywzCczrXZQX/RNz0sAACAAQAAgAAAAIAEAAAABgAAACEH+Ya/M9lXW6AbwhjuwehMxaH5/03HXqIyLlY+djoFzO05AZGXg5QJlj3rb4xYXOkRQZYsZUMGukk9qdbHXZ6syeb/TYhYKywAAIABAACAAAAAgAIAAAAGAAAAIQf96VZf4cW1CHwR0Bmn+WAAru+/TaK6uOqmegs3OhUVqjkBkZeDlAmWPetvjFhc6RFBlixlQwa6ST2p1sddnqzJ5v/mkuUxLAAAgAEAAIAAAACAAgAAAAYAAAAAAQUgAT7PNIbE/7DElPZY3PSAkK+BSiLRRuR47LJxlbHr+7MBBv2aBAHAziBC7IED8ALOLHypomQA5fzsPpVd8/BIIqrB6FrtIGWW7qwg2azLuqa93hAA45YLG1ZrgEskhpCChas7KJnAWQH7D7i6ILu8I891VO8oCG25vovURDebNAz567O2Nj2d67u27diAuiAfUTgjb+jsyzNDUPoB36VkHeCAKuVbitrscAYFegGqDLogFJd3aFEuChPEO6eNjNXipoRHozVHX38AuWk4pSflmim6IBcVBtJwhlIUuu3ssEx4RJRGCFVg5GnIk7EXLZvHRU8UulacBMCOIOBVKM9g5CyV1IgwnPk9BNo5Cl8tOITbfYPwppq0YHnJrCDeq5N1lV+rro7MhN4fufC1rQSc7YvczL+JAZbGOy5tMbogclxwRSZJO5mL5ljGluaRzz6o7ldvKUUntj2Rvn/ty2K6IISYzgwGtgHlrBbjgR858UAtsHc1uh3DfCT58fNPhxg1ulOdAugDsgTAayC8oVQztIoXVfbzBreDOlE/ikWfUZzCF6dU8fRYInK9P6wg3uf1Ljadbba939IwYDYpdFDZNgWRPDjsFCS40fHDT4u6IEiKNCWx8K6uhbf2A0RTXIBPylCA3QisQ9rfzCSOWSaOulKdAXiyBMDRIPW1IfXHF+d8GPQ6+a4Rsn+WkDhNmdgq3U2klbMo3r0lrCAxv80eMiJRwpCkrLE6faInoMV95dBJQ94gCKvmcgoHjbog9qSLcODD28mYssMcZdoRB/8gv2biFmKfU4VQ5dpnoGS6INvSxgdi34Mn+FMfzeud7/SVoLIR8tgizLECxkYzvNyBuiCffm7tlTlKDlBCAoNniIqYGa4wQ/2OVQq9sz0ZMLl327ogbS6WSnTu6pcaAVB8ezAnzBO39MHWETTkTtkCSaXEJxK6VJ0BPLIEwNEgFXGFiMzJ41rTbId5pxd5L87kSetksrJZDfTMzspmTA2sILg31GshJnZ9Pb4XTJrtvjO595B/O3ZvQQDAyZ14p06GuiDYVQzGZnCvHG2lwaxhD3KgvIv83yDosFaz89z1AC/YarogztWoVsOlGMGHvqFtd4owUKJZl9MMinaszTQH655D72G6IBmx4NuYfBkN0sbGURWd/oEzRIGsi0TZd1Uq9aINdyLfuiAQpOr2BS0SMDsImTZEXlUhJ8jMthYQ+QEIB+Ul90js9LpVnQEUsgPAjiCKiYOJz3FMpEbX0TCDi8WsvNkL1AzsCvmGWc8LRdiBt6wg2c5DT4wSLLTOVzbacVcpHgjsgBzqHfFC+dDd23GQXji6IJ46zeDTUxdpvsJR6B1SonooSB3QwWpDEWaTiu1+SV3zuiA3PkaPb6yGQQ+qZQ4OUWGkjjVqYM1PwwMfUTyAj2RoGLpTnQLoA7IDwI4ggtKAXJ5304yFpm0NVqu+36Q8z1ZRfMp3O1cCGO5uvsusINxISQiAe/TBJIMkWMDQ2vqbiXjoBIy4BO53Zr/IbCj9uiAY9GWY6VrWqVxNiJGKj/0i6abLS/jS+Ei8QZiXMed5krogvZVCSBA7JWulJl3kGkOIoI//lyf8YY7L9D1capM2V9u6U50C6AOyIQcBPs80hsT/sMSU9ljc9ICQr4FKItFG5HjssnGVsev7sw0AfEYeXQEAAAAAAAAAIQcQpOr2BS0SMDsImTZEXlUhJ8jMthYQ+QEIB+Ul90js9DkBMbqc+hCYzASzEL3t+HGy0SLoNC9Gs0bzNG342KJDAHIFYDf5LAAAgAEAAIAAAACAAwAAAAAAAAAhBxSXd2hRLgoTxDunjYzV4qaER6M1R19/ALlpOKUn5ZopOQHpFzDud8exzF4BzhFCmLHSRASlYw39tnuK2/TNyRPfGuaS5TEsAACAAQAAgAAAAIABAAAAAAAAACEHFXGFiMzJ41rTbId5pxd5L87kSetksrJZDfTMzspmTA05ATG6nPoQmMwEsxC97fhxstEi6DQvRrNG8zRt+NiiQwBy1qc/5SwAAIABAACAAAAAgAMAAAAAAAAAIQcXFQbScIZSFLrt7LBMeESURghVYORpyJOxFy2bx0VPFDkB6Rcw7nfHscxeAc4RQpix0kQEpWMN/bZ7itv0zckT3xoPBWlDVgAAgAEAAIAAAACAAQAAAAAAAAAhBxj0ZZjpWtapXE2IkYqP/SLppstL+NL4SLxBmJcx53mSOQFQZXkwmevHd+YewqSxZYRKDZyf13D7SpPPlQAAeiaCO3/RNz0sAACAAQAAgAAAAIAJAAAAAAAAACEHGbHg25h8GQ3SxsZRFZ3+gTNEgayLRNl3VSr1og13It85ATG6nPoQmMwEsxC97fhxstEi6DQvRrNG8zRt+NiiQwByf9E3PSwAAIABAACAAAAAgAMAAAAAAAAAIQcfUTgjb+jsyzNDUPoB36VkHeCAKuVbitrscAYFegGqDDkB6Rcw7nfHscxeAc4RQpix0kQEpWMN/bZ7itv0zckT3xrWpz/lLAAAgAEAAIAAAACAAQAAAAAAAAAhBzG/zR4yIlHCkKSssTp9oiegxX3l0ElD3iAIq+ZyCgeNOQGxZE8T5qFYGhaMRL054fRWjUEoEzTZlYolNBYosQXb4eaS5TEsAACAAQAAgAAAAIAFAAAAAAAAACEHNz5Gj2+shkEPqmUODlFhpI41amDNT8MDH1E8gI9kaBg5ARaIzqpQY2fBmDkYvmcN6ob6Tgiq8lHZNLt9e5yH2mgMBWA3+SwAAIABAACAAAAAgAsAAAAAAAAAIQdC7IED8ALOLHypomQA5fzsPpVd8/BIIqrB6FrtIGWW7jkB6Rcw7nfHscxeAc4RQpix0kQEpWMN/bZ7itv0zckT3xpNiFgrLAAAgAEAAIAAAACAAQAAAAAAAAAhB0iKNCWx8K6uhbf2A0RTXIBPylCA3QisQ9rfzCSOWSaOOQGwCAK60Lrlh4gWHawyXZDMJPMYsQaotxlf13xOIjZSww8FaUNWAACAAQAAgAAAAIAHAAAAAAAAACEHbS6WSnTu6pcaAVB8ezAnzBO39MHWETTkTtkCSaXEJxI5AbFkTxPmoVgaFoxEvTnh9FaNQSgTNNmViiU0FiixBdvhBWA3+SwAAIABAACAAAAAgAUAAAAAAAAAIQdyXHBFJkk7mYvmWMaW5pHPPqjuV28pRSe2PZG+f+3LYjkB0E9bIDF1fyf8ApzqSwaKCHFmyRDkJdqGIylz2y1LNIR/0Tc9LAAAgAEAAIAAAACABwAAAAAAAAAhB4LSgFyed9OMhaZtDVarvt+kPM9WUXzKdztXAhjubr7LOQFQZXkwmevHd+YewqSxZYRKDZyf13D7SpPPlQAAeiaCO+aS5TEsAACAAQAAgAAAAIAJAAAAAAAAACEHhJjODAa2AeWsFuOBHznxQC2wdzW6HcN8JPnx80+HGDU5AdBPWyAxdX8n/AKc6ksGighxZskQ5CXahiMpc9stSzSEBWA3+SwAAIABAACAAAAAgAcAAAAAAAAAIQeKiYOJz3FMpEbX0TCDi8WsvNkL1AzsCvmGWc8LRdiBtzkBFojOqlBjZ8GYORi+Zw3qhvpOCKryUdk0u317nIfaaAwPBWlDVgAAgAEAAIAAAACACQAAAAAAAAAhB546zeDTUxdpvsJR6B1SonooSB3QwWpDEWaTiu1+SV3zOQEWiM6qUGNnwZg5GL5nDeqG+k4IqvJR2TS7fXuch9poDH/RNz0sAACAAQAAgAAAAIALAAAAAAAAACEHn35u7ZU5Sg5QQgKDZ4iKmBmuMEP9jlUKvbM9GTC5d9s5AbFkTxPmoVgaFoxEvTnh9FaNQSgTNNmViiU0FiixBdvhf9E3PSwAAIABAACAAAAAgAUAAAAAAAAAIQe4N9RrISZ2fT2+F0ya7b4zufeQfzt2b0EAwMmdeKdOhjkBMbqc+hCYzASzEL3t+HGy0SLoNC9Gs0bzNG342KJDAHLmkuUxLAAAgAEAAIAAAACAAwAAAAAAAAAhB7u8I891VO8oCG25vovURDebNAz567O2Nj2d67u27diAOQHpFzDud8exzF4BzhFCmLHSRASlYw39tnuK2/TNyRPfGgVgN/ksAACAAQAAgAAAAIABAAAAAAAAACEHvKFUM7SKF1X28wa3gzpRP4pFn1GcwhenVPH0WCJyvT85AbAIArrQuuWHiBYdrDJdkMwk8xixBqi3GV/XfE4iNlLD1qc/5SwAAIABAACAAAAAgAcAAAAAAAAAIQe9lUJIEDsla6UmXeQaQ4igj/+XJ/xhjsv0PVxqkzZX2zkBUGV5MJnrx3fmHsKksWWESg2cn9dw+0qTz5UAAHomgjsFYDf5LAAAgAEAAIAAAACACQAAAAAAAAAhB87VqFbDpRjBh76hbXeKMFCiWZfTDIp2rM00B+ueQ+9hOQExupz6EJjMBLMQve34cbLRIug0L0azRvM0bfjYokMAck2IWCssAACAAQAAgAAAAIADAAAAAAAAACEH2FUMxmZwrxxtpcGsYQ9yoLyL/N8g6LBWs/Pc9QAv2Go5ATG6nPoQmMwEsxC97fhxstEi6DQvRrNG8zRt+NiiQwByDwVpQ1YAAIABAACAAAAAgAMAAAAAAAAAIQfZrMu6pr3eEADjlgsbVmuASySGkIKFqzsomcBZAfsPuDkB6Rcw7nfHscxeAc4RQpix0kQEpWMN/bZ7itv0zckT3xp/0Tc9LAAAgAEAAIAAAACAAQAAAAAAAAAhB9nOQ0+MEiy0zlc22nFXKR4I7IAc6h3xQvnQ3dtxkF44OQEWiM6qUGNnwZg5GL5nDeqG+k4IqvJR2TS7fXuch9poDE2IWCssAACAAQAAgAAAAIALAAAAAAAAACEH29LGB2Lfgyf4Ux/N653v9JWgshHy2CLMsQLGRjO83IE5AbFkTxPmoVgaFoxEvTnh9FaNQSgTNNmViiU0FiixBdvhTYhYKywAAIABAACAAAAAgAUAAAAAAAAAIQfcSEkIgHv0wSSDJFjA0Nr6m4l46ASMuATud2a/yGwo/TkBUGV5MJnrx3fmHsKksWWESg2cn9dw+0qTz5UAAHomgjtNiFgrLAAAgAEAAIAAAACACQAAAAAAAAAhB96rk3WVX6uujsyE3h+58LWtBJzti9zMv4kBlsY7Lm0xOQHQT1sgMXV/J/wCnOpLBooIcWbJEOQl2oYjKXPbLUs0hE2IWCssAACAAQAAgAAAAIAHAAAAAAAAACEH3uf1Ljadbba939IwYDYpdFDZNgWRPDjsFCS40fHDT4s5AbAIArrQuuWHiBYdrDJdkMwk8xixBqi3GV/XfE4iNlLD5pLlMSwAAIABAACAAAAAgAcAAAAAAAAAIQfgVSjPYOQsldSIMJz5PQTaOQpfLTiE232D8KaatGB5yTkB0E9bIDF1fyf8ApzqSwaKCHFmyRDkJdqGIylz2y1LNITWpz/lLAAAgAEAAIAAAACACQAAAAAAAAAhB/W1IfXHF+d8GPQ6+a4Rsn+WkDhNmdgq3U2klbMo3r0lOQGxZE8T5qFYGhaMRL054fRWjUEoEzTZlYolNBYosQXb4danP+UsAACAAQAAgAAAAIAFAAAAAAAAACEH9qSLcODD28mYssMcZdoRB/8gv2biFmKfU4VQ5dpnoGQ5AbFkTxPmoVgaFoxEvTnh9FaNQSgTNNmViiU0FiixBdvhDwVpQ1YAAIABAACAAAAAgAUAAAAAAAAAAAEFIGXA/nYQ/+uu9xLUGxst/kiKL2SANplmnJS0Z7NXp4OqAQb9mgQBwM4gQVhnpWyXUSyaZXLzL/HiGUJ2wbRmZ0XsqkFRwDLp7KmsIE5LokAOGwXpRu/SAXnI7LjbJR5QGFOOpDsiJpQulc12uiDzaAr9RLRQ3bHoDrbNmrHCq0TW6iD6BZ3cRINj/+9O/bogO62JA5gMzgMBFChy5gHWbZl6chRmuXER5kXFbCcPi3S6IHcL93Nhc9v4A0WnqK+XCcugcVJIsBrnde44SSoGLF5puiDI5N8htxTmJN6KVZ2ADfmK6lP7o2ZeGSE0Yj9GcPau9LpWnATAjiCSFe0rXTdQ+rQgLqswtLoh+SdJVRrN3dQ1UMjOVkVHtqwg4iwyc5Tvn0QEeBCEy1WgiwvTo1lsu5MTXX9NFEzPMUC6IEe+ZN9tDCMeAMaLNqX/3N/0frcaYjnnhhVjk0UEED5tuiAb7nEQ0mRNW9MwylgZC7MPYZmN5fs/ZNakZNTEse73XrpTnQLoA7IEwGsglbKphY/kU70IS19seep5fSpEex+fAjSw7DX+vwEmFI2sIP+7ONtqIWdOJMdLFMuFiZvWEOuyCVOgnYQ2r34D7JQruiClmaQNFt0fY38ZsupeijFcLlrEMldmFQKgaAwJMoKWELpSnQF4sgTA0SDTnBPiHqq5T4ZQkDNuaJ3EJZoKTjYG+VEakDGnFS3WtKwgl2GcDUn6Od65Z4lqwUIWeJ7cgZ2DC1nCl0SQMkC+h6e6IJyqv3e2QZeH60fcZfJe6niqR7pdhfJ043cA0W+kuKBsuiCGnczCQazxCxrc08HA/WxEY+HvPZUn3LKSVF9fGrV08LogFkcV7Rj2m+IqGyRsl2HIH7DivsiO90fqQjb4xOWkZpu6ICb9P0jbXjXytcheCcKZsRC67jkLm3Q8BoOYR13QRVlGulSdATyyBMDRIB4ZtHbw8LBUzdrjYqwCTYVPHFqvgfZRalJOLZsKyNMHrCD/P99i3rjjRA60JsnCWVQjdC7Ji96gwVhQ7RrvtxNbELogPSElbzhyRSjS2wdbh+NI6/Aa409RHSaW6LZnHKZ+ESG6IIogyug/PNl5MoqKKKEuQUEFVxiDXc1dIeQpKbIB2hq/uiDBn4YDU8zpKWbzV/vGMhucGCSZTAmyxw8zMCq3oyRNxLog/oJ03PhzXUIgYzzXjrJIpBuD6UqjaiVonNRFqQYOCD26VZ0BFLIDwI4gkq41QYEhh1w4XhXItEEuvgeSZTDGPIAoKVTBID43+qisIE3kGijzx4ijuVMLWfol4QOamXu3dKELGszP6COhbom4uiDjFxPMPKEykNlybLbBNw/jCblY24xF87WFrJ2CQO5C2rogWAoqUfs2gK469U2FK/IIbWAaN0wTI8yyvkSqWB78BRi6U50C6AOyA8COIKMCCTewtDaQ8UWuiInyuj5TEaepL7q54ceIWtHMCh0trCAf38skWqxHMPNHtTR8vLUrPQnSLLerGubB0OtdS5Pei7ogyV9ntszVRYq9nZ3Z1ofGydXGY/fqUnBW68U7DUP+q6y6IHJMxdwv1i2rTsOGcpiwmjOoUGozuBPSHzmZgSiya1M2ulOdAugDsiEHFkcV7Rj2m+IqGyRsl2HIH7DivsiO90fqQjb4xOWkZps5AeYHguDlGotygVSjfxANcUfg7+n07ZAuVov5dUasJSRCf9E3PSwAAIABAACAAAAAgAQAAAAHAAAAIQcb7nEQ0mRNW9MwylgZC7MPYZmN5fs/ZNakZNTEse73XjkBgUWDRbkF059yZTBmfpZ69bwwQJFCdur3oqyJrH0mCFMFYDf5LAAAgAEAAIAAAACABgAAAAcAAAAhBx4ZtHbw8LBUzdrjYqwCTYVPHFqvgfZRalJOLZsKyNMHOQGtXxcLzpV9EfJU4WCuKJlyUK9PGv4XzVbxpdKp2Ge0kNanP+UsAACAAQAAgAAAAIACAAAABwAAACEHH9/LJFqsRzDzR7U0fLy1Kz0J0iy3qxrmwdDrXUuT3os5AXbYi/NZ5/8v7Zsr/Mvw4PD7ytRZ6VfR6MBnbSep3ochTYhYKywAAIABAACAAAAAgAgAAAAHAAAAIQcm/T9I21418rXIXgnCmbEQuu45C5t0PAaDmEdd0EVZRjkB5geC4OUai3KBVKN/EA1xR+Dv6fTtkC5Wi/l1RqwlJEIFYDf5LAAAgAEAAIAAAACABAAAAAcAAAAhBzutiQOYDM4DARQocuYB1m2ZenIUZrlxEeZFxWwnD4t0OQEUkslTixOKG8z2Xgzidi2nBlqz5vfffVelZ1dMfXENKdanP+UsAACAAQAAgAAAAIAAAAAABwAAACEHPSElbzhyRSjS2wdbh+NI6/Aa409RHSaW6LZnHKZ+ESE5Aa1fFwvOlX0R8lThYK4omXJQr08a/hfNVvGl0qnYZ7SQDwVpQ1YAAIABAACAAAAAgAIAAAAHAAAAIQdBWGelbJdRLJplcvMv8eIZQnbBtGZnReyqQVHAMunsqTkBFJLJU4sTihvM9l4M4nYtpwZas+b3331XpWdXTH1xDSlNiFgrLAAAgAEAAIAAAACAAAAAAAcAAAAhB0e+ZN9tDCMeAMaLNqX/3N/0frcaYjnnhhVjk0UEED5tOQGBRYNFuQXTn3JlMGZ+lnr1vDBAkUJ26veirImsfSYIU3/RNz0sAACAAQAAgAAAAIAGAAAABwAAACEHTeQaKPPHiKO5UwtZ+iXhA5qZe7d0oQsazM/oI6Fuibg5AQyFxEEYb/hoBtcSEH4nD4zj6ezGomMOIb+9gtKz8uwhTYhYKywAAIABAACAAAAAgAoAAAAHAAAAIQdOS6JADhsF6Ubv0gF5yOy42yUeUBhTjqQ7IiaULpXNdjkBFJLJU4sTihvM9l4M4nYtpwZas+b3331XpWdXTH1xDSl/0Tc9LAAAgAEAAIAAAACAAAAAAAcAAAAhB1gKKlH7NoCuOvVNhSvyCG1gGjdMEyPMsr5Eqlge/AUYOQEMhcRBGG/4aAbXEhB+Jw+M4+nsxqJjDiG/vYLSs/LsIQVgN/ksAACAAQAAgAAAAIAKAAAABwAAACEHZcD+dhD/6673EtQbGy3+SIovZIA2mWaclLRns1eng6oNAHxGHl0AAAAABwAAACEHckzF3C/WLatOw4ZymLCaM6hQajO4E9IfOZmBKLJrUzY5AXbYi/NZ5/8v7Zsr/Mvw4PD7ytRZ6VfR6MBnbSep3ochBWA3+SwAAIABAACAAAAAgAgAAAAHAAAAIQd3C/dzYXPb+ANFp6ivlwnLoHFSSLAa53XuOEkqBixeaTkBFJLJU4sTihvM9l4M4nYtpwZas+b3331XpWdXTH1xDSnmkuUxLAAAgAEAAIAAAACAAAAAAAcAAAAhB4adzMJBrPELGtzTwcD9bERj4e89lSfcspJUX18atXTwOQHmB4Lg5RqLcoFUo38QDXFH4O/p9O2QLlaL+XVGrCUkQk2IWCssAACAAQAAgAAAAIAEAAAABwAAACEHiiDK6D882XkyiooooS5BQQVXGINdzV0h5CkpsgHaGr85Aa1fFwvOlX0R8lThYK4omXJQr08a/hfNVvGl0qnYZ7SQTYhYKywAAIABAACAAAAAgAIAAAAHAAAAIQeSFe0rXTdQ+rQgLqswtLoh+SdJVRrN3dQ1UMjOVkVHtjkBgUWDRbkF059yZTBmfpZ69bwwQJFCdur3oqyJrH0mCFPWpz/lLAAAgAEAAIAAAACACAAAAAcAAAAhB5KuNUGBIYdcOF4VyLRBLr4HkmUwxjyAKClUwSA+N/qoOQEMhcRBGG/4aAbXEhB+Jw+M4+nsxqJjDiG/vYLSs/LsIQ8FaUNWAACAAQAAgAAAAIAIAAAABwAAACEHlbKphY/kU70IS19seep5fSpEex+fAjSw7DX+vwEmFI05AeQmPgf0lGFxuOLA0S7dlhpzQyfivlVsHZL5GF9Rnhpd1qc/5SwAAIABAACAAAAAgAYAAAAHAAAAIQeXYZwNSfo53rlniWrBQhZ4ntyBnYMLWcKXRJAyQL6HpzkB5geC4OUai3KBVKN/EA1xR+Dv6fTtkC5Wi/l1RqwlJELmkuUxLAAAgAEAAIAAAACABAAAAAcAAAAhB5yqv3e2QZeH60fcZfJe6niqR7pdhfJ043cA0W+kuKBsOQHmB4Lg5RqLcoFUo38QDXFH4O/p9O2QLlaL+XVGrCUkQg8FaUNWAACAAQAAgAAAAIAEAAAABwAAACEHowIJN7C0NpDxRa6IifK6PlMRp6kvurnhx4ha0cwKHS05AXbYi/NZ5/8v7Zsr/Mvw4PD7ytRZ6VfR6MBnbSep3och5pLlMSwAAIABAACAAAAAgAgAAAAHAAAAIQelmaQNFt0fY38ZsupeijFcLlrEMldmFQKgaAwJMoKWEDkB5CY+B/SUYXG44sDRLt2WGnNDJ+K+VWwdkvkYX1GeGl0PBWlDVgAAgAEAAIAAAACABgAAAAcAAAAhB8GfhgNTzOkpZvNX+8YyG5wYJJlMCbLHDzMwKrejJE3EOQGtXxcLzpV9EfJU4WCuKJlyUK9PGv4XzVbxpdKp2Ge0kH/RNz0sAACAAQAAgAAAAIACAAAABwAAACEHyOTfIbcU5iTeilWdgA35iupT+6NmXhkhNGI/RnD2rvQ5ARSSyVOLE4obzPZeDOJ2LacGWrPm9999V6VnV0x9cQ0pDwVpQ1YAAIABAACAAAAAgAAAAAAHAAAAIQfJX2e2zNVFir2dndnWh8bJ1cZj9+pScFbrxTsNQ/6rrDkBdtiL81nn/y/tmyv8y/Dg8PvK1FnpV9HowGdtJ6nehyF/0Tc9LAAAgAEAAIAAAACACAAAAAcAAAAhB9OcE+IeqrlPhlCQM25oncQlmgpONgb5URqQMacVLda0OQHmB4Lg5RqLcoFUo38QDXFH4O/p9O2QLlaL+XVGrCUkQtanP+UsAACAAQAAgAAAAIAEAAAABwAAACEH4iwyc5Tvn0QEeBCEy1WgiwvTo1lsu5MTXX9NFEzPMUA5AYFFg0W5BdOfcmUwZn6WevW8MECRQnbq96Ksiax9JghTTYhYKywAAIABAACAAAAAgAYAAAAHAAAAIQfjFxPMPKEykNlybLbBNw/jCblY24xF87WFrJ2CQO5C2jkBDIXEQRhv+GgG1xIQficPjOPp7MaiYw4hv72C0rPy7CF/0Tc9LAAAgAEAAIAAAACACgAAAAcAAAAhB/NoCv1EtFDdsegOts2ascKrRNbqIPoFndxEg2P/7079OQEUkslTixOKG8z2Xgzidi2nBlqz5vfffVelZ1dMfXENKQVgN/ksAACAAQAAgAAAAIAAAAAABwAAACEH/oJ03PhzXUIgYzzXjrJIpBuD6UqjaiVonNRFqQYOCD05Aa1fFwvOlX0R8lThYK4omXJQr08a/hfNVvGl0qnYZ7SQBWA3+SwAAIABAACAAAAAgAIAAAAHAAAAIQf/P99i3rjjRA60JsnCWVQjdC7Ji96gwVhQ7RrvtxNbEDkBrV8XC86VfRHyVOFgriiZclCvTxr+F81W8aXSqdhntJDmkuUxLAAAgAEAAIAAAACAAgAAAAcAAAAhB/+7ONtqIWdOJMdLFMuFiZvWEOuyCVOgnYQ2r34D7JQrOQHkJj4H9JRhcbjiwNEu3ZYac0Mn4r5VbB2S+RhfUZ4aXeaS5TEsAACAAQAAgAAAAIAGAAAABwAAAAABBSBXmrWtnUJjtJZnWti2tK79XJTOuWmqH74tYlKOO32vAAEG/ZoEAcDOINtcLKj4rFF2arbEIyzHBPZxJLBl2UckhHTXlD9BXjImrCDEAoNtgim+PK6s6ZeRCWeSc75erW4QwKutRW+txS4LUrogVlSlrR66r1LfBvwRDO+7lSx3CXrWdtXXVrexvABEUU26IAA6FataEltV7vyiRG8Rfd/hw+3CJDQs3rUbcirDN4LBuiBO/ZJmPt45H+2dYvRBd76xIVa/WfX8emh14CzXNPxqw7ogj/kA4KEODb0p1ff2a30zkAsGw4cgeGC9nEmb+Nxh3FS6VpwEwI4gI/gxBB2/2R3SRIGhLX+X5HlZZ96+pxDMjTUQFN04NImsIEyxTfzKxrhqJenyMAzuF2y1gPQ6LGPNfjw7nzOk+IpJuiCBWCUv4OtlDgQA++A7VUcvs6/fP8vLPKuiizfmbhzsvLoggx+1GesQyGjHSw9rJxu4mLUFybXTg9Blc5gEEYndnhy6U50C6AOyBMBrIAItnlsrm2EHFep2ELjscGkSVqlAI8fcbjUxVGLu0DVPrCDRa5NDpYLgS+DDWFo3T7xYm4elZkvWUPBBguVKwzxliLogtxNpuNJqve7LuMAE5XuufuY60EDB1+TnUy9e0/D5gSq6Up0BeLIEwNEgoSEQPhth8FiobDdQAxw/wRnzNfaj+eh9QVBCkvedfn6sINCnOJRaOSFlj6pJXi7nBU8CM81pyoxGLCDqEE/A7nSYuiCrhnsTuGQ9Gc51pl2JtTvLTd8sHCxVdCL9NnwykIIgpLogeciNVByLnp/wBdDs7u1+NUSW0yVVsHxg545IqHHsOC66IG0l9tYDX1bT6nlJe0Cl24DckWpSbKuTOxjadJ/oHGUnuiCSeGAcT6AheFAaa1e9Go6hAKpGuQfypSh0D9RFecfE6LpUnQE8sgTA0SC8ol8DrShzZCbrK0neGfLLL9yndBoJVoeaqcHCRpLZB6wgomd/37B9YCxkzCOMYsAykwjzYQh4j3ck2IBNxpWlJsG6IPCYeQrRU0sNgk0AuNIL98bfB67w+m3y9eCX+YCzub4juiD6ciwL2iO8YM6kwr/ZlYSi//oLRzhl4+zot56tvzjKcbogK12NTZnvbAUa9MSdLppOQXAxlspXwnJNxTqrghtnK3u6IBaRMg9QBHqobDv6w2dAgCFjLd9kM0CGnZS9Ne7N7MTsulWdARSyA8COIAGCBGrdpn8wp9j4P2v+j9HiYHTb9r4NzaUwB+rW/AWNrCBGAfjel4KOGi6Swm39PD73ChQWcFY8O3NusA7t23o4zLogJdBLm2QOw1/SB2VrdwQbic1AJaF4PrusXZ/5aYLIz7e6IC15u5Kz9L7swt+5quhrJfKVmyxojK/mCpYWQhyBqYbqulOdAugDsgPAjiAPYajkaQESysjvuAKpYxlVECMn7wEFNrwEfJRVu0vgsKwgY4Su9x3fqzy0NGunZmw0VftYHYqCSMicXly6M7Pqmn66IPfjPyJz9k1Yf3PdKslwqnERG+HSUeMpBOsrsiiu7bMhuiDxD2sccFkbwlSfq+E7+hsjaSlDlgZSYL5JxWG4fD1rOrpTnQLoA7IhBwA6FataEltV7vyiRG8Rfd/hw+3CJDQs3rUbcirDN4LBOQGuweRlXLlEmJAt7iD1zTFheSBDjJvtvezeRn+lafQuMtanP+UsAACAAQAAgAAAAIAAAAAACAAAACEHAYIEat2mfzCn2Pg/a/6P0eJgdNv2vg3NpTAH6tb8BY05AVYkfli4LA4dZdxsy/x7XbtwJwX5m1LKvRkqupWBJpKIDwVpQ1YAAIABAACAAAAAgAgAAAAIAAAAIQcCLZ5bK5thBxXqdhC47HBpElapQCPH3G41MVRi7tA1TzkBlRXvM/VV7c5Hure0uLfAD/RRzQcOaMFzI5IaqNUPV1DWpz/lLAAAgAEAAIAAAACABgAAAAgAAAAhBw9hqORpARLKyO+4AqljGVUQIyfvAQU2vAR8lFW7S+CwOQH1yxH/dlaEfu5jjtAZ5NL+qGEZyA3GbyMz5v5lCNHUOOaS5TEsAACAAQAAgAAAAIAIAAAACAAAACEHFpEyD1AEeqhsO/rDZ0CAIWMt32QzQIadlL017s3sxOw5Aariiw27G7ycCobSBTKi6SSRPTvf3sKjq9mZ3xJH0whRBWA3+SwAAIABAACAAAAAgAIAAAAIAAAAIQcj+DEEHb/ZHdJEgaEtf5fkeVln3r6nEMyNNRAU3Tg0iTkBL59FCvb0pu1Fsb7T9e8ybUCA/L5YzEpQT/fx7S6GjX7Wpz/lLAAAgAEAAIAAAACACAAAAAgAAAAhByXQS5tkDsNf0gdla3cEG4nNQCWheD67rF2f+WmCyM+3OQFWJH5YuCwOHWXcbMv8e127cCcF+ZtSyr0ZKrqVgSaSiH/RNz0sAACAAQAAgAAAAIAKAAAACAAAACEHK12NTZnvbAUa9MSdLppOQXAxlspXwnJNxTqrghtnK3s5Aariiw27G7ycCobSBTKi6SSRPTvf3sKjq9mZ3xJH0whRf9E3PSwAAIABAACAAAAAgAIAAAAIAAAAIQctebuSs/S+7MLfuaroayXylZssaIyv5gqWFkIcgamG6jkBViR+WLgsDh1l3GzL/Htdu3AnBfmbUsq9GSq6lYEmkogFYDf5LAAAgAEAAIAAAACACgAAAAgAAAAhB0YB+N6Xgo4aLpLCbf08PvcKFBZwVjw7c26wDu3bejjMOQFWJH5YuCwOHWXcbMv8e127cCcF+ZtSyr0ZKrqVgSaSiE2IWCssAACAAQAAgAAAAIAKAAAACAAAACEHTLFN/MrGuGol6fIwDO4XbLWA9DosY81+PDufM6T4ikk5AS+fRQr29KbtRbG+0/XvMm1AgPy+WMxKUE/38e0uho1+TYhYKywAAIABAACAAAAAgAYAAAAIAAAAIQdO/ZJmPt45H+2dYvRBd76xIVa/WfX8emh14CzXNPxqwzkBrsHkZVy5RJiQLe4g9c0xYXkgQ4yb7b3s3kZ/pWn0LjLmkuUxLAAAgAEAAIAAAACAAAAAAAgAAAAhB1ZUpa0euq9S3wb8EQzvu5Usdwl61nbV11a3sbwARFFNOQGuweRlXLlEmJAt7iD1zTFheSBDjJvtvezeRn+lafQuMgVgN/ksAACAAQAAgAAAAIAAAAAACAAAACEHV5q1rZ1CY7SWZ1rYtrSu/VyUzrlpqh++LWJSjjt9rwANAHxGHl0AAAAACAAAACEHY4Su9x3fqzy0NGunZmw0VftYHYqCSMicXly6M7Pqmn45AfXLEf92VoR+7mOO0Bnk0v6oYRnIDcZvIzPm/mUI0dQ4TYhYKywAAIABAACAAAAAgAgAAAAIAAAAIQdtJfbWA19W0+p5SXtApduA3JFqUmyrkzsY2nSf6BxlJzkBhbh2ug7MKs/Vu7ebh735GL4nZFyQ402yQHL07CkD68N/0Tc9LAAAgAEAAIAAAACABAAAAAgAAAAhB3nIjVQci56f8AXQ7O7tfjVEltMlVbB8YOeOSKhx7DguOQGFuHa6Dswqz9W7t5uHvfkYvidkXJDjTbJAcvTsKQPrw02IWCssAACAAQAAgAAAAIAEAAAACAAAACEHgVglL+DrZQ4EAPvgO1VHL7Ov3z/Lyzyroos35m4c7Lw5AS+fRQr29KbtRbG+0/XvMm1AgPy+WMxKUE/38e0uho1+f9E3PSwAAIABAACAAAAAgAYAAAAIAAAAIQeDH7UZ6xDIaMdLD2snG7iYtQXJtdOD0GVzmAQRid2eHDkBL59FCvb0pu1Fsb7T9e8ybUCA/L5YzEpQT/fx7S6GjX4FYDf5LAAAgAEAAIAAAACABgAAAAgAAAAhB4/5AOChDg29KdX39mt9M5ALBsOHIHhgvZxJm/jcYdxUOQGuweRlXLlEmJAt7iD1zTFheSBDjJvtvezeRn+lafQuMg8FaUNWAACAAQAAgAAAAIAAAAAACAAAACEHknhgHE+gIXhQGmtXvRqOoQCqRrkH8qUodA/URXnHxOg5AYW4droOzCrP1bu3m4e9+Ri+J2RckONNskBy9OwpA+vDBWA3+SwAAIABAACAAAAAgAQAAAAIAAAAIQehIRA+G2HwWKhsN1ADHD/BGfM19qP56H1BUEKS951+fjkBhbh2ug7MKs/Vu7ebh735GL4nZFyQ402yQHL07CkD68PWpz/lLAAAgAEAAIAAAACABAAAAAgAAAAhB6Jnf9+wfWAsZMwjjGLAMpMI82EIeI93JNiATcaVpSbBOQGq4osNuxu8nAqG0gUyoukkkT07397Co6vZmd8SR9MIUeaS5TEsAACAAQAAgAAAAIACAAAACAAAACEHq4Z7E7hkPRnOdaZdibU7y03fLBwsVXQi/TZ8MpCCIKQ5AYW4droOzCrP1bu3m4e9+Ri+J2RckONNskBy9OwpA+vDDwVpQ1YAAIABAACAAAAAgAQAAAAIAAAAIQe3E2m40mq97su4wATle65+5jrQQMHX5OdTL17T8PmBKjkBlRXvM/VV7c5Hure0uLfAD/RRzQcOaMFzI5IaqNUPV1APBWlDVgAAgAEAAIAAAACABgAAAAgAAAAhB7yiXwOtKHNkJusrSd4Z8ssv3Kd0GglWh5qpwcJGktkHOQGq4osNuxu8nAqG0gUyoukkkT07397Co6vZmd8SR9MIUdanP+UsAACAAQAAgAAAAIACAAAACAAAACEHxAKDbYIpvjyurOmXkQlnknO+Xq1uEMCrrUVvrcUuC1I5Aa7B5GVcuUSYkC3uIPXNMWF5IEOMm+297N5Gf6Vp9C4yf9E3PSwAAIABAACAAAAAgAAAAAAIAAAAIQfQpziUWjkhZY+qSV4u5wVPAjPNacqMRiwg6hBPwO50mDkBhbh2ug7MKs/Vu7ebh735GL4nZFyQ402yQHL07CkD68PmkuUxLAAAgAEAAIAAAACABAAAAAgAAAAhB9Frk0OlguBL4MNYWjdPvFibh6VmS9ZQ8EGC5UrDPGWIOQGVFe8z9VXtzke6t7S4t8AP9FHNBw5owXMjkhqo1Q9XUOaS5TEsAACAAQAAgAAAAIAGAAAACAAAACEH21wsqPisUXZqtsQjLMcE9nEksGXZRySEdNeUP0FeMiY5Aa7B5GVcuUSYkC3uIPXNMWF5IEOMm+297N5Gf6Vp9C4yTYhYKywAAIABAACAAAAAgAAAAAAIAAAAIQfwmHkK0VNLDYJNALjSC/fG3weu8Ppt8vXgl/mAs7m+IzkBquKLDbsbvJwKhtIFMqLpJJE9O9/ewqOr2ZnfEkfTCFEPBWlDVgAAgAEAAIAAAACAAgAAAAgAAAAhB/EPaxxwWRvCVJ+r4Tv6GyNpKUOWBlJgvknFYbh8PWs6OQH1yxH/dlaEfu5jjtAZ5NL+qGEZyA3GbyMz5v5lCNHUOAVgN/ksAACAAQAAgAAAAIAIAAAACAAAACEH9+M/InP2TVh/c90qyXCqcREb4dJR4ykE6yuyKK7tsyE5AfXLEf92VoR+7mOO0Bnk0v6oYRnIDcZvIzPm/mUI0dQ4f9E3PSwAAIABAACAAAAAgAgAAAAIAAAAIQf6ciwL2iO8YM6kwr/ZlYSi//oLRzhl4+zot56tvzjKcTkBquKLDbsbvJwKhtIFMqLpJJE9O9/ewqOr2ZnfEkfTCFFNiFgrLAAAgAEAAIAAAACAAgAAAAgAAAAAAQUgBDZZM+y3+WmWv0I9ylQoNQAlldL4+EWWJ6941Pc37LUBBv2aBAHAziCj4fuw5tKIyWvyRRMPq2xA5Uswto/e/w/YftiYFIHP4qwgKgC5nUi0nwCsMobgrPWVLFN89G4UkjFkvQoxzpFtFfi6IGPvduXIexYzC0zR7cWfn2dBrmRPKBJOh+W4gMo5hVZLuiBoX27ctYXgMqhqSTZytqGNjkyVlyj9wOBLQaz8gBqjaLognuQbm+9QQ/djSDBPz5ubmVYcV9gbWI52zOFmYIekwkG6IN4ilb9zN16LLe/yrSeTSbXT6PToqeemKytggEj4jSbmulacBMCOIOReFs3k4WXCElioJNIoPgDdoeyRl7vmJVbnpkZ0tMq/rCCLtDOqIGPRyH8R/wV+ID8PRTzZVxKUsRqxnXCBQ5qPqbogqC5s1sVfaMPPEWixd56osXJY4ULjIgQpMOpuiIS9pYK6ID2lZF8kE+YqJi7RJ0RHwPnBTIU8m6IjQ9kMaPjjSGilulOdAugDsgTAayDw5WBeBRSvKdNi6c7nPz87wI+jMIoWLUF6VSIDTV5B3qwgXXixY/ZzsD6WLd2/8I/jIzMDRng+JeAoDoswhOJdU6W6IEGg3UAIR0OwuoCmEaXnWAKHbMdO/BDw6enj7+W4ve5lulKdAXiyBMDRIG+oGhtylRMI6oH/ixU93tHiC7+mSGSazMVG6qWhgGBNrCDV+ujS0y1tUoMqu3Con6un8ohhCqOLT+hW3AlIinFpcLogT+O3WgX4zszXRq98gBM0ekmEZEecyt39V7WJWUVMmDK6IIeStPBuwtXANm7tyAj6yjfHsoSIVj86g5IeyI1YYL9YuiCj/BqAuXPrNZuLJqpVEIkvZ0ActV+ehpvYr6xO88cLfrogIDbOeI9ytH+IPfG8v2RhU7tsznDPur1WMpJB0tkHndy6VJ0BPLIEwNEgfMUcZXdkhkljHKPARL+5Qc7Smysixbmyqtp5vSDMw++sIFBMqHUYF3v+jwq+uevMYanuvPgGTbT5vtsTeSrpCnxSuiCKkK1FjcxZkflnHoV5LIqO+cmrR7SywelJHJbIk15VIrogJ46splOAhrHfEmxHHY//PT1uVOfBQ5oySJJyBbiSEC66IPgqRCW8uGAdn23v01toKQwD4TvgUfulkJLGSvVk9bWJuiDP6wJPqYOO0kRJboXpu/CuQsLM0GfgeKtpHyP7K4jVELpVnQEUsgPAjiD6WUyaEnYk+x3BLH5pOQA2as9MPAlNkKhtipC8R7A8lqwgnt1vXUZ5r4Koqzbwh5AqQgyl5Gd9uGC/LTkwHllr/cO6IF2dwh7cR6skPJnMwcpVCffn/PosKZHRdDcVaZc9XvgAuiDD6IDTSvGOq5TG1LHttsGpYDjK/avToA+9AbRB2bgpTrpTnQLoA7IDwI4gZoRNDZeyYNW127MIkg3sG4H1Cs7SzFysMEp+vP0nxuCsIJZSWLkj2e5YCmDg+TtP/n+GdXltMK/d2Zmwoh/R5xMSuiAuwm1pCHz74OjtdKi7YQStWCfxNqZfeJ/2SvbfQKSl9bogDpZiL3pHu8HstIkZF5k6usnI2gZvTOtmFTlwu1kbjNG6U50C6AOyIQcENlkz7Lf5aZa/Qj3KVCg1ACWV0vj4RZYnr3jU9zfstQ0AfEYeXQAAAAAJAAAAIQcOlmIveke7wey0iRkXmTq6ycjaBm9M62YVOXC7WRuM0TkBDLpTZ/nMVWR5QeAg/ieNgiWd2hti+680gRSuvQ/lGFcFYDf5LAAAgAEAAIAAAACACAAAAAkAAAAhByA2zniPcrR/iD3xvL9kYVO7bM5wz7q9VjKSQdLZB53cOQEa56g9WUtTvyiUV8IHhmlxEpemGTkvSdsdK3eL3zKR2gVgN/ksAACAAQAAgAAAAIAEAAAACQAAACEHJ46splOAhrHfEmxHHY//PT1uVOfBQ5oySJJyBbiSEC45ARw857vizb3c1TRkMLRijfzq5ZkIo2omLlP+kpMPknlETYhYKywAAIABAACAAAAAgAIAAAAJAAAAIQcqALmdSLSfAKwyhuCs9ZUsU3z0bhSSMWS9CjHOkW0V+DkByjwMO0+8xRPNiwPD0vKSifeZWv89vAOKGWKYEuONddB/0Tc9LAAAgAEAAIAAAACAAAAAAAkAAAAhBy7CbWkIfPvg6O10qLthBK1YJ/E2pl94n/ZK9t9ApKX1OQEMulNn+cxVZHlB4CD+J42CJZ3aG2L7rzSBFK69D+UYV3/RNz0sAACAAQAAgAAAAIAIAAAACQAAACEHPaVkXyQT5iomLtEnREfA+cFMhTyboiND2Qxo+ONIaKU5Ab6txrRQkboFJ2+cXBGLfiF7/v60MDCHSwU+sN3pPYQHBWA3+SwAAIABAACAAAAAgAYAAAAJAAAAIQdBoN1ACEdDsLqAphGl51gCh2zHTvwQ8Onp4+/luL3uZTkBDdg6oVh4bFtqa3z8W0vy1ZqMFKfwJQB4D3nkQZl9jqUPBWlDVgAAgAEAAIAAAACABgAAAAkAAAAhB0/jt1oF+M7M10avfIATNHpJhGRHnMrd/Ve1iVlFTJgyOQEa56g9WUtTvyiUV8IHhmlxEpemGTkvSdsdK3eL3zKR2g8FaUNWAACAAQAAgAAAAIAEAAAACQAAACEHUEyodRgXe/6PCr6568xhqe68+AZNtPm+2xN5KukKfFI5ARw857vizb3c1TRkMLRijfzq5ZkIo2omLlP+kpMPknlE5pLlMSwAAIABAACAAAAAgAIAAAAJAAAAIQddeLFj9nOwPpYt3b/wj+MjMwNGeD4l4CgOizCE4l1TpTkBDdg6oVh4bFtqa3z8W0vy1ZqMFKfwJQB4D3nkQZl9jqXmkuUxLAAAgAEAAIAAAACABgAAAAkAAAAhB12dwh7cR6skPJnMwcpVCffn/PosKZHRdDcVaZc9XvgAOQEE1F5vc2YrcQ07UjKjVjCf6qnUGZPH3YNhZ1cYkBg8tH/RNz0sAACAAQAAgAAAAIAKAAAACQAAACEHY+925ch7FjMLTNHtxZ+fZ0GuZE8oEk6H5biAyjmFVks5Aco8DDtPvMUTzYsDw9Lykon3mVr/PbwDihlimBLjjXXQBWA3+SwAAIABAACAAAAAgAAAAAAJAAAAIQdmhE0Nl7Jg1bXbswiSDewbgfUKztLMXKwwSn68/SfG4DkBDLpTZ/nMVWR5QeAg/ieNgiWd2hti+680gRSuvQ/lGFfmkuUxLAAAgAEAAIAAAACACAAAAAkAAAAhB2hfbty1heAyqGpJNnK2oY2OTJWXKP3A4EtBrPyAGqNoOQHKPAw7T7zFE82LA8PS8pKJ95la/z28A4oZYpgS44110NanP+UsAACAAQAAgAAAAIAAAAAACQAAACEHb6gaG3KVEwjqgf+LFT3e0eILv6ZIZJrMxUbqpaGAYE05ARrnqD1ZS1O/KJRXwgeGaXESl6YZOS9J2x0rd4vfMpHa1qc/5SwAAIABAACAAAAAgAQAAAAJAAAAIQd8xRxld2SGSWMco8BEv7lBztKbKyLFubKq2nm9IMzD7zkBHDznu+LNvdzVNGQwtGKN/OrlmQijaiYuU/6Skw+SeUTWpz/lLAAAgAEAAIAAAACAAgAAAAkAAAAhB4eStPBuwtXANm7tyAj6yjfHsoSIVj86g5IeyI1YYL9YOQEa56g9WUtTvyiUV8IHhmlxEpemGTkvSdsdK3eL3zKR2k2IWCssAACAAQAAgAAAAIAEAAAACQAAACEHipCtRY3MWZH5Zx6FeSyKjvnJq0e0ssHpSRyWyJNeVSI5ARw857vizb3c1TRkMLRijfzq5ZkIo2omLlP+kpMPknlEDwVpQ1YAAIABAACAAAAAgAIAAAAJAAAAIQeLtDOqIGPRyH8R/wV+ID8PRTzZVxKUsRqxnXCBQ5qPqTkBvq3GtFCRugUnb5xcEYt+IXv+/rQwMIdLBT6w3ek9hAdNiFgrLAAAgAEAAIAAAACABgAAAAkAAAAhB5ZSWLkj2e5YCmDg+TtP/n+GdXltMK/d2Zmwoh/R5xMSOQEMulNn+cxVZHlB4CD+J42CJZ3aG2L7rzSBFK69D+UYV02IWCssAACAAQAAgAAAAIAIAAAACQAAACEHnt1vXUZ5r4Koqzbwh5AqQgyl5Gd9uGC/LTkwHllr/cM5AQTUXm9zZitxDTtSMqNWMJ/qqdQZk8fdg2FnVxiQGDy0TYhYKywAAIABAACAAAAAgAoAAAAJAAAAIQee5Bub71BD92NIME/Pm5uZVhxX2BtYjnbM4WZgh6TCQTkByjwMO0+8xRPNiwPD0vKSifeZWv89vAOKGWKYEuONddDmkuUxLAAAgAEAAIAAAACAAAAAAAkAAAAhB6Ph+7Dm0ojJa/JFEw+rbEDlSzC2j97/D9h+2JgUgc/iOQHKPAw7T7zFE82LA8PS8pKJ95la/z28A4oZYpgS44110E2IWCssAACAAQAAgAAAAIAAAAAACQAAACEHo/wagLlz6zWbiyaqVRCJL2dAHLVfnoab2K+sTvPHC345ARrnqD1ZS1O/KJRXwgeGaXESl6YZOS9J2x0rd4vfMpHaf9E3PSwAAIABAACAAAAAgAQAAAAJAAAAIQeoLmzWxV9ow88RaLF3nqixcljhQuMiBCkw6m6IhL2lgjkBvq3GtFCRugUnb5xcEYt+IXv+/rQwMIdLBT6w3ek9hAd/0Tc9LAAAgAEAAIAAAACABgAAAAkAAAAhB8PogNNK8Y6rlMbUse22walgOMr9q9OgD70BtEHZuClOOQEE1F5vc2YrcQ07UjKjVjCf6qnUGZPH3YNhZ1cYkBg8tAVgN/ksAACAAQAAgAAAAIAKAAAACQAAACEHz+sCT6mDjtJESW6F6bvwrkLCzNBn4HiraR8j+yuI1RA5ARw857vizb3c1TRkMLRijfzq5ZkIo2omLlP+kpMPknlEBWA3+SwAAIABAACAAAAAgAIAAAAJAAAAIQfV+ujS0y1tUoMqu3Con6un8ohhCqOLT+hW3AlIinFpcDkBGueoPVlLU78olFfCB4ZpcRKXphk5L0nbHSt3i98ykdrmkuUxLAAAgAEAAIAAAACABAAAAAkAAAAhB94ilb9zN16LLe/yrSeTSbXT6PToqeemKytggEj4jSbmOQHKPAw7T7zFE82LA8PS8pKJ95la/z28A4oZYpgS44110A8FaUNWAACAAQAAgAAAAIAAAAAACQAAACEH5F4WzeThZcISWKgk0ig+AN2h7JGXu+YlVuemRnS0yr85Ab6txrRQkboFJ2+cXBGLfiF7/v60MDCHSwU+sN3pPYQH1qc/5SwAAIABAACAAAAAgAgAAAAJAAAAIQfw5WBeBRSvKdNi6c7nPz87wI+jMIoWLUF6VSIDTV5B3jkBDdg6oVh4bFtqa3z8W0vy1ZqMFKfwJQB4D3nkQZl9jqXWpz/lLAAAgAEAAIAAAACABgAAAAkAAAAhB/gqRCW8uGAdn23v01toKQwD4TvgUfulkJLGSvVk9bWJOQEcPOe74s293NU0ZDC0Yo386uWZCKNqJi5T/pKTD5J5RH/RNz0sAACAAQAAgAAAAIACAAAACQAAACEH+llMmhJ2JPsdwSx+aTkANmrPTDwJTZCobYqQvEewPJY5AQTUXm9zZitxDTtSMqNWMJ/qqdQZk8fdg2FnVxiQGDy0DwVpQ1YAAIABAACAAAAAgAgAAAAJAAAAAAEFIPiAIUDlObBYPlLrcuo3OSXrT7QqVUwxM7nO8FcscKd6AQb9mgQBwM4gjcjvwwZywWobWgPsw2dH8SDQLs2SUAbu0Ex2OUz+Ie2sILpC2yKjSfy8dRzsKb/lFvE9WqNkDIOsidga+PuFrO9SuiB/VA+YlfhIPKY0pRvzL3R+HVkLMvg+M4iKVc+0LA3sH7ogZFQ/0TN+f47OdTQyNbT7pnnA9rWphJumU0UHHWPZStO6IHE8CPR3YMfjw/y9dfJZ3jg9hRv4IBoAs0w+nV2mBYcZuiABnEf3KUEYzzQzeoqURIuyybxOCiw9vnw5nQAyP9fbDLpWnATAjiDCemFspWck2P4cZvGQKdUNHbLzip2B4gpYG2PYmaEuqawgK+r0EzxbYGSyt7uMlewldVCdfBPyAZIWBXucD0lj4mi6ICuzVhFscmioThs61Df8leSNOhq+1HR+ZbJFpvYia6G9uiCgJfqyNE2y+Y6gnPS35JiyZmoJ4JIVO0HY7L761Qvdr7pTnQLoA7IEwGsgdj6/XOlPhiNRMzbIbvOhlJX61kTdxJMJnLv53IExaYesICGJUcugOQYIoZ9L3DRiRPqeb2LdYPLnVkFGd8P+gNT/uiCfX5sBnF6VKxlgUnNAsm2kQnkTaWDDys42E1au4VWIgrpSnQF4sgTA0SDM9eqLZcBSbB2uheAeQ7z7E5bmVNIhy6p8llHKTQo5bqwg6zacM18Tx4AqLeRNn8goDQfowYKVNkSZz1k9Z4Gg4G+6ILTa9dQbBDWtsBchKNUxTIMXx23FYUwMop/cgBNb6Kv8uiDNO9YsEXfGqZaC3SwvLEYeOx1ENyXRuhJn5IsKKXDqsbogMOnTwLNmJSxAUgKYQDL/LT3CQWSC+vSkJKjzhaUx+k66IOhB+3/4vmUAL4BxpXDs3V3/rROgr33IlQL8XySoMNFFulSdATyyBMDRIJDuEFmWwoMv32pEbXrR4kuHvsO6HFxuf+NtecLJekWvrCB/DXqcYQdhptadDbm+SPqEkJSX/RQ1jscQajK7RbDbV7ogQiU2PZCDwVre+RsGqOryk9ejjEU1dylU4o4z1co1It26IO4Gl6Dk3rZQM7Uo0wyDeCOYPsaZXXn0BU1jjIyAYjdDuiBCDhlsgAZV2dJvLyj/8VA0/es4T2mtMJ7k/ePnanZmMLogVZa6m2rsHKqAMj6bD2NgMJ6PKg5xVUBVFhJ+p/m9hSC6VZ0BFLIDwI4g+q4gf8RXTKmbQSxkZki6Uq7uSibWu3eEZQXP8zF5HVGsIH8cJpX77R8oq3+e28gugmqU4jyOvOiW0MwIew4Nof8CuiB+x2/BqwZefHYSiZs/RrZEipT0/95qz6iqio7w8mkatLogFjGS5R8SZ9mkZS5x+lQelFdXYBeZmmLKjOptx/06HkS6U50C6AOyA8COIKv2cXTpoPJEf9yXh74y+75bo0l6XtxxTlvDimxKI2pXrCD0/x1zVCeZJ/V6uezPFVNiEysJtQ1bBHVzrq3RqG4h3Loglntjz1WNogF4ByTzJjDy9V3zKayuNTxA02qjaoo4m/K6IMUR5hEud2J7IBl09D6wxJb/6cgiA35x2viibx/nPUTxulOdAugDsiEHAZxH9ylBGM80M3qKlESLssm8TgosPb58OZ0AMj/X2ww5AYgmY0CnqG/zciKIsU/vBTiWmrj6NSX67eJioAiMJgLBDwVpQ1YAAIABAACAAAAAgAAAAAAKAAAAIQcWMZLlHxJn2aRlLnH6VB6UV1dgF5maYsqM6m3H/ToeRDkBmYHfDrR4Htmoz183ReZFnr/oLTp3jy99XfpfBP1HmzQFYDf5LAAAgAEAAIAAAACACgAAAAoAAAAhByGJUcugOQYIoZ9L3DRiRPqeb2LdYPLnVkFGd8P+gNT/OQFTpWRHcXcODI9k/DrbvXOWr+mDdY+t48lzmr8XnQjdg+aS5TEsAACAAQAAgAAAAIAGAAAACgAAACEHK7NWEWxyaKhOGzrUN/yV5I06Gr7UdH5lskWm9iJrob05AR69UUL9Jx56pjoq1jfNtJ4jjhjnE7d6KaTpeCQmpLIRf9E3PSwAAIABAACAAAAAgAYAAAAKAAAAIQcr6vQTPFtgZLK3u4yV7CV1UJ18E/IBkhYFe5wPSWPiaDkBHr1RQv0nHnqmOirWN820niOOGOcTt3oppOl4JCakshFNiFgrLAAAgAEAAIAAAACABgAAAAoAAAAhBzDp08CzZiUsQFICmEAy/y09wkFkgvr0pCSo84WlMfpOOQHbtyVIl2ulDxDRgANJtWSd0/vkyeQvdAMHcGRG30QSLn/RNz0sAACAAQAAgAAAAIAEAAAACgAAACEHQg4ZbIAGVdnSby8o//FQNP3rOE9prTCe5P3j52p2ZjA5AU6R1o+39mYKY8pZ8bfiM1qOFKfVhvo0PNIYopnssjyaf9E3PSwAAIABAACAAAAAgAIAAAAKAAAAIQdCJTY9kIPBWt75Gwao6vKT16OMRTV3KVTijjPVyjUi3TkBTpHWj7f2Zgpjylnxt+IzWo4Up9WG+jQ80hiimeyyPJoPBWlDVgAAgAEAAIAAAACAAgAAAAoAAAAhB1WWuptq7ByqgDI+mw9jYDCejyoOcVVAVRYSfqf5vYUgOQFOkdaPt/ZmCmPKWfG34jNajhSn1Yb6NDzSGKKZ7LI8mgVgN/ksAACAAQAAgAAAAIACAAAACgAAACEHZFQ/0TN+f47OdTQyNbT7pnnA9rWphJumU0UHHWPZStM5AYgmY0CnqG/zciKIsU/vBTiWmrj6NSX67eJioAiMJgLB1qc/5SwAAIABAACAAAAAgAAAAAAKAAAAIQdxPAj0d2DH48P8vXXyWd44PYUb+CAaALNMPp1dpgWHGTkBiCZjQKeob/NyIoixT+8FOJaauPo1Jfrt4mKgCIwmAsHmkuUxLAAAgAEAAIAAAACAAAAAAAoAAAAhB3Y+v1zpT4YjUTM2yG7zoZSV+tZE3cSTCZy7+dyBMWmHOQFTpWRHcXcODI9k/DrbvXOWr+mDdY+t48lzmr8XnQjdg9anP+UsAACAAQAAgAAAAIAGAAAACgAAACEHfsdvwasGXnx2EombP0a2RIqU9P/eas+oqoqO8PJpGrQ5AZmB3w60eB7ZqM9fN0XmRZ6/6C06d48vfV36XwT9R5s0f9E3PSwAAIABAACAAAAAgAoAAAAKAAAAIQd/DXqcYQdhptadDbm+SPqEkJSX/RQ1jscQajK7RbDbVzkBTpHWj7f2Zgpjylnxt+IzWo4Up9WG+jQ80hiimeyyPJrmkuUxLAAAgAEAAIAAAACAAgAAAAoAAAAhB38cJpX77R8oq3+e28gugmqU4jyOvOiW0MwIew4Nof8COQGZgd8OtHge2ajPXzdF5kWev+gtOnePL31d+l8E/UebNE2IWCssAACAAQAAgAAAAIAKAAAACgAAACEHf1QPmJX4SDymNKUb8y90fh1ZCzL4PjOIilXPtCwN7B85AYgmY0CnqG/zciKIsU/vBTiWmrj6NSX67eJioAiMJgLBBWA3+SwAAIABAACAAAAAgAAAAAAKAAAAIQeNyO/DBnLBahtaA+zDZ0fxINAuzZJQBu7QTHY5TP4h7TkBiCZjQKeob/NyIoixT+8FOJaauPo1Jfrt4mKgCIwmAsFNiFgrLAAAgAEAAIAAAACAAAAAAAoAAAAhB5DuEFmWwoMv32pEbXrR4kuHvsO6HFxuf+NtecLJekWvOQFOkdaPt/ZmCmPKWfG34jNajhSn1Yb6NDzSGKKZ7LI8mtanP+UsAACAAQAAgAAAAIACAAAACgAAACEHlntjz1WNogF4ByTzJjDy9V3zKayuNTxA02qjaoo4m/I5AS0sTOcF7vHFozjH7pT631eZ7unHOChG7SCWwd7IaMXJf9E3PSwAAIABAACAAAAAgAgAAAAKAAAAIQefX5sBnF6VKxlgUnNAsm2kQnkTaWDDys42E1au4VWIgjkBU6VkR3F3DgyPZPw6271zlq/pg3WPrePJc5q/F50I3YMPBWlDVgAAgAEAAIAAAACABgAAAAoAAAAhB6Al+rI0TbL5jqCc9LfkmLJmagngkhU7QdjsvvrVC92vOQEevVFC/SceeqY6KtY3zbSeI44Y5xO3eimk6XgkJqSyEQVgN/ksAACAAQAAgAAAAIAGAAAACgAAACEHq/ZxdOmg8kR/3JeHvjL7vlujSXpe3HFOW8OKbEojalc5AS0sTOcF7vHFozjH7pT631eZ7unHOChG7SCWwd7IaMXJ5pLlMSwAAIABAACAAAAAgAgAAAAKAAAAIQe02vXUGwQ1rbAXISjVMUyDF8dtxWFMDKKf3IATW+ir/DkB27clSJdrpQ8Q0YADSbVkndP75MnkL3QDB3BkRt9EEi4PBWlDVgAAgAEAAIAAAACABAAAAAoAAAAhB7pC2yKjSfy8dRzsKb/lFvE9WqNkDIOsidga+PuFrO9SOQGIJmNAp6hv83IiiLFP7wU4lpq4+jUl+u3iYqAIjCYCwX/RNz0sAACAAQAAgAAAAIAAAAAACgAAACEHwnphbKVnJNj+HGbxkCnVDR2y84qdgeIKWBtj2JmhLqk5AR69UUL9Jx56pjoq1jfNtJ4jjhjnE7d6KaTpeCQmpLIR1qc/5SwAAIABAACAAAAAgAgAAAAKAAAAIQfFEeYRLndieyAZdPQ+sMSW/+nIIgN+cdr4om8f5z1E8TkBLSxM5wXu8cWjOMfulPrfV5nu6cc4KEbtIJbB3shoxckFYDf5LAAAgAEAAIAAAACACAAAAAoAAAAhB8z16otlwFJsHa6F4B5DvPsTluZU0iHLqnyWUcpNCjluOQHbtyVIl2ulDxDRgANJtWSd0/vkyeQvdAMHcGRG30QSLtanP+UsAACAAQAAgAAAAIAEAAAACgAAACEHzTvWLBF3xqmWgt0sLyxGHjsdRDcl0boSZ+SLCilw6rE5Adu3JUiXa6UPENGAA0m1ZJ3T++TJ5C90AwdwZEbfRBIuTYhYKywAAIABAACAAAAAgAQAAAAKAAAAIQfoQft/+L5lAC+AcaVw7N1d/60ToK99yJUC/F8kqDDRRTkB27clSJdrpQ8Q0YADSbVkndP75MnkL3QDB3BkRt9EEi4FYDf5LAAAgAEAAIAAAACABAAAAAoAAAAhB+s2nDNfE8eAKi3kTZ/IKA0H6MGClTZEmc9ZPWeBoOBvOQHbtyVIl2ulDxDRgANJtWSd0/vkyeQvdAMHcGRG30QSLuaS5TEsAACAAQAAgAAAAIAEAAAACgAAACEH7gaXoOTetlAztSjTDIN4I5g+xpldefQFTWOMjIBiN0M5AU6R1o+39mYKY8pZ8bfiM1qOFKfVhvo0PNIYopnssjyaTYhYKywAAIABAACAAAAAgAIAAAAKAAAAIQf0/x1zVCeZJ/V6uezPFVNiEysJtQ1bBHVzrq3RqG4h3DkBLSxM5wXu8cWjOMfulPrfV5nu6cc4KEbtIJbB3shoxclNiFgrLAAAgAEAAIAAAACACAAAAAoAAAAhB/iAIUDlObBYPlLrcuo3OSXrT7QqVUwxM7nO8FcscKd6DQB8Rh5dAAAAAAoAAAAhB/quIH/EV0ypm0EsZGZIulKu7kom1rt3hGUFz/MxeR1ROQGZgd8OtHge2ajPXzdF5kWev+gtOnePL31d+l8E/UebNA8FaUNWAACAAQAAgAAAAIAIAAAACgAAAAAA' + for fname, psbt in [(fname0, psbt0), (fname1, psbt1)]: + print(fname) # debug + microsd_wipe() + shutil.copy(f"{src_root_dir}/testing/data/migration_640/{fname}", microsd_path("")) + # need some other seed as main secret as we are gonna use simulator words as tmp seed + set_seed_words("type goat number acoustic embark allow onion express monitor pudding mutual thank") + goto_home() + pick_menu_item("Advanced/Tools") + pick_menu_item("Danger Zone") + pick_menu_item("I Am Developer.") + pick_menu_item("Restore Bkup") + pick_menu_item(fname) + time.sleep(.1) + enter_complex(32*"a", apply=False, b39pass=False) + time.sleep(.5) + press_select() + time.sleep(.1) + press_select() + + with open(microsd_path(fname.split(".")[0]+".psbt"), "w") as f: + f.write(psbt) + + pick_menu_item("Ready To Sign") + time.sleep(1) + title, story = cap_story() + assert "OK TO SEND" in title + press_select() + time.sleep(1) + title, stoty = cap_story() + assert title == "PSBT Signed" + + msc = settings_get("miniscript") + assert len(msc) == 1 + assert len(msc[0]) == 4 # new format + press_cancel() + + +def test_anchor_bug(goto_home, pick_menu_item, microsd_path, src_root_dir, press_select, + unit_test, cap_menu): + fname = "bonus101.txt" + shutil.copy(f"{src_root_dir}/testing/data/migration_640/{fname}", microsd_path("")) + # unit_test('devtest/clear_seed.py') + goto_home() + pick_menu_item("Advanced/Tools") + pick_menu_item("Danger Zone") + pick_menu_item("I Am Developer.") + pick_menu_item("Restore Bkup") + pick_menu_item(fname) + time.sleep(.1) + press_select() + + time.sleep(.1) + press_select() + + goto_home() + pick_menu_item("Settings") + pick_menu_item("Miniscript") + time.sleep(2) + m = cap_menu() + assert len(m) == 17 + assert all(len(name) <= 30 for name in m) + + +def test_multisig_miniscript_migration(settings_append, clear_miniscript, settings_get, + settings_remove, settings_set, goto_home, pick_menu_item): + + clear_miniscript() + settings_remove("multisig") + + for msc in [msc0, msc1, msc2, msc3, msc4, msc5, msc6, msc7, msc8, msc9, msc10, + msc11, msc12, msc14, msc15, msc16, msc17, msc18, msc19, msc20]: + settings_append("miniscript", msc) + + settings_set("multisig", [ms0, ms1, ms2, ms3]) + + goto_home() + pick_menu_item("Settings") + pick_menu_item("Miniscript") # migration happened here + + miniscripts = settings_get("miniscript") + assert len(miniscripts) == 24 # 20 miniscript wallets & 4 multisigs + for m in miniscripts: + assert len(m) == 4 + + assert settings_get("multisig", None) is None + + +def test_name_clash(settings_set, clear_miniscript, settings_remove, goto_home, pick_menu_item, + settings_get): + # names need to be unique per miniscript/multisig + # but now we are merging them together - check and resolve + # miniscript names are preserved, multisig names can be altered of needed + clear_miniscript() + settings_remove("multisig") + + new_msc6 = list(msc6) + new_msc6[0] = "ms0" # same name as ms0 + + # length issue, name cannot be longer than 20 chars + # but adding '1' would cause length failure - need some replacing + new_ms2 = list(ms2) + new_ms2[0] = 35*"a" + + new_msc16 = list(msc16) + new_msc16[0] = 31*"a" + + settings_set("miniscript", [new_msc6, msc11, new_msc16]) + settings_set("multisig", [ms0, ms1, new_ms2, ms3]) + + goto_home() + pick_menu_item("Settings") + pick_menu_item("Miniscript") + + assert settings_get("multisig", None) is None + miniscripts = settings_get("miniscript") + + assert all([len(m[0]) <= 30 for m in miniscripts]) + assert len(set([m[0] for m in miniscripts])) == 7 + +# EOF \ No newline at end of file diff --git a/testing/test_addr.py b/testing/test_addr.py index fc245c54..a8566537 100644 --- a/testing/test_addr.py +++ b/testing/test_addr.py @@ -96,7 +96,10 @@ def test_addr_vs_bitcoind(addr_fmt, use_regtest, press_select, dev, bitcoind_d_s ("m/0/0/0/0/0/0/0/0/0/0/0/0/0\np2pkh", "too deep"), ("m/0/0/0/0/0/q/0/0/0\np2pkh", "invalid characters"), ]) -def test_show_addr_nfc_invalid(body_err, goto_home, pick_menu_item, nfc_write_text, cap_story): +def test_show_addr_nfc_invalid(body_err, goto_home, pick_menu_item, nfc_write_text, cap_story, + skip_if_useless_way): + skip_if_useless_way("nfc") + body, err = body_err goto_home() pick_menu_item('Advanced/Tools') @@ -111,7 +114,9 @@ def test_show_addr_nfc_invalid(body_err, goto_home, pick_menu_item, nfc_write_te @pytest.mark.parametrize("str_addr_fmt", ["p2pkh", "", "p2wpkh", "p2wpkh-p2sh", "p2sh-p2wpkh", "p2tr"]) def test_show_addr_nfc(path, str_addr_fmt, nfc_write_text, nfc_read_text, pick_menu_item, goto_home, cap_story, press_nfc, addr_vs_path, press_select, is_q1, - cap_screen): + cap_screen, skip_if_useless_way): + + skip_if_useless_way("nfc") # import pdb;pdb.set_trace() for _ in range(5): # need to wait for ApproveMessageSign to be popped from ux stack diff --git a/testing/test_address_explorer.py b/testing/test_address_explorer.py index 5fb66dd6..4321b32b 100644 --- a/testing/test_address_explorer.py +++ b/testing/test_address_explorer.py @@ -94,15 +94,10 @@ def generate_addresses_file(goto_address_explorer, need_keypress, cap_story, mic assert len(addresses.split("\n")) == expected_qty raise pytest.xfail("PASSED - different export format for NFC") - if is_p2tr: - # p2tr - no signature file - contents = load_export(way, label="Address summary", is_json=False, - sig_check=False, skip_query=True) - sig_addr = None - else: - time.sleep(.5) # always long enough to write the file? - title, body = cap_story() - contents, sig_addr = load_export_and_verify_signature(body, way, label="Address summary") + + time.sleep(.5) # always long enough to write the file? + title, body = cap_story() + contents, sig_addr, _ = load_export_and_verify_signature(body, way, label="Address summary") addr_dump = io.StringIO(contents) cc = csv.reader(addr_dump) @@ -112,7 +107,10 @@ def generate_addresses_file(goto_address_explorer, need_keypress, cap_story, mic assert int(idx) == n if n == start_idx: if sig_addr: - assert sig_addr == addr + if is_p2tr: + pass + else: + assert sig_addr == addr if not is_custom_single: assert ('/%s' % idx) in deriv @@ -508,7 +506,7 @@ def test_custom_path(path_sidx, which_fmt, addr_vs_path, pick_menu_item, goto_ad assert "Press (0) to sign message with this key" in body need_keypress('0') msg = "COLDCARD the rock solid HWW" - sign_msg_from_address(msg, addr, path, which_fmt, "sd", True) + sign_msg_from_address(msg, addr, path, which_fmt, "sd", "XTN") press_cancel() else: n = 10 diff --git a/testing/test_backup.py b/testing/test_backup.py index e293dc6e..d6768388 100644 --- a/testing/test_backup.py +++ b/testing/test_backup.py @@ -7,6 +7,7 @@ from constants import simulator_fixed_words, simulator_fixed_tprv from charcodes import KEY_QR from bip32 import BIP32Node from mnemonic import Mnemonic +from ckcc_protocol.protocol import CCProtocolPacker @pytest.fixture @@ -93,10 +94,7 @@ def backup_system(settings_set, settings_remove, goto_home, pick_menu_item, # st -> seed type # ct -> cleartext backup if reuse_pw: - if isinstance(reuse_pw, list): - assert len(reuse_pw) == 12 - else: - assert reuse_pw is True # default + if reuse_pw is True: reuse_pw = ['zoo' for _ in range(12)] settings_set('bkpw', ' '.join(reuse_pw)) @@ -129,20 +127,24 @@ def backup_system(settings_set, settings_remove, goto_home, pick_menu_item, need_keypress("6") time.sleep(.1) - _, story = cap_story() - assert "Are you SURE ?!?" in story + title, story = cap_story() + assert "Are you SURE ?!?" in (title if is_q1 else story) assert "**NOT** be encrypted" in story press_select() return # nothing more to be done if reuse_pw: - assert (' 1: %s' % reuse_pw[0]) in body - assert ('12: %s' % reuse_pw[-1]) in body + if len(reuse_pw) == 1: + reuse_pw = reuse_pw[0] + assert f"{reuse_pw[0]}...{reuse_pw[-1]}" in body + else: + assert (' 1: %s' % reuse_pw[0]) in body + assert ('12: %s' % reuse_pw[-1]) in body press_select() words = ['zoo'] * 12 else: assert title == 'NO-TITLE' - assert 'Record this' in body + assert 'Record this (12 word)' in body assert 'password:' in body words = seed_story_to_words(body) @@ -176,6 +178,31 @@ def backup_system(settings_set, settings_remove, goto_home, pick_menu_item, return doit +@pytest.fixture +def make_big_notes(settings_set, sim_exec): + def doit(count=9): + print(">>> Making huge backup file") + + # - to bypass USB msg limit, append as we go + notes = [] + settings_set('notes', []) + for n in range(count): + v = { fld:('a'*30) if fld != 'misc' else 'b'*1800 + for fld in ['user', 'password', 'site', 'misc'] } + v['title'] = f'Note {n+1}' + notes.append(v) + rv = sim_exec(cmd := f'settings.current["notes"].append({v!r})') + assert 'error' not in rv.lower() + + rv = sim_exec('settings.changed()') + assert 'error' not in rv.lower() + + assert len(notes) == count + + return notes + + return doit + @pytest.mark.qrcode @pytest.mark.parametrize('multisig', [False, 'multisig']) @@ -189,11 +216,11 @@ def test_make_backup(multisig, goto_home, pick_menu_item, cap_story, need_keypre pass_word_quiz, reset_seed_words, import_ms_wallet, get_setting, reuse_pw, save_pw, settings_set, settings_remove, press_select, generate_ephemeral_words, set_bip39_pw, verify_backup_file, - check_and_decrypt_backup, restore_backup_cs, clear_ms, seedvault, + check_and_decrypt_backup, restore_backup_cs, clear_miniscript, seedvault, restore_main_seed, import_ephemeral_xprv, backup_system, - press_cancel, sim_exec, pass_way, garbage_collector): + press_cancel, sim_exec, pass_way, garbage_collector, make_big_notes): # Make an encrypted 7z backup, verify it, and even restore it! - clear_ms() + clear_miniscript() reset_seed_words() settings_set("seedvault", int(seedvault)) settings_set("seeds", [] if seedvault else None) @@ -201,20 +228,7 @@ def test_make_backup(multisig, goto_home, pick_menu_item, cap_story, need_keypre # test larger backup files > 10,000 bytes if multisig == False and st == None and not reuse_pw and not save_pw and not seedvault: # pick just one test case. - # - to bypass USB msg limit, append as we go - print(">>> Making huge backup file") - notes = [] - settings_set('notes', []) - for n in range(9): - v = { fld:('a'*30) if fld != 'misc' else 'b'*1800 - for fld in ['user', 'password', 'site', 'misc'] } - v['title'] = f'Note {n+1}' - notes.append(v) - rv = sim_exec(cmd := f'settings.current["notes"].append({v!r})') - print(rv) - assert 'error' not in rv.lower() - rv = sim_exec(cmd := f'settings.changed()') - assert 'error' not in rv.lower() + notes = make_big_notes() else: notes = None @@ -223,7 +237,7 @@ def test_make_backup(multisig, goto_home, pick_menu_item, cap_story, need_keypre import_ms_wallet(15, 15) press_select() time.sleep(.1) - assert len(get_setting('multisig')) == 1 + assert len(get_setting('miniscript')) == 1 if not reuse_pw: # drop saved bkpw before we get to ephemeral settings @@ -231,7 +245,7 @@ def test_make_backup(multisig, goto_home, pick_menu_item, cap_story, need_keypre if st == "b39pass": xfp_pass = set_bip39_pw("coinkite", reset=False, seed_vault=seedvault) - assert not get_setting('multisig', None) + assert not get_setting('miniscript', None) elif st == "eph": eph_seed = generate_ephemeral_words(num_words=24, dice=False, from_main=True, seed_vault=seedvault) @@ -240,7 +254,7 @@ def test_make_backup(multisig, goto_home, pick_menu_item, cap_story, need_keypre import_ms_wallet(15, 15, dev_key=True, common="605'/0'/0'") press_select() time.sleep(.1) - assert len(get_setting('multisig')) == 1 + assert len(get_setting('miniscript')) == 1 else: # create ephemeral seed - add to seed vault if necessary # and restore master (just so we have something in setting.seeds) @@ -257,7 +271,7 @@ def test_make_backup(multisig, goto_home, pick_menu_item, cap_story, need_keypre # multisig is only in main wallet # must not be copied from main to b39pass # must not be available after backup done - assert not get_setting('multisig', None) + assert not get_setting('miniscript', None) if notes: # verify large notes survived @@ -309,7 +323,7 @@ def test_make_backup(multisig, goto_home, pick_menu_item, cap_story, need_keypre # test verify on device (CRC check) if multisig: - avail_settings.append("multisig") + avail_settings.append("miniscript") restore_backup_cs(files[0], words, avail_settings=avail_settings, pass_way=pass_way) @@ -547,28 +561,10 @@ def test_seed_vault_backup(settings_set, reset_seed_words, generate_ephemeral_wo assert xfp_ui in sv_xfp_menu -def test_seed_vault_backup_frozen(reset_seed_words, settings_set, repl): - from test_ephemeral import SEEDVAULT_TEST_DATA - +def test_seed_vault_backup_frozen(reset_seed_words, settings_set, repl, build_test_seed_vault): reset_seed_words() settings_set("seedvault", 1) - - sv = [] - for item in SEEDVAULT_TEST_DATA: - xfp, entropy, mnemonic = item - - # build stashed encoded secret - entropy_bytes = bytes.fromhex(entropy) - if mnemonic: - vlen = len(entropy_bytes) - assert vlen in [16, 24, 32] - marker = 0x80 | ((vlen // 8) - 2) - stored_secret = bytes([marker]) + entropy_bytes - else: - stored_secret = entropy_bytes - - sv.append((xfp, stored_secret.hex(), f"[{xfp}]", "meta")) - + sv = build_test_seed_vault() settings_set("seeds", sv) bk = repl.exec('import backups; RV.write(backups.render_backup_contents())', raw=1) assert 'Coldcard backup file' in bk @@ -576,13 +572,14 @@ def test_seed_vault_backup_frozen(reset_seed_words, settings_set, repl): assert target in bk -def test_clone_start(reset_seed_words, pick_menu_item, cap_story, goto_home): - sd_dir = "../unix/work/MicroSD" +def test_clone_start(reset_seed_words, pick_menu_item, cap_story, goto_home, src_root_dir, + sim_root_dir): + sd_dir = f"{sim_root_dir}/MicroSD" num_7z = len([i for i in os.listdir(sd_dir) if i.endswith(".7z")]) fname = "ccbk-start.json" reset_seed_words() goto_home() - shutil.copy(f"data/{fname}", sd_dir) + shutil.copy(f"{src_root_dir}/testing/data/{fname}", sd_dir) pick_menu_item("Advanced/Tools") pick_menu_item("Backup") pick_menu_item("Clone Coldcard") @@ -598,17 +595,25 @@ def test_clone_start(reset_seed_words, pick_menu_item, cap_story, goto_home): def test_bkpw_override(reset_seed_words, override_bkpw, goto_home, pick_menu_item, - cap_story, press_select, garbage_collector, microsd_path): + cap_story, press_select, garbage_collector, microsd_path, + restore_backup_cs, is_q1): reset_seed_words() # clean slate old_pw = None test_cases = [ - " ".join(12 * ["elevator"]), - " ".join(12 * ["fever"]), 32 * "a", - (16 * "0") + " " + (16 *"1"), - 64 * "Q", (26 * "?") + "!@#$%^&*()", ] + if is_q1: + # not needed on mk4 - even tho works (takes too much time) + # Mk4 display is not suitable for these type of passwords anyways + test_cases += [ + "arm prob slot merc hub fiel wing aver tale undo diar boos army cabl mous teac drif risk frow achi poet ecol boss grit", + " ".join(12 * ["elevator"]), + " ".join(12 * ["fever"]), + 64 * "Q", + ] + + fnames = [] for pw in test_cases: override_bkpw(pw, old_pw) @@ -630,7 +635,211 @@ def test_bkpw_override(reset_seed_words, override_bkpw, goto_home, pick_menu_ite time.sleep(1) title, story = cap_story() assert "Backup file written" in story - garbage_collector.append(microsd_path(story.split("\n\n")[1])) + fname = story.split("\n\n")[1] + garbage_collector.append(microsd_path(fname)) + fnames.append(fname) press_select() + for pw, fn in zip(test_cases, fnames): + restore_backup_cs(fn, pw, custom_bkpw=True) + + +@pytest.mark.parametrize('btype', ["classic", "custom_bkpw", "plaintext"]) +@pytest.mark.parametrize('force_tmp', [True, False]) +def test_restore_usb_backup(backup_system, set_seed_words, cap_story, verify_ephemeral_secret_ui, + settings_slots, reset_seed_words, word_menu_entry, confirm_tmp_seed, + dev, microsd_path, press_select, btype, force_tmp, + unit_test, restore_main_seed, cap_menu, is_q1, enter_complex): + + from test_ephemeral import SEEDVAULT_TEST_DATA + xfp_str, encoded_str, mnemonic = SEEDVAULT_TEST_DATA[2] + set_seed_words(mnemonic) + bkpw = 34*"Z" + plaintext = (btype == "plaintext") + password = False + + # ACTUAL BACKUP + if plaintext: + bk_pw = backup_system(ct=True) + elif btype == "custom_bkpw": + # encrypted but with custom pwd + password = True + bk_pw = backup_system(reuse_pw=[bkpw]) + else: + # classic word-based encrypted backup + bk_pw = backup_system() + + time.sleep(.1) + title, story = cap_story() + fname = story.split("\n\n")[1] + + # remove all saved slots, one of them will be the one where we just created backup + # slot where backup was created needs to be removed - otherwise we will load back to it + # and see multisig wallet there without the need for backup to actually copy it + for s in settings_slots(): + try: + os.remove(s) + except: pass + + # clear seed + unit_test('devtest/clear_seed.py') + + with open(microsd_path(fname), "rb") as f: + file_len, sha = dev.upload_file(f.read()) + + dev.send_recv(CCProtocolPacker.restore_backup(file_len, sha, password, plaintext, force_tmp), + timeout=None) + time.sleep(.2) + _, story = cap_story() + assert f"Restore uploaded backup as a {'temporary' if force_tmp else 'master'} seed" in story + press_select() + + time.sleep(.1) + if btype == "classic": + word_menu_entry(bk_pw, has_checksum=False) + elif password: + enter_complex(bkpw, apply=False, b39pass=False) + + time.sleep(.2) + mnemonic = mnemonic.split(" ") + + title, story = cap_story() + assert f"[{xfp_str}]" == title + assert "Above is the master fingerprint of the seed stored in the backup." in story + assert f"load backup as {'temporary' if force_tmp else 'master'} seed" in story + press_select() + time.sleep(.1) + + if force_tmp: + confirm_tmp_seed(seedvault=False) + verify_ephemeral_secret_ui(mnemonic=mnemonic, xpub=None, seed_vault=False) + restore_main_seed() + time.sleep(.1) + assert "New Seed Words" in cap_menu() + else: + _, story = cap_story() + assert "configured for best security practices" in story + press_select() + time.sleep(.1) + _, story = cap_story() + assert "now reboot" in story + + +@pytest.mark.parametrize('way', ["sd", "usb"]) +@pytest.mark.parametrize('tmp', [True, False]) +def test_refuse_backup(way, tmp, set_seed_words, backup_system, cap_story, unit_test, microsd_path, + dev, press_select, word_menu_entry, X, press_cancel, cap_menu, pick_menu_item, + reset_seed_words, need_keypress, get_secrets, goto_home): + + from test_ephemeral import SEEDVAULT_TEST_DATA + xfp_str, encoded_str, mnemonic = SEEDVAULT_TEST_DATA[0] + set_seed_words(mnemonic) + bk_pw = backup_system() + + time.sleep(.1) + title, story = cap_story() + fname = story.split("\n\n")[1] + press_select() + + if tmp: + reset_seed_words() + press_cancel() + else: + unit_test('devtest/clear_seed.py') + + if way == "usb": + with open(microsd_path(fname), "rb") as f: + file_len, sha = dev.upload_file(f.read()) + + dev.send_recv(CCProtocolPacker.restore_backup(file_len, sha), timeout=None) + time.sleep(.2) + press_select() + else: + if tmp: + pick_menu_item("Advanced/Tools") + pick_menu_item("Temporary Seed") + need_keypress("4") + pick_menu_item("Coldcard Backup") + else: + pick_menu_item("Import Existing") + pick_menu_item("Restore Backup") + + pick_menu_item(fname) + + time.sleep(.2) + word_menu_entry(bk_pw, has_checksum=False) + time.sleep(.2) + title, story = cap_story() + assert f"[{xfp_str}]" == title + assert "Above is the master fingerprint of the seed stored in the backup." in story + assert f"load backup as {'temporary' if tmp else 'master'} seed" in story + assert f"Press {X} to abort" in story + press_cancel() # refuse backup + time.sleep(.1) + if tmp: + cur_mnemonic = get_secrets()["mnemonic"] + assert mnemonic != cur_mnemonic # nothing was loaded + else: + goto_home() + assert "New Seed Words" in cap_menu() # nothing was loaded + + +@pytest.mark.parametrize('tmp', [True, False]) +def test_exit_dev_backup(tmp, unit_test, goto_home, pick_menu_item, need_keypress, src_root_dir, + microsd_path, press_cancel, cap_menu, cap_story): + fname = 'backup.7z' + fn = microsd_path(fname) + shutil.copy(f'{src_root_dir}/docs/backup.7z', fn) + + if not tmp: + unit_test('devtest/clear_seed.py') + + goto_home() + pick_menu_item('Advanced/Tools') + if tmp: + pick_menu_item("Danger Zone") + pick_menu_item('I Am Developer.') + pick_menu_item('Restore Bkup') + + time.sleep(.1) + pick_menu_item(fname) + + # do not write anything just exit + # yikes + press_cancel() + time.sleep(.2) + pick_menu_item("Restore Bkup") + press_cancel() + + +@pytest.mark.parametrize("fname", [ + '03edd162a5f57eece68d8eea3891e2a150383a225187179ecb1599efe00d16dd70-ccbk.7z', + ('W'*31) + ".7z", +]) +def test_backup_long_name_display(fname, goto_home, pick_menu_item, need_keypress, src_root_dir, + microsd_path, press_cancel, cap_screen, is_q1): + if not is_q1: + raise pytest.skip("Only Q") + + fn = microsd_path(fname) + shutil.copy(f'{src_root_dir}/docs/backup.7z', fn) + + goto_home() + pick_menu_item('Advanced/Tools') + pick_menu_item('Temporary Seed') + need_keypress("4") + pick_menu_item('Coldcard Backup') + + time.sleep(.1) + pick_menu_item(fname) + time.sleep(.1) + scr = cap_screen() + if len(fname) > 34: # CHARS_W + assert fname[:16] in scr + assert fname[-16:] in scr + else: + assert fname in scr + + press_cancel() + # EOF diff --git a/testing/test_bbqr.py b/testing/test_bbqr.py index 08ccc713..f71d27f0 100644 --- a/testing/test_bbqr.py +++ b/testing/test_bbqr.py @@ -7,6 +7,7 @@ from helpers import prandom from binascii import a2b_hex from bbqr import split_qrs, join_qrs from charcodes import KEY_QR +from base64 import b32decode, b32encode # All tests in this file are exclusively meant for Q # @@ -149,6 +150,60 @@ def render_bbqr(need_keypress, cap_screen_qr, sim_exec, readback_bbqr_ll): return doit + +@pytest.fixture +def split_scan_bbqr(scan_a_qr, goto_home, need_keypress): + + # take big data and send it via series of BBQr thru emulated scanner + def doit(raw_data, type_code, **kws): + goto_home() + need_keypress(KEY_QR) + + # def split_qrs(raw, type_code, encoding=None, + # min_split=1, max_split=1295, min_version=5, max_version=40 + actual_vers, parts = split_qrs(raw_data, type_code, **kws) + random.shuffle(parts) + + for p in parts: + scan_a_qr(p) + time.sleep(2.0 / len(parts)) # just so we can watch + + return doit + +@pytest.fixture +def try_sign_bbqr(cap_story, scan_a_qr, press_select, press_cancel, need_keypress, + readback_bbqr, split_scan_bbqr): + def doit(psbt, type_code="P", approve=True, nfc_push_tx=False, **kws): + + split_scan_bbqr(psbt, type_code, **kws) + + for r in range(20): + title, story = cap_story() + if 'OK TO SEND' in title: + break + time.sleep(.1) + else: + raise pytest.fail('never saw it?') + + if not approve: + press_cancel() + return + + # approve it + press_select() + + if nfc_push_tx: + return psbt, None, None + + time.sleep(.2) + + # expect signed txn back + file_type, rb = readback_bbqr() + assert file_type in 'TP' + return psbt, file_type, rb + + return doit + @pytest.mark.parametrize('size', [ 1, 20, 990, 2060*2, 5000, 65537] ) def test_show_bbqr_sizes(size, cap_screen_qr, sim_exec, render_bbqr): # test lengths @@ -164,14 +219,14 @@ def test_show_bbqr_sizes(size, cap_screen_qr, sim_exec, render_bbqr): assert ft == 'U' @pytest.mark.parametrize('src', [ 'rng', 'gpu', 'bigger'] ) -def test_show_bbqr_contents(src, cap_screen_qr, sim_exec, render_bbqr, load_shared_mod): +def test_show_bbqr_contents(src, cap_screen_qr, sim_exec, render_bbqr, load_shared_mod, src_root_dir): args = dict(msg=f'Test {src}', file_type='B') if src == 'rng': args['data'] = expect = prandom(500) # limited by simulated USB path elif src in { 'gpu', 'bigger' }: args['setup'] = 'from gpu_binary import BINARY' - cc_gpu_bin = load_shared_mod('cc_gpu_bin', '../shared/gpu_binary.py') + cc_gpu_bin = load_shared_mod('cc_gpu_bin', f'{src_root_dir}/shared/gpu_binary.py') if src == 'gpu': args['str_expr'] = 'BINARY' expect = cc_gpu_bin.BINARY @@ -188,67 +243,36 @@ def test_show_bbqr_contents(src, cap_screen_qr, sim_exec, render_bbqr, load_shar assert ft == 'B' @pytest.mark.bitcoind +@pytest.mark.reexport @pytest.mark.parametrize('size', [ 2, 10 ] ) @pytest.mark.parametrize('max_ver', [ 20 ] ) # 20 max due to 4k USB buffer limit @pytest.mark.parametrize('encoding', '2HZ' ) @pytest.mark.parametrize('partial', [False, True]) @pytest.mark.parametrize('base64str', [False, True]) -@pytest.mark.parametrize('segwit', [True, False]) -def test_bbqr_psbt(size, encoding, max_ver, partial, segwit, scan_a_qr, readback_bbqr, +@pytest.mark.parametrize('addr_fmt', ["p2wpkh", "p2tr"]) +def test_bbqr_psbt(size, encoding, max_ver, partial, addr_fmt, scan_a_qr, readback_bbqr, cap_screen_qr, render_bbqr, goto_home, use_regtest, cap_story, decode_psbt_with_bitcoind, decode_with_bitcoind, fake_txn, dev, start_sign, end_sign, press_cancel, press_select, need_keypress, - base64str): + base64str, try_sign_bbqr, signing_artifacts_reexport, sim_root_dir): num_in = size num_out = size*10 - def hack(psbt): - if partial: - # change first input to not be ours - pk = list(psbt.inputs[0].bip32_paths.keys())[0] - pp = psbt.inputs[0].bip32_paths[pk] - psbt.inputs[0].bip32_paths[pk] = b'what' + pp[4:] + inputs = [[]] * (num_in - int(partial)) + if partial: + inputs += [[addr_fmt, None, None, False]] # foreign input + + psbt = fake_txn(inputs, num_out, dev.master_xpub, addr_fmt=addr_fmt) - if not segwit: - psbt = fake_txn(num_in, num_out, dev.master_xpub, psbt_hacker=hack) - else: - psbt = fake_txn(num_in, num_out, dev.master_xpub, psbt_hacker=hack, - segwit_in=True, outstyles=['p2wpkh']) if base64str: psbt = base64.b64encode(psbt).decode() - open('debug/last.psbt', 'w' if base64str else 'wb').write(psbt) + with open(f'{sim_root_dir}/debug/last.psbt', 'w' if base64str else 'wb') as f: + f.write(psbt) - goto_home() - need_keypress(KEY_QR) - - # def split_qrs(raw, type_code, encoding=None, - # min_split=1, max_split=1295, min_version=5, max_version=40 - actual_vers, parts = split_qrs(psbt, 'U' if base64str else 'P', - max_version=max_ver, encoding=encoding) - random.shuffle(parts) - - for p in parts: - scan_a_qr(p) - time.sleep(4.0 / len(parts)) # just so we can watch - - for r in range(20): - title, story = cap_story() - if 'OK TO SEND' in title: - break - time.sleep(.1) - else: - raise pytest.fail('never saw it?') - - # approve it - press_select() - - time.sleep(.2) - - # expect signed txn back - file_type, rb = readback_bbqr() - assert file_type in 'TP' + _, file_type, rb = try_sign_bbqr(psbt, type_code="U" if base64str else "P", + max_version=max_ver, encoding=encoding) if file_type == 'T': assert not partial @@ -274,6 +298,12 @@ def test_bbqr_psbt(size, encoding, max_ver, partial, segwit, scan_a_qr, readback assert oc == num_out press_cancel() # back to menu + _psbt, _txn = signing_artifacts_reexport("qr", tx_final=not partial, + encoding="binary") + if partial: + assert _psbt == rb + else: + assert _txn == rb @pytest.mark.parametrize('test_size', [7854, 4592, 758, 375, 465, # v15 capacity @@ -330,38 +360,13 @@ def test_split_unit(test_size, encoding, sim_exec, sim_eval): ]) def test_psbt_static(file, goto_home, cap_story, scan_a_qr, press_select, readback_bbqr, need_keypress, press_cancel, start_sign, - end_sign, bitcoind): - - goto_home() - need_keypress(KEY_QR) + end_sign, bitcoind, try_sign_bbqr): + # final tx qrs are versions 23,24,25 with open(file, "rb") as f: psbt = f.read() - # def split_qrs(raw, type_code, encoding=None, - # min_split=1, max_split=1295, min_version=5, max_version=40 - actual_vers, parts = split_qrs(psbt, 'P', max_version=20, encoding="2") - random.shuffle(parts) - - for p in parts: - scan_a_qr(p) - time.sleep(4.0 / len(parts)) # just so we can watch - - for r in range(20): - title, story = cap_story() - if 'OK TO SEND' in title: - break - time.sleep(.1) - else: - raise pytest.fail('never saw it?') - - # approve it - press_select() - time.sleep(.3) - - # expect signed txn back - file_type, rb = readback_bbqr() - assert file_type in 'TP' + _, file_type, rb = try_sign_bbqr(psbt, type_code="P", max_version=20, encoding="2") press_cancel() # back to menu @@ -394,5 +399,17 @@ KDOloGMDU3fv+Y3NRSe17SoO4uSKo9IUU2+baJ/pqaHZBuvmW6j5nnv/N4M5BCVawiUig/qzExZpFsA7 title, story = cap_story() assert "Good signature by address" in story +@pytest.mark.qrcode +@pytest.mark.manual +@pytest.mark.parametrize("i", range(1,25)) +def test_qr_sizes(i, dev, fake_txn, press_cancel, cap_screen_qr, try_sign_bbqr): + + # QRs from version 10 to version 25, everything from v26(included) and above is BBQR + # only v17 contains 2 lines of txid + psbt = fake_txn(1, i, dev.master_xpub, addr_fmt='p2wpkh') + + try_sign_bbqr(psbt, type_code="P") + cap_screen_qr() + press_cancel() # EOF diff --git a/testing/test_bip39pw.py b/testing/test_bip39pw.py index decd2b47..4dde91ae 100644 --- a/testing/test_bip39pw.py +++ b/testing/test_bip39pw.py @@ -50,7 +50,7 @@ def test_b9p_basic(pw, set_bip39_pw): set_bip39_pw(pw) -@pytest.fixture() +@pytest.fixture def set_bip39_pw(dev, need_keypress, reset_seed_words, cap_story, sim_execfile, press_select): @@ -274,10 +274,9 @@ def test_cancel_on_empty_added_numbers(pick_menu_item, is_q1, cap_menu, @pytest.mark.parametrize('stype', ["bip39pw", "words", "xprv", None]) -def test_lockdown_ux(stype, pick_menu_item, set_bip39_pw, goto_home, - press_cancel, get_setting, reset_seed_words, - generate_ephemeral_words, import_ephemeral_xprv, - press_select, is_q1, cap_story, cap_menu): +def test_lockdown_ux(stype, pick_menu_item, set_bip39_pw, goto_home, is_q1, + get_setting, reset_seed_words, import_ephemeral_xprv, + generate_ephemeral_words, cap_story, cap_menu, press_select): # test UX and operation of the 'seed lockdown' option if stype: @@ -313,7 +312,10 @@ def test_lockdown_ux(stype, pick_menu_item, set_bip39_pw, goto_home, assert "Convert currently used BIP-39 passphrase to master seed" in story assert "but the passphrase itself is erased" in story - press_cancel() + assert "Press (4) to prove you read to the end of this message and accept all consequences" in story + press_select() # enter does not active, sends you back to menu + time.sleep(.1) + assert "Lock Down Seed" in cap_menu() reset_seed_words() # real code does reboot, which is poorly simulated; avoid that # this needs to be tested with real HW !!! @@ -484,7 +486,6 @@ def test_tmp_on_xprv_master(generate_ephemeral_words, cap_menu, go_to_passphrase time.sleep(.1) title, story = cap_story() - assert parent_fp in title # no choice story assert "current active temporary seed" in story press_select() diff --git a/testing/test_bsms.py b/testing/test_bsms.py index e93968f0..eb6a6d11 100644 --- a/testing/test_bsms.py +++ b/testing/test_bsms.py @@ -103,7 +103,7 @@ def bsms_sr1_fname(token, is_extended, suffix, index=None): @pytest.fixture def make_signer_round1(settings_get, settings_set, settings_remove, microsd_path, virtdisk_path): def doit(token, way, root_xprv=None, bsms_version=BSMS_VERSION, description=None, purge_bsms=True, - add_to_settings=False, data_only=False, index=None, wrong_sig=False, wrong_encryption=False, slip=False): + add_to_settings=False, data_only=False, index=None, wrong_sig=False, wrong_encryption=False): is_extended = len(token) == 32 if purge_bsms: settings_remove(BSMS_SETTINGS) # clear bsms @@ -123,8 +123,6 @@ def make_signer_round1(settings_get, settings_set, settings_remove, microsd_path path = random.choice(paths) sk = wk.subkey_for_path(path) xpub = sk.hwif(as_private=False) - if slip: - xpub = xpub.replace("tpub", random.choice(["upub", "vpub", "Upub", "Vpub"])) key_expr = "[%s/%s]%s" % (root_xfp, path, xpub) data = "%s\n" % bsms_version data += "%s\n" % token @@ -269,9 +267,10 @@ def make_coordinator_round2(make_coordinator_round1, settings_get, settings_set, @pytest.mark.parametrize("encryption_type", ["1", "2", "3"]) @pytest.mark.parametrize("M_N", [(2,2), (3, 5), (15, 15)]) @pytest.mark.parametrize("addr_fmt", ["p2wsh", "p2sh-p2wsh"]) -def test_coordinator_round1(way, encryption_type, M_N, addr_fmt, clear_ms, goto_home, need_keypress, +def test_coordinator_round1(way, encryption_type, M_N, addr_fmt, clear_miniscript, goto_home, need_keypress, pick_menu_item, cap_menu, cap_story, microsd_path, settings_remove, - nfc_read_text, request, settings_get, microsd_wipe, press_select, is_q1): + nfc_read_text, request, settings_get, microsd_wipe, press_select, + is_q1, press_cancel): if way == "vdisk": virtdisk_wipe = request.getfixturevalue("virtdisk_wipe") virtdisk_path = request.getfixturevalue("virtdisk_path") @@ -283,7 +282,7 @@ def test_coordinator_round1(way, encryption_type, M_N, addr_fmt, clear_ms, goto_ settings_remove(BSMS_SETTINGS) # clear bsms goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') pick_menu_item('BSMS (BIP-129)') title, story = cap_story() assert "Bitcoin Secure Multisig Setup (BIP-129) is a mechanism to securely create multisig wallets." in story @@ -335,7 +334,7 @@ def test_coordinator_round1(way, encryption_type, M_N, addr_fmt, clear_ms, goto_ time.sleep(0.2) bsms_tokens = nfc_read_text() time.sleep(0.2) - press_select() # exit NFC UI simulation + press_cancel() # exit NFC UI simulation time.sleep(0.5) else: # virtual disk @@ -423,10 +422,10 @@ def test_coordinator_round1(way, encryption_type, M_N, addr_fmt, clear_ms, goto_ @pytest.mark.parametrize("encryption_type", ["1", "2", "3"]) @pytest.mark.parametrize("M_N", [(2,2), (3, 5), (15, 15)]) @pytest.mark.parametrize("addr_fmt", ["p2wsh", "p2sh-p2wsh"]) -def test_signer_round1(way, encryption_type, M_N, addr_fmt, clear_ms, goto_home, need_keypress, pick_menu_item, cap_menu, +def test_signer_round1(way, encryption_type, M_N, addr_fmt, clear_miniscript, goto_home, need_keypress, cap_story, microsd_path, settings_remove, nfc_read_text, request, settings_get, make_coordinator_round1, nfc_write_text, microsd_wipe, press_select, - is_q1): + is_q1, pick_menu_item, cap_menu, press_cancel): if way == "vdisk": virtdisk_wipe = request.getfixturevalue("virtdisk_wipe") virtdisk_path = request.getfixturevalue("virtdisk_path") @@ -441,7 +440,7 @@ def test_signer_round1(way, encryption_type, M_N, addr_fmt, clear_ms, goto_home, assert tokens == [] goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') pick_menu_item('BSMS (BIP-129)') title, story = cap_story() assert "Bitcoin Secure Multisig Setup (BIP-129) is a mechanism to securely create multisig wallets." in story @@ -513,7 +512,7 @@ def test_signer_round1(way, encryption_type, M_N, addr_fmt, clear_ms, goto_home, time.sleep(0.2) signer_r1 = nfc_read_text() time.sleep(0.2) - press_select() # exit NFC UI simulation + press_cancel() # exit NFC UI simulation time.sleep(0.5) else: # virtual disk @@ -580,10 +579,10 @@ def test_signer_round1(way, encryption_type, M_N, addr_fmt, clear_ms, goto_home, @pytest.mark.parametrize("M_N", [(2,2), (3, 5), (15, 15)]) @pytest.mark.parametrize("addr_fmt", ["p2wsh", "p2sh-p2wsh"]) @pytest.mark.parametrize("auto_collect", [True, False]) -def test_coordinator_round2(way, encryption_type, M_N, addr_fmt, auto_collect, clear_ms, goto_home, need_keypress, +def test_coordinator_round2(way, encryption_type, M_N, addr_fmt, auto_collect, clear_miniscript, goto_home, cap_menu, cap_story, microsd_path, settings_remove, nfc_read_text, request, settings_get, make_coordinator_round1, make_signer_round1, nfc_write_text, - microsd_wipe, pick_menu_item, press_select, is_q1): + microsd_wipe, pick_menu_item, press_select, is_q1, need_keypress, press_cancel): def get_token(index): if len(tokens) == 1 and encryption_type == "1": token = tokens[0] @@ -612,7 +611,7 @@ def test_coordinator_round2(way, encryption_type, M_N, addr_fmt, auto_collect, c goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') pick_menu_item('BSMS (BIP-129)') title, story = cap_story() assert "Bitcoin Secure Multisig Setup (BIP-129) is a mechanism to securely create multisig wallets." in story @@ -724,7 +723,7 @@ def test_coordinator_round2(way, encryption_type, M_N, addr_fmt, auto_collect, c rv = nfc_read_text() time.sleep(.5) descriptor_templates.append(rv) - press_select() # exit animation + press_cancel() # exit animation time.sleep(.1) title, story = cap_story() @@ -735,7 +734,7 @@ def test_coordinator_round2(way, encryption_type, M_N, addr_fmt, auto_collect, c rv = nfc_read_text() time.sleep(.5) descriptor_templates.append(rv) - press_select() # exit animation + press_cancel() # exit animation else: if way == "sd": path_fn = microsd_path @@ -805,7 +804,7 @@ def test_coordinator_round2(way, encryption_type, M_N, addr_fmt, auto_collect, c @pytest.mark.parametrize("with_checksum", [True, False]) @pytest.mark.parametrize("M_N", [(2,2), (3, 5), (15, 15)]) @pytest.mark.parametrize("addr_fmt", ["p2wsh", "p2sh-p2wsh"]) -def test_signer_round2(refuse, way, encryption_type, M_N, addr_fmt, clear_ms, goto_home, need_keypress, pick_menu_item, +def test_signer_round2(refuse, way, encryption_type, M_N, addr_fmt, clear_miniscript, goto_home, need_keypress, pick_menu_item, cap_menu, cap_story, microsd_path, settings_remove, nfc_read_text, request, settings_get, make_coordinator_round2, nfc_write_text, microsd_wipe, with_checksum, press_select, press_cancel, is_q1): @@ -814,12 +813,12 @@ def test_signer_round2(refuse, way, encryption_type, M_N, addr_fmt, clear_ms, go virtdisk_path = request.getfixturevalue("virtdisk_path") virtdisk_wipe() M, N = M_N - clear_ms() + clear_miniscript() microsd_wipe() desc_template, token = make_coordinator_round2(M, N, addr_fmt, encryption_type, way=way, add_checksum=with_checksum) goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') pick_menu_item('BSMS (BIP-129)') title, story = cap_story() assert "Bitcoin Secure Multisig Setup (BIP-129) is a mechanism to securely create multisig wallets." in story @@ -874,18 +873,17 @@ def test_signer_round2(refuse, way, encryption_type, M_N, addr_fmt, clear_ms, go time.sleep(0.5) _, story = cap_story() - assert "Create new multisig wallet?" in story + assert "Create new miniscript wallet?" in story assert "bsms" in story # part of the name policy = "Policy: %d of %d" % (M, N) assert policy in story assert addr_fmt.upper() in story ms_wal_name = story.split("\n\n")[1].split("\n")[-1].strip() - ms_wal_menu_item = "%d/%d: %s" % (M, N, ms_wal_name) if refuse: press_cancel() time.sleep(0.1) menu = cap_menu() - assert ms_wal_menu_item not in menu + assert ms_wal_name not in menu bsms_settings = settings_get(BSMS_SETTINGS) # signer round 2 NOT removed assert bsms_settings.get(BSMS_SIGNER_SETTINGS) @@ -893,7 +891,7 @@ def test_signer_round2(refuse, way, encryption_type, M_N, addr_fmt, clear_ms, go press_select() time.sleep(0.1) menu = cap_menu() - assert ms_wal_menu_item in menu + assert ms_wal_name in menu bsms_settings = settings_get(BSMS_SETTINGS) # signer round 2 removed assert not bsms_settings.get(BSMS_SIGNER_SETTINGS, None) @@ -911,7 +909,7 @@ def test_invalid_token_signer_round1(token, way, pick_menu_item, cap_story, need press_select, is_q1): goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') pick_menu_item('BSMS (BIP-129)') title, story = cap_story() assert "Bitcoin Secure Multisig Setup (BIP-129) is a mechanism to securely create multisig wallets." in story @@ -963,7 +961,7 @@ def test_invalid_token_signer_round1(token, way, pick_menu_item, cap_story, need assert "Invalid token length. Expected 64 or 128 bits (16 or 32 hex characters)" in story -@pytest.mark.parametrize("failure", ["slip", "wrong_sig", "bsms_version"]) +@pytest.mark.parametrize("failure", ["wrong_sig", "bsms_version"]) @pytest.mark.parametrize("encryption_type", ["1", "2", "3"]) def test_failure_coordinator_round2(encryption_type, make_coordinator_round1, make_signer_round1, microsd_wipe, cap_menu, pick_menu_item, press_select, goto_home, cap_story, failure, @@ -992,7 +990,7 @@ def test_failure_coordinator_round2(encryption_type, make_coordinator_round1, ma make_signer_round1(token, "sd", purge_bsms=False, index=index, **kws) goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') pick_menu_item('BSMS (BIP-129)') title, story = cap_story() assert "Bitcoin Secure Multisig Setup (BIP-129) is a mechanism to securely create multisig wallets." in story @@ -1028,9 +1026,7 @@ def test_failure_coordinator_round2(encryption_type, make_coordinator_round1, ma title, story = cap_story() assert title == "FAILURE" assert "BSMS coordinator round2 failed" in story - if failure == "slip": - failure_msg = "no slip" - elif failure == "wrong_sig": + if failure == "wrong_sig": failure_msg = "Recovered key from signature does not equal key provided. Wrong signature?" else: failure_msg = "Incompatible BSMS version. Need BSMS 1.0 got BSMS 1.1" @@ -1061,7 +1057,7 @@ def test_wrong_encryption_coordinator_round2(encryption_type, make_coordinator_r make_signer_round1(token, "sd", purge_bsms=False, index=index, wrong_encryption=True) goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') pick_menu_item('BSMS (BIP-129)') title, story = cap_story() assert "Bitcoin Secure Multisig Setup (BIP-129) is a mechanism to securely create multisig wallets." in story @@ -1154,7 +1150,7 @@ def test_failure_signer_round2(encryption_type, goto_home, press_select, pick_me failure_msg = failure_msg.format(token=token[:4]) goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') pick_menu_item('BSMS (BIP-129)') title, story = cap_story() assert "Bitcoin Secure Multisig Setup (BIP-129) is a mechanism to securely create multisig wallets." in story @@ -1183,7 +1179,7 @@ def test_failure_signer_round2(encryption_type, goto_home, press_select, pick_me @pytest.mark.parametrize("encryption_type", ["1", "2", "3"]) @pytest.mark.parametrize("M_N", [(2,2), (3, 5), (15, 15)]) @pytest.mark.parametrize("addr_fmt", ["p2wsh", "p2sh-p2wsh"]) -def test_integration_signer(encryption_type, M_N, addr_fmt, clear_ms, microsd_wipe, goto_home, pick_menu_item, cap_story, +def test_integration_signer(encryption_type, M_N, addr_fmt, clear_miniscript, microsd_wipe, goto_home, pick_menu_item, cap_story, press_select, settings_remove, microsd_path, settings_get, cap_menu, use_mainnet, need_keypress): # test CC signer full with bsms lib coordinator (test just SD card no need to retest IO paths again - tested above) @@ -1199,7 +1195,7 @@ def test_integration_signer(encryption_type, M_N, addr_fmt, clear_ms, microsd_wi M, N = M_N settings_remove(BSMS_SETTINGS) use_mainnet() - clear_ms() + clear_miniscript() microsd_wipe() coordinator = CoordinatorSession(M, N, addr_fmt, et_map[encryption_type]) session_data = coordinator.generate_token_key_pairs() @@ -1211,7 +1207,7 @@ def test_integration_signer(encryption_type, M_N, addr_fmt, clear_ms, microsd_wi # ROUND 1 goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') pick_menu_item('BSMS (BIP-129)') title, story = cap_story() assert "Bitcoin Secure Multisig Setup (BIP-129) is a mechanism to securely create multisig wallets." in story @@ -1292,7 +1288,7 @@ def test_integration_signer(encryption_type, M_N, addr_fmt, clear_ms, microsd_wi time.sleep(0.1) goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') pick_menu_item('BSMS (BIP-129)') title, story = cap_story() assert "Bitcoin Secure Multisig Setup (BIP-129) is a mechanism to securely create multisig wallets." in story @@ -1311,17 +1307,16 @@ def test_integration_signer(encryption_type, M_N, addr_fmt, clear_ms, microsd_wi pick_menu_item(menu_item) time.sleep(0.1) title, story = cap_story() - assert "Create new multisig wallet?" in story + assert "Create new miniscript wallet?" in story assert "bsms" in story # part of the name policy = "Policy: %d of %d" % (M, N) assert policy in story assert addr_fmt.upper() in story ms_wal_name = story.split("\n\n")[1].split("\n")[-1].strip() - ms_wal_menu_item = "%d/%d: %s" % (M, N, ms_wal_name) press_select() time.sleep(0.1) menu = cap_menu() - assert ms_wal_menu_item in menu + assert ms_wal_name in menu bsms_settings = settings_get(BSMS_SETTINGS) # signer round 2 removed assert not bsms_settings.get(BSMS_SIGNER_SETTINGS, None) @@ -1331,17 +1326,17 @@ def test_integration_signer(encryption_type, M_N, addr_fmt, clear_ms, microsd_wi @pytest.mark.parametrize("M_N", [(2,2), (3, 5), (15, 15)]) @pytest.mark.parametrize("addr_fmt", ["p2wsh", "p2sh-p2wsh"]) @pytest.mark.parametrize("cr1_shortcut", [True, False]) -def test_integration_coordinator(encryption_type, M_N, addr_fmt, clear_ms, microsd_wipe, goto_home, pick_menu_item, +def test_integration_coordinator(encryption_type, M_N, addr_fmt, clear_miniscript, microsd_wipe, goto_home, pick_menu_item, cap_story, need_keypress, settings_remove, microsd_path, settings_get, cap_menu, use_mainnet, cr1_shortcut, press_select): M, N = M_N settings_remove(BSMS_SETTINGS) use_mainnet() - clear_ms() + clear_miniscript() microsd_wipe() goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') pick_menu_item('BSMS (BIP-129)') title, story = cap_story() assert "Bitcoin Secure Multisig Setup (BIP-129) is a mechanism to securely create multisig wallets." in story @@ -1470,7 +1465,7 @@ def test_integration_coordinator(encryption_type, M_N, addr_fmt, clear_ms, micro goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') pick_menu_item('BSMS (BIP-129)') title, story = cap_story() assert "Bitcoin Secure Multisig Setup (BIP-129) is a mechanism to securely create multisig wallets." in story @@ -1547,7 +1542,7 @@ def test_integration_coordinator(encryption_type, M_N, addr_fmt, clear_ms, micro # still need to add our signer goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') pick_menu_item('BSMS (BIP-129)') press_select() pick_menu_item('Signer') @@ -1562,17 +1557,16 @@ def test_integration_coordinator(encryption_type, M_N, addr_fmt, clear_ms, micro pick_menu_item(fnames[0]) time.sleep(0.1) title, story = cap_story() - assert "Create new multisig wallet?" in story + assert "Create new miniscript wallet?" in story assert "bsms" in story # part of the name policy = "Policy: %d of %d" % (M, N) assert policy in story assert addr_fmt.upper() in story ms_wal_name = story.split("\n\n")[1].split("\n")[-1].strip() - ms_wal_menu_item = "%d/%d: %s" % (M, N, ms_wal_name) press_select() time.sleep(0.1) menu = cap_menu() - assert ms_wal_menu_item in menu + assert ms_wal_name in menu bsms_settings = settings_get(BSMS_SETTINGS) # signer round 2 removed assert not bsms_settings.get(BSMS_SIGNER_SETTINGS, None) @@ -1637,7 +1631,7 @@ def test_auto_collection_coordinator_r2(encryption_type, M_N, goto_home, need_ke all_data.append(make_signer_round1(token, "sd", purge_bsms=False, index=index)) goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') pick_menu_item('BSMS (BIP-129)') title, story = cap_story() assert "Bitcoin Secure Multisig Setup (BIP-129) is a mechanism to securely create multisig wallets." in story diff --git a/testing/test_ccc.py b/testing/test_ccc.py new file mode 100644 index 00000000..2e83b33d --- /dev/null +++ b/testing/test_ccc.py @@ -0,0 +1,1267 @@ +# (c) Copyright 2024 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# +# tests related to CCC feature +# +# run simulator without --eff +# +# +import pytest, pdb, requests, re, time, random, json, glob, os, hashlib, base64, uuid +from base64 import urlsafe_b64encode +from onetimepass import get_totp +from helpers import prandom, slip132undo +from pysecp256k1.ecdh import ecdh, ECDH_HASHFP_CLS +from pysecp256k1 import ec_seckey_verify, ec_pubkey_parse, ec_pubkey_serialize, ec_pubkey_create +from mnemonic import Mnemonic +from bip32 import BIP32Node +from constants import AF_P2WSH +from charcodes import KEY_QR, KEY_DELETE +from bbqr import split_qrs +from psbt import BasicPSBT + +# pubkey for production server. +SERVER_PUBKEY = '0231301ec4acec08c1c7d0181f4ffb8be70d693acccc86cccb8f00bf2e00fcabfd' + +@pytest.fixture +def goto_ccc_menu(goto_home, pick_menu_item, is_mark4): + def doit(): + goto_home() + pick_menu_item("Advanced/Tools") + pick_menu_item("Spending Policy") + pick_menu_item("Co-Sign Multi." if is_mark4 else "Co-Sign Multisig (CCC)") + + return doit + +def make_session_key(his_pubkey=None): + + # - second call: given the pubkey of far side, calculate the shared pt on curve + # - creates session key based on that + while True: + my_seckey = prandom(32) + try: + ec_seckey_verify(my_seckey) + break + except: continue + + my_pubkey = ec_pubkey_create(my_seckey) + + his_pubkey = ec_pubkey_parse(bytes.fromhex(SERVER_PUBKEY)) + + # do the D-H thing + + def _py_ckcc_hashfp(output, x, y, data=None): + try: + m = hashlib.sha256() + m.update(x.contents.raw) + m.update(y.contents.raw) + output.contents.raw = m.digest() + return 1 + except: + return 0 + + ckcc_hashfp = ECDH_HASHFP_CLS(_py_ckcc_hashfp) + + shared_key = ecdh(my_seckey, his_pubkey, hashfp=ckcc_hashfp) + + return shared_key, ec_pubkey_serialize(my_pubkey) + + +@pytest.fixture +def make_2fa_url(request): + def doit(shared_secret=b'A'*16, nonce='12345678', + wallet='Example wallet name', is_q=0, encrypted=False): + + lh = request.config.getoption("--localhost") + + base = 'http://127.0.0.1:5070/2fa?' if lh else 'https://coldcard.com/2fa?' + + assert is_q in {0, 1} + assert len(shared_secret) == 16 # base32 + assert isinstance(nonce, str) # hex digits or 8 dec digits in Mk4 mode + + from urllib.parse import quote + + qs = f'ss={shared_secret}&q={is_q}&g={nonce}&nm={quote(wallet)}' + + print(f'2fa URL: {qs}') + + if not encrypted: + return base + qs + + # pick eph key + ses_key, pubkey = make_session_key() + + import pyaes + enc = pyaes.AESModeOfOperationCTR(ses_key, pyaes.Counter(0)).encrypt + + qs = urlsafe_b64encode(pubkey + enc(qs.encode('ascii'))).rstrip(b'=') + + return base + qs.decode('ascii') + + return doit + +@pytest.fixture +def roundtrip_2fa(): + def doit(url, shared_secret, local=False): + if local: + url = url.replace('https://coldcard.com/', 'http://127.0.0.1:5070/') + + if int(time.time() % 30) > 29: + # avoid end of time period + time.sleep(3) + + # build right TOTP answer + answer = '%06d' % get_totp(shared_secret) + assert len(answer) == 6 + + # send both request and answer at same time (we know it works that way) + resp = requests.post(url, data=dict(answer=answer)) + + # server HTML will have this line in response for our use + # + + if ' actual words @@ -397,6 +399,7 @@ def generate_ephemeral_words(goto_eph_seed_menu, pick_menu_item, press_select, assert len(e_seed_words) == num_words need_keypress("6") # skip quiz + time.sleep(.1) press_select() # yes - I'm sure confirm_tmp_seed(seedvault=seed_vault) @@ -792,9 +795,6 @@ def test_seed_vault_menus(dev, data, settings_set, master_settings_get, pick_men sim_exec, goto_home, seed_vault_enable, is_q1, enter_text, press_select, press_cancel, press_delete): # Verify "seed vault" feature works as intended - - - reset_seed_words() xfp, entropy, mnemonic = data @@ -854,6 +854,18 @@ def test_seed_vault_menus(dev, data, settings_set, master_settings_get, pick_men m = cap_menu() assert m[0] == "AAAA" + pick_menu_item("AAAA") # bug issues/920 + # would be yikes here, if not fixed + time.sleep(.1) + _, story = cap_story() + assert "AAAA" in story + assert xfp in story + if mnemonic: + assert ('%d words' % (6 * (vlen // 8))) in story + else: + assert 'xprv' in story + press_cancel() + # check parent menu - must be updated too press_cancel() m = cap_menu() @@ -889,7 +901,7 @@ def test_seed_vault_menus(dev, data, settings_set, master_settings_get, pick_men e_master_xpub = dev.send_recv(CCProtocolPacker.get_xpub(), timeout=5000) assert e_master_xpub != simulator_fixed_tpub - psbt = fake_txn(2, 2, master_xpub=e_master_xpub, segwit_in=True) + psbt = fake_txn(2, 2, master_xpub=e_master_xpub, addr_fmt=random.choice(ADDR_STYLES_SINGLE)) try_sign(psbt, accept=True, finalize=True) # MUST NOT raise press_select() @@ -1241,16 +1253,37 @@ def test_xfp_collision(reset_seed_words, settings_set, import_ephemeral_xprv, @pytest.mark.parametrize("refuse", [False, True]) def test_add_current_active(reset_seed_words, settings_set, import_ephemeral_xprv, goto_home, pick_menu_item, cap_story, cap_menu, - press_cancel, verify_ephemeral_secret_ui, - seed_vault_enable, refuse, press_select): + press_cancel, verify_ephemeral_secret_ui, is_q1, + seed_vault_enable, refuse, press_select, set_bip39_pw, + need_some_notes, need_some_passwords, import_ms_wallet, + restore_main_seed, settings_get, clear_miniscript): ADD_MI = "Add current tmp" reset_seed_words() goto_home() seed_vault_enable(True) + # clear settings_set("seeds", []) + clear_miniscript() + settings_set("notes", []) + + if not refuse: + # add something to seed vault + sv_pass_xfp = set_bip39_pw('dogsNcats', seed_vault=True, reset=False) + restore_main_seed(seed_vault=True) + + # add secure notes and passwords + if is_q1: + need_some_notes() + need_some_passwords() + + # save multisig wallet to master settings + ms_name = "aaa" + import_ms_wallet(2,3,"p2wsh", name=ms_name, accept=True) + + time.sleep(.2) + goto_home() - time.sleep(.2) # in master - do not offer pick_menu_item("Seed Vault") time.sleep(.1) @@ -1281,19 +1314,33 @@ def test_add_current_active(reset_seed_words, settings_set, import_ephemeral_xpr else: press_select() verify_ephemeral_secret_ui(xpub=node.hwif(), seed_vault=True) + restore_main_seed(seed_vault=True) + time.sleep(.2) + curr_xfp = settings_get("xfp", None) + assert curr_xfp is not None + assert curr_xfp != 0 + mss = settings_get("miniscript") + assert len(mss) == 1 + assert mss[0][0] == ms_name + if is_q1: + assert len(settings_get("notes")) == 3 + sv = settings_get("seeds") + assert len(sv) == 2 + assert sv[0][0] == xfp2str(sv_pass_xfp) # added passphrase wallet + assert sv[1][0] == xfp # added via `Add current tmp` -@pytest.mark.parametrize('multisig', [False, 'multisig']) +@pytest.mark.parametrize('multisig', [True, False]) @pytest.mark.parametrize('seedvault', [False, True]) @pytest.mark.parametrize('data', SEEDVAULT_TEST_DATA) def test_temporary_from_backup(multisig, backup_system, import_ms_wallet, get_setting, data, press_select, cap_story, set_encoded_secret, - reset_seed_words, check_and_decrypt_backup, + reset_seed_words, check_and_decrypt_backup, clear_miniscript, goto_eph_seed_menu, pick_menu_item, word_menu_entry, verify_ephemeral_secret_ui, seedvault, settings_set, - seed_vault_enable, confirm_tmp_seed, settings_path, - seed_vault_delete, restore_main_seed, set_seed_words): - + seed_vault_enable, confirm_tmp_seed, set_seed_words, + seed_vault_delete, restore_main_seed, settings_slots): + xfp_str, encoded_str, mnemonic = data if mnemonic: set_seed_words(mnemonic) @@ -1302,12 +1349,15 @@ def test_temporary_from_backup(multisig, backup_system, import_ms_wallet, get_se set_encoded_secret(encoded) settings_set("chain", "XTN") + clear_miniscript() if multisig: import_ms_wallet(15, 15, dev_key=True) press_select() time.sleep(.1) - assert len(get_setting('multisig')) == 1 + assert len(get_setting('miniscript')) == 1 + else: + assert get_setting('miniscript') is None # ACTUAL BACKUP bk_pw = backup_system() @@ -1317,6 +1367,14 @@ def test_temporary_from_backup(multisig, backup_system, import_ms_wallet, get_se check_and_decrypt_backup(fname, bk_pw) + # remove all saved slots, one of them will be the one where we just created backup + # slot where backup was created needs to be removed - otherwise we will load back to it + # and see multisig wallet there without the need for backup to actually copy it + for s in settings_slots(): + try: + os.remove(s) + except: pass + # restore fixed simulator reset_seed_words() seed_vault_enable(seedvault) @@ -1329,20 +1387,103 @@ def test_temporary_from_backup(multisig, backup_system, import_ms_wallet, get_se word_menu_entry(bk_pw, has_checksum=False) + time.sleep(.5) + title, story = cap_story() + assert f"[{xfp_str}]" == title + assert "Above is the master fingerprint of the seed stored in the backup." in story + assert f"load backup as temporary seed" in story + press_select() + confirm_tmp_seed(seedvault) time.sleep(.1) if mnemonic: mnemonic = mnemonic.split(" ") - xfp = verify_ephemeral_secret_ui(mnemonic=mnemonic, xpub=None, # xpub veriphy ephemeral secret not tested here + xfp = verify_ephemeral_secret_ui(mnemonic=mnemonic, xpub=None, # XPUB verify ephemeral secret not tested here seed_vault=seedvault) + # actual bug, multisig key copied with "setting." prefix -> therefore not visible in Multisig menu + assert get_setting("setting.miniscript") is None + # correct multisig was copied during loading backup as tmp seed + ms = get_setting('miniscript') + if multisig: + assert len(ms) == 1 + assert ms[0][-1]["m_n"] == [15,15] + else: + assert ms is None + if seedvault: - seed_vault_delete(xfp, not False) + seed_vault_delete(xfp, True) else: restore_main_seed(False) +@pytest.mark.parametrize('btype', ["classic", "custom_bkpw", "plaintext"]) +def test_temporary_from_backup_usb(backup_system, set_seed_words, cap_story, verify_ephemeral_secret_ui, + settings_slots, reset_seed_words, word_menu_entry, confirm_tmp_seed, + dev, microsd_path, press_select, btype, enter_complex): + + xfp_str, encoded_str, mnemonic = SEEDVAULT_TEST_DATA[0] + set_seed_words(mnemonic) + bkpw = 32*"X" + plaintext = (btype == "plaintext") + password = False + + # ACTUAL BACKUP + if plaintext: + bk_pw = backup_system(ct=True) + elif btype == "custom_bkpw": + # encrypted but with custom pwd + password = True + bk_pw = backup_system(reuse_pw=[bkpw]) + else: + # classic word-based encrypted backup + bk_pw = backup_system() + + time.sleep(.1) + title, story = cap_story() + fname = story.split("\n\n")[1] + + # remove all saved slots, one of them will be the one where we just created backup + # slot where backup was created needs to be removed - otherwise we will load back to it + # and see multisig wallet there without the need for backup to actually copy it + for s in settings_slots(): + try: + os.remove(s) + except: pass + + # restore fixed simulator + reset_seed_words() + + from ckcc_protocol.protocol import CCProtocolPacker + with open(microsd_path(fname), "rb") as f: + file_len, sha = dev.upload_file(f.read()) + + dev.send_recv(CCProtocolPacker.restore_backup(file_len, sha, password, plaintext), timeout=None) + time.sleep(.2) + _, story = cap_story() + assert "Restore uploaded backup as a temporary seed" in story + press_select() + + time.sleep(.1) + if btype == "classic": + word_menu_entry(bk_pw, has_checksum=False) + elif password: + enter_complex(bkpw, apply=False, b39pass=False) + + time.sleep(.5) + title, story = cap_story() + assert f"[{xfp_str}]" == title + assert "Above is the master fingerprint of the seed stored in the backup." in story + assert f"load backup as temporary seed" in story + press_select() + + time.sleep(.1) + confirm_tmp_seed(seedvault=False) + time.sleep(.1) + mnemonic = mnemonic.split(" ") + verify_ephemeral_secret_ui(mnemonic=mnemonic, xpub=None, seed_vault=False) + def test_tmp_upgrade_disabled(reset_seed_words, pick_menu_item, cap_story, cap_menu, goto_home, unit_test, @@ -1479,26 +1620,30 @@ def test_home_menu_xfp(goto_home, pick_menu_item, press_select, cap_story, cap_m pick_menu_item("Always Show") time.sleep(.3) m = cap_menu() - assert m[1] == "Ready To Sign" assert m[0] == "<" + xfp2str(settings_get("xfp")) + ">" + assert m[1] == "Ready To Sign" + goto_eph_seed_menu() pick_menu_item("Generate Words") pick_menu_item(f"12 Words") time.sleep(0.1) - need_keypress("6") # skip words + need_keypress("6") # skip quiz press_select() + time.sleep(.1) _, story = cap_story() if "Press (1) to store temporary seed" in story: # seed vault enabled press_select() # do not save press_select() # new tmp seed + time.sleep(.2) m = cap_menu() assert m[1] == "Ready To Sign" assert m[0] == "[" + xfp2str(settings_get("xfp")) + "]" pick_menu_item("Restore Master") press_select() + time.sleep(.3) m = cap_menu() assert m[1] == "Ready To Sign" @@ -1506,11 +1651,13 @@ def test_home_menu_xfp(goto_home, pick_menu_item, press_select, cap_story, cap_m # disable now pick_menu_item("Settings") pick_menu_item("Home Menu XFP") + time.sleep(.1) _, story = cap_story() if "Forces display of XFP" in story: press_select() pick_menu_item("Only Tmp") + time.sleep(.3) m = cap_menu() assert m[0] == "Ready To Sign" diff --git a/testing/test_export.py b/testing/test_export.py index 46a7c8f7..4466859c 100644 --- a/testing/test_export.py +++ b/testing/test_export.py @@ -332,24 +332,25 @@ def test_export_electrum(way, dev, mode, acct_num, pick_menu_item, goto_home, ca @pytest.mark.parametrize('acct_num', [ None, '99', '1236']) @pytest.mark.parametrize('way', ["sd", "vdisk", "nfc", "qr"]) -@pytest.mark.parametrize('chain', ["BTC", "XTN"]) +@pytest.mark.parametrize('netcode', ["XTN", "BTC"]) @pytest.mark.parametrize('app', [ # no need to run them all - just name check differs ("Generic JSON", "Generic Export"), - ("Nunchuk", "Nunchuk Wallet"), + # ("Nunchuk", "Nunchuk Wallet"), # These differ only in the menu title. If that changes, add them back here... test latest only # ("Lily Wallet", "Lily Wallet"), # ("Sparrow Wallet", "Sparrow Wallet"), - ("Theya", "Theya Wallet"), + # ("Theya", "Theya Wallet"), + ("Bitcoin Safe", "Bitcoin Safe Wallet"), ]) def test_export_coldcard(way, dev, acct_num, app, pick_menu_item, goto_home, cap_story, need_keypress, microsd_path, nfc_read_json, virtdisk_path, addr_vs_path, enter_number, - load_export, chain, use_mainnet, press_select, + load_export, netcode, use_mainnet, press_select, skip_if_useless_way, expect_acctnum_captured): skip_if_useless_way(way) - if chain == "BTC": + if netcode == "BTC": use_mainnet() export_mi, app_f_name = app @@ -404,8 +405,8 @@ def test_export_coldcard(way, dev, acct_num, app, pick_menu_item, goto_home, cap addr = v.get('first', None) if fn == 'bip44': - assert first.address(chain=chain) == v['first'] - addr_vs_path(addr, v['deriv'] + '/0/0', AF_CLASSIC, chain=chain) + assert first.address(chain=netcode) == v['first'] + addr_vs_path(addr, v['deriv'] + '/0/0', AF_CLASSIC, chain=netcode) elif ('bip48_' in fn) or (fn == 'bip45'): # multisig: cant do addrs assert addr == None @@ -416,11 +417,11 @@ def test_export_coldcard(way, dev, acct_num, app, pick_menu_item, goto_home, cap h20 = first.hash160() if fn == 'bip84': assert addr == bech32.encode(addr[0:2], 0, h20) - addr_vs_path(addr, v['deriv'] + '/0/0', AF_P2WPKH, chain=chain) + addr_vs_path(addr, v['deriv'] + '/0/0', AF_P2WPKH, chain=netcode) elif fn == 'bip49': # don't have test logic for verifying these addrs # - need to make script, and bleh - assert first.address(addr_fmt="p2sh-p2wpkh", chain=chain) == v['first'] + assert first.address(addr_fmt="p2sh-p2wpkh", chain=netcode) == v['first'] else: assert False @@ -458,7 +459,7 @@ def test_export_unchained(way, dev, pick_menu_item, goto_home, cap_story, need_k press_select() expect_acctnum_captured(acct_num) - obj = load_export(way, label="Unchained", is_json=True, sig_check=False) + obj = load_export(way, label="Unchained", is_json=True) ek = simulator_fixed_tprv if testnet else simulator_fixed_xprv root = BIP32Node.from_wallet_key(ek) @@ -482,14 +483,16 @@ def test_export_unchained(way, dev, pick_menu_item, goto_home, cap_story, need_k @pytest.mark.parametrize('way', ["sd", "vdisk", "nfc", "qr"]) -@pytest.mark.parametrize('chain', ["BTC", "XTN"]) +@pytest.mark.parametrize('netcode', ["BTC", "XTN"]) def test_export_public_txt(way, dev, pick_menu_item, goto_home, press_select, microsd_path, - addr_vs_path, virtdisk_path, nfc_read_text, cap_story, use_testnet, - load_export, chain, skip_if_useless_way): + addr_vs_path, virtdisk_path, nfc_read_text, cap_story, use_mainnet, + load_export, netcode, skip_if_useless_way): # test UX and values produced. skip_if_useless_way(way) - use_testnet(chain == "XTN") + if netcode == "BTC": + use_mainnet() + goto_home() pick_menu_item('Advanced/Tools') pick_menu_item('File Management') @@ -507,7 +510,7 @@ def test_export_public_txt(way, dev, pick_menu_item, goto_home, press_select, mi xfp = xfp2str(simulator_fixed_xfp).upper() - ek = simulator_fixed_tprv if chain == "XTN" else simulator_fixed_xprv + ek = simulator_fixed_tprv if netcode == "XTN" else simulator_fixed_xprv root = BIP32Node.from_wallet_key(ek) for ln in fp: @@ -543,7 +546,7 @@ def test_export_public_txt(way, dev, pick_menu_item, goto_home, press_select, mi else: raise ValueError(rhs) - addr_vs_path(rhs, path=lhs, addr_fmt=f, chain=chain) + addr_vs_path(rhs, path=lhs, addr_fmt=f, chain=netcode) @pytest.mark.qrcode @@ -552,7 +555,7 @@ def test_export_public_txt(way, dev, pick_menu_item, goto_home, press_select, mi def test_export_xpub(chain, acct_num, dev, cap_menu, pick_menu_item, goto_home, cap_story, need_keypress, enter_number, cap_screen_qr, settings_set, nfc_read_text, is_q1, press_select, press_cancel, - press_nfc, expect_acctnum_captured): + press_nfc, expect_acctnum_captured, nfc_disabled): # XPUB's via QR settings_set("chain", chain) chain_num = 0 if chain == "BTC" else 1 @@ -582,12 +585,13 @@ def test_export_xpub(chain, acct_num, dev, cap_menu, pick_menu_item, goto_home, if is_xfp: got = cap_screen_qr().decode('ascii') time.sleep(.1) - press_nfc() - time.sleep(.2) - nfc_got = nfc_read_text() - time.sleep(.2) - assert nfc_got == got == xfp2str(simulator_fixed_xfp).upper() - press_cancel() # cancel animation + if not nfc_disabled(): + press_nfc() + time.sleep(.2) + nfc_got = nfc_read_text() + time.sleep(.2) + assert nfc_got == got == xfp2str(simulator_fixed_xfp).upper() + press_cancel() # cancel animation press_cancel() # cancel QR continue @@ -619,9 +623,10 @@ def test_export_xpub(chain, acct_num, dev, cap_menu, pick_menu_item, goto_home, got_nfc_pub = nfc_read_text() time.sleep(0.1) press_cancel() # cancel animation - press_cancel() # cancel QR assert got_nfc_pub == got_pub + press_cancel() # cancel QR + time.sleep(.1) _, story = cap_story() assert got_pub[0] in 'xt' @@ -670,7 +675,9 @@ def test_export_xpub(chain, acct_num, dev, cap_menu, pick_menu_item, goto_home, def test_generic_descriptor_export(chain, addr_fmt, acct_num, goto_home, settings_set, need_keypress, expect_acctnum_captured, OK, pick_menu_item, way, cap_story, cap_menu, int_ext, settings_get, - virtdisk_path, load_export, press_select): + virtdisk_path, load_export, press_select, skip_if_useless_way): + + skip_if_useless_way(way) settings_set('chain', chain) chain_num = 1 if chain in ["XTN", "XRT"] else 0 @@ -838,6 +845,47 @@ def test_zeus_descriptor_export(addr_fmt, acct_num, goto_home, need_keypress, pi assert xpub_target in xpub +@pytest.mark.parametrize("chain", ["BTC", "XTN"]) +def test_bullbitcoin_descriptor_export(goto_home, need_keypress, pick_menu_item, + cap_story, cap_menu, nfc_read_text, settings_get, chain, + press_select, skip_if_useless_way, + settings_set, press_cancel, cap_screen_qr, + expect_acctnum_captured): + + settings_set('chain', chain) + chain_num = 1 if chain == "XTN" else 0 + + goto_home() + pick_menu_item("Advanced/Tools") + pick_menu_item("Export Wallet") + pick_menu_item("Bull Bitcoin") + + time.sleep(.1) + expect_acctnum_captured(0) + + contents = cap_screen_qr().decode('ascii') + descriptor = contents.strip() + + press_cancel() + time.sleep(.1) + assert "Bull Bitcoin" in cap_menu() # back to menu + + assert descriptor.startswith("wpkh(") + desc_obj = Descriptor.parse(descriptor) + assert desc_obj.serialize(int_ext=True) == descriptor + assert desc_obj.addr_fmt == AF_P2WPKH + assert len(desc_obj.keys) == 1 + xfp, derive, xpub = desc_obj.keys[0] + assert xfp == settings_get("xfp") + assert derive == f"m/84h/{chain_num}h/0h" + seed = Mnemonic.to_seed(simulator_fixed_words) + node = BIP32Node.from_master_secret( + seed, netcode="BTC" if chain == "BTC" else "XTN" + ).subkey_for_path(derive) + xpub_target = node.hwif() + assert xpub_target in xpub + + @pytest.mark.parametrize("chain", ["BTC", "XTN", "XRT"]) @pytest.mark.parametrize("account", ["Postmix", "Premix"]) def test_samourai_vs_generic(chain, account, settings_set, pick_menu_item, goto_home, @@ -864,6 +912,7 @@ def test_samourai_vs_generic(chain, account, settings_set, pick_menu_item, goto_ pick_menu_item("Segwit P2WPKH") # both postmix and premix are p2wpkh only file_desc_generic = load_export("sd", label="Descriptor", is_json=False, addr_fmt=AF_P2WPKH) press_select() # written + press_cancel() # leave export options press_cancel() # back to export submenu press_cancel() # back to advanced pick_menu_item("Export Wallet") diff --git a/testing/test_hobble.py b/testing/test_hobble.py new file mode 100644 index 00000000..08dcfd1b --- /dev/null +++ b/testing/test_hobble.py @@ -0,0 +1,485 @@ +# (c) Copyright 2025 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# +# Verify hobble works: a restricted access mode, without export/view of seed and more. +# +# - spending policy menu and txn checks should not be in this file, instead expand +# test_ccc.py or create test_sssp.py +# +# Additional tests, elsewhere: +# +# - test_teleport.py::test_teleport_ms_sign +# - verifies: MS psbt KT should still work in hobbled mode +# +# - test_teleport.py::test_hobble_limited +# - verifies: scan a KT and have it rejected if not PSBT type: so R and E types +# +# - login_settings_tests.py for login/bypass UX +# +# +import pytest, time, os, pdb +from bip32 import BIP32Node +from constants import simulator_fixed_words, simulator_fixed_xprv +from test_ephemeral import SEEDVAULT_TEST_DATA, WORDLISTS +from test_ephemeral import confirm_tmp_seed, verify_ephemeral_secret_ui +from test_ux import word_menu_entry +from charcodes import KEY_QR + +@pytest.fixture +def set_hobble(sim_exec, settings_set, settings_remove, goto_home): + def doit(mode, enabled={}): # okeys, words, notes + assert mode in { True, False, 2 } + + if mode: + v = dict(en=True, pol={}) + for w in enabled: + v[w] = True + settings_set('sssp', v) + print(f'sssp = {v!r}') + else: + settings_remove('sssp') + + sim_exec(f''' +from pincodes import pa; from actions import goto_top_menu +pa.hobbled_mode = {mode!r} +goto_top_menu() +''') + goto_home() # required, not sure why + + yield doit + + doit(False) + +@pytest.mark.parametrize('en_okeys', [ True, False] ) +@pytest.mark.parametrize('en_notes', [ True, False] ) +@pytest.mark.parametrize('en_nfc', [ True, False] ) +@pytest.mark.parametrize('en_miniscript', [ True, False] ) +def test_menu_contents(set_hobble, pick_menu_item, cap_menu, en_okeys, en_notes, settings_set, + need_some_notes, is_q1, is_mark4, en_nfc, sim_exec, en_miniscript, + vdisk_disabled): + + # just enough to pass/fail the menu predicates! + settings_set('seedvault', True) + + #settings_set('nfc', en_nfc) + sim_exec(f'import glob; glob.NFC = {(True if en_nfc else None)!r};') + + settings_set('miniscript', en_miniscript) + + if is_q1: + need_some_notes() + + # main menu basics + expect = {'Ready To Sign', 'Address Explorer', 'Advanced/Tools' } + + if is_q1: + expect.add('Scan Any QR Code') + else: + expect.add('Secure Logout') + + en = set() + if en_okeys: + en.add('okeys') + expect.add('Seed Vault') + expect.add('Passphrase') + + if en_notes: + en.add('notes') + if is_q1: + expect.add('Secure Notes & Passwords') + + # enables hobble and goes to top menu + set_hobble(True, en) + + m = cap_menu() + assert set(m) == expect, 'Main menu wrong' + + # advanced menu + pick_menu_item("Advanced/Tools") + + adv_expect = { 'File Management', + 'Export Wallet', + 'View Identity', + 'Paper Wallets', + 'Destroy Seed', + f'Show {"Firmware" if is_q1 else "FW"} Version' } + + if is_q1 and en_miniscript: + adv_expect.add('Teleport Miniscript PSBT') + + if en_nfc: + adv_expect.add('NFC Tools') + + if en_okeys: + adv_expect.add('Temporary Seed') + + m = cap_menu() + assert set(m) == adv_expect, "Adv menu wrong" + + # file management + pick_menu_item("File Management") + + fm_expect = { 'Sign Text File', + 'Batch Sign PSBT', + 'List Files', + 'Export Wallet', + 'Verify Sig File', + 'Format SD Card' } + + if not vdisk_disabled: + fm_expect.add('Format RAM Disk') + + if en_nfc: + fm_expect.add('NFC File Share') + if is_q1: + fm_expect.add('BBQr File Share') + fm_expect.add('QR File Share') + + m = cap_menu() + assert set(m) == fm_expect, "File Mgmt menu wrong" + + +def test_h_notes(only_q1, set_hobble, pick_menu_item, cap_menu, settings_set, need_some_notes, + sim_exec, settings_remove): + ''' + * load a secure note/pw; check readonly once hobbled + * cannot export + * cannot edit + * can view / use for kbd emulation + * check notes not offered if none defined + * check readonly features on notes when note pre-defined before entering hobbled mode + ''' + need_some_notes() + set_hobble(True, {'notes'}) + + pick_menu_item('Secure Notes & Passwords') + + m = cap_menu() + assert m == [ '1: Title Here' ] + pick_menu_item(m[0]) + + m = cap_menu() + assert m == [ '"Title Here"', 'View Note', 'Sign Note Text' ] + + # clear notes, should not be offered + settings_remove('notes') + settings_remove('secnap') + set_hobble(True, {'notes'}) + + m = cap_menu() + assert 'Secure Notes & Passwords' not in m + +def test_kt_limits(only_q1, set_hobble, pick_menu_item, cap_menu, settings_set, need_some_notes, + sim_exec, settings_remove): + ''' + - key teleport + * check KT only offered if MS wallet setup + ''' + settings_remove('multisig') + set_hobble(True) + pick_menu_item("Advanced/Tools") + + assert 'Teleport Miniscript PSBT' not in cap_menu() + # converse already tested in test_menu_contents + +@pytest.mark.parametrize('sv_empty', [ True, False] ) +def test_h_seedvault(sv_empty, set_hobble, pick_menu_item, cap_menu, settings_set, sim_exec, + settings_remove, restore_main_seed, settings_get, press_cancel, press_select, + cap_story): + ''' + - seed vault can be accessed, when enabled + - temp seeds are read-only: no create, no rename, etc. + - SV menu item is offered iff SV enabled; can be empty or not. + ''' + + settings_set('seedvault', True) + if sv_empty: + settings_set('seeds', []) + else: + settings_set('seeds', []) + xfp, enc = SEEDVAULT_TEST_DATA[0][0:2] + settings_set("seeds", [(xfp, '80'+enc, f"Menu Label", "meta-source")]) + + set_hobble(True, {'okeys'}) + + assert cap_menu()[0] == 'Ready To Sign', 'restart simulator now' + pick_menu_item('Seed Vault') + + m = cap_menu() + if sv_empty: + assert m == ['(none saved yet)'] + else: + assert m == [' 1: Menu Label'] + + pick_menu_item(m[0]) + m = cap_menu() + assert m == ['Menu Label', 'Use This Seed'] + + pick_menu_item(m[0]) + title, story = cap_story() + assert 'Origin:\nmeta-source' in story + press_cancel() + + pick_menu_item('Use This Seed') + title, story = cap_story() + assert 'temporary master key is in effect' in story + press_select() + + # arrive back in main menu, w/ tmp seed in effect + # - but we are still hobbled. + # - XFP shown + # - Restore master should be offered. + m = cap_menu() + assert m[0] == f'[{xfp}]' + assert m[-1] == 'Restore Master' + assert "Settings" not in m # in hobbled mode + + pick_menu_item("Advanced/Tools") + m = cap_menu() + # we are in tmp seed session, restore master if you want to destroy seed + assert 'Destroy Seed' not in m + press_cancel() + + pick_menu_item("Restore Master") + title, story = cap_story() + assert 'main wallet' in story + press_select() + + + # clear keys from sv, should not be offered in menu, even if okeys set. + settings_remove('seedvault') + set_hobble(True, {'okey'}) + + m = cap_menu() + assert 'Seed Vault' not in m + +@pytest.mark.parametrize('mode', [ 'words', 'qr', 'xprv', 'tapsigner', 'coldcard', 'b39pass']) +def test_h_tempseeds(mode, set_hobble, pick_menu_item, cap_menu, settings_set, is_q1, + press_select, cap_story, word_menu_entry, confirm_tmp_seed, enter_complex, + verify_ephemeral_secret_ui, scan_a_qr, tapsigner_encrypted_backup, + need_keypress, enter_hex, open_microsd, microsd_path, go_to_passphrase): + ''' + - can import and use a key for signing + - NOT offered chance to save into seedvault + ''' + if not is_q1 and mode == 'qr': return + + settings_set('seedvault', True) + settings_set('seeds', []) + + set_hobble(True, {'okeys'}) + + if mode != "b39pass": + pick_menu_item("Advanced/Tools") + pick_menu_item('Temporary Seed') + + m = cap_menu() + assert 'Generate Words' not in m + assert all((i.startswith("Import ") or i.endswith(' Backup') or i == 'Restore Seed XOR') + for i in m), m + + words, expect_xfp = WORDLISTS[12] + + if mode == 'words': + # just quick tests here, not in-depth + # - from test_ephemeral_seed_import_words() + pick_menu_item("Import Words") + pick_menu_item(f"12 Words") + time.sleep(0.1) + word_menu_entry(words.split()) + + elif mode == 'qr': + pick_menu_item("Import from QR Scan") + val = ' '.join(words.split()).upper() + scan_a_qr(val) + time.sleep(0.2) + + elif mode == 'tapsigner': + # like test_ephemeral_seed_import_tapsigner() + fname, backup_key_hex, node = tapsigner_encrypted_backup('sd', testnet=True) + expect_xfp = node.fingerprint().hex().upper() + pick_menu_item("Tapsigner Backup") + time.sleep(0.1) + need_keypress('1') + time.sleep(0.1) + pick_menu_item(fname) + + time.sleep(0.1) + _, story = cap_story() + assert "your TAPSIGNER" in story + + press_select() # yes I have backup key + enter_hex(backup_key_hex) + + elif mode == 'coldcard': + # like test_temporary_from_backup() + # - but skip making new bk file + fn = 'data/tip-index-famous-embark-tobacco-rice-attitude-interest-mask-random-amazing-initial.7z' + pw = fn[5:-3].split('-') + + contents = open(fn, 'rb').read() + with open_microsd('example.7z', 'wb') as fd: + fd.write(contents) + + pick_menu_item("Coldcard Backup") + time.sleep(0.1) + need_keypress('1') + time.sleep(0.1) + pick_menu_item('example.7z') + + word_menu_entry(pw, has_checksum=False) + + time.sleep(.1) + press_select() # confirm loading of the backup + time.sleep(.1) + title, story = cap_story() + assert title == 'FAILED' + assert 'successfully tested recovery' in story + + press_select() + return + + elif mode == 'xprv': + fname = "ek.txt" + node = BIP32Node.from_master_secret(os.urandom(32), netcode="XTN") + expect_xfp = node.fingerprint().hex().upper() + ek = node.hwif(as_private=True) + with open(microsd_path(fname), "w") as f: + f.write(ek) + + pick_menu_item("Import XPRV") + time.sleep(0.1) + _, story = cap_story() + if "Press (1) to import extended private key" in story: + need_keypress("1") + + time.sleep(0.1) + pick_menu_item(fname) + + elif mode == "b39pass": + from mnemonic import Mnemonic + go_to_passphrase() + passphrase = "sssp" + seed = Mnemonic.to_seed(simulator_fixed_words, passphrase=passphrase) + node = BIP32Node.from_master_secret(seed, netcode="XTN") + expect_xfp = node.fingerprint().hex().upper() + + enter_complex(passphrase, apply=True) + time.sleep(.2) + title, story = cap_story() + assert title[1:-1] == expect_xfp + assert "Above is the master key fingerprint of the new wallet" in story + press_select() + time.sleep(.1) + title, story = cap_story() + assert "store temporary seed into Seed Vault" not in story + time.sleep(.1) + + else: + raise pytest.fail(mode) + + if mode != "b39pass": + # different UX for passphrase - verified above + confirm_tmp_seed(seedvault=False, check_sv_not_offered=True) + + # do not verify presence of Seed Vault menu item - irrelevant + verify_ephemeral_secret_ui(expected_xfp=expect_xfp, mnemonic=None, seed_vault=None) + + time.sleep(.1) + m = cap_menu() + if mode in ["words", "qr"]: + # verify okeys is respected in tmp seed + assert "Passphrase" in m + + pick_menu_item("Restore Master") + press_select() + + +@pytest.mark.parametrize('en_okeys', [ True, False]) +def test_h_usbcmds(en_okeys, set_hobble, dev): + # test various usb commands are blocked during hobble + + from ckcc_protocol.protocol import CCProtoError + + set_hobble(True, {'okeys'} if en_okeys else {}) + + block_list = [ 'back', 'enrl', 'bagi', 'hsms', 'user', 'nwur', 'rmur' ] + + if not en_okeys: + block_list.insert(0, 'pass') + + for cmd in block_list: + with pytest.raises(CCProtoError) as ee: + got = dev.send_recv(cmd) + assert 'Spending policy in effect' in str(ee) + + +@pytest.mark.parametrize('en_okeys', [ True, False]) +def test_h_qrscan(en_okeys, set_hobble, scan_a_qr, need_keypress, press_cancel, cap_screen, only_q1, + cap_story, press_select, pick_menu_item): + # verify whitelist of QR types is correct when in hobbled mode + # - no private key material, unless "okeys" is set + # - no teleport starting, except multisig co-signing + # + set_hobble(True, {'okeys'} if en_okeys else {}) + + words, _ = WORDLISTS[12] + keys = [ + ' '.join(w[0:4] for w in words.split()), + simulator_fixed_xprv] + + for ss in keys: + need_keypress(KEY_QR) + scan_a_qr(ss) + time.sleep(1) + + title, story = cap_story() + if en_okeys: + assert 'New temporary master key is in effect' in story + press_select() + + pick_menu_item("Restore Master") + press_select() + else: + assert 'Blocked when Spending Policy is in force.' in story + press_select() + + for dt in 'RSE': + need_keypress(KEY_QR) + tt = f'B$H{dt}0100'+('A'*80) + scan_a_qr(tt) + time.sleep(1) + + if dt == 'E': + title, story = cap_story() + assert 'Incoming PSBT requires miniscript wallet' in story + press_cancel() + else: + scr = cap_screen() # stays in scanning mode + assert 'KT Blocked' in scr + +def test_h_seedxor(set_hobble, need_keypress, press_cancel, cap_screen, + cap_story, press_select, pick_menu_item, settings_set): + # can start import via seed XOR, but cannot include master seed phrase + # as part of it. + + settings_set('seedvault', True) + settings_set('seeds', []) + set_hobble(True, {'okeys'}) + + pick_menu_item("Advanced/Tools") + pick_menu_item('Temporary Seed') + pick_menu_item('Restore Seed XOR') + + title, story = cap_story() + assert 'A/B/C' in story + press_select() # select 24 words + time.sleep(0.1) + + title, story = cap_story() + assert 'Since you have' in story + assert "include this Coldcard's seed" not in story # WEAK: fragile if UX changes + + press_cancel() + + +# EOF diff --git a/testing/test_hsm.py b/testing/test_hsm.py index d08929eb..f8bf66ae 100644 --- a/testing/test_hsm.py +++ b/testing/test_hsm.py @@ -71,7 +71,7 @@ def compute_policy_hash(policy): if type_ == Deriv: rv = [] for orig in value or []: - rv.append(orig if orig in ["any", "p2sh"] else orig.replace('p', "h").replace("'", 'h')) + rv.append(orig if orig in ["any", "msas"] else orig.replace('p', "h").replace("'", 'h')) elif type_ == WhitelistOpts: rv = OrderedDict() rv["mode"] = value.get("mode", "BASIC") @@ -122,7 +122,7 @@ def enable_hsm_commands(dev, sim_exec, only_mk4): sim_exec(cmd) -@pytest.fixture(scope='function') +@pytest.fixture def hsm_reset(dev, sim_exec): # filename for the policy file, as stored on simulated CC @@ -170,10 +170,10 @@ def hsm_reset(dev, sim_exec): (DICT(msg_paths=["any"]), "(any path)"), # data sharing - (DICT(share_addrs=["m/1'/2p/3H"]), ['Address values values will be shared', "m/1h/2h/3h"]), - (DICT(share_addrs=["m/1", "m/2"]), ['Address values values will be shared', "m/1 OR m/2"]), - (DICT(share_addrs=["any"]), ['Address values values will be shared', "(any path)"]), - (DICT(share_addrs=["p2sh", "any"]), ['Address values values will be shared', "(any P2SH)", "(any path"]), + (DICT(share_addrs=["m/1'/2p/3H"]), ['Address values will be shared', "m/1h/2h/3h"]), + (DICT(share_addrs=["m/1", "m/2"]), ['Address values will be shared', "m/1 OR m/2"]), + (DICT(share_addrs=["any"]), ['Address values will be shared', "(any path)"]), + (DICT(share_addrs=["msas", "any"]), ['Address values will be shared', "(any miniscript)", "(any path"]), (DICT(share_xpubs=["m/1'/2p/3H"]), ['XPUB values will be shared', "m/1h/2h/3h"]), (DICT(share_xpubs=["m/1", "m/2"]), ['XPUB values will be shared', "m/1 OR m/2"]), @@ -476,10 +476,11 @@ def wait_til_signed(dev): return result @pytest.fixture -def attempt_psbt(hsm_status, start_sign, dev): +def attempt_psbt(hsm_status, start_sign, dev, sim_root_dir): def doit(psbt, refuse=None, remote_error=None): - open('debug/attempt.psbt', 'wb').write(psbt) + with open(f'{sim_root_dir}/debug/attempt.psbt', 'wb') as f: + f.write(psbt) start_sign(psbt) try: @@ -532,54 +533,54 @@ def test_simple_limit(dev, amount, over, start_hsm, fake_txn, attempt_psbt, twea assert 'Rule #2' not in stat.summary # create a transaction - psbt = fake_txn(2, 2, dev.master_xpub, outvals=[amount, 2E8-amount], - change_outputs=[1], fee=0) + psbt = fake_txn(2, [["p2tr", int(amount)],["p2wpkh", int(2E8-amount), True]], + dev.master_xpub, fee=0) attempt_psbt(psbt) - psbt = fake_txn(2, 2, dev.master_xpub, outvals=[amount+over, 2E8-amount-over], - change_outputs=[1], fee=0) + psbt = fake_txn(2, [["p2tr", int(amount+over)],["p2wpkh", int(2E8-amount-over), True]], + dev.master_xpub, fee=0) attempt_psbt(psbt, "amount exceeded") if tweak_rule: tweak_rule(0, dict(max_amount=int(amount+over))) attempt_psbt(psbt) -def test_named_wallets(dev, start_hsm, tweak_rule, make_myself_wallet, hsm_status, - attempt_psbt, fake_txn, fake_ms_txn, amount=5E6, incl_xpubs=False): +def test_named_wallets(dev, start_hsm, tweak_rule, import_ms_wallet, hsm_status, + attempt_psbt, fake_txn, fake_ms_txn, amount=5E6): wname = 'Myself-4' M = 4 stat = hsm_status() assert not stat.active - for retry in range(3): - keys, _ = make_myself_wallet(4) # slow AF + keys = import_ms_wallet(M,M, name=wname, accept=True) + time.sleep(.2) - stat = hsm_status() - if wname in stat.wallets: - break + stat = hsm_status() + assert wname in stat.wallets # policy: only allow multisig w/ that name policy = DICT(rules=[dict(wallet=wname)]) stat = start_hsm(policy) - assert 'Any amount from multisig wallet' in stat.summary + assert 'Any amount from miniscript wallet' in stat.summary assert wname in stat.summary assert 'wallets' not in stat # simple p2pkh should fail - psbt = fake_txn(1, 2, dev.master_xpub, outvals=[amount, 1E8-amount], change_outputs=[1], fee=0) + psbt = fake_txn(1, [["p2tr", int(amount)],["p2wpkh", int(1E8-amount), True]], + dev.master_xpub, fee=0) attempt_psbt(psbt, "singlesig only") # but txn w/ multisig wallet should work psbt = fake_ms_txn(1, 2, M, keys, fee=0, outvals=[amount, 1E8-amount], outstyles=['p2wsh'], - change_outputs=[1], incl_xpubs=incl_xpubs) + change_outputs=[1]) attempt_psbt(psbt) # check ms txn not accepted when rule spec's a single signer tweak_rule(0, dict(wallet='1')) - attempt_psbt(psbt, 'wrong multisig wallet') + attempt_psbt(psbt, 'wrong miniscript wallet') @pytest.mark.bitcoind def test_named_wallets_miniscript(dev, start_hsm, tweak_rule, make_myself_wallet, @@ -610,7 +611,7 @@ def test_named_wallets_miniscript(dev, start_hsm, tweak_rule, make_myself_wallet pick_menu_item(name) pick_menu_item("Descriptors") pick_menu_item("Bitcoin Core") - text = load_export("sd", label="Bitcoin Core miniscript", is_json=False, sig_check=False) + text = load_export("sd", label="Bitcoin Core miniscript", is_json=False) text = text.replace("importdescriptors ", "").strip() # remove junk r1 = text.find("[") @@ -648,7 +649,7 @@ def test_named_wallets_miniscript(dev, start_hsm, tweak_rule, make_myself_wallet assert 'wallets' not in stat # simple p2pkh should fail - psbt = fake_txn(1, 2, outvals=[5E6, 1E8-5E6], change_outputs=[1], fee=0) + psbt = fake_txn(1, [["p2tr", int(5E6)],["p2wpkh", int(1E8-5E6), True]], fee=0) attempt_psbt(psbt, "singlesig only") # but txn from target miniscript wallet 0 must work @@ -708,11 +709,9 @@ def test_whitelist_single(dev, start_hsm, tweak_rule, attempt_psbt, fake_txn, wi # try all addr types for style in ['p2wpkh', 'p2wsh', 'p2sh', 'p2pkh', 'p2wsh-p2sh', 'p2wpkh-p2sh', 'p2tr']: dests = [] - psbt = fake_txn(1, 2, dev.master_xpub, - outstyles=[style, 'p2wpkh'], - outvals=[amount, 1E8-amount], change_outputs=[1], fee=0, - capture_scripts=dests) + psbt = fake_txn(1, [[style, int(amount)], ["p2wpkh", int(1E8-amount), True]], + dev.master_xpub, fee=0, capture_scripts=dests) dest = render_address(dests[0]) tweak_rule(0, dict(whitelist=[dest])) @@ -734,8 +733,7 @@ def test_whitelist_multi(dev, start_hsm, tweak_rule, attempt_psbt, fake_txn, amo # make a txn that sends to every type of output styles = ['p2wpkh', 'p2wsh', 'p2sh', 'p2pkh', 'p2wsh-p2sh', 'p2wpkh-p2sh'] dests = [] - psbt = fake_txn(1, len(styles), dev.master_xpub, - outstyles=styles, capture_scripts=dests) + psbt = fake_txn(1, [[outs] for outs in styles], dev.master_xpub, capture_scripts=dests) dests = [render_address(s) for s in dests] @@ -870,7 +868,7 @@ def test_big_txn(num_in, num_out, dev, quick_start_hsm, hsm_status, is_simulator attempt_psbt(psbt) -@pytest.mark.veryslow +@pytest.mark.manual def test_multiple_signings(dev, quick_start_hsm, is_simulator, attempt_psbt, fake_txn, load_hsm_users, auth_user): @@ -880,19 +878,20 @@ def test_multiple_signings(dev, quick_start_hsm, is_simulator, quick_start_hsm(policy) for count in range(400): - psbt = fake_txn(2, 2, dev.master_xpub, change_outputs=[0]) + psbt = fake_txn(2, [["p2wpkh", None, True],["p2sh-p2wpkh", None]], + dev.master_xpub, addr_fmt="p2wpkh") auth_user.psbt_hash = sha256(psbt).digest() auth_user("pw") attempt_psbt(psbt) -@pytest.mark.veryslow +@pytest.mark.manual @pytest.mark.parametrize("cc_first", [True, False]) @pytest.mark.parametrize("M_N", [(2,3), (3,5), (15,15)]) def test_multiple_signings_multisig(cc_first, M_N, dev, quick_start_hsm, is_simulator, attempt_psbt, fake_txn, load_hsm_users, auth_user, bitcoind, - request): + request, sim_root_dir): # signs 400 different PSBTs in loop beaing one leg of multisig # CC must be on regtest if testing with real thing af = "bech32" @@ -962,7 +961,9 @@ def test_multiple_signings_multisig(cc_first, M_N, dev, quick_start_hsm, # uploading only external to CC file_len, sha = dev.upload_file(desc_ext.encode('ascii')) - open('debug/last-config.txt', 'wt').write(desc_ext) + with open(f'{sim_root_dir}/debug/last-config.txt', 'wt') as f: + f.write(desc_ext) + dev.send_recv(CCProtocolPacker.multisig_enroll(file_len, sha), timeout=30000) time.sleep(.2) @@ -1187,7 +1188,7 @@ def test_storage_locker(package, count, start_hsm, dev): def test_usb_cmds_block(quick_start_hsm, dev): # check these commands return errors (test whitelist) block_list = [ - 'rebo', 'dfu_', 'enrl', 'enok', + 'rebo', 'dfu_', 'enrl', 'enok', 'rest', 'back', 'pass', 'bagi', 'hsms', 'nwur', 'rmur', 'pwok', 'bkok', ] @@ -1195,8 +1196,8 @@ def test_usb_cmds_block(quick_start_hsm, dev): for cmd in block_list: with pytest.raises(CCProtoError) as ee: - got = dev.send_recv(cmd) - assert 'HSM' in str(ee) + dev.send_recv(cmd) + assert 'Not allowed in HSM mode' in str(ee) def test_unit_local_conf(sim_exec, enter_local_code, quick_start_hsm): # just testing our fixture really @@ -1238,37 +1239,6 @@ def test_show_addr(dev, quick_start_hsm, change_hsm): path = path.replace('*', '73') addr = doit(path, addr_fmt) -def test_show_p2sh_addr(dev, hsm_reset, start_hsm, change_hsm, make_myself_wallet, addr_vs_path): - # MULTISIG addrs - from test_multisig import HARD, make_redeem - M = 4 - pm = lambda i: [HARD(45), i, 0,0] - - # can't amke ms wallets inside HSM mode - hsm_reset() - keys, _ = make_myself_wallet(M) # slow AF - - permit = ['p2sh', 'm/73'] - start_hsm(DICT(share_addrs=permit)) - - - scr, pubkeys, xfp_paths = make_redeem(M, keys, path_mapper=pm) - assert len(scr) <= 520, "script too long for standard!" - - got_addr = dev.send_recv(CCProtocolPacker.show_p2sh_address( - M, xfp_paths, scr, addr_fmt=AF_P2WSH)) - addr_vs_path(got_addr, addr_fmt=AF_P2WSH, script=scr) - - # turn it off; p2sh must be explicitly allowed - for allow in ['m', 'any']: - change_hsm(DICT(share_addrs=[allow])) - dev.send_recv(CCProtocolPacker.show_address('m', AF_CLASSIC)) - - with pytest.raises(CCProtoError) as ee: - got_addr = dev.send_recv(CCProtocolPacker.show_p2sh_address( - M, xfp_paths, scr, addr_fmt=AF_P2WSH)) - assert 'Not allowed in HSM mode' in str(ee) - def test_show_miniscript_addr(dev, offer_minsc_import, start_hsm, change_hsm, need_keypress, clear_miniscript): clear_miniscript() @@ -1281,7 +1251,7 @@ def test_show_miniscript_addr(dev, offer_minsc_import, start_hsm, need_keypress("y") time.sleep(.2) - policy = DICT(share_addrs=["any", "p2sh"], rules=[dict(wallet=name)]) + policy = DICT(share_addrs=["any"], rules=[dict(wallet=name)]) start_hsm(policy) with pytest.raises(CCProtoError) as ee: @@ -1289,7 +1259,7 @@ def test_show_miniscript_addr(dev, offer_minsc_import, start_hsm, assert "Not allowed in HSM mode" in ee.value.args[0] # change policy to allow miniscript address show - policy = DICT(share_addrs=["any", "p2sh", "msas"], rules=[dict(wallet=name)]) + policy = DICT(share_addrs=["any", "msas"], rules=[dict(wallet=name)]) change_hsm(policy) addr = dev.send_recv(CCProtocolPacker.miniscript_address(name, False, 0)) assert addr[2:4] == "1q" @@ -1356,7 +1326,7 @@ def test_velocity(dev, start_hsm, fake_txn, attempt_psbt, fast_forward, hsm_stat psbt = fake_txn(2, 10, dev.master_xpub) attempt_psbt(psbt, 'would exceed period spending') - psbt = fake_txn(2, 2, dev.master_xpub, outvals=[level, 2E8-level], change_outputs=[1]) + psbt = fake_txn(2, [["p2wpkh", level], ["p2tr", int(2E8-level), True]], dev.master_xpub) attempt_psbt(psbt) # exactly the limit s = hsm_status() @@ -1375,7 +1345,7 @@ def test_velocity(dev, start_hsm, fake_txn, attempt_psbt, fast_forward, hsm_stat assert 'has_spend' not in s amt = 0.30E8 - psbt = fake_txn(1, 2, dev.master_xpub, outvals=[amt, 1E8-amt], change_outputs=[1]) + psbt = fake_txn(1, [["p2tr", int(amt)], ["p2wpkh", int(1E8-amt), True]], dev.master_xpub) attempt_psbt(psbt) # 1/3rd of limit attempt_psbt(psbt) # 1/3rd of limit attempt_psbt(psbt) # 1/3rd of limit @@ -1390,16 +1360,16 @@ def test_min_pct_self_transfer(dev, start_hsm, fake_txn, attempt_psbt): start_hsm(policy) - psbt = fake_txn(1, 2, invals = [1000], outvals = [500, 500], change_outputs = [], fee = 0) + psbt = fake_txn([["p2pkh", None, 1000]], [["p2tr", 500], ["p2pkh", 500]], fee = 0) attempt_psbt(psbt, 'does not meet self transfer threshold, expected: %.2f, actual: %.2f' % (75, 0)) - psbt = fake_txn(1, 2, invals = [1000], outvals = [750, 250], change_outputs = [1], fee = 0) + psbt = fake_txn([["p2tr", None, 1000]], [["p2pkh", 750], ["p2tr", 250, True]], fee = 0) attempt_psbt(psbt, 'does not meet self transfer threshold, expected: %.2f, actual: %.2f' % (75, 25)) - psbt = fake_txn(1, 2, invals = [1000], outvals = [250, 750], change_outputs = [1], fee = 0) + psbt = fake_txn([["p2wpkh", None, 1000]], [["p2tr", 250], ["p2wpkh", 750, True]], fee = 0) attempt_psbt(psbt) # exact threshold - psbt = fake_txn(1, 2, invals = [1000], outvals = [1, 999], change_outputs = [1], fee = 0) + psbt = fake_txn([["p2sh-p2wpkh", None, 1000]], [["p2tr", 1], ["p2sh-p2wpkh", 999, True]], fee = 0) attempt_psbt(psbt) # exceeding the threshold @pytest.mark.parametrize('pattern', ['EQ_NUM_INS_OUTS', 'EQ_NUM_OWN_INS_OUTS', 'EQ_OUT_AMOUNTS'] ) @@ -1419,17 +1389,17 @@ def test_patterns(pattern, dev, start_hsm, fake_txn, attempt_psbt): psbt = fake_txn(2, 2) attempt_psbt(psbt, 'unequal number of own inputs and outputs') - psbt = fake_txn(2, 2, change_outputs = [0]) + psbt = fake_txn(2, [["p2pkh", None, True], ["p2tr"]]) attempt_psbt(psbt, 'unequal number of own inputs and outputs') - psbt = fake_txn(2, 2, change_outputs = [0, 1]) + psbt = fake_txn(2, [["p2pkh", None, True], ["p2tr", None, True]]) attempt_psbt(psbt) # equal number of own ins and outs if pattern == 'EQ_OUT_AMOUNTS': - psbt = fake_txn(1, 2, invals = [1500], outvals = [1000, 500], fee = 0) + psbt = fake_txn([["p2wpkh", None, 1500]], [["p2tr", 1000], ["p2pkh", 500]], fee=0) attempt_psbt(psbt, 'not all output amounts are equal') - psbt = fake_txn(1, 2, invals = [2000], outvals = [1000, 1000], fee = 0) + psbt = fake_txn([["p2tr", None, 2000]], [["p2wpkh", 1000], ["p2tr", 1000]], fee=0) attempt_psbt(psbt) # all output amounts are equal def test_user_subset(dev, start_hsm, tweak_rule, load_hsm_users, fake_txn, attempt_psbt, auth_user): @@ -1573,7 +1543,7 @@ def worst_case_policy(): addrs = [render_address(b'\x00\x14' + prandom(20)) for i in range(5)] - p = DICT(period=30, share_xpubs=paths, share_addrs=paths+['p2sh'], msg_paths=paths, + p = DICT(period=30, share_xpubs=paths, share_addrs=paths+['msas'], msg_paths=paths, warnings_ok=False, must_log=True) p.rules = [dict( local_conf=True, @@ -1655,7 +1625,9 @@ def test_priv_over_ux(quick_start_hsm, hsm_status, load_hsm_users): @pytest.mark.parametrize("allow_op_return", [False, True]) def test_op_return_output_local(op_return_data, start_hsm, attempt_psbt, fake_txn, allow_op_return): dests = [] - psbt = fake_txn(2, 2, op_return=[(0, op_return_data)], capture_scripts=dests) + psbt = fake_txn(2, [["p2tr", 10000], ["p2tr", 10000], ["op_return", 0, None, op_return_data]], + input_amount=10000, capture_scripts=dests) + if allow_op_return: policy = DICT(rules=[dict(whitelist=[render_address(d) for d in dests[0:2]], whitelist_opts=dict(allow_zeroval_outs=True))]) @@ -1695,7 +1667,8 @@ def test_hsm_commands_disabled(dev, goto_home, pick_menu_item, hsm_reset, start_ # disable HSM related commands (now enabled because module scope fixture 'enable_hsm_commands') goto_home() pick_menu_item("Advanced/Tools") - pick_menu_item("Enable HSM") + pick_menu_item("Spending Policy") + pick_menu_item("HSM Mode") pick_menu_item("Default Off") goto_home() try: diff --git a/testing/test_miniscript.py b/testing/test_miniscript.py index 0af70548..18a11b6b 100644 --- a/testing/test_miniscript.py +++ b/testing/test_miniscript.py @@ -6,7 +6,7 @@ import pytest, json, time, itertools, struct, random, os, base64 from ckcc.protocol import CCProtocolPacker from constants import AF_P2TR from psbt import BasicPSBT -from charcodes import KEY_QR, KEY_RIGHT, KEY_CANCEL +from charcodes import KEY_QR, KEY_RIGHT, KEY_CANCEL, KEY_DELETE from bbqr import split_qrs from bip32 import BIP32Node @@ -22,7 +22,10 @@ TREE = { 7: '{{%s,{%s,%s}},{%s,{%s,{%s,%s}}}}', 8: '{{{%s,%s},{%s,%s}},{{%s,%s},{%s,%s}}}', # more than MAX (4) for test purposes - 9: '{{{%s{%s,%s}},{%s,%s}},{{%s,%s},{%s,%s}}}' + 9: '{{{%s,{%s,%s}},{%s,%s}},{{%s,%s},{%s,%s}}}', + 10: '{{{{%s,%s},{%s,%s}},{%s,%s}},{{%s,%s},{%s,%s}}}', + 11: '{{{{%s,%s},{%s,%s}},{%s,%s}},{{%s,%s},{%s,{%s,%s}}}}', + 12: '{{{{%s,%s},{%s,%s}},{%s,%s}},{{%s,%s},{{%s,%s},{%s,%s}}}}', } @@ -35,12 +38,13 @@ def ranged_unspendable_internal_key(chain_code=32 * b"\x01", subderiv="/<0;1>/*" @pytest.fixture -def offer_minsc_import(cap_story, dev): +def offer_minsc_import(cap_story, dev, sim_root_dir): def doit(config, allow_non_ascii=False): # upload the file, trigger import file_len, sha = dev.upload_file(config.encode('utf-8' if allow_non_ascii else 'ascii')) - open('debug/last-config-msc.txt', 'wt').write(config) + with open(f'{sim_root_dir}/debug/last-config-msc.txt', 'wt') as f: + f.write(config) dev.send_recv(CCProtocolPacker.miniscript_enroll(file_len, sha)) time.sleep(.2) @@ -51,63 +55,102 @@ def offer_minsc_import(cap_story, dev): @pytest.fixture -def import_miniscript(goto_home, pick_menu_item, cap_story, need_keypress, - nfc_write_text, press_select, scan_a_qr, press_nfc): - def doit(fname, way="sd", data=None): - goto_home() - pick_menu_item('Settings') - pick_menu_item('Miniscript') - pick_menu_item('Import') - time.sleep(.3) - _, story = cap_story() - if way == "nfc": - if "via NFC" not in story: - pytest.skip("nfc disabled") +def import_miniscript(request, is_q1, need_keypress, offer_minsc_import, press_cancel): + def doit(fname=None, way="sd", data=None, name=None): + assert fname or data - press_nfc() - time.sleep(.1) - if isinstance(data, dict): - data = json.dumps(data) - nfc_write_text(data) - time.sleep(1) - return cap_story() - elif way == "qr": - if isinstance(data, dict): - data = json.dumps(data) - - need_keypress(KEY_QR) - try: - scan_a_qr(data) - except: - # always as text - even if it is json - actual_vers, parts = split_qrs(data, 'U', max_version=20) - random.shuffle(parts) - - for p in parts: - scan_a_qr(p) - time.sleep(1) # just so we can watch - - time.sleep(1) - return cap_story() - - if "Press (1) to import miniscript wallet file from SD Card" in story: - # in case Vdisk or NFC is enabled + if fname: if way == "sd": - need_keypress("1") + microsd_path = request.getfixturevalue("microsd_path") + fpath = microsd_path(fname) + else: + virtdisk_path = request.getfixturevalue("virtdisk_path") + fpath = virtdisk_path(fname) + with open(fpath, 'r') as f: + config = f.read() + else: + config = data - elif way == "vdisk": - if "ress (2)" not in story: + if way in ("usb", None): + return offer_minsc_import(config) + else: + # only get those simulator related fixtures here, to be able to + # use this with real HW + cap_menu = request.getfixturevalue('cap_menu') + cap_story = request.getfixturevalue('cap_story') + goto_home = request.getfixturevalue('goto_home') + press_nfc = request.getfixturevalue('press_nfc') + pick_menu_item = request.getfixturevalue('pick_menu_item') + + goto_home() + pick_menu_item("Settings") + pick_menu_item("Miniscript") + time.sleep(.1) + + pick_menu_item('Import') + time.sleep(.2) + _, story = cap_story() + if way == "nfc": + if "via NFC" not in story: + press_cancel() + pytest.skip("nfc disabled") + + press_nfc() + time.sleep(.1) + if isinstance(config, dict): + config = json.dumps(config) + + nfc_write_text = request.getfixturevalue('nfc_write_text') + nfc_write_text(config) + time.sleep(1) + return cap_story() + elif way == "qr": + scan_a_qr = request.getfixturevalue('scan_a_qr') + if isinstance(data, dict): + data = json.dumps(data) + + need_keypress(KEY_QR) + try: + scan_a_qr(data) + except: + # always as text - even if it is json + actual_vers, parts = split_qrs(data, 'U', max_version=20) + random.shuffle(parts) + + for p in parts: + scan_a_qr(p) + time.sleep(1) # just so we can watch + + time.sleep(1) + return cap_story() + + if not fname: + microsd_path = request.getfixturevalue("microsd_path") + virtdisk_path = request.getfixturevalue("virtdisk_path") + path_f = microsd_path if way == "sd" else virtdisk_path + fname = (name or "ms_wal") + ".txt" + with open(path_f(fname), "w") as f: + f.write(config) + + if "Press (1) to import miniscript wallet file from SD Card" in story: + # in case Vdisk or NFC is enabled + if way == "sd": + need_keypress("1") + + elif way == "vdisk": + if "ress (2)" not in story: + press_cancel() + pytest.xfail(way) + + need_keypress("2") + else: + if way != "sd": pytest.xfail(way) - need_keypress("2") - else: - if way != "sd": - pytest.xfail(way) - - time.sleep(.5) - pick_menu_item(fname) - time.sleep(.1) - return cap_story() + time.sleep(.3) + pick_menu_item(fname) + time.sleep(.1) + return cap_story() return doit @@ -138,10 +181,11 @@ def import_duplicate(import_miniscript, press_cancel, virtdisk_path, microsd_pat with open(new_fpath, "w") as f: f.write(res) + press_cancel() title, story = import_miniscript(new_fname, way, data=data) time.sleep(.2) - assert "duplicate of already saved wallet" in story + assert "Duplicate wallet" in story assert "OK to approve" not in story press_cancel() @@ -156,14 +200,13 @@ def miniscript_descriptors(goto_home, pick_menu_item, need_keypress, cap_story, garbage_collector): def doit(minsc_name): - qr_external = None + qr_data = None goto_home() pick_menu_item("Settings") pick_menu_item("Miniscript") pick_menu_item(minsc_name) pick_menu_item("Descriptors") pick_menu_item("Export") - need_keypress("1") # internal and external separately time.sleep(.1) if is_q1: # check QR @@ -171,15 +214,13 @@ def miniscript_descriptors(goto_home, pick_menu_item, need_keypress, cap_story, try: file_type, data = readback_bbqr() assert file_type == "U" - data = data.decode() + qr_data = data.decode().strip() except: - data = cap_screen_qr().decode('ascii') + qr_data = cap_screen_qr().decode('ascii').strip() - qr_external, qr_internal = data.split("\n") need_keypress(KEY_CANCEL) pick_menu_item("Export") - need_keypress("1") # internal and external separately time.sleep(.2) title, story = cap_story() @@ -189,16 +230,16 @@ def miniscript_descriptors(goto_home, pick_menu_item, need_keypress, cap_story, title, story = cap_story() assert "Miniscript file written" in story - fname = story.split("\n\n")[-1] + assert "signature file written" in story + fname = story.split("\n\n")[1] fpath = microsd_path(fname) garbage_collector.append(fpath) with open(fpath, "r") as f: - cont = f.read() - external, internal = cont.split("\n") - if qr_external: - assert qr_external == external - assert qr_internal == internal - return external, internal + cont = f.read().strip() + + if qr_data: + assert qr_data == cont + return cont return doit @@ -213,6 +254,15 @@ def usb_miniscript_get(dev): return doit +@pytest.fixture +def usb_miniscript_policy(dev): + def doit(name): + dev.check_mitm() + resp = dev.send_recv(CCProtocolPacker.miniscript_policy(name)) + return json.loads(resp) + + return doit + @pytest.fixture def usb_miniscript_delete(dev): def doit(name): @@ -273,8 +323,8 @@ def bitcoin_core_signer(bitcoind): @pytest.fixture def address_explorer_check(goto_home, pick_menu_item, need_keypress, cap_menu, - cap_story, load_export, miniscript_descriptors, - usb_miniscript_addr, cap_screen_qr): + cap_story, miniscript_descriptors, load_export, + usb_miniscript_addr, cap_screen_qr, press_select): def doit(way, addr_fmt, wallet, cc_minsc_name, export_check=True): goto_home() pick_menu_item("Address Explorer") @@ -283,9 +333,7 @@ def address_explorer_check(goto_home, pick_menu_item, need_keypress, cap_menu, wal_name = m[-1] pick_menu_item(wal_name) - title, story = cap_story() - assert "Taproot internal key" not in story - + time.sleep(1) if way == "qr": need_keypress(KEY_QR) cc_addrs = [] @@ -295,16 +343,20 @@ def address_explorer_check(goto_home, pick_menu_item, need_keypress, cap_menu, time.sleep(.2) need_keypress(KEY_CANCEL) else: - contents = load_export(way, label="Address summary", is_json=False, sig_check=False) + contents = load_export(way, label="Address summary", is_json=False) addr_cont = contents.strip() + press_select() - time.sleep(.5) + + time.sleep(1) title, story = cap_story() - assert "(0)" in story - assert "change addresses." in story + + assert "change addresses." in story and "(0)" in story need_keypress("0") - time.sleep(.5) + + time.sleep(1) title, story = cap_story() + assert "(0)" not in story assert "change addresses." not in story @@ -317,8 +369,7 @@ def address_explorer_check(goto_home, pick_menu_item, need_keypress, cap_menu, time.sleep(.2) need_keypress(KEY_CANCEL) else: - contents_change = load_export(way, label="Address summary", is_json=False, - sig_check=False) + contents_change = load_export(way, label="Address summary", is_json=False) addr_cont_change = contents_change.strip() if way == "nfc": @@ -333,23 +384,11 @@ def address_explorer_check(goto_home, pick_menu_item, need_keypress, cap_menu, addr_range = [0, 249] cc_addrs_split = addr_cont.split("\n") cc_addrs_split_change = addr_cont_change.split("\n") - # header is different for taproot - if addr_fmt == "bech32m": - try: - assert "Internal Key" in cc_addrs_split[0] - except AssertionError: - assert "Unspendable Internal Key" in cc_addrs_split[0] - assert "Taptree" in cc_addrs_split[0] - else: - assert "Internal Key" not in cc_addrs_split[0] - assert "Taptree" not in cc_addrs_split[0] cc_addrs = cc_addrs_split[1:] cc_addrs_change = cc_addrs_split_change[1:] part_addr_index = 1 - time.sleep(2) - internal_desc = None external_desc = None descriptors = wallet.listdescriptors()["descriptors"] @@ -359,30 +398,28 @@ def address_explorer_check(goto_home, pick_menu_item, need_keypress, cap_menu, else: external_desc = desc["desc"] + time.sleep(1) + if export_check: - cc_external, cc_internal = miniscript_descriptors(cc_minsc_name) + desc_export = miniscript_descriptors(cc_minsc_name) - unspend = "unspend(" - if unspend in cc_external: - assert "unspend(" in cc_internal - netcode = "XTN" if "tpub" in cc_external else "BTC" - # bitcoin core does not recognize unspend( - needs hack - # CC properly exports any imported unspend( for bitcoin core - # as extended key serialization xpub/<0;1>/* - start_idx = cc_external.find(unspend) - assert start_idx != -1 - end_idx = start_idx + len(unspend) + 64 + 1 - uns = cc_external[start_idx: end_idx] - chain_code = bytes.fromhex(uns[len(unspend):-1]) - node = BIP32Node.from_chaincode_pubkey(chain_code, - b"\x02" + bytes.fromhex(H), - netcode=netcode) - ek = node.hwif() - cc_external = cc_external.replace(uns, ek) - cc_internal = cc_internal.replace(uns, ek) + def remove_minisc_syntactic_sugar(descriptor, a, b): + # syntactic sugar https://bitcoin.sipa.be/miniscript/ + target_len = len(a) + idx = 0 + while idx != -1: + idx = descriptor.find(a, idx) + if idx == -1: break + # needs colon more identities than just 'c' + rep = f":{b}" if descriptor[idx-1] in "asctdvjnlu" else f"{b}" + descriptor = descriptor[:idx] + rep + descriptor[idx+target_len:] - assert cc_external.split("#")[0] == external_desc.split("#")[0].replace("'", "h") - assert cc_internal.split("#")[0] == internal_desc.split("#")[0].replace("'", "h") + return descriptor + + desc_export = remove_minisc_syntactic_sugar(desc_export, "c:pk_k(", "pk(") + desc_export = remove_minisc_syntactic_sugar(desc_export, "c:pk_h(", "pkh(") + # TODO format with and without multipath expression + # assert desc_export.split("#")[0] == external_desc.split("#")[0].replace("'", "h") bitcoind_addrs = wallet.deriveaddresses(external_desc, addr_range) bitcoind_addrs_change = wallet.deriveaddresses(internal_desc, addr_range) @@ -419,6 +456,166 @@ def address_explorer_check(goto_home, pick_menu_item, need_keypress, cap_menu, return doit +@pytest.fixture +def create_core_wallet(goto_home, pick_menu_item, load_export, bitcoind): + def doit(name, addr_type, way="sd", funded=True): + try: + pick_menu_item(name) # pick imported descriptor multisig wallet + except: + # probably not in Miniscript + goto_home() + pick_menu_item('Settings') + pick_menu_item('Miniscript') + pick_menu_item(name) + + pick_menu_item("Descriptors") + pick_menu_item("Bitcoin Core") + text = load_export(way, label="Bitcoin Core miniscript", is_json=False) + text = text.replace("importdescriptors ", "").strip() + # remove junk + r1 = text.find("[") + r2 = text.find("]", -1, 0) + text = text[r1: r2] + core_desc_object = json.loads(text) + + # watch only wallet where miniscript descriptor will be imported + ms = bitcoind.create_wallet( + wallet_name=name, disable_private_keys=True, + blank=True, passphrase=None, avoid_reuse=False, descriptors=True + ) + + # import descriptors to watch only wallet + res = ms.importdescriptors(core_desc_object) + for obj in res: + assert obj["success"] + + if funded: + addr = ms.getnewaddress("", addr_type) + if addr_type == "bech32": + sw = "bcrt1q" + elif addr_type == "bech32m": + sw = "bcrt1p" + else: + sw = "2" + assert addr.startswith(sw) + # get some coins and fund above multisig address + bitcoind.supply_wallet.sendtoaddress(addr, 49) + bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) # mine above + + return ms + return doit + + +@pytest.fixture +def bitcoind_miniscript(bitcoind, need_keypress, cap_story, load_export, + pick_menu_item, goto_home, cap_menu, microsd_path, + use_regtest, get_cc_key, import_miniscript, + bitcoin_core_signer, import_duplicate, press_select, + virtdisk_path, garbage_collector, create_core_wallet): + def doit(M, N, script_type, internal_key=None, cc_account=0, funded=True, + tapscript_threshold=False, add_own_pk=False, same_account=False, way="sd"): + + use_regtest() + bitcoind_signers = [] + bitcoind_signers_xpubs = [] + for i in range(N - 1): + s, core_key = bitcoin_core_signer(f"bitcoind--signer{i}") + s.keypoolrefill(10) + bitcoind_signers.append(s) + bitcoind_signers_xpubs.append(core_key) + + me_pth = f"m/48h/1h/{cc_account}h/3h" + me = get_cc_key(me_pth) + ik = internal_key or ranged_unspendable_internal_key() + + if tapscript_threshold: + signers_xp = [me] + bitcoind_signers_xpubs + assert len(signers_xp) == N + desc = f"tr({ik},%s)" + + scripts = [] + for c in itertools.combinations(signers_xp, M): + tmplt = f"sortedmulti_a({M},{','.join(c)})" + scripts.append(tmplt) + + if len(scripts) > 8: + while True: + # just some of them but at least one has to have my key + x = random.sample(scripts, 8) + if any(me in s for s in x): + scripts = x + break + + if add_own_pk: + if len(scripts) < 8: + if same_account: + cc_key = get_cc_key(me_pth, subderiv="/<2;3>/*") + else: + cc_key = get_cc_key("m/86h/1h/1000h") + cc_pk_leaf = f"pk({cc_key})" + scripts.append(cc_pk_leaf) + else: + pytest.skip("Scripts full") + + temp = TREE[len(scripts)] + temp = temp % tuple(scripts) + + desc = desc % temp + + else: + if add_own_pk: + if same_account: + ss = [get_cc_key(me_pth, subderiv="/<4;5>/*")] + bitcoind_signers_xpubs + cc_key = get_cc_key(me_pth, subderiv="/<6;7>/*") + else: + ss = [get_cc_key("m/86h/1h/0h")] + bitcoind_signers_xpubs + cc_key = get_cc_key("m/86h/1h/1000h") + + tmplt = f"sortedmulti_a({M},{','.join(ss)})" + cc_pk_leaf = f"pk({cc_key})" + desc = f"tr({ik},{{{tmplt},{cc_pk_leaf}}})" + else: + desc = f"tr({ik},sortedmulti_a({M},{me},{','.join(bitcoind_signers_xpubs)}))" + + name = "minisc" + fname = None + if way in ["sd", "vdisk"]: + data = None + fname = f"{name}.txt" + path_f = microsd_path if way == 'sd' else virtdisk_path + fpath = path_f(fname) + with open(fpath, "w") as f: + f.write(desc + "\n") + garbage_collector.append(fpath) + else: + data = dict(name=name, desc=desc) + + _, story = import_miniscript(fname, way=way, data=data) + assert "Create new miniscript wallet?" in story + assert name in story + assert "Press (1) to see extended public keys" in story + if script_type == "p2wsh": + af = "bech32" + assert "P2WSH" in story + elif script_type == "p2sh": + af = "legacy" + assert "P2SH" in story + elif script_type == "p2tr": + af = "bech32m" + assert "P2TR" in story + else: + af = "p2sh-segwit" + assert "P2SH-P2WSH" in story + # assert "Derivation:\n Varies (2)" in story + press_select() # approve multisig import + import_duplicate(fname, way=way, data=data) + ms = create_core_wallet(name, af, way, funded) + + return ms, bitcoind_signers + + return doit + + @pytest.mark.bitcoind @pytest.mark.parametrize("addr_fmt", ["bech32", "p2sh-segwit"]) @pytest.mark.parametrize("lt_type", ["older", "after"]) # this is actually not generated by liana (liana is relative only) @@ -433,12 +630,13 @@ def address_explorer_check(goto_home, pick_menu_item, need_keypress, cap_menu, "or_d(pk(@A),and_v(v:multi(2,@B,@C),locktime(N)))", ]) -def test_liana_miniscripts_simple(addr_fmt, recovery, lt_type, minisc, clear_miniscript, goto_home, - pick_menu_item, cap_menu, cap_story, microsd_path, way, - use_regtest, bitcoind, microsd_wipe, load_export, dev, +def test_liana_miniscripts_simple(addr_fmt, recovery, lt_type, minisc, clear_miniscript, + pick_menu_item, cap_story, microsd_path, way, dev, + use_regtest, bitcoind, microsd_wipe, load_export, address_explorer_check, get_cc_key, import_miniscript, bitcoin_core_signer, import_duplicate, press_select, - virtdisk_path, skip_if_useless_way, garbage_collector): + virtdisk_path, skip_if_useless_way, garbage_collector, + create_core_wallet, goto_home): skip_if_useless_way(way) normal_cosign_core = False recovery_cosign_core = False @@ -489,6 +687,7 @@ def test_liana_miniscripts_simple(addr_fmt, recovery, lt_type, minisc, clear_min fname = f"{name}.txt" if way in ["qr", "nfc"]: data = dict(name=name, desc=desc) + fname = None else: path_f = microsd_path if way == "sd" else virtdisk_path data = None @@ -497,41 +696,18 @@ def test_liana_miniscripts_simple(addr_fmt, recovery, lt_type, minisc, clear_min with open(fpath, "w") as f: f.write(desc) - wo = bitcoind.create_wallet(wallet_name=name, disable_private_keys=True, blank=True, - passphrase=None, avoid_reuse=False, descriptors=True) - _, story = import_miniscript(fname, way=way, data=data) - try: - assert "Create new miniscript wallet?" in story - except: - time.sleep(.2) - _, story = cap_story() - assert "Create new miniscript wallet?" in story - # do some checks on policy --> helper function to replace keys with letters + time.sleep(.2) + assert "Create new miniscript wallet?" in story press_select() - import_duplicate(fname, way=way, data=data) - menu = cap_menu() - assert menu[0] == name - pick_menu_item(menu[0]) # pick imported descriptor multisig wallet - pick_menu_item("Descriptors") - pick_menu_item("Bitcoin Core") - text = load_export(way, label="Bitcoin Core miniscript", is_json=False, sig_check=False) - text = text.replace("importdescriptors ", "").strip() - # remove junk - r1 = text.find("[") - r2 = text.find("]", -1, 0) - text = text[r1: r2] - core_desc_object = json.loads(text) - res = wo.importdescriptors(core_desc_object) - for obj in res: - assert obj["success"] - addr = wo.getnewaddress("", addr_fmt) - addr_dest = wo.getnewaddress("", addr_fmt) # self-spend - assert bitcoind.supply_wallet.sendtoaddress(addr, 49) - bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) + # import_duplicate(fname, way=way, data=data) + + wo = create_core_wallet(name, addr_fmt, way, True) + all_of_it = wo.getbalance() unspent = wo.listunspent() assert len(unspent) == 1 + addr_dest = wo.getnewaddress("", addr_fmt) # self-spend inp = {"txid": unspent[0]["txid"], "vout": unspent[0]["vout"]} if recovery and sequence: inp["sequence"] = sequence @@ -609,7 +785,7 @@ def test_liana_miniscripts_complex(addr_fmt, minsc, bitcoind, use_regtest, clear load_export, goto_home, address_explorer_check, cap_menu, get_cc_key, import_miniscript, bitcoin_core_signer, import_duplicate, press_select, way, skip_if_useless_way, - garbage_collector): + garbage_collector, create_core_wallet): skip_if_useless_way(way) use_regtest() clear_miniscript() @@ -667,33 +843,16 @@ def test_liana_miniscripts_complex(addr_fmt, minsc, bitcoind, use_regtest, clear garbage_collector.append(fpath) - wo = bitcoind.create_wallet(wallet_name=name, disable_private_keys=True, blank=True, - passphrase=None, avoid_reuse=False, descriptors=True) _, story = import_miniscript(fname, way=way, data=data) + time.sleep(.2) assert "Create new miniscript wallet?" in story # do some checks on policy --> helper function to replace keys with letters press_select() import_duplicate(fname, way=way, data=data) - menu = cap_menu() - assert menu[0] == name - pick_menu_item(menu[0]) # pick imported descriptor multisig wallet - pick_menu_item("Descriptors") - pick_menu_item("Bitcoin Core") - text = load_export(way, label="Bitcoin Core miniscript", is_json=False, sig_check=False) - text = text.replace("importdescriptors ", "").strip() - # remove junk - r1 = text.find("[") - r2 = text.find("]", -1, 0) - text = text[r1: r2] - core_desc_object = json.loads(text) - res = wo.importdescriptors(core_desc_object) - for obj in res: - assert obj["success"] - addr = wo.getnewaddress("", addr_fmt) + wo = create_core_wallet(name, addr_fmt, way, True) + addr_dest = wo.getnewaddress("", addr_fmt) # self-spend - assert bitcoind.supply_wallet.sendtoaddress(addr, 49) - bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) unspent = wo.listunspent() assert len(unspent) == 1 inp = {"txid": unspent[0]["txid"], "vout": unspent[0]["vout"]} @@ -763,159 +922,6 @@ def test_liana_miniscripts_complex(addr_fmt, minsc, bitcoind, use_regtest, clear address_explorer_check(way, addr_fmt, wo, name) -@pytest.fixture -def bitcoind_miniscript(bitcoind, need_keypress, cap_story, load_export, - pick_menu_item, goto_home, cap_menu, microsd_path, - use_regtest, get_cc_key, import_miniscript, - bitcoin_core_signer, import_duplicate, press_select, - virtdisk_path, garbage_collector): - def doit(M, N, script_type, internal_key=None, cc_account=0, funded=True, - tapscript_threshold=False, add_own_pk=False, same_account=False, way="sd"): - - use_regtest() - bitcoind_signers = [] - bitcoind_signers_xpubs = [] - for i in range(N - 1): - s, core_key = bitcoin_core_signer(f"bitcoind--signer{i}") - s.keypoolrefill(10) - bitcoind_signers.append(s) - bitcoind_signers_xpubs.append(core_key) - - # watch only wallet where multisig descriptor will be imported - ms = bitcoind.create_wallet( - wallet_name=f"watch_only_{script_type}_{M}of{N}", disable_private_keys=True, - blank=True, passphrase=None, avoid_reuse=False, descriptors=True - ) - me_pth = f"m/48h/1h/{cc_account}h/3h" - me = get_cc_key(me_pth) - ik = internal_key or ranged_unspendable_internal_key() - - if tapscript_threshold: - signers_xp = [me] + bitcoind_signers_xpubs - assert len(signers_xp) == N - desc = f"tr({ik},%s)" - - scripts = [] - for c in itertools.combinations(signers_xp, M): - tmplt = f"sortedmulti_a({M},{','.join(c)})" - scripts.append(tmplt) - - if len(scripts) > 8: - while True: - # just some of them but at least one has to have my key - x = random.sample(scripts, 8) - if any(me in s for s in x): - scripts = x - break - - if add_own_pk: - if len(scripts) < 8: - if same_account: - cc_key = get_cc_key(me_pth, subderiv="/<2;3>/*") - else: - cc_key = get_cc_key("m/86h/1h/1000h") - cc_pk_leaf = f"pk({cc_key})" - scripts.append(cc_pk_leaf) - else: - pytest.skip("Scripts full") - - temp = TREE[len(scripts)] - temp = temp % tuple(scripts) - - desc = desc % temp - - else: - if add_own_pk: - if same_account: - ss = [get_cc_key(me_pth, subderiv="/<4;5>/*")] + bitcoind_signers_xpubs - cc_key = get_cc_key(me_pth, subderiv="/<6;7>/*") - else: - ss = [get_cc_key("m/86h/1h/0h")] + bitcoind_signers_xpubs - cc_key = get_cc_key("m/86h/1h/1000h") - - tmplt = f"sortedmulti_a({M},{','.join(ss)})" - cc_pk_leaf = f"pk({cc_key})" - desc = f"tr({ik},{{{tmplt},{cc_pk_leaf}}})" - else: - desc = f"tr({ik},sortedmulti_a({M},{me},{','.join(bitcoind_signers_xpubs)}))" - - name = "minisc" - fname = None - if way in ["sd", "vdisk"]: - data = None - fname = f"{name}.txt" - path_f = microsd_path if way == 'sd' else virtdisk_path - fpath = path_f(fname) - with open(fpath, "w") as f: - f.write(desc + "\n") - garbage_collector.append(fpath) - else: - data = dict(name=name, desc=desc) - - _, story = import_miniscript(fname, way=way, data=data) - assert "Create new miniscript wallet?" in story - assert name in story - if script_type == "p2tr": - assert "Taproot internal key" in story - assert "Tapscript" in story - assert "Press (1) to see extended public keys" in story - if script_type == "p2wsh": - assert "P2WSH" in story - elif script_type == "p2sh": - assert "P2SH" in story - elif script_type == "p2tr": - assert "P2TR" in story - else: - assert "P2SH-P2WSH" in story - # assert "Derivation:\n Varies (2)" in story - press_select() # approve multisig import - import_duplicate(fname, way=way, data=data) - goto_home() - pick_menu_item('Settings') - pick_menu_item('Miniscript') - menu = cap_menu() - pick_menu_item(menu[0]) # pick imported descriptor multisig wallet - pick_menu_item("Descriptors") - pick_menu_item("Bitcoin Core") - text = load_export(way, label="Bitcoin Core miniscript", is_json=False, sig_check=False) - text = text.replace("importdescriptors ", "").strip() - # remove junk - r1 = text.find("[") - r2 = text.find("]", -1, 0) - text = text[r1: r2] - core_desc_object = json.loads(text) - # import descriptors to watch only wallet - res = ms.importdescriptors(core_desc_object) - assert res[0]["success"] - assert res[1]["success"] - - if funded: - if script_type == "p2wsh": - addr_type = "bech32" - elif script_type == "p2tr": - addr_type = "bech32m" - elif script_type == "p2sh": - addr_type = "legacy" - else: - addr_type = "p2sh-segwit" - - addr = ms.getnewaddress("", addr_type) - if script_type == "p2wsh": - sw = "bcrt1q" - elif script_type == "p2tr": - sw = "bcrt1p" - else: - sw = "2" - assert addr.startswith(sw) - # get some coins and fund above multisig address - bitcoind.supply_wallet.sendtoaddress(addr, 49) - bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) # mine above - - return ms, bitcoind_signers - - return doit - - @pytest.mark.bitcoind @pytest.mark.parametrize("cc_first", [True, False]) @pytest.mark.parametrize("add_pk", [True, False]) @@ -992,20 +998,15 @@ def test_tapscript(M_N, cc_first, clear_miniscript, goto_home, pick_menu_item, @pytest.mark.parametrize("add_pk", [True, False]) @pytest.mark.parametrize('M_N', [(3, 15), (2, 2), (3, 5)]) @pytest.mark.parametrize('way', ["qr", "sd", "vdisk", "nfc"]) -@pytest.mark.parametrize('internal_type', ["unspend(", "xpub"]) def test_bitcoind_tapscript_address(M_N, clear_miniscript, bitcoind_miniscript, use_regtest, way, csa, address_explorer_check, - add_pk, internal_type, skip_if_useless_way): + add_pk, skip_if_useless_way): skip_if_useless_way(way) use_regtest() clear_miniscript() M, N = M_N - ik = None # default static - if internal_type == "unspend(": - ik = f"unspend({os.urandom(32).hex()})/<20;21>/*" - elif internal_type == "xpub": - ik = ranged_unspendable_internal_key(os.urandom(32)) + ik = ranged_unspendable_internal_key(os.urandom(32), subderiv=f"/<22;23>/*") ms_wo, _ = bitcoind_miniscript(M, N, "p2tr", funded=False, tapscript_threshold=csa, add_own_pk=add_pk, way=way, internal_key=ik) @@ -1020,12 +1021,11 @@ def test_bitcoind_tapscript_address(M_N, clear_miniscript, bitcoind_miniscript, True, False, "tpubD6NzVbkrYhZ4WhUnV3cPSoRWGf9AUdG2dvNpsXPiYzuTnxzAxemnbajrATDBWhaAVreZSzoGSe3YbbkY2K267tK3TrRmNiLH2pRBpo8yaWm/<2;3>/*", - "unspend(c72231504cf8c1bbefa55974db4e0cdac781049a9a81a87e7ff5beeb45b34d3d)/<0;1>/*" ]) def test_tapscript_multisig(cc_first, m_n, internal_key_spendable, use_regtest, bitcoind, goto_home, cap_menu, pick_menu_item, cap_story, microsd_path, load_export, microsd_wipe, dev, way, bitcoind_miniscript, clear_miniscript, get_cc_key, press_cancel, press_select, - skip_if_useless_way, garbage_collector): + skip_if_useless_way, garbage_collector, file_tx_signing_done): skip_if_useless_way(way) M, N = m_n clear_miniscript() @@ -1073,22 +1073,8 @@ def test_tapscript_multisig(cc_first, m_n, internal_key_spendable, use_regtest, press_select() time.sleep(0.1) title, story = cap_story() - split_story = story.split("\n\n") - cc_tx_id = None - if "(ready for broadcast)" in story: - signed_fname = split_story[1] - signed_txn_fname = split_story[-2] - cc_tx_id = split_story[-1].split("\n")[-1] - txn_fpath = microsd_path(signed_txn_fname) - with open(txn_fpath, "r") as f: - signed_txn = f.read().strip() - garbage_collector.append(txn_fpath) - else: - signed_fname = split_story[-1] - fpath = microsd_path(signed_fname) - with open(fpath, "r") as f: - signed_psbt = f.read().strip() + signed_psbt, signed_txn, cc_tx_id = file_tx_signing_done(story) garbage_collector.append(fpath) if cc_first: @@ -1112,7 +1098,7 @@ def test_tapscript_pk(num_leafs, use_regtest, clear_miniscript, microsd_wipe, bi internal_key_spendable, dev, microsd_path, get_cc_key, pick_menu_item, cap_story, goto_home, cap_menu, load_export, import_miniscript, bitcoin_core_signer, import_duplicate, - press_select, garbage_collector): + press_select, garbage_collector, create_core_wallet): use_regtest() clear_miniscript() microsd_wipe() @@ -1137,11 +1123,6 @@ def test_tapscript_pk(num_leafs, use_regtest, clear_miniscript, microsd_wipe, bi random.shuffle(leafs) desc = f"tr({internal_key},{tmplt % (*leafs,)})" - ts = bitcoind.create_wallet( - wallet_name=f"watch_only_pk_ts", disable_private_keys=True, - blank=True, passphrase=None, avoid_reuse=False, descriptors=True - ) - fname = "ts_pk.txt" fpath = microsd_path(fname) with open(fpath, "w") as f: @@ -1151,35 +1132,18 @@ def test_tapscript_pk(num_leafs, use_regtest, clear_miniscript, microsd_wipe, bi _, story = import_miniscript(fname) assert "Create new miniscript wallet?" in story assert fname.split(".")[0] in story - assert "Taproot internal key" in story - assert "Tapscript" in story assert "Press (1) to see extended public keys" in story assert "P2TR" in story press_select() import_duplicate(fname) + goto_home() pick_menu_item('Settings') pick_menu_item('Miniscript') menu = cap_menu() - pick_menu_item(menu[0]) - pick_menu_item("Descriptors") - pick_menu_item("Bitcoin Core") - text = load_export("sd", label="Bitcoin Core miniscript", is_json=False, sig_check=False) - text = text.replace("importdescriptors ", "").strip() - # remove junk - r1 = text.find("[") - r2 = text.find("]", -1, 0) - text = text[r1: r2] - core_desc_object = json.loads(text) - # import descriptors to watch only wallet - res = ts.importdescriptors(core_desc_object) - assert res[0]["success"] - assert res[1]["success"] - addr = ts.getnewaddress("", "bech32m") - assert bitcoind.supply_wallet.sendtoaddress(addr, 49) - bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) + ts = create_core_wallet(menu[0], "bech32m", "sd", True) dest_addr = ts.getnewaddress("", "bech32m") # selfspend psbt = ts.walletcreatefundedpsbt([], [{dest_addr: 1.0}], 0, {"fee_rate": 2})["psbt"] @@ -1227,16 +1191,19 @@ def test_tapscript_pk(num_leafs, use_regtest, clear_miniscript, microsd_wipe, bi @pytest.mark.parametrize("desc", [ - "tr(unspend(61350cde0f20e0268d0f33c22967863d9ebcbc3f448b78c9e83810d2152692e0)/<0;1>/*,{{sortedmulti_a(2,[0f056943/48h/1h/0h/3h]tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/<0;1>/*,[b7fe820c/48h/1h/0h/3h]tpubDFdQ1sNV53TbogAMPEd2egY5NXfbdKD1Mnr2iBrJrcwRHJbKC7tuuUMHT8SSHJ2VEKdCf5WYBMfevvWCnyJV53gYUT2wFyxEV8SuUTedBp7/<0;1>/*),sortedmulti_a(2,[0f056943/48h/1h/0h/3h]tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/<0;1>/*,[30afbe54/48h/1h/0h/3h]tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/<0;1>/*)},sortedmulti_a(2,[b7fe820c/48h/1h/0h/3h]tpubDFdQ1sNV53TbogAMPEd2egY5NXfbdKD1Mnr2iBrJrcwRHJbKC7tuuUMHT8SSHJ2VEKdCf5WYBMfevvWCnyJV53gYUT2wFyxEV8SuUTedBp7/<0;1>/*,[30afbe54/48h/1h/0h/3h]tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/<0;1>/*)})", - "tr(unspend(af042dea4fdb855b7b66732ce8512829d95bbf4963a7b28279d5a0b5b48e5bea)/<0;1>/*,{sortedmulti_a(2,[b7fe820c/48'/1'/0'/3']tpubDFdQ1sNV53TbogAMPEd2egY5NXfbdKD1Mnr2iBrJrcwRHJbKC7tuuUMHT8SSHJ2VEKdCf5WYBMfevvWCnyJV53gYUT2wFyxEV8SuUTedBp7/0/*,[30afbe54/48'/1'/0'/3']tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/0/*),{sortedmulti_a(2,[0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*,[b7fe820c/48'/1'/0'/3']tpubDFdQ1sNV53TbogAMPEd2egY5NXfbdKD1Mnr2iBrJrcwRHJbKC7tuuUMHT8SSHJ2VEKdCf5WYBMfevvWCnyJV53gYUT2wFyxEV8SuUTedBp7/0/*),sortedmulti_a(2,[0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*,[30afbe54/48'/1'/0'/3']tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/0/*)}})", - "tr(tpubD6NzVbkrYhZ4XB7hZjurMYsPsgNY32QYGZ8YFVU7cy1VBRNoYpKAVuUfqfUFss6BooXRrCeYAdK9av2yFnqWXZaUMJuZdpE9Kuh6gubCVHu/<0;1>/*,{sortedmulti_a(2,[b7fe820c/48'/1'/0'/3']tpubDFdQ1sNV53TbogAMPEd2egY5NXfbdKD1Mnr2iBrJrcwRHJbKC7tuuUMHT8SSHJ2VEKdCf5WYBMfevvWCnyJV53gYUT2wFyxEV8SuUTedBp7/0/*,[30afbe54/48'/1'/0'/3']tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/0/*),{sortedmulti_a(2,[0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*,[b7fe820c/48'/1'/0'/3']tpubDFdQ1sNV53TbogAMPEd2egY5NXfbdKD1Mnr2iBrJrcwRHJbKC7tuuUMHT8SSHJ2VEKdCf5WYBMfevvWCnyJV53gYUT2wFyxEV8SuUTedBp7/0/*),sortedmulti_a(2,[0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*,[30afbe54/48'/1'/0'/3']tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/0/*)}})", - "tr(unspend(f19573a10866ee9881769e24464f9a0e989c2cb8e585db385934130462abed90)/<0;1>/*,{{sortedmulti_a(2,[0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*,[b7fe820c/48'/1'/0'/3']tpubDFdQ1sNV53TbogAMPEd2egY5NXfbdKD1Mnr2iBrJrcwRHJbKC7tuuUMHT8SSHJ2VEKdCf5WYBMfevvWCnyJV53gYUT2wFyxEV8SuUTedBp7/0/*),sortedmulti_a(2,[0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*,[30afbe54/48'/1'/0'/3']tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/0/*)},sortedmulti_a(2,[b7fe820c/48'/1'/0'/3']tpubDFdQ1sNV53TbogAMPEd2egY5NXfbdKD1Mnr2iBrJrcwRHJbKC7tuuUMHT8SSHJ2VEKdCf5WYBMfevvWCnyJV53gYUT2wFyxEV8SuUTedBp7/0/*,[30afbe54/48'/1'/0'/3']tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/0/*)})", - "tr(unspend(dfed64ff493dca2ab09eadefaa0c88be8404908fa6eff869ff71c0d359d086b9)/<2;3>/*,{{sortedmulti_a(2,[0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*,[b7fe820c/48'/1'/0'/3']tpubDFdQ1sNV53TbogAMPEd2egY5NXfbdKD1Mnr2iBrJrcwRHJbKC7tuuUMHT8SSHJ2VEKdCf5WYBMfevvWCnyJV53gYUT2wFyxEV8SuUTedBp7/0/*),sortedmulti_a(2,[0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*,[30afbe54/48'/1'/0'/3']tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/0/*)},or_d(pk([0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*),and_v(v:pkh([30afbe54/48'/1'/0'/3']tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/0/*),older(500)))})", - "tr(unspend(b320077905d0954b01a8a328ea08c0ac3b4b066d1240f47a1b2c58651dcda4eb)/<0;1>/*,{{sortedmulti_a(2,[0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*,[b7fe820c/48'/1'/0'/3']tpubDFdQ1sNV53TbogAMPEd2egY5NXfbdKD1Mnr2iBrJrcwRHJbKC7tuuUMHT8SSHJ2VEKdCf5WYBMfevvWCnyJV53gYUT2wFyxEV8SuUTedBp7/0/*),sortedmulti_a(2,[0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*,[30afbe54/48'/1'/0'/3']tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/0/*)},or_d(pk([0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*),and_v(v:pkh([30afbe54/48'/1'/0'/3']tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/0/*),older(500)))})", + "tr(unspend(),{{sortedmulti_a(2,[0f056943/48h/1h/0h/3h]tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/<0;1>/*,[b7fe820c/48h/1h/0h/3h]tpubDFdQ1sNV53TbogAMPEd2egY5NXfbdKD1Mnr2iBrJrcwRHJbKC7tuuUMHT8SSHJ2VEKdCf5WYBMfevvWCnyJV53gYUT2wFyxEV8SuUTedBp7/<0;1>/*),sortedmulti_a(2,[0f056943/48h/1h/0h/3h]tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/<0;1>/*,[30afbe54/48h/1h/0h/3h]tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/<0;1>/*)},sortedmulti_a(2,[b7fe820c/48h/1h/0h/3h]tpubDFdQ1sNV53TbogAMPEd2egY5NXfbdKD1Mnr2iBrJrcwRHJbKC7tuuUMHT8SSHJ2VEKdCf5WYBMfevvWCnyJV53gYUT2wFyxEV8SuUTedBp7/<0;1>/*,[30afbe54/48h/1h/0h/3h]tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/<0;1>/*)})", + "tr(unspend(),{sortedmulti_a(2,[b7fe820c/48'/1'/0'/3']tpubDFdQ1sNV53TbogAMPEd2egY5NXfbdKD1Mnr2iBrJrcwRHJbKC7tuuUMHT8SSHJ2VEKdCf5WYBMfevvWCnyJV53gYUT2wFyxEV8SuUTedBp7/0/*,[30afbe54/48'/1'/0'/3']tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/0/*),{sortedmulti_a(2,[0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*,[b7fe820c/48'/1'/0'/3']tpubDFdQ1sNV53TbogAMPEd2egY5NXfbdKD1Mnr2iBrJrcwRHJbKC7tuuUMHT8SSHJ2VEKdCf5WYBMfevvWCnyJV53gYUT2wFyxEV8SuUTedBp7/0/*),sortedmulti_a(2,[0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*,[30afbe54/48'/1'/0'/3']tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/0/*)}})", + "tr(unspend(),{sortedmulti_a(2,[b7fe820c/48'/1'/0'/3']tpubDFdQ1sNV53TbogAMPEd2egY5NXfbdKD1Mnr2iBrJrcwRHJbKC7tuuUMHT8SSHJ2VEKdCf5WYBMfevvWCnyJV53gYUT2wFyxEV8SuUTedBp7/0/*,[30afbe54/48'/1'/0'/3']tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/0/*),{sortedmulti_a(2,[0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*,[b7fe820c/48'/1'/0'/3']tpubDFdQ1sNV53TbogAMPEd2egY5NXfbdKD1Mnr2iBrJrcwRHJbKC7tuuUMHT8SSHJ2VEKdCf5WYBMfevvWCnyJV53gYUT2wFyxEV8SuUTedBp7/0/*),sortedmulti_a(2,[0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*,[30afbe54/48'/1'/0'/3']tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/0/*)}})", + "tr(unspend(),{{sortedmulti_a(2,[0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*,[b7fe820c/48'/1'/0'/3']tpubDFdQ1sNV53TbogAMPEd2egY5NXfbdKD1Mnr2iBrJrcwRHJbKC7tuuUMHT8SSHJ2VEKdCf5WYBMfevvWCnyJV53gYUT2wFyxEV8SuUTedBp7/0/*),sortedmulti_a(2,[0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*,[30afbe54/48'/1'/0'/3']tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/0/*)},sortedmulti_a(2,[b7fe820c/48'/1'/0'/3']tpubDFdQ1sNV53TbogAMPEd2egY5NXfbdKD1Mnr2iBrJrcwRHJbKC7tuuUMHT8SSHJ2VEKdCf5WYBMfevvWCnyJV53gYUT2wFyxEV8SuUTedBp7/0/*,[30afbe54/48'/1'/0'/3']tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/0/*)})", + "tr(unspend(),{{sortedmulti_a(2,[0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*,[b7fe820c/48'/1'/0'/3']tpubDFdQ1sNV53TbogAMPEd2egY5NXfbdKD1Mnr2iBrJrcwRHJbKC7tuuUMHT8SSHJ2VEKdCf5WYBMfevvWCnyJV53gYUT2wFyxEV8SuUTedBp7/0/*),sortedmulti_a(2,[0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*,[30afbe54/48'/1'/0'/3']tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/0/*)},or_d(pk([0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*),and_v(v:pkh([30afbe54/48'/1'/0'/3']tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/0/*),older(500)))})", + "tr(unspend(),{{sortedmulti_a(2,[0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*,[b7fe820c/48'/1'/0'/3']tpubDFdQ1sNV53TbogAMPEd2egY5NXfbdKD1Mnr2iBrJrcwRHJbKC7tuuUMHT8SSHJ2VEKdCf5WYBMfevvWCnyJV53gYUT2wFyxEV8SuUTedBp7/0/*),sortedmulti_a(2,[0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*,[30afbe54/48'/1'/0'/3']tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/0/*)},or_d(pk([0f056943/48'/1'/0'/3']tpubDF2rnouQaaYrY6CUWTapYkeFEs3h3qrzL4M52ZGoPeU9dkarJMtrw6VF1zJRGuGuAFxYS3kXtavfAwQPTQkU5dyNYpbgxcpftrR8H3U85Ez/0/*),and_v(v:pkh([30afbe54/48'/1'/0'/3']tpubDFLVv7cuiLjn3QcsCend5kn3yw5sx6Czazy7hZvdGX61v8pkU95k2Byz9M5jnabzeUg7qWtHYLeKQyCWWAHhUmQQMeZ4Dee2CfGR2TsZqrN/0/*),older(500)))})", ]) def test_tapscript_import_export(clear_miniscript, pick_menu_item, cap_story, import_miniscript, load_export, desc, microsd_path, press_select): + i = random.randint(2, 10) # needs to be disjoint + unspend = ranged_unspendable_internal_key(os.urandom(32), subderiv=f"/<{i};{i+1}>/*") + desc = desc.replace("unspend()", unspend) clear_miniscript() fname = "imdesc.txt" with open(microsd_path(fname), "w") as f: @@ -1246,12 +1213,7 @@ def test_tapscript_import_export(clear_miniscript, pick_menu_item, cap_story, pick_menu_item(fname.split(".")[0]) pick_menu_item("Descriptors") pick_menu_item("Export") - time.sleep(.1) - title, story = cap_story() - assert "(<0;1> notation) press OK" in story - press_select() - contents = load_export("sd", label="Miniscript", is_json=False, addr_fmt=AF_P2TR, - sig_check=False) + contents = load_export("sd", label="Miniscript", is_json=False, addr_fmt=AF_P2TR) descriptor = contents.strip() assert desc.split("#")[0].replace("<0;1>/*", "0/*").replace("'", "h") == descriptor.split("#")[0].replace("<0;1>/*", "0/*").replace("'", "h") @@ -1259,14 +1221,15 @@ def test_tapscript_import_export(clear_miniscript, pick_menu_item, cap_story, def test_duplicate_tapscript_leaves(use_regtest, clear_miniscript, microsd_wipe, bitcoind, dev, goto_home, pick_menu_item, microsd_path, import_miniscript, cap_story, load_export, get_cc_key, garbage_collector, - bitcoin_core_signer, import_duplicate, press_select): + bitcoin_core_signer, import_duplicate, press_select, + create_core_wallet): # works in core - but some discussions are ongoing # https://github.com/bitcoin/bitcoin/issues/27104 # CC also allows this for now... (experimental branch) use_regtest() clear_miniscript() microsd_wipe() - ss, core_key = bitcoin_core_signer(f"dup_leafs") + ss, core_key = bitcoin_core_signer(f"s1_dup_leafs") cc_key = get_cc_key("86h/0h/100h") cc_leaf = f"pk({cc_key})" @@ -1284,39 +1247,13 @@ def test_duplicate_tapscript_leaves(use_regtest, clear_miniscript, microsd_wipe, _, story = import_miniscript(fname) assert "Create new miniscript wallet?" in story assert fname.split(".")[0] in story - assert "Taproot internal key" in story - assert "Tapscript" in story assert "Press (1) to see extended public keys" in story assert "P2TR" in story press_select() import_duplicate(fname) - goto_home() - pick_menu_item('Settings') - pick_menu_item('Miniscript') - pick_menu_item(fname.split(".")[0]) - pick_menu_item("Descriptors") - pick_menu_item("Bitcoin Core") - text = load_export("sd", label="Bitcoin Core miniscript", is_json=False, sig_check=False) - text = text.replace("importdescriptors ", "").strip() - # remove junk - r1 = text.find("[") - r2 = text.find("]", -1, 0) - text = text[r1: r2] - core_desc_object = json.loads(text) - # wo wallet - ts = bitcoind.create_wallet( - wallet_name=f"dup_leafs_wo", disable_private_keys=True, - blank=True, passphrase=None, avoid_reuse=False, descriptors=True - ) - # import descriptors to watch only wallet - res = ts.importdescriptors(core_desc_object) - assert res[0]["success"] - assert res[1]["success"] - addr = ts.getnewaddress("", "bech32m") - assert bitcoind.supply_wallet.sendtoaddress(addr, 49) - bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) + ts = create_core_wallet(fname.split(".")[0], "bech32m", "sd", True) dest_addr = ts.getnewaddress("", "bech32m") # selfspend psbt = ts.walletcreatefundedpsbt([], [{dest_addr: 1.0}], 0, {"fee_rate": 2})["psbt"] @@ -1363,7 +1300,7 @@ def test_duplicate_tapscript_leaves(use_regtest, clear_miniscript, microsd_wipe, def test_same_key_account_based_minisc(goto_home, pick_menu_item, cap_story, clear_miniscript, microsd_path, load_export, bitcoind, import_miniscript, use_regtest, import_duplicate, - press_select, garbage_collector): + press_select, garbage_collector, create_core_wallet): clear_miniscript() use_regtest() @@ -1387,32 +1324,8 @@ def test_same_key_account_based_minisc(goto_home, pick_menu_item, cap_story, press_select() import_duplicate(fname) - goto_home() - pick_menu_item('Settings') - pick_menu_item('Miniscript') - pick_menu_item(fname.split(".")[0]) - pick_menu_item("Descriptors") - pick_menu_item("Bitcoin Core") - text = load_export("sd", label="Bitcoin Core miniscript", is_json=False, sig_check=False) - text = text.replace("importdescriptors ", "").strip() - # remove junk - r1 = text.find("[") - r2 = text.find("]", -1, 0) - text = text[r1: r2] - core_desc_object = json.loads(text) - # wo wallet - wo = bitcoind.create_wallet( - wallet_name=f"multi-account", disable_private_keys=True, - blank=True, passphrase=None, avoid_reuse=False, descriptors=True - ) - # import descriptors to watch only wallet - res = wo.importdescriptors(core_desc_object) - assert res[0]["success"] - assert res[1]["success"] - addr = wo.getnewaddress("", "bech32") - assert bitcoind.supply_wallet.sendtoaddress(addr, 49) - bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) + wo = create_core_wallet(fname.split(".")[0], "bech32", "sd", True) dest_addr = wo.getnewaddress("", "bech32") # selfspend psbt = wo.walletcreatefundedpsbt([], [{dest_addr: 1.0}], 0, {"fee_rate": 2})["psbt"] @@ -1504,7 +1417,7 @@ CHANGE_BASED_DESCS = [ def test_same_key_change_based_minisc(goto_home, pick_menu_item, cap_story, clear_miniscript, microsd_path, load_export, bitcoind, import_miniscript, address_explorer_check, use_regtest, - desc, press_select, garbage_collector): + desc, press_select, garbage_collector, create_core_wallet): clear_miniscript() use_regtest() if desc.startswith("tr("): @@ -1523,34 +1436,9 @@ def test_same_key_change_based_minisc(goto_home, pick_menu_item, cap_story, assert "Create new miniscript wallet?" in story assert fname.split(".")[0] in story assert "Press (1) to see extended public keys" in story - press_select() - goto_home() - pick_menu_item('Settings') - pick_menu_item('Miniscript') - pick_menu_item(fname.split(".")[0]) - pick_menu_item("Descriptors") - pick_menu_item("Bitcoin Core") - text = load_export("sd", label="Bitcoin Core miniscript", is_json=False, sig_check=False) - text = text.replace("importdescriptors ", "").strip() - # remove junk - r1 = text.find("[") - r2 = text.find("]", -1, 0) - text = text[r1: r2] - core_desc_object = json.loads(text) - # wo wallet - wo = bitcoind.create_wallet( - wallet_name=f"minsc-change", disable_private_keys=True, - blank=True, passphrase=None, avoid_reuse=False, descriptors=True - ) - # import descriptors to watch only wallet - res = wo.importdescriptors(core_desc_object) - assert res[0]["success"] - assert res[1]["success"] - addr = wo.getnewaddress("", af) - assert bitcoind.supply_wallet.sendtoaddress(addr, 49) - bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) + wo = create_core_wallet(name, af, "sd", True) dest_addr = wo.getnewaddress("", af) # selfspend psbt = wo.walletcreatefundedpsbt([], [{dest_addr: 1.0}], 0, {"fee_rate": 2})["psbt"] @@ -1639,26 +1527,6 @@ def test_same_key_change_based_minisc(goto_home, pick_menu_item, cap_story, address_explorer_check("sd", af, wo, "mini-change") -def test_same_key_account_based_multisig(goto_home, pick_menu_item, cap_story, - clear_miniscript, microsd_path, load_export, bitcoind, - import_miniscript, garbage_collector): - clear_miniscript() - desc = ("wsh(sortedmulti(2," - "[0f056943/84'/1'/0']tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<0;1>/*," - "[0f056943/84'/1'/9']tpubDC7jGaaSE66QBAcX8TUD3JKWari1zmGH4gNyKZcrfq6NwCofKujNF2kyeVXgKshotxw5Yib8UxLrmmCmWd8NVPVTAL8rGfMdc7TsAKqsy6y/<0;1>/*" - "))") - name = "multi-accounts" - fname = f"{name}.txt" - fpath = microsd_path(fname) - with open(fpath, "w") as f: - f.write(desc) - garbage_collector.append(fpath) - - _, story = import_miniscript(fname) - assert "Failed to import" in story - assert "Use Settings -> Multisig Wallets" in story - - @pytest.mark.parametrize("desc", [ "wsh(or_d(pk(@A),and_v(v:pkh(@A),older(5))))", "tr(@ik,multi_a(2,@A,@A))", @@ -1706,7 +1574,6 @@ def test_tapscript_depth(get_cc_key, pick_menu_item, cap_story, @pytest.mark.parametrize("same_acct", [True, False]) @pytest.mark.parametrize("recovery", [True, False]) @pytest.mark.parametrize("leaf2_mine", [True, False]) -@pytest.mark.parametrize("internal_type", ["unspend(", "xpub"]) @pytest.mark.parametrize("minisc", [ "or_d(pk(@A),and_v(v:pkh(@B),locktime(N)))", @@ -1717,11 +1584,11 @@ def test_tapscript_depth(get_cc_key, pick_menu_item, cap_story, "or_d(pk(@A),and_v(v:multi_a(2,@B,@C),locktime(N)))", ]) def test_minitapscript(leaf2_mine, recovery, minisc, clear_miniscript, goto_home, - pick_menu_item, cap_menu, cap_story, microsd_path, internal_type, + pick_menu_item, cap_menu, cap_story, microsd_path, use_regtest, bitcoind, microsd_wipe, load_export, dev, address_explorer_check, get_cc_key, import_miniscript, bitcoin_core_signer, same_acct, import_duplicate, press_select, - garbage_collector): + garbage_collector, start_sign, end_sign, create_core_wallet): lt_type = "older" # needs bitcoind 26.0 normal_cosign_core = False @@ -1748,6 +1615,7 @@ def test_minitapscript(leaf2_mine, recovery, minisc, clear_miniscript, goto_home for i in range(3): # core signers signer, core_key = bitcoin_core_signer(f"co-signer{i}") + signer.keypoolrefill(25) core_keys.append(core_key) signers.append(signer) @@ -1770,11 +1638,7 @@ def test_minitapscript(leaf2_mine, recovery, minisc, clear_miniscript, goto_home if "@C" in minisc: minisc = minisc.replace("@C", core_keys[1]) - if internal_type == "unspend(": - ik = f"unspend({os.urandom(32).hex()})/<2;3>/*" - else: - assert internal_type == "xpub" - ik = ranged_unspendable_internal_key(os.urandom(32)) + ik = ranged_unspendable_internal_key(os.urandom(32)) if leaf2_mine: desc = f"tr({ik},{{{minisc},pk({cc_key1})}})" @@ -1790,50 +1654,38 @@ def test_minitapscript(leaf2_mine, recovery, minisc, clear_miniscript, goto_home f.write(desc) garbage_collector.append(fpath) - - wo = bitcoind.create_wallet(wallet_name=name, disable_private_keys=True, blank=True, - passphrase=None, avoid_reuse=False, descriptors=True) - _, story = import_miniscript(fname) assert "Create new miniscript wallet?" in story # do some checks on policy --> helper function to replace keys with letters press_select() import_duplicate(fname) - menu = cap_menu() - assert menu[0] == name - pick_menu_item(menu[0]) # pick imported descriptor multisig wallet - pick_menu_item("Descriptors") - pick_menu_item("Bitcoin Core") - text = load_export("sd", label="Bitcoin Core miniscript", is_json=False, sig_check=False) - text = text.replace("importdescriptors ", "").strip() - # remove junk - r1 = text.find("[") - r2 = text.find("]", -1, 0) - text = text[r1: r2] - core_desc_object = json.loads(text) - res = wo.importdescriptors(core_desc_object) - for obj in res: - assert obj["success"] - addr = wo.getnewaddress("", "bech32m") - addr_dest = wo.getnewaddress("", "bech32m") # self-spend - assert bitcoind.supply_wallet.sendtoaddress(addr, 49) - bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) + + wo = create_core_wallet(name, "bech32m", "sd", True) + all_of_it = wo.getbalance() unspent = wo.listunspent() assert len(unspent) == 1 inp = {"txid": unspent[0]["txid"], "vout": unspent[0]["vout"]} + if recovery and sequence and not leaf2_mine: inp["sequence"] = sequence + + # split to + num_outs = 20 + nVal = all_of_it / num_outs + conso_addrs = [{wo.getnewaddress("", "bech32m"): nVal} for _ in range(num_outs)] # self-spend psbt_resp = wo.walletcreatefundedpsbt( [inp], - [{addr_dest: all_of_it - 1}], + conso_addrs, locktime if (recovery and not leaf2_mine) else 0, - {"fee_rate": 20, "change_type": "bech32m", "subtractFeeFromOutputs": [0]}, + {"fee_rate": 2, "change_type": "bech32m", "subtractFeeFromOutputs": [0]}, ) psbt = psbt_resp.get("psbt") if (normal_cosign_core or recovery_cosign_core) and not leaf2_mine: - psbt = signers[1].walletprocesspsbt(psbt, True, "ALL")["psbt"] + psbt_res = signers[1].walletprocesspsbt(psbt, True, "DEFAULT") + assert psbt_res["psbt"] != psbt + psbt = psbt_res.get("psbt") name = f"{name}.psbt" fpath = microsd_path(name) @@ -1850,6 +1702,9 @@ def test_minitapscript(leaf2_mine, recovery, minisc, clear_miniscript, goto_home time.sleep(0.1) title, story = cap_story() assert title == "OK TO SEND?" + assert "warning" not in story + assert "1 input" in story + assert "20 outputs" in story assert "Consolidating" in story press_select() # confirm signing time.sleep(0.5) @@ -1882,6 +1737,63 @@ def test_minitapscript(leaf2_mine, recovery, minisc, clear_miniscript, goto_home res = wo.sendrawtransaction(tx_hex) assert len(res) == 64 # tx id + bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) + unspent = wo.listunspent() + assert len(unspent) == 20 + ins = [{"txid": u["txid"], "vout": u["vout"]} for u in unspent] + + if recovery and sequence and not leaf2_mine: + for i in ins: + i["sequence"] = sequence + + # consolidate multiple inputs to one for us + # BUT also send 1 corn back to supply (so not a consolidation) + outs = [ + {wo.getnewaddress("", "bech32m"): wo.getbalance() - 1}, + {bitcoind.supply_wallet.getnewaddress("", "bech32"): 1}, + ] + psbt_resp = wo.walletcreatefundedpsbt( + ins, + outs, + locktime if (recovery and not leaf2_mine) else 0, + {"fee_rate": 2, "change_type": "bech32m", "subtractFeeFromOutputs": [0]}, + ) + psbt = psbt_resp.get("psbt") + + # now CC first + start_sign(base64.b64decode(psbt)) + time.sleep(.1) + title, story = cap_story() + assert title == "OK TO SEND?" + assert "warning" not in story + assert "Consolidating" not in story + assert "20 inputs" in story + assert "2 outputs" in story + final_psbt = end_sign(True) + psbt = base64.b64encode(final_psbt).decode() + + if (normal_cosign_core or recovery_cosign_core) and not leaf2_mine: + # core co-signer second after CC (if needed) + psbt_res = signers[1].walletprocesspsbt(psbt, True, "DEFAULT") + assert psbt_res["psbt"] != psbt + psbt = psbt_res.get("psbt") + + res = wo.finalizepsbt(psbt) + assert res["complete"] + tx_hex = res["hex"] + res = wo.testmempoolaccept([tx_hex]) + if recovery and not leaf2_mine: + assert not res[0]["allowed"] + assert res[0]["reject-reason"] == 'non-BIP68-final' if sequence else "non-final" + bitcoind.supply_wallet.generatetoaddress(6, bitcoind.supply_wallet.getnewaddress()) + res = wo.testmempoolaccept([tx_hex]) + assert res[0]["allowed"] + else: + assert res[0]["allowed"] + + res = wo.sendrawtransaction(tx_hex) + assert len(res) == 64 # tx id + # check addresses address_explorer_check("sd", "bech32m", wo, "minitapscript") @@ -1913,7 +1825,7 @@ def test_timelock_mixin(): def test_d_wrapper(addr_fmt, bitcoind, get_cc_key, goto_home, pick_menu_item, cap_story, cap_menu, load_export, microsd_path, use_regtest, clear_miniscript, cc_first, address_explorer_check, import_miniscript, bitcoin_core_signer, press_select, - garbage_collector): + garbage_collector, create_core_wallet): # check D wrapper u property for segwit v0 and v1 # https://github.com/bitcoin/bitcoin/pull/24906/files @@ -1945,9 +1857,6 @@ def test_d_wrapper(addr_fmt, bitcoind, get_cc_key, goto_home, pick_menu_item, ca f.write(desc) garbage_collector.append(fpath) - wo = bitcoind.create_wallet(wallet_name=name, disable_private_keys=True, blank=True, - passphrase=None, avoid_reuse=False, descriptors=True) - clear_miniscript() use_regtest() _, story = import_miniscript(fname) @@ -1959,26 +1868,10 @@ def test_d_wrapper(addr_fmt, bitcoind, get_cc_key, goto_home, pick_menu_item, ca assert "Create new miniscript wallet?" in story # do some checks on policy --> helper function to replace keys with letters press_select() - menu = cap_menu() - assert menu[0] == name - pick_menu_item(menu[0]) # pick imported descriptor multisig wallet - pick_menu_item("Descriptors") - pick_menu_item("Bitcoin Core") - text = load_export("sd", label="Bitcoin Core miniscript", is_json=False, sig_check=False) - text = text.replace("importdescriptors ", "").strip() - # remove junk - r1 = text.find("[") - r2 = text.find("]", -1, 0) - text = text[r1: r2] - core_desc_object = json.loads(text) - res = wo.importdescriptors(core_desc_object) - for obj in res: - assert obj["success"] - addr = wo.getnewaddress("", addr_fmt) # self-spend + wo = create_core_wallet(name, addr_fmt, "sd", True) + addr_dest = wo.getnewaddress("", addr_fmt) # self-spend - assert bitcoind.supply_wallet.sendtoaddress(addr, 49) - bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) all_of_it = wo.getbalance() unspent = wo.listunspent() assert len(unspent) == 1 @@ -2082,10 +1975,10 @@ def test_chain_switching(use_mainnet, use_regtest, settings_get, settings_set, import_miniscript(fname_xtn) press_select() - # assert that wallets created at XRT always store XTN anywas (key_chain) - res = settings_get("miniscript") + time.sleep(.1) + res = settings_get("miniscript", []) assert len(res) == 1 - assert res[0][1] == "XTN" + assert res[0][-1]["ct"] == "XRT" goto_home() pick_menu_item("Settings") @@ -2100,9 +1993,8 @@ def test_chain_switching(use_mainnet, use_regtest, settings_get, settings_set, pick_menu_item("Miniscript") time.sleep(0.1) m = cap_menu() - # asterisk hints that some wallets are already stored # but not on current active chain - assert "(none setup yet)*" in m + assert "(none setup yet)" in m import_miniscript(fname_btc) press_select() goto_home() @@ -2140,12 +2032,10 @@ def test_chain_switching(use_mainnet, use_regtest, settings_get, settings_set, "or_d(pk(@A),and_v(v:pkh(@B),after(100)))", "or_d(multi(2,@A,@C),and_v(v:pkh(@B),after(100)))", ]) -def test_import_same_policy_same_keys_diff_order(taproot_ikspendable, minisc, - clear_miniscript, use_regtest, - get_cc_key, bitcoin_core_signer, - offer_minsc_import, cap_menu, - bitcoind, pick_menu_item, - press_select): +def test_import_same_policy_same_keys_diff_order(taproot_ikspendable, minisc, use_regtest, + clear_miniscript, bitcoin_core_signer, + get_cc_key, settings_get, cap_menu, + offer_minsc_import, bitcoind, press_select): use_regtest() clear_miniscript() taproot, ik_spendable = taproot_ikspendable @@ -2189,21 +2079,16 @@ def test_import_same_policy_same_keys_diff_order(taproot_ikspendable, minisc, title, story = offer_minsc_import(desc1) assert "Create new miniscript wallet?" in story press_select() - pick_menu_item("Settings") - pick_menu_item("Miniscript") - m = cap_menu() - m = [i for i in m if not i.startswith("Import")] - assert len(m) == 2 + time.sleep(.2) + assert len(settings_get("miniscript", [])) == 2 @pytest.mark.parametrize("cs", [True, False]) @pytest.mark.parametrize("way", ["usb", "nfc", "sd", "vdisk"]) -def test_import_miniscript_usb_json(use_regtest, cs, way, cap_menu, - clear_miniscript, pick_menu_item, - get_cc_key, bitcoin_core_signer, - offer_minsc_import, bitcoind, microsd_path, - virtdisk_path, import_miniscript, goto_home, - press_select): +def test_import_miniscript_usb_json(use_regtest, cs, way, cap_menu, clear_miniscript, get_cc_key, + bitcoin_core_signer, offer_minsc_import, bitcoind, microsd_path, + virtdisk_path, import_miniscript, goto_home, press_select, + settings_get): name = "my_minisc" minsc = f"tr({ranged_unspendable_internal_key()},or_d(multi_a(2,@A,@C),and_v(v:pkh(@B),after(100))))" use_regtest() @@ -2246,13 +2131,9 @@ def test_import_miniscript_usb_json(use_regtest, cs, way, cap_menu, assert name in story press_select() time.sleep(.2) - goto_home() - pick_menu_item("Settings") - pick_menu_item("Miniscript") - m = cap_menu() - m = [i for i in m if not i.startswith("Import")] - assert len(m) == 1 - assert m[0] == name + msc = settings_get("miniscript", []) + assert len(msc) == 1 + assert msc[0][0] == name @pytest.mark.parametrize("config", [ @@ -2297,23 +2178,21 @@ def test_unique_name(clear_miniscript, use_regtest, offer_minsc_import, pick_menu_item("Settings") pick_menu_item("Miniscript") m = cap_menu() - m = [i for i in m if not i.startswith("Import")] - assert len(m) == 1 assert m[0] == name + assert m[1] == "Import" # completely different wallet but with the same name (USB) yd = json.dumps({"name": name, "desc": y}) title, story = offer_minsc_import(yd) - assert title == "FAILED" + assert ("'%s' already exists" % name) in story assert "MUST have unique names" in story press_select() # nothing imported pick_menu_item("Settings") pick_menu_item("Miniscript") m = cap_menu() - m = [i for i in m if not i.startswith("Import")] - assert len(m) == 1 assert m[0] == name + assert m[1] == "Import" goto_home() fname = f"{name}.txt" @@ -2335,7 +2214,7 @@ def test_unique_name(clear_miniscript, use_regtest, offer_minsc_import, f.write(yd if is_json else y) title, story = import_miniscript(fname=fname, way=way, data=nfc_data) - assert "FAILED" == title + assert ("'%s' already exists" % name) in story assert "MUST have unique names" in story @@ -2527,7 +2406,8 @@ aA+bduIqWCMpBW2K5F0FuxfY4ofjfGWLKDMAAAgAEAAIAAAACAAgAAgAEAAAADAAAAAA==""" def test_expanding_multisig(tmplt, clear_miniscript, goto_home, pick_menu_item, garbage_collector, cap_menu, cap_story, microsd_path, use_regtest, bitcoind, microsd_wipe, load_export, dev, address_explorer_check, get_cc_key, import_miniscript, - bitcoin_core_signer, import_duplicate, press_select, start_sign, end_sign): + bitcoin_core_signer, import_duplicate, press_select, start_sign, end_sign, + create_core_wallet): use_regtest() clear_miniscript() sequence = 10 @@ -2565,33 +2445,12 @@ def test_expanding_multisig(tmplt, clear_miniscript, goto_home, pick_menu_item, garbage_collector.append(fpath) - wo = bitcoind.create_wallet(wallet_name=wname, disable_private_keys=True, blank=True, - passphrase=None, avoid_reuse=False, descriptors=True) - _, story = import_miniscript(fname) assert "Create new miniscript wallet?" in story # do some checks on policy --> helper function to replace keys with letters press_select() - menu = cap_menu() - assert menu[0] == wname - pick_menu_item(menu[0]) # pick imported descriptor multisig wallet - pick_menu_item("Descriptors") - pick_menu_item("Bitcoin Core") - text = load_export("sd", label="Bitcoin Core miniscript", is_json=False, sig_check=False) - text = text.replace("importdescriptors ", "").strip() - # remove junk - r1 = text.find("[") - r2 = text.find("]", -1, 0) - text = text[r1: r2] - core_desc_object = json.loads(text) - res = wo.importdescriptors(core_desc_object) - for obj in res: - assert obj["success"] - # fund wallet - addr = wo.getnewaddress("", af) - assert bitcoind.supply_wallet.sendtoaddress(addr, 49) - bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) + wo = create_core_wallet(wname, af, "sd", True) # use non-recovery path to split into 5 utxos + 1 going back to supply (not a conso) unspent = wo.listunspent() @@ -2614,17 +2473,21 @@ def test_expanding_multisig(tmplt, clear_miniscript, goto_home, pick_menu_item, psbt = csigner0.walletprocesspsbt(psbt, True)["psbt"] # now CC - start_sign(base64.b64decode(psbt)) + start_sign(base64.b64decode(psbt), finalize=have_internal) time.sleep(.1) title, story = cap_story() assert title == "OK TO SEND?" assert "Consolidating" not in story - final_psbt = end_sign(True) + final_psbt = end_sign(True, finalize=have_internal) + + if have_internal: + tx_hex = final_psbt.hex() # it is final tx actually + else: + # client software finalization + res = wo.finalizepsbt(base64.b64encode(final_psbt).decode()) + assert res["complete"] + tx_hex = res["hex"] - # client software finalization - res = wo.finalizepsbt(base64.b64encode(final_psbt).decode()) - assert res["complete"] - tx_hex = res["hex"] res = wo.testmempoolaccept([tx_hex]) assert res[0]["allowed"] res = wo.sendrawtransaction(tx_hex) @@ -2645,23 +2508,27 @@ def test_expanding_multisig(tmplt, clear_miniscript, goto_home, pick_menu_item, psbt = psbt_resp.get("psbt") # now CC signing first - start_sign(base64.b64decode(psbt)) + start_sign(base64.b64decode(psbt), finalize=have_internal) time.sleep(.1) title, story = cap_story() assert title == "OK TO SEND?" assert "Consolidating" in story - updated_psbt = end_sign(True) - updated_psbt = base64.b64encode(updated_psbt).decode() + updated_psbt = end_sign(True, finalize=have_internal) if not have_internal: # now cosigner (still on non-recovery path) + updated_psbt = base64.b64encode(updated_psbt).decode() final_psbt = csigner0.walletprocesspsbt(updated_psbt, True, "DEFAULT"if "tr(" == tmplt[:3] else "ALL")["psbt"] - # client software finalization - res = wo.finalizepsbt(final_psbt) - assert res["complete"] - tx_hex = res["hex"] + # client software finalization + res = wo.finalizepsbt(final_psbt) + assert res["complete"] + tx_hex = res["hex"] + else: + # actually a final tx + tx_hex = updated_psbt.hex() + res = wo.testmempoolaccept([tx_hex]) assert res[0]["allowed"] res = wo.sendrawtransaction(tx_hex) @@ -2726,7 +2593,8 @@ def test_expanding_multisig(tmplt, clear_miniscript, goto_home, pick_menu_item, @pytest.mark.parametrize("blinded", [True, False]) def test_big_boy(use_regtest, clear_miniscript, bitcoin_core_signer, get_cc_key, microsd_path, garbage_collector, pick_menu_item, bitcoind, import_miniscript, press_select, - cap_story, cap_menu, load_export, start_sign, end_sign, blinded): + cap_story, cap_menu, load_export, start_sign, end_sign, blinded, + create_core_wallet): # keys (@0,@4,@5) are more important (primary) than keys (@1,@2,@3) (secondary) # currently requires to tweak MAX_TR_SIGNERS = 33 # with blinded=True, all co-signer keys are blinded (have no key origin info) @@ -2769,33 +2637,12 @@ def test_big_boy(use_regtest, clear_miniscript, bitcoin_core_signer, get_cc_key, garbage_collector.append(fpath) - wo = bitcoind.create_wallet(wallet_name=wname, disable_private_keys=True, blank=True, - passphrase=None, avoid_reuse=False, descriptors=True) - _, story = import_miniscript(fname) assert "Create new miniscript wallet?" in story # do some checks on policy --> helper function to replace keys with letters press_select() - menu = cap_menu() - assert menu[0] == wname - pick_menu_item(menu[0]) # pick imported descriptor multisig wallet - pick_menu_item("Descriptors") - pick_menu_item("Bitcoin Core") - text = load_export("sd", label="Bitcoin Core miniscript", is_json=False, sig_check=False) - text = text.replace("importdescriptors ", "").strip() - # remove junk - r1 = text.find("[") - r2 = text.find("]", -1, 0) - text = text[r1: r2] - core_desc_object = json.loads(text) - res = wo.importdescriptors(core_desc_object) - for obj in res: - assert obj["success"] - # fund wallet - addr = wo.getnewaddress("", af) - assert bitcoind.supply_wallet.sendtoaddress(addr, 49) - bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) + wo = create_core_wallet(wname, af, "sd", True) unspent = wo.listunspent() assert len(unspent) == 1 @@ -2840,7 +2687,7 @@ def test_big_boy(use_regtest, clear_miniscript, bitcoin_core_signer, get_cc_key, def test_single_key_miniscript(af, settings_set, clear_miniscript, goto_home, get_cc_key, garbage_collector, microsd_path, bitcoind, import_miniscript, press_select, cap_menu, pick_menu_item, load_export, cap_story, - start_sign, end_sign): + start_sign, end_sign, create_core_wallet): sequence = 10 goto_home() clear_miniscript() @@ -2863,33 +2710,12 @@ def test_single_key_miniscript(af, settings_set, clear_miniscript, goto_home, ge garbage_collector.append(fpath) - wo = bitcoind.create_wallet(wallet_name=wname, disable_private_keys=True, blank=True, - passphrase=None, avoid_reuse=False, descriptors=True) - _, story = import_miniscript(fname) assert "Create new miniscript wallet?" in story # do some checks on policy --> helper function to replace keys with letters press_select() - menu = cap_menu() - assert menu[0] == wname - pick_menu_item(menu[0]) # pick imported descriptor multisig wallet - pick_menu_item("Descriptors") - pick_menu_item("Bitcoin Core") - text = load_export("sd", label="Bitcoin Core miniscript", is_json=False, sig_check=False) - text = text.replace("importdescriptors ", "").strip() - # remove junk - r1 = text.find("[") - r2 = text.find("]", -1, 0) - text = text[r1: r2] - core_desc_object = json.loads(text) - res = wo.importdescriptors(core_desc_object) - for obj in res: - assert obj["success"] - # fund wallet - addr = wo.getnewaddress("", af) - assert bitcoind.supply_wallet.sendtoaddress(addr, 49) - bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) + wo = create_core_wallet(wname, af, "sd", True) unspent = wo.listunspent() assert len(unspent) == 1 @@ -2980,7 +2806,7 @@ def test_single_key_miniscript(af, settings_set, clear_miniscript, goto_home, ge def test_originless_keys(tmplt, offer_minsc_import, get_cc_key, bitcoin_core_signer, bitcoind, pick_menu_item, load_export, goto_home, cap_menu, clear_miniscript, use_regtest, press_select, start_sign, end_sign, cap_story, cc_sign, - has_orig, address_explorer_check): + has_orig, address_explorer_check, create_core_wallet): # can be both: # a.) just ranged xpub without origin info -> xpub1/<0;1>/* # b.) ranged xpub with its fp -> [xpub1_fp]xpub1/<0;1>/* @@ -3005,32 +2831,7 @@ def test_originless_keys(tmplt, offer_minsc_import, get_cc_key, bitcoin_core_sig offer_minsc_import(json.dumps(to_import)) press_select() - wo = bitcoind.create_wallet(wallet_name=name, disable_private_keys=True, blank=True, - passphrase=None, avoid_reuse=False, descriptors=True) - - goto_home() - pick_menu_item("Settings") - pick_menu_item("Miniscript") - menu = cap_menu() - assert menu[0] == name - pick_menu_item(menu[0]) # pick imported descriptor miniscript wallet - pick_menu_item("Descriptors") - pick_menu_item("Bitcoin Core") - text = load_export("sd", label="Bitcoin Core miniscript", is_json=False, sig_check=False) - text = text.replace("importdescriptors ", "").strip() - # remove junk - r1 = text.find("[") - r2 = text.find("]", -1, 0) - text = text[r1: r2] - core_desc_object = json.loads(text) - res = wo.importdescriptors(core_desc_object) - for obj in res: - assert obj["success"] - - # fund wallet - addr = wo.getnewaddress("", af) - assert bitcoind.supply_wallet.sendtoaddress(addr, 49) - bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) + wo = create_core_wallet(name, af, "sd", True) unspent = wo.listunspent() assert len(unspent) == 1 @@ -3103,4 +2904,515 @@ def test_static_internal_key(internal_key, clear_miniscript, microsd_path, pick_ title, story = import_miniscript(fname) assert "Failed to import" in story - assert "only extended keys allowed" in story \ No newline at end of file + assert "only extended pubkeys allowed" in story + + +# @pytest.mark.bitcoind +# def test_csa_tapscript(clear_miniscript, bitcoin_core_signer, get_cc_key, +# use_regtest, address_explorer_check, bitcoind, +# offer_minsc_import, create_core_wallet, press_select): +# use_regtest() +# clear_miniscript() +# M, N = 11, 12 +# +# bitcoind_signers = [] +# bitcoind_signers_xpubs = [] +# for i in range(N - 1): +# s, core_key = bitcoin_core_signer(f"bitcoind--signer{i}") +# s.keypoolrefill(10) +# bitcoind_signers.append(s) +# bitcoind_signers_xpubs.append(core_key) +# +# me = get_cc_key(f"m/48h/1h/0h/3h") +# ik = ranged_unspendable_internal_key() +# +# signers_xp = [me] + bitcoind_signers_xpubs +# assert len(signers_xp) == N +# desc = f"tr({ik},%s)" +# +# scripts = [] +# for c in itertools.combinations(signers_xp, M): +# tmplt = f"multi_a({M},{','.join(c)})" +# scripts.append(tmplt) +# +# assert len(scripts) == 12 +# temp = TREE[len(scripts)] +# temp = temp % tuple(scripts) +# +# desc = desc % temp +# +# title, story = offer_minsc_import(desc) +# name = story.split("\n")[3].strip() +# assert "Create new miniscript wallet?" in story +# press_select() +# ms_wo = create_core_wallet(name, "bech32m", "sd", False) +# address_explorer_check("sd", "bech32m", ms_wo, "minisc") + + +# @pytest.mark.parametrize("desc", [ +# +# # "wsh(or_i(and_v(v:pkh(@A),older(100)),or_d(multi(3,@A,@B,@C),and_v(v:thresh(2,pkh(@A),a:pkh(@B),a:pkh(@C)),older(500)))))" +# ]) +def test_tapscript_disjoint_derivation(cap_story, offer_minsc_import, microsd_path, + get_cc_key, bitcoin_core_signer): + desc = "tr(unspend(),{{sortedmulti_a(2,@A,@B),sortedmulti_a(2,@AA,@C)},sortedmulti_a(2,@AAA,@BB,@CC)})" + + # internal key is OK + unspend = ranged_unspendable_internal_key(os.urandom(32), subderiv=f"/<0;1>/*") + desc = desc.replace("unspend()", unspend) + + # @A, @AA & @AAA is us - all OK + kA = get_cc_key("m/999h/1h/66h") + kAA = kA.replace("/<0;1>/*", "/<2;3>/*") + kAAA = kA.replace("/<0;1>/*", "/<4;5>/*") + + desc = desc.replace("@AAA", kAAA) + desc = desc.replace("@AA", kAA) + desc = desc.replace("@A", kA) + + s0, kB = bitcoin_core_signer("B") + # this is problematic - as it is nto disjoint + kB = kB.replace("/0/*", "/<1;2>/*") + kBB = kB.replace("/<1;2>/*", "/<0;1>/*") + + s1, kC = bitcoin_core_signer("C") + kC = kC.replace("/0/*", "/<0;1>/*") + kCC = kC.replace("/<0;1>/*", "/<2;3>/*") + + desc = desc.replace("@BB", kBB) + desc = desc.replace("@B", kB) + desc = desc.replace("@CC", kCC) + desc = desc.replace("@C", kC) + + with pytest.raises(Exception) as e: + offer_minsc_import(desc) + assert "Non-disjoint multipath" in e.value.args[0] + + # now make internal key non-disjoint + desc = desc.replace(unspend, ranged_unspendable_internal_key(os.urandom(32), subderiv=f"/<3;4>/*")) + # previously invalid key + desc = desc.replace(kB, kB.replace("/<1;2>/*", "/<2;3>/*")) + + with pytest.raises(Exception) as e: + offer_minsc_import(desc) + assert "Non-disjoint multipath" in e.value.args[0] + + +@pytest.mark.bitcoind +@pytest.mark.parametrize("way", ["usb", "nfc", "sd", "vdisk", "qr"]) +def test_same_key_set_miniscript(get_cc_key, bitcoin_core_signer, create_core_wallet, way, + offer_minsc_import, press_select, bitcoind, start_sign, + cap_story, end_sign, clear_miniscript, goto_home, scan_a_qr, + pick_menu_item, microsd_path, garbage_collector, press_cancel, + need_keypress, press_nfc, nfc_write_text, nfc_read, + readback_bbqr, virtdisk_path, skip_if_useless_way): + # same keys in miniscript, impossible to match correct wallet with auto-match + skip_if_useless_way(way) + goto_home() + clear_miniscript() + + msc1 = "wsh(andor(pk(@D),after(1767225600),multi(2,@A,@B,@C)))" + msc2 = "wsh(or_d(pk(@D),and_v(v:multi(2,@A,@B,@C),older(65535))))" + + ak = get_cc_key("m/48h/1h/0h/2h") + bs, bk = bitcoin_core_signer("bb") + cs, ck = bitcoin_core_signer("cc") + ds, dk = bitcoin_core_signer("dd") + + bk = bk.replace("/0/*", "/<0;1>/*") + ck = ck.replace("/0/*", "/<0;1>/*") + dk = dk.replace("/0/*", "/<0;1>/*") + + msc1 = msc1.replace("@A", ak) + msc1 = msc1.replace("@B", bk) + msc1 = msc1.replace("@C", ck) + msc1 = msc1.replace("@D", dk) + + msc2 = msc2.replace("@A", ak) + msc2 = msc2.replace("@B", bk) + msc2 = msc2.replace("@C", ck) + msc2 = msc2.replace("@D", dk) + + title, story = offer_minsc_import(json.dumps(dict(name="msc1", desc=msc1))) + assert "msc1" in story + assert "Create new miniscript wallet?" in story + press_select() + + title, story = offer_minsc_import(json.dumps(dict(name="msc2", desc=msc2))) + assert "msc2" in story + assert "Create new miniscript wallet?" in story + press_select() + + m1 = create_core_wallet("msc1", "bech32") + m2 = create_core_wallet("msc2", "bech32") + + # now try to sign (via Ready To Sign) PSBT from msc2 + # this will not work, as msc1 has same key set and was imported first + # so we match msc1 + psbt = m2.walletcreatefundedpsbt([], [{bitcoind.supply_wallet.getnewaddress(): 1.0}], + 0, {"fee_rate": 2})["psbt"] + + if way == "usb": + # first try classic way without specifying wallet name + # will fail with scriptPubKey mismatch + start_sign(base64.b64decode(psbt)) + time.sleep(.1) + title, story = cap_story() + assert "spk mismatch" in story + + # now with name specified via USB + start_sign(base64.b64decode(psbt), miniscript="msc2") + time.sleep(.1) + title, story = cap_story() + assert title == "OK TO SEND?" + assert "msc2" in story + end_sign(accept=True) + + else: + fname = "the_txn.psbt" + fpath = microsd_path(fname) + garbage_collector.append(fpath) + with open(fpath, "w") as f: + f.write(psbt) + + goto_home() + # just try SD for normal matching without name + pick_menu_item("Ready To Sign") + title, story = cap_story() + if 'OK TO SEND' not in title: + try: + pick_menu_item(fname) + time.sleep(0.1) + title, story = cap_story() + except: pass + + assert "spk mismatch" in story + press_select() # exit + + # now correct way via miniscript wallet + pick_menu_item("Settings") + pick_menu_item("Miniscript") + pick_menu_item("msc2") + pick_menu_item("Sign PSBT") + title, story = cap_story() + if way == "nfc": + if "import via NFC" not in story: + raise pytest.skip("NFC disabled") + + press_nfc() + nfc_write_text(psbt) + time.sleep(1) + title, story = cap_story() + assert title == "OK TO SEND?" + assert "msc2" in story + press_select() # confirm signing + time.sleep(0.1) + got = nfc_read() + time.sleep(1) + assert got + press_cancel() # exit NFC loop + + elif way == "qr": + if "scan QR code" not in story: + raise pytest.skip("Mk4 no QR") + + need_keypress(KEY_QR) + # base64 PSBT as text + actual_vers, parts = split_qrs(psbt, 'U', max_version=20) + random.shuffle(parts) + + for p in parts: + scan_a_qr(p) + time.sleep(1) # just so we can watch + + title, story = cap_story() + assert title == "OK TO SEND?" + assert "msc2" in story + press_select() # confirm signing + time.sleep(.2) + file_type, rb = readback_bbqr() + assert file_type == 'P' + press_cancel() + else: + if way == "sd": + assert "Press (1)" in story + need_keypress("1") + else: + assert way == "vdisk" + if "import from Virtual Disk" not in story: + raise pytest.skip("Virtual Disk disabled") + + fpath = virtdisk_path(fname) + garbage_collector.append(fpath) + with open(fpath, "w") as f: + f.write(psbt) + + need_keypress("2") + + title, story = cap_story() + if 'OK TO SEND' not in title: + pick_menu_item(fname) + time.sleep(0.1) + title, story = cap_story() + + assert title == "OK TO SEND?" + assert "msc2" in story + press_select() # confirm signing + time.sleep(0.1) + title, story = cap_story() + assert title == 'PSBT Signed' + + +@pytest.mark.parametrize("desc", CHANGE_BASED_DESCS) +@pytest.mark.parametrize("way", ["usb", "sd", "vdisk", "nfc", "qr"]) +def test_bip388_policies(desc, way, offer_minsc_import, press_select, pick_menu_item, goto_home, + clear_miniscript, microsd_path, virtdisk_path, garbage_collector, + need_keypress, cap_story, load_export, press_cancel, usb_miniscript_get, + skip_if_useless_way, scan_a_qr, press_nfc, nfc_write_text, + usb_miniscript_policy): + + skip_if_useless_way(way) + clear_miniscript() + title, story = offer_minsc_import(json.dumps(dict(name="msc1", desc=desc))) + assert "msc1" in story + assert "Create new miniscript wallet?" in story + press_select() + + goto_home() + pick_menu_item("Settings") + pick_menu_item("Miniscript") + pick_menu_item("msc1") + pick_menu_item("Descriptors") + pick_menu_item("BIP-388 Policy") + + if way == "usb": + contents = usb_miniscript_policy("msc1") + else: + contents = load_export(way, "BIP-388 Wallet Policy", is_json=True) + press_cancel() + press_cancel() + if way != "nfc": + press_cancel() + + pick_menu_item("Import") + + # try import - must raise duplicate + new_name = "b388_reimport" + # change name - make it harder + contents["name"] = new_name + to_import = json.dumps(contents) + + if way == "nfc": + press_nfc() + nfc_write_text(to_import) + time.sleep(1) + title, story = cap_story() + assert "Duplicate wallet. Wallet 'msc1' is the same." in story + assert "b388_reimport" in story + press_cancel() + + clear_miniscript() + pick_menu_item("Import") + press_nfc() + + nfc_write_text(to_import) + time.sleep(1) + + elif way == "qr": + need_keypress(KEY_QR) + # base64 PSBT as text + actual_vers, parts = split_qrs(to_import, 'U', max_version=20) + random.shuffle(parts) + + for p in parts: + scan_a_qr(p) + time.sleep(1) # just so we can watch + + title, story = cap_story() + assert "Duplicate wallet. Wallet 'msc1' is the same." in story + assert "b388_reimport" in story + press_cancel() + + clear_miniscript() + pick_menu_item("Import") + need_keypress(KEY_QR) + + for p in parts: + scan_a_qr(p) + time.sleep(1) # just so we can watch + + elif way == "usb": + goto_home() + title, story = offer_minsc_import(to_import) + assert "Duplicate wallet. Wallet 'msc1' is the same." in story + assert "b388_reimport" in story + press_cancel() + + clear_miniscript() + offer_minsc_import(to_import) + + else: + path_f = microsd_path if way == "sd" else virtdisk_path + fname = "b388_reimport.json" + fpath = path_f(fname) + garbage_collector.append(fpath) + with open(path_f(fname), "w") as f: + f.write(to_import) + + if way == "sd": + assert "Press (1)" in story + need_keypress("1") + else: + assert way == "vdisk" + if "import from Virtual Disk" not in story: + raise pytest.skip("Virtual Disk disabled") + + need_keypress("2") + + # try to import duplicate + time.sleep(.1) + pick_menu_item(fname) + time.sleep(.1) + title, story = cap_story() + assert "Duplicate wallet. Wallet 'msc1' is the same." in story + assert "b388_reimport" in story + + press_cancel() + # now clear imported miniscript and import + clear_miniscript() + pick_menu_item("Import") + need_keypress("1" if way == "sd" else "2") + time.sleep(.1) + pick_menu_item(fname) + + + time.sleep(.1) + title, story = cap_story() + assert "Duplicate wallet" not in story + assert "Create new miniscript wallet?" in story + assert "b388_reimport" in story + press_select() + + # verify that the descriptor matches + assert usb_miniscript_get(new_name)["desc"].split("#")[0] == desc.split("#")[0].replace("'", 'h') + + +def test_miniscript_rename(offer_minsc_import, clear_miniscript, press_select, goto_home, + pick_menu_item, enter_complex, cap_menu, cap_screen, is_q1, + need_keypress, press_cancel): + clear_miniscript() + name = "old_name" + title, story = offer_minsc_import(json.dumps(dict(name=name, desc=CHANGE_BASED_DESCS[0]))) + assert "old_name" in story + assert "Create new miniscript wallet?" in story + press_select() + + goto_home() + pick_menu_item("Settings") + pick_menu_item("Miniscript") + pick_menu_item(name) + pick_menu_item("Rename") + if is_q1: + # old name is filled in input field + # same for Mk4, just not possible with cap_screen, or cap_story + time.sleep(.1) + scr = cap_screen() + assert name in scr + + new_name = 35 * "0" + # first delete old one + for _ in range(len(name) - (0 if is_q1 else 1)): + need_keypress(KEY_DELETE if is_q1 else "x") + + if is_q1: + # attempt to use empty string as a name + # on Mk4 it is not possible to not have at least one char + press_select() + time.sleep(.1) + scr = cap_screen() + assert "Need 1" in scr + + # it is not possible to input more than 30 characters + enter_complex(new_name, apply=False, b39pass=False) + + real_name = new_name[:30] + + # specific wallet menu has changed + time.sleep(.1) + m = cap_menu() + assert name not in m + assert real_name == m[0] + + # miniscript wallets menu has changed + press_cancel() # one back + + time.sleep(.1) + m = cap_menu() + assert name not in m + assert real_name == m[0] + + +def test_legacy_sh_miniscript(offer_minsc_import, press_select, create_core_wallet, clear_miniscript): + clear_miniscript() + desc = ("sh(" + "or_d(pk([0f056943/84'/1'/0']tpubDC7jGaaSE66Pn4dgtbAAstde4bCyhSUs4r3P8WhMVvPByvcRrzrwqSvpF9Ghx83Z1LfVugGRrSBko5UEKELCz9HoMv5qKmGq3fqnnbS5E9r/<0;1>/*)," + "and_v(" + "v:pkh([0f056943/84'/1'/9']tpubDC7jGaaSE66QBAcX8TUD3JKWari1zmGH4gNyKZcrfq6NwCofKujNF2kyeVXgKshotxw5Yib8UxLrmmCmWd8NVPVTAL8rGfMdc7TsAKqsy6y/<0;1>/*)," + "older(5))))") + + name = "legacy_sh_msc" + with pytest.raises(Exception) as e: + offer_minsc_import(json.dumps(dict(name=name, desc=desc))) + + assert "Miniscript in legacy P2SH not allowed" in str(e) + + +@pytest.mark.parametrize("lock", [ + ("older", 0), + ("after", 0), + ("older", 65536), + ("after", 2147483648), + # time-based relative locks + ("older", 4194304), + ("older", 4259840), +]) +def test_timelocks_without_consesnsus_meaning(lock, clear_miniscript, goto_home, get_cc_key, + offer_minsc_import, press_select): + goto_home() + clear_miniscript() + policy = "and_v(v:pk(@0/<0;1>/*),locktime())" + + # not allowed to import on CC + _type, val = lock + to_replace = f"{_type}({val})" + + policy = policy.replace("locktime()", to_replace) + + tmplt = f"wsh({policy})" + + cc_key = get_cc_key("m/88h/0h/0h",).replace('/<0;1>/*', '') + desc = tmplt.replace("@0", cc_key) + + wname = "locks_oob" + + with pytest.raises(Exception) as e: + offer_minsc_import(json.dumps(dict(name=wname, desc=desc))) + + if _type == "older": + if val & (1 << 22): + what = "Time-based " + x = 4194305 + y = 4259839 + else: + what = "Block-based " + x = 1 + y = (2**16)-1 + else: + what = "" + x = 1 + y = (2**31)-1 + + assert f"{what}{lock[0]} out of range [{x}, {y}]" in e.value.args[0] + press_select() + +# EOF \ No newline at end of file diff --git a/testing/test_msg.py b/testing/test_msg.py index 6c2cb17b..332010f2 100644 --- a/testing/test_msg.py +++ b/testing/test_msg.py @@ -125,8 +125,6 @@ def msg_sign_export(cap_story, press_nfc, nfc_read_text, press_select, press_can time.sleep(0.3) press_cancel() time.sleep(.1) - title, story = cap_story() - assert f"Press {OK} to share again" in story press_cancel() elif way == "qr": @@ -253,7 +251,7 @@ def sign_msg_from_text(pick_menu_item, enter_number, press_select, @pytest.fixture def sign_msg_from_address(need_keypress, scan_a_qr, press_select, enter_complex, cap_story, addr_vs_path, verify_msg_sign_story, msg_sign_export): - def doit(msg, addr, subpath, addr_fmt, way=None, testnet=True): + def doit(msg, addr, subpath, addr_fmt, way=None, chain="XTN"): if way == 'qr': # scan text via QR need_keypress(KEY_QR) @@ -265,17 +263,17 @@ def sign_msg_from_address(need_keypress, scan_a_qr, press_select, enter_complex, time.sleep(.1) title, story = cap_story() - verify_msg_sign_story(story, msg, subpath, addr_fmt, testnet, addr) + verify_msg_sign_story(story, msg, subpath, addr_fmt, chain=="XTN", addr) press_select() time.sleep(.1) signed_msg = msg_sign_export(way) ret_msg, addr, sig = parse_signed_message(signed_msg) - addr_vs_path(addr, subpath, addr_fmt, chain="XTN" if testnet else "BTC") + addr_vs_path(addr, subpath, addr_fmt, chain=chain) return doit -@pytest.mark.parametrize('path,expect', [ +@pytest.mark.parametrize('path,expect', [ ('1/1hard/2', 'invalid characters'), ('m/m/m/1/1hard/2', 'invalid characters'), ('m/', 'empty path component'), @@ -389,7 +387,8 @@ def test_sign_msg_microsd_good(sign_on_microsd, msg, path, addr_vs_path, addr_fmt, testnet, settings_set, bitcoind, use_json): - settings_set("chain", "XTN" if testnet else "BTC") + chain = "XTN" if testnet else "BTC" + settings_set("chain", chain) # cases we expect to work sig, addr, ret_msg = sign_on_microsd(msg, path, addr_fmt, testnet=testnet, use_json=use_json) @@ -405,7 +404,7 @@ def test_sign_msg_microsd_good(sign_on_microsd, msg, path, addr_vs_path, path = default_derivation_by_af(addr_fmt, testnet=testnet) # check expected addr was used - addr_vs_path(addr, path, addr_fmt, chain="XTN" if testnet else "BTC") + addr_vs_path(addr, path, addr_fmt, chain=chain) assert verify_message(addr, sig, msg) is True if addr_fmt == AF_CLASSIC and testnet: res = bitcoind.rpc.verifymessage(addr, sig, ret_msg) @@ -459,13 +458,10 @@ def sign_using_nfc(goto_home, pick_menu_item, nfc_write_text, cap_story, press_s addr_vs_path(addr, subpath, addr_fmt, chain="XTN" if testnet else "BTC") assert verify_message(addr, sig, msg) is True time.sleep(0.5) - _, story = cap_story() - assert f"Press {OK} to share again" in story press_select() signed_msg_again = nfc_read_text() assert signed_msg == signed_msg_again press_cancel() # exit NFC animation - press_cancel() # do not want to share again return sig, addr, msg @@ -505,9 +501,9 @@ def test_sign_msg_with_ascii_non_printable_chars(msg, way, sign_on_microsd, addr ('hello%20sworld'%'', "m", AF_CLASSIC, 'many spaces', 0, 0), # spaces ('hello%10sworld'%'', "m/1h/3h", AF_P2WPKH_P2SH, 'many spaces', 0, 0), # spaces ('hello%5sworld'%'', "m", AF_CLASSIC, 'many spaces', 0, 0), # spaces - ("coinkite", "m", AF_P2WSH, "Unsupported address format", 0, 0), # invalid address format + ("coinkite", "m", AF_P2WSH, "Unsupported address format: 'p2wsh'", 0, 0), # invalid address format ("coinkite", "m", AF_P2WSH_P2SH, "Unsupported address format", 0, 0), # invalid address format - ("coinkite", " m", AF_P2TR, "Unsupported address format", 0, 0), # invalid address format + ("coinkite", " m", AF_P2TR, "Unsupported address format: 'p2tr'", 0, 0), # invalid address format ("coinkite", "m/0/0/0/0/0/0/0/0/0/0/0/0/0", AF_CLASSIC, "too deep", 0, 0), # invalid path ("coinkite", "m/0/0/0/0/0/q/0/0/0", AF_P2WPKH, "invalid characters in path", 0, 0), # invalid path ("coinkite ", "m", AF_CLASSIC, "trailing space(s)", 0, 0), # invalid msg - trailing space @@ -548,7 +544,7 @@ def test_sign_msg_fails(dev, sign_on_microsd, msg, subpath, addr_fmt, concern, assert concern in story -@pytest.mark.parametrize('msg,num_iter,expect', [ +@pytest.mark.parametrize('msg,num_iter,expect', [ ('Test2', 1, 'IHra0jSywF1TjIJ5uf7IDECae438cr4o3VmG6Ri7hYlDL+pUEXyUfwLwpiAfUQVqQFLgs6OaX0KsoydpuwRI71o='), ('Test', 2, 'IDgMx1ljPhLHlKUOwnO/jBIgK+K8n8mvDUDROzTgU8gOaPDMs+eYXJpNXXINUx5WpeV605p5uO6B3TzBVcvs478='), ('Test1', 3, 'IEt/v9K95YVFuRtRtWaabPVwWOFv1FSA/e874I8ABgYMbRyVvHhSwLFz0RZuO87ukxDd4TOsRdofQwMEA90LCgI='), @@ -937,7 +933,6 @@ def test_verify_signature_file_truncated(way, microsd_path, cap_story, verify_ar else: assert title == "FAILURE" assert "Armor text MUST be surrounded by exactly five (5) dashes" in story - assert "auth.py" in story @pytest.mark.parametrize("msg", ["this is the message to sign", "this is meessage to sign\n with newline", "a"*200]) diff --git a/testing/test_multisig.py b/testing/test_multisig.py index f434a785..4b01e5bb 100644 --- a/testing/test_multisig.py +++ b/testing/test_multisig.py @@ -13,7 +13,7 @@ from pprint import pprint from base64 import b64encode, b64decode from base58 import encode_base58_checksum from helpers import B2A, fake_dest_addr, xfp2str, addr_from_display_format -from helpers import path_to_str, str_to_path, slip132undo, swab32, hash160 +from helpers import path_to_str, str_to_path, slip132undo, swab32, hash160, bitcoind_addr_fmt from struct import unpack, pack from constants import * from bip32 import BIP32Node @@ -22,7 +22,7 @@ from io import BytesIO from hashlib import sha256 from bbqr import split_qrs from descriptor import MULTI_FMT_TO_SCRIPT, MultisigDescriptor, parse_desc_str -from charcodes import KEY_QR +from charcodes import KEY_QR, KEY_DELETE def HARD(n=0): @@ -43,26 +43,8 @@ def str2ipath(s): yield here -@pytest.fixture(scope='function') -def has_ms_checks(request, sim_exec): - # Add this fixture to any test that should FAIL if ms checks are disabled - # - in other words, tests that test the checks which are disabled. - # - still need to run w/ --ms-danger flag set to test those cases - # - also mark testcase with ms_danger - danger_mode = (request.config.getoption('--ms-danger')) - if danger_mode: - print("Enabling multisig danger mode") - - request.node.add_marker(pytest.mark.xfail(True, strict=True, - reason="check was bypassed, so testcase should fail")) - - sim_exec(f'from multisig import MultisigWallet; MultisigWallet.disable_checks={danger_mode}') - - return danger_mode - - -@pytest.fixture() +@pytest.fixture def bitcoind_p2sh(bitcoind): # Use bitcoind to generate a p2sh addres based on public keys. @@ -84,13 +66,6 @@ def bitcoind_p2sh(bitcoind): return doit - -@pytest.fixture -def clear_ms(unit_test): - def doit(): - unit_test('devtest/wipe_ms.py') - return doit - @pytest.fixture def make_multisig(dev, sim_execfile): # make a multsig wallet, always with simulator as an element @@ -98,7 +73,11 @@ def make_multisig(dev, sim_execfile): # default is BIP-45: m/45'/... (but no co-signer idx) # - but can provide str format for deriviation, use {idx} for cosigner idx - def doit(M, N, unique=0, deriv=None, dev_key=False, chain="XTN"): + def doit(M, N, unique=0, deriv=None, dev_key=False, netcode="XTN"): + + if netcode == "XRT": + # makes no sense keys wise + netcode = "XTN" def _derive(master, origin_der, idx): if origin_der == "m": @@ -115,7 +94,7 @@ def make_multisig(dev, sim_execfile): keys = [] for i in range(N-1): - pk = BIP32Node.from_master_secret(b'CSW is a fraud %d - %d' % (i, unique), chain) + pk = BIP32Node.from_master_secret(b'CSW is a fraud %d - %d' % (i, unique), netcode) xfp = unpack("I', xfp_bytes)[0]) else: - pk = BIP32Node.from_wallet_key(simulator_fixed_tprv if chain == "XTN" else simulator_fixed_xprv) + pk = BIP32Node.from_wallet_key(simulator_fixed_tprv if netcode == "XTN" else simulator_fixed_xprv) xfp = simulator_fixed_xfp dev_sim = _derive(pk, deriv, N-1) @@ -140,194 +119,71 @@ def make_multisig(dev, sim_execfile): return doit @pytest.fixture -def offer_ms_import(cap_story, dev): - def doit(config, allow_non_ascii=False): - # upload the file, trigger import - file_len, sha = dev.upload_file(config.encode('utf-8' if allow_non_ascii else 'ascii')) - - open('debug/last-config.txt', 'wt').write(config) - - dev.send_recv(CCProtocolPacker.multisig_enroll(file_len, sha)) - - time.sleep(.2) - title, story = cap_story() - #print(repr(story)) - - return title, story - - return doit - -@pytest.fixture -def import_multisig(request, is_q1, need_keypress, offer_ms_import): - def doit(fname=None, way="sd", data=None, name=None): - assert fname or data - if fname: - if way == "sd": - microsd_path = request.getfixturevalue("microsd_path") - fpath = microsd_path(fname) - else: - virtdisk_path = request.getfixturevalue("virtdisk_path") - fpath = virtdisk_path(fname) - with open(fpath, 'r') as f: - config = f.read() - else: - config = data - if way is None: # USB - title, story = offer_ms_import(config) - else: - # only get those simulator related fixtures here, to be able to - # use this with real HW - cap_menu = request.getfixturevalue('cap_menu') - cap_story = request.getfixturevalue('cap_story') - goto_home = request.getfixturevalue('goto_home') - pick_menu_item = request.getfixturevalue('pick_menu_item') - - if "Skip Checks?" not in cap_menu(): - # we are not in multisig menu - goto_home() - pick_menu_item("Settings") - pick_menu_item("Multisig Wallets") - time.sleep(.1) - - ms_menu = cap_menu() - if way == "qr": - if "Import from QR" not in ms_menu and not is_q1: - pytest.skip("No QR support") - - scan_a_qr = request.getfixturevalue('scan_a_qr') - pick_menu_item("Import from QR") - - actual_vers, parts = split_qrs(config, 'U', max_version=20) - random.shuffle(parts) - - for p in parts: - scan_a_qr(p) - time.sleep(2.0 / len(parts)) - - elif way == "nfc": - if "Import via NFC" not in ms_menu: - pytest.skip("NFC disabled") - - nfc_write_text = request.getfixturevalue('nfc_write_text') - pick_menu_item("Import via NFC") - nfc_write_text(config) - time.sleep(0.5) - - else: - assert way in ("sd", "vdisk") - if way == "sd": - path_f = request.getfixturevalue('microsd_path') - else: - path_f = request.getfixturevalue('virtdisk_path') - - if not fname: - fname = (name or "ms_wal.txt") + ".txt" - with open(path_f(fname), "w") as f: - f.write(config) - - pick_menu_item("Import from File") - time.sleep(.1) - _, story = cap_story() - if way == "vdisk": - if "(2) to import from Virtual Disk" not in story: - pytest.skip("VDisk disabled") - need_keypress("2") - else: - if "Press (1)" in story: - need_keypress("1") - - pick_menu_item(fname) - - time.sleep(.1) - title, story = cap_story() - return title, story - - return doit - -@pytest.fixture -def import_ms_wallet(dev, make_multisig, offer_ms_import, press_select, - is_q1, request, need_keypress, import_multisig, - settings_set): +def import_ms_wallet(dev, make_multisig, offer_minsc_import, press_select, + is_q1, request, need_keypress, usb_miniscript_get, + settings_set, sim_root_dir, import_miniscript): def doit(M, N, addr_fmt=None, name=None, unique=0, accept=False, common=None, - keys=None, do_import=True, derivs=None, descriptor=False, + keys=None, do_import=True, derivs=None, int_ext_desc=False, dev_key=False, way=None, bip67=True, - force_unsort_ms=True, chain="XTN"): - # param: bip67 if false, only usable together with descriptor=True - if not bip67: - assert descriptor, "needs descriptor=True" - - if (not bip67) and force_unsort_ms: - settings_set("unsort_ms", 1) + chain="XTN"): keys = keys or make_multisig(M, N, unique=unique, dev_key=dev_key, deriv=common or (derivs[0] if derivs else None), - chain=chain) - name = name or f'test-{M}-{N}' + netcode=chain) + + if addr_fmt is None: + addr_fmt = "p2wsh" + + if not derivs: + if not common: + common = "m/45h" + key_list = [(xfp, common, dd.hwif(as_private=False)) for xfp, m, dd in keys] + else: + assert len(derivs) == N + key_list = [(xfp, derivs[idx], dd.hwif(as_private=False)) + for idx, (xfp, m, dd) in enumerate(keys)] + + desc = MultisigDescriptor(M=M, N=N, keys=key_list, addr_fmt=addr_fmt, + is_sorted=bip67) + if int_ext_desc: + config = desc.serialize(int_ext=True) + else: + config = desc.serialize() + + if name: + config = json.dumps({"name": name, "desc": config}) if not do_import: - return keys + return keys, config - if descriptor: - if not derivs: - if not common: - common = "m/45h" - key_list = [(xfp, common, dd.hwif(as_private=False)) for xfp, m, dd in keys] - else: - assert len(derivs) == N - key_list = [(xfp, derivs[idx], dd.hwif(as_private=False)) for idx, (xfp, m, dd) in enumerate(keys)] - desc = MultisigDescriptor(M=M, N=N, keys=key_list, addr_fmt=addr_fmt, is_sorted=bip67) - if int_ext_desc: - desc_str = desc.serialize(int_ext=True) - else: - desc_str = desc.serialize() - config = "%s\n" % desc_str - else: - # render as a file for import - config = f"name: {name}\npolicy: {M} / {N}\n\n" + with open(f'{sim_root_dir}/debug/last-ms.txt', 'wt') as f: + f.write(config) - if addr_fmt: - if isinstance(addr_fmt, int): - addr_fmt = addr_fmt_names[addr_fmt] - config += f'format: {addr_fmt.title()}\n' + title, story = import_miniscript(data=config, way=way) - # not good enuf anymore, but maybe in some cases, just need one at top - if common: - config += f'derivation: {common}\n' - - if not derivs: - config += '\n'.join('%s: %s' % (xfp2str(xfp), dd.hwif(as_private=False)) - for xfp, m, dd in keys) - else: - # for cases where derivation of each leg is not same/simple - assert not common and len(derivs) == N - for idx, (xfp, m, dd) in enumerate(keys): - config += 'Derivation: %s\n%s: %s\n\n' % (derivs[idx], - xfp2str(xfp), dd.hwif(as_private=False)) - - #print(config) - open('debug/last-ms.txt', 'wt').write(config) - - title, story = import_multisig(data=config, way=way) - - assert 'Create new multisig' in story \ + assert 'Create new miniscript wallet' in story \ or 'Update existing multisig wallet' in story \ or 'new wallet is similar to' in story - if descriptor is False: - # descriptors wallet does not have a name - assert name in story + + story_name = None + assert addr_fmt.upper() in story assert f'Policy: {M} of {N}\n' in story + for ll in story.split("\n\n"): + if ll.startswith("Wallet Name"): + story_name = ll.split("\n")[-1].strip() + + assert story_name + if name: + assert name == story_name if accept: time.sleep(.1) press_select() - # Test it worked. time.sleep(.1) # required - xor = 0 - for xfp, _, _ in keys: - xor ^= xfp - assert dev.send_recv(CCProtocolPacker.multisig_check(M, N, xor)) == 1 + # below raises if miniscript wallet not enrolled + usb_miniscript_get(story_name) return keys @@ -335,63 +191,39 @@ def import_ms_wallet(dev, make_multisig, offer_ms_import, press_select, @pytest.mark.parametrize('N', [ 3, 15]) -def test_ms_import_variations(N, make_multisig, offer_ms_import, press_cancel, is_q1): +def test_ms_import_variations(N, offer_minsc_import, press_cancel, is_q1, get_cc_key): # all the different ways... - keys = make_multisig(N, N) - + my_key = get_cc_key(path="").replace("/<0;1>/*", "") + keys = [BIP32Node.from_master_secret(os.urandom(32), "XTN").hwif() for _ in range(N-1)] + keys = [my_key] + keys # bare, no fingerprints # - no xfps # - no meta data - config = '\n'.join(sk.hwif(as_private=False) for xfp,m,sk in keys) - title, story = offer_ms_import(config) + k0 = ','.join(keys) + title, story = offer_minsc_import(f"sh(multi({N},{k0}))") assert f'Policy: {N} of {N}\n' in story press_cancel() # exclude myself (expect fail) - config = '\n'.join(sk.hwif(as_private=False) - for xfp,m,sk in keys if xfp != simulator_fixed_xfp) - + k1 = ','.join(keys[1:]) with pytest.raises(BaseException) as ee: - title, story = offer_ms_import(config) - assert 'my key not included' in str(ee.value) - + title, story = offer_minsc_import(f"wsh(sortedmulti({N-1},{k1}))") + assert "My key 0F056943 missing in descriptor" in str(ee.value) + desc0 = f"wsh(sortedmulti({N},{k0}))" # normal names for name in [ 'Zy', 'Z'*20, 'Vault #3' ]: - config = f'name: {name}\n' - config += '\n'.join(sk.hwif(as_private=False) for xfp,m,sk in keys) - title, story = offer_ms_import(config) + title, story = offer_minsc_import(json.dumps({"name": name, "desc": desc0})) press_cancel() assert name in story # too long name - config = 'name: ' + ('A'*21) + '\n' - config += '\n'.join(sk.hwif(as_private=False) for xfp,m,sk in keys) + name = 'A' * 31 with pytest.raises(BaseException) as ee: - title, story = offer_ms_import(config) - assert '20 long' in str(ee.value) + title, story = offer_minsc_import(json.dumps({"name": name, "desc": desc0})) + assert 'name len' in str(ee.value) - # comments, blank lines - config = [sk.hwif(as_private=False) for xfp,m,sk in keys] - for i in range(len(config)): - config.insert(i, '# comment') - config.insert(i, ' #') - config.insert(i, ' # ') - config.insert(i, ' # ') - config.insert(i, '') - title, story = offer_ms_import('\n'.join(config)) - assert f'Policy: {N} of {N}\n' in story - press_cancel() - - # the different addr formats - for af in unmap_addr_fmt.keys(): - if af == "p2tr": continue - config = f'format: {af}\n' - config += '\n'.join(sk.hwif(as_private=False) for xfp,m,sk in keys) - title, story = offer_ms_import(config) - press_cancel() - assert f'Policy: {N} of {N}\n' in story def make_redeem(M, keys, path_mapper=None, violate_script_key_order=False, tweak_redeem=None, tweak_xfps=None, finalizer_hack=None, @@ -463,8 +295,8 @@ def make_redeem(M, keys, path_mapper=None, violate_script_key_order=False, def make_ms_address(M, keys, idx=0, is_change=0, addr_fmt=AF_P2SH, testnet=1, bip67=True, **make_redeem_args): # Construct addr and script need to represent a p2sh address - if 'path_mapper' not in make_redeem_args: - make_redeem_args['path_mapper'] = lambda cosigner: [HARD(45), cosigner, is_change, idx] + if not make_redeem_args.get('path_mapper'): + make_redeem_args['path_mapper'] = lambda cosigner: [HARD(45), is_change, idx] script, pubkeys, xfp_paths = make_redeem(M, keys, bip67=bip67, **make_redeem_args) @@ -491,47 +323,27 @@ def make_ms_address(M, keys, idx=0, is_change=0, addr_fmt=AF_P2SH, testnet=1, @pytest.fixture -def test_ms_show_addr(dev, cap_story, press_select, addr_vs_path, bitcoind_p2sh, - has_ms_checks, is_q1): - def doit(M, keys, addr_fmt=AF_P2SH, bip45=True, chain="XTN", **make_redeem_args): +def test_ms_show_addr(dev, cap_story, press_select, bitcoind, is_q1, + usb_miniscript_addr, usb_miniscript_get): + def doit(name, idx=0, change=False): # test we are showing addresses correctly # - verifies against bitcoind as well - addr_fmt = unmap_addr_fmt.get(addr_fmt, addr_fmt) - # make a redeem script, using provided keys/pubkeys - if bip45: - make_redeem_args['path_mapper'] = lambda i: [HARD(45), i, 0,0] - - scr, pubkeys, xfp_paths = make_redeem(M, keys, **make_redeem_args) - assert len(scr) <= 520, "script too long for standard!" - - got_addr = dev.send_recv( - CCProtocolPacker.show_p2sh_address(M, xfp_paths, scr, addr_fmt=addr_fmt), - timeout=None - ) + got_addr = usb_miniscript_addr(name, idx, change) title, story = cap_story() - #print(story) - - if not has_ms_checks: - assert got_addr == addr_from_display_format(story.split("\n\n")[0]) - assert all((xfp2str(xfp) in story) for xfp,_,_ in keys) - if bip45: - for i in range(len(keys)): - assert ('/_/%d/0/0' % i) in story - else: - assert 'UNVERIFIED' in story + assert got_addr == addr_from_display_format(story.split("\n\n")[0]) press_select() - # check expected addr was generated based on my math - addr_vs_path(got_addr, addr_fmt=addr_fmt, script=scr, chain=chain) - - # also check against bitcoind - core_addr, core_scr = bitcoind_p2sh(M, pubkeys, addr_fmt) - assert B2A(scr) == core_scr - assert core_addr == got_addr + # check against bitcoind + desc_obj = usb_miniscript_get(name) + ext_a, int_a = bitcoind.supply_wallet.deriveaddresses(desc_obj["desc"], [idx, idx]) + if change: + assert int_a[0] == got_addr + else: + assert ext_a[0] == got_addr return doit @@ -539,198 +351,207 @@ def test_ms_show_addr(dev, cap_story, press_select, addr_vs_path, bitcoind_p2sh, @pytest.mark.bitcoind @pytest.mark.parametrize('m_of_n', [(1,3), (2,3), (3,3), (3,6), (10, 15), (15,15)]) @pytest.mark.parametrize('addr_fmt', ['p2sh-p2wsh', 'p2sh', 'p2wsh' ]) -def test_import_ranges(m_of_n, use_regtest, addr_fmt, clear_ms, import_ms_wallet, test_ms_show_addr): +def test_import_ranges(m_of_n, use_regtest, addr_fmt, clear_miniscript, import_ms_wallet, + usb_miniscript_addr, test_ms_show_addr): use_regtest() M, N = m_of_n - keys = import_ms_wallet(M, N, addr_fmt, accept=1) + wname = "my_rand_wal" + import_ms_wallet(M, N, addr_fmt, name=wname, accept=True) #print("imported: %r" % [x for x,_,_ in keys]) try: # test an address that should be in that wallet. time.sleep(.1) - test_ms_show_addr(M, keys, addr_fmt=addr_fmt, chain="XRT") + test_ms_show_addr(wname) finally: - clear_ms() + clear_miniscript() @pytest.mark.bitcoind @pytest.mark.ms_danger -def test_violate_bip67(clear_ms, use_regtest, import_ms_wallet, - test_ms_show_addr, has_ms_checks, - fake_ms_txn, try_sign): +def test_violate_bip67(clear_miniscript, use_regtest, import_ms_wallet, + test_ms_show_addr, sim_root_dir, try_sign, + fake_ms_txn): # detect when pubkeys are not in order in the redeem script - clear_ms() + clear_miniscript() M, N = 1, 15 keys = import_ms_wallet(M, N, accept=True) - # test an address that should be in that wallet. - time.sleep(.1) - with pytest.raises(BaseException) as ee: - test_ms_show_addr(M, keys, violate_script_key_order=True) - assert 'BIP-67' in str(ee.value) - psbt = fake_ms_txn(1, 3, M, keys, outstyles=ADDR_STYLES_MS, change_outputs=[1], violate_script_key_order=True) - with open('debug/last.psbt', 'wb') as f: + with open(f'{sim_root_dir}/debug/last.psbt', 'wb') as f: f.write(psbt) with pytest.raises(Exception) as e: try_sign(psbt) - assert 'BIP-67' in e.value.args[0] + assert 'spk mismatch' in e.value.args[0] @pytest.mark.parametrize("has_change", [True, False]) -def test_violate_import_order_multi(has_change, clear_ms, import_ms_wallet, - fake_ms_txn, try_sign, test_ms_show_addr): - clear_ms() +def test_violate_import_order_multi(has_change, clear_miniscript, import_ms_wallet, + fake_ms_txn, try_sign, test_ms_show_addr, + sim_root_dir): + clear_miniscript() M, N = 3, 5 - keys = import_ms_wallet(M, N, accept=True, descriptor=True, bip67=False) + keys = import_ms_wallet(M, N, accept=True, bip67=False) time.sleep(.1) - with pytest.raises(BaseException) as ee: - test_ms_show_addr(M, keys, violate_script_key_order=True) - assert "script key order" in str(ee.value) psbt = fake_ms_txn(4, 2, M, keys, outstyles=ADDR_STYLES_MS, change_outputs=[1] if has_change else [], bip67=False, violate_script_key_order=True) - with open('debug/last.psbt', 'wb') as f: + with open(f'{sim_root_dir}/debug/last.psbt', 'wb') as f: f.write(psbt) with pytest.raises(Exception) as e: try_sign(psbt) - assert "script key order" in e.value.args[0] - - -@pytest.mark.bitcoind -@pytest.mark.parametrize('which_pubkey', [0, 1, 14]) -def test_bad_pubkey(has_ms_checks, use_regtest, clear_ms, import_ms_wallet, - test_ms_show_addr, which_pubkey): - # give incorrect pubkey inside redeem script - M, N = 1, 15 - keys = import_ms_wallet(M, N, accept=True) - - try: - # test an address that should be in that wallet. - time.sleep(.1) - def tweaker(scr): - # corrupt the pubkey - return bytes((s if i != (5 + (34*which_pubkey)) else s^0x1) for i,s in enumerate(scr)) - - with pytest.raises(BaseException) as ee: - test_ms_show_addr(M, keys, tweak_redeem=tweaker) - assert ('pk#%d wrong' % (which_pubkey+1)) in str(ee.value) - finally: - clear_ms() + assert "spk mismatch" in e.value.args[0] @pytest.mark.bitcoind @pytest.mark.parametrize('addr_fmt', ['p2sh-p2wsh', 'p2sh', 'p2wsh' ]) -def test_zero_depth(clear_ms, use_regtest, addr_fmt, import_ms_wallet - , test_ms_show_addr, make_multisig): - # test having a co-signer with "m" only key ... ie. depth=0 +@pytest.mark.parametrize('desc_type', ['multi', 'sortedmulti' ]) +def test_zero_depth(dev, clear_miniscript, use_regtest, addr_fmt, offer_minsc_import, + make_multisig, bitcoind, desc_type, settings_set, press_select, + goto_home, pick_menu_item, load_export, goto_address_explorer, + cap_story, need_keypress, try_sign): - M, N = 1, 2 - keys = make_multisig(M, N, unique=99) + settings_set("chain", "XRT") + ms_name = "zero_depth" + clear_miniscript() + bitcoind.delete_wallet_files(pattern="zero_depth_s") + bitcoind.delete_wallet_files(pattern="zero_depth_wo") + # create multiple bitcoin wallets (N-1) as one signer is CC + cosig = bitcoind.create_wallet(wallet_name="zero_depth_s", disable_private_keys=False, + blank=False, passphrase=None, avoid_reuse=False, + descriptors=True) + cosig.keypoolrefill(100) + descs = cosig.listdescriptors()["descriptors"] + target_desc = None + for desc in descs: + if desc["desc"].startswith("wpkh(") and desc["internal"] is False: + target_desc = desc["desc"] + core_desc, checksum = target_desc.split("#") + # remove wpkh(....) + core_key = core_desc[5:-1] + my_master_xpub = dev.send_recv(CCProtocolPacker.get_xpub("m"), timeout=None) + my_xfp = dev.master_fingerprint + my_xfp = xfp2str(my_xfp).lower() # if any letters - lower them + my_data = f"[{my_xfp}]{my_master_xpub}/0/*" + # watch only wallet where multisig descriptor will be imported + wo = bitcoind.create_wallet( + wallet_name="zero_depth_wo", disable_private_keys=True, + blank=True, passphrase=None, avoid_reuse=False, descriptors=True + ) - # censor first co-signer to look like a master key - from copy import deepcopy - kk = deepcopy(keys[0][1]) - kk.node.depth = 0 - kk.node.index = 0 - kk.node.parsed_parent_fingerprint = None - keys[0] = (keys[0][0], keys[0][1], kk) + if addr_fmt == 'p2wsh': + tmplt = "wsh(%s)" + af = "bech32" + elif addr_fmt == "p2sh-p2wsh": + tmplt = "sh(wsh(%s))" + af = "p2sh-segwit" + else: + assert addr_fmt == "p2sh" + tmplt = "sh(%s)" + af = "legacy" - try: - keys = import_ms_wallet(M, N, accept=1, keys=keys, - addr_fmt=addr_fmt, derivs=["m", "m/45'"]) - def pm(i): - return [] if i == 0 else [HARD(45), i, 0,0] + inner = "%s(2,%s)" % (desc_type, ",".join([core_key, my_data])) + desc = tmplt % inner + desc_info = wo.getdescriptorinfo(desc) + desc_w_checksum = desc_info["descriptor"] # with checksum + + + title, story = offer_minsc_import(json.dumps({"desc": desc_w_checksum, "name": ms_name})) + assert "Create new miniscript wallet?" in story + press_select() + + pick_menu_item("Settings") + pick_menu_item("Miniscript") + pick_menu_item(ms_name) + pick_menu_item("Descriptors") + pick_menu_item("Bitcoin Core") + text = load_export("sd", label="Bitcoin Core miniscript", is_json=False) + text = text.replace("importdescriptors ", "").strip() + # remove junk + r1 = text.find("[") + r2 = text.find("]", -1, 0) + text = text[r1: r2] + core_desc_object = json.loads(text) + # import descriptors to watch only wallet + res = wo.importdescriptors(core_desc_object) + for obj in res: + assert obj["success"], obj + + goto_address_explorer() + pick_menu_item(ms_name) + time.sleep(.1) + _, story = cap_story() + ea = [i.replace("\x02", "") for i in story.split("\n") if i and i.startswith("\x02")] + need_keypress("0") # change + time.sleep(.1) + _, story = cap_story() + ia = [i.replace("\x02", "") for i in story.split("\n") if i and i.startswith("\x02")] + + # check both external and internal + eabc, iabc = wo.deriveaddresses(core_desc_object[0]["desc"], [0, 9]) + for i in range(10): + assert eabc[i] == ea[i] + assert iabc[i] == ia[i] + + multi_addr = wo.getnewaddress("", af) + dest_addr = bitcoind.supply_wallet.getnewaddress("") + bitcoind.supply_wallet.sendtoaddress(multi_addr, 2) + bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress("")) + # create funded PSBT + psbt_resp = wo.walletcreatefundedpsbt([], [{dest_addr: 1.2}], 0, + {"fee_rate": 2, "change_type": af}) + psbt = psbt_resp.get("psbt") + + _, updated = try_sign(base64.b64decode(psbt), finalize=False) + signed = cosig.walletprocesspsbt(b64encode(updated).decode('ascii'), True, "ALL")["psbt"] + + # finalize and send + rr = bitcoind.supply_wallet.finalizepsbt(signed, True) + assert rr['complete'] + tx_hex = rr["hex"] + res = bitcoind.supply_wallet.testmempoolaccept([tx_hex]) + assert res[0]["allowed"] + txn_id = bitcoind.supply_wallet.sendrawtransaction(rr['hex']) + assert len(txn_id) == 64 - test_ms_show_addr(M, keys, bip45=False, path_mapper=pm) - finally: - clear_ms() -@pytest.mark.parametrize('mode', ['wrong-xfp', 'long-path', 'short-path', 'zero-path']) -@pytest.mark.ms_danger @pytest.mark.bitcoind -def test_bad_xfp(mode, clear_ms, use_regtest, import_ms_wallet - , test_ms_show_addr, has_ms_checks, request): - # give incorrect xfp+path args during show_address - - if has_ms_checks and (mode in {'zero-path', 'wrong-xfp'}): - # for these 2 cases, we detect the issue regardless of has_ms_checks mode - request.node.get_closest_marker('xfail').kwargs['strict'] = False - - M, N = 1, 15 - keys = import_ms_wallet(M, N, accept=1) - try: - time.sleep(.1) - - def tweaker(xfps): - print(f"xfps={xfps}") - if mode == 'wrong-xfp': - # bad XFP => not right multisig wallet - xfps[0][0] ^= 0x55 - elif mode == 'long-path': - # add garbage - xfps[0].extend([69, 69, 69, 69, 69]) - elif mode == 'short-path': - # trim last derivation part - xfps[0] = xfps[0][0:-1] - elif mode == 'zero-path': - # just XFP, no path - xfps[0] = xfps[0][0:1] - else: - raise ValueError - - with pytest.raises(BaseException) as ee: - test_ms_show_addr(M, keys, tweak_xfps=tweaker) - - if mode in { 'wrong-xfp', 'zero-path' }: - assert 'with those fingerprints not found' in str(ee.value) - else: - assert 'pk#1 wrong' in str(ee.value) - if ('zero' in mode): - assert 'shallow' in str(ee.value) - - finally: - clear_ms() - -@pytest.mark.parametrize('cpp', [ - "m///", - "m/", - "m/1/2/3/4/5/6/7/8/9/10/11/12/13", # assuming MAX_PATH_DEPTH==12 -]) -@pytest.mark.bitcoind -def test_bad_common_prefix(cpp, use_regtest, clear_ms, import_ms_wallet, +def test_bad_common_prefix(use_regtest, clear_miniscript, import_ms_wallet, test_ms_show_addr): - # give some incorrect path values as the common prefix derivation - + # assuming MAX_PATH_DEPTH==12 + cpp = "m/1/2/3/4/5/6/7/8/9/10/11/12/13" + clear_miniscript() M, N = 1, 15 with pytest.raises(BaseException) as ee: - keys = import_ms_wallet(M, N, accept=1, common=cpp) - assert 'bad derivation line' in str(ee) + keys = import_ms_wallet(M, N, accept=True, common=cpp) + assert 'origin too deep' in str(ee) @pytest.mark.parametrize("desc", ["multi", "sortedmulti"]) -def test_import_detail(desc, clear_ms, import_ms_wallet, need_keypress, +def test_import_detail(desc, clear_miniscript, import_ms_wallet, need_keypress, cap_story, is_q1, press_cancel): # check all details are shown right M,N = 14, 15 descriptor, bip67 = (True, False) if desc == "multi" else (False, True) - keys = import_ms_wallet(M, N, descriptor=descriptor, bip67=bip67) + keys = import_ms_wallet(M, N, bip67=bip67) time.sleep(.2) title, story = cap_story() assert f'{M} of {N}' in story + + # TODO emitting no warning here if desc == "multi": assert "WARNING" in story assert "BIP-67 disabled" in story @@ -738,16 +559,12 @@ def test_import_detail(desc, clear_ms, import_ms_wallet, need_keypress, assert "WARNING" not in story assert "BIP-67 disabled" not in story + assert f'{M} of {N}' in story + need_keypress('1') time.sleep(.1) title, story = cap_story() - if desc == "sortedmulti": - assert title == f'test-{M}-{N}' - else: - # imported from descriptor - name will be just M N - assert title == f'{M}-of-{N}' - xpubs = [sk.hwif() for _,_,sk in keys] for xp in xpubs: assert xp in story @@ -772,7 +589,7 @@ def test_export_airgap(acct_num, goto_home, cap_story, pick_menu_item, cap_menu, goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') pick_menu_item('Export XPUB') time.sleep(.1) @@ -790,7 +607,7 @@ def test_export_airgap(acct_num, goto_home, cap_story, pick_menu_item, cap_menu, need_keypress(n) press_select() - rv = load_export(way, is_json=True, label="Multisig XPUB", fpattern="ccxp-", sig_check=False) + rv = load_export(way, is_json=True, label="Multisig XPUB", fpattern="ccxp-") assert 'xfp' in rv assert len(rv) >= 6 @@ -809,6 +626,7 @@ def test_export_airgap(acct_num, goto_home, cap_story, pick_menu_item, cap_menu, expect = e.subkey_for_path("m/45'") assert expect.hwif() == n.hwif() + assert rv["p2sh_key_exp"] == f"[{rv['xfp']}/45h]{n.hwif()}" for name, deriv in [ ('p2sh_p2wsh', f"m/48h/{int(testnet)}h/{acct_num}h/1h"), @@ -824,35 +642,36 @@ def test_export_airgap(acct_num, goto_home, cap_story, pick_menu_item, cap_menu, assert n.node.index & 0xff == int(deriv[-2]) expect = e.subkey_for_path(deriv) assert expect.hwif() == n.hwif() + assert rv[name+"_key_exp"] == f"[{rv['xfp']}/{deriv.replace('m/', '')}]{n.hwif()}" - # TODO add tests for descriptor template @pytest.mark.parametrize('N', [ 3, 15]) @pytest.mark.parametrize('vdisk', [True, False]) def test_import_ux(N, vdisk, goto_home, cap_story, pick_menu_item, - need_keypress, microsd_path, make_multisig, + need_keypress, microsd_path, get_cc_key, virtdisk_path, is_q1, press_cancel, press_select): # test menu-based UX for importing wallet file from SD M = N-1 - keys = make_multisig(M, N) + keys = [BIP32Node.from_master_secret(os.urandom(32)).hwif() for _ in range(M)] + keys.append(get_cc_key("", "")) name = 'named-%d' % random.randint(10000,99999) - config = f'policy: {M} of {N}\n' - config += '\n'.join(sk.hwif(as_private=False) for xfp,m,sk in keys) + config = {"name": name, "desc": f"wsh(sortedmulti({M},{','.join(keys)}))"} if vdisk: fname = virtdisk_path(f'ms-{name}.txt') else: fname = microsd_path(f'ms-{name}.txt') + with open(fname, 'wt') as fp: - fp.write(config) + fp.write(json.dumps(config)) try: goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') - pick_menu_item('Import from File') - time.sleep(0.5) + pick_menu_item('Miniscript') + pick_menu_item('Import') + time.sleep(0.1) _, story = cap_story() if vdisk: if "(2) to import from Virtual Disk" not in story: @@ -860,7 +679,7 @@ def test_import_ux(N, vdisk, goto_home, cap_story, pick_menu_item, else: need_keypress("2") else: - if "(1) to import multisig wallet file from SD Card" in story: + if "(1) to import miniscript wallet file from SD Card" in story: need_keypress("1") time.sleep(.1) @@ -869,7 +688,7 @@ def test_import_ux(N, vdisk, goto_home, cap_story, pick_menu_item, time.sleep(.1) _, story = cap_story() - assert 'Create new multisig' in story + assert 'Create new miniscript' in story assert name in story, 'didnt infer wallet name from filename' assert f'Policy: {M} of {N}\n' in story @@ -881,102 +700,16 @@ def test_import_ux(N, vdisk, goto_home, cap_story, pick_menu_item, try: os.unlink(fname) except: pass -@pytest.mark.parametrize("way", [None, "sd", "vdisk", "nfc", "qr"]) -@pytest.mark.parametrize('addr_fmt', ['p2sh-p2wsh', 'p2sh', 'p2wsh' ]) -@pytest.mark.parametrize('comm_prefix', ['m/1/2/3/4/5/6/7/8/9/10/11/12', None, "m/45h"]) -def test_export_single_ux(goto_home, comm_prefix, cap_story, pick_menu_item, cap_menu, press_select, - microsd_path, import_ms_wallet, addr_fmt, clear_ms, way, load_export, is_q1): - - # create a wallet, export to SD card, check file created. - # - checks some values for derivation path, assuming MAX_PATH_DEPTH==12 - - clear_ms() - - name = 'ex-test-%d' % random.randint(10000,99999) - M,N = 3, 5 - keys = import_ms_wallet(M, N, name=name, addr_fmt=addr_fmt, accept=1, - common=comm_prefix, way=way) - - goto_home() - pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') - - menu = cap_menu() - item = [i for i in menu if name in i][0] - pick_menu_item(item) - - pick_menu_item('Coldcard Export') - contents = load_export(way or "sd", label="Coldcard multisig setup", is_json=False, sig_check=False) - if way == "qr": - # QR code still displayed on screen - press_select() - - got = set() - for ln in io.StringIO(contents).readlines(): - ln = ln.strip() - if '#' in ln: - assert ln[0] == '#' - continue - if not ln: - continue - - assert ':' in ln - label, value = ln.split(': ') - - if label == 'Name': - assert value == name - got.add(label) - elif label == 'Policy': - assert value == f'{M} of {N}' - got.add(label) - elif label == 'Derivation': - assert value == (comm_prefix or "m/45h") - got.add(label) - elif label == 'Format': - assert value == addr_fmt.upper() - assert addr_fmt != 'p2sh' - got.add(label) - else: - assert len(label) == 8, label - xfp = swab32(int(label, 16)) - got.add(xfp) - assert xfp in [x for x,_,_ in keys] - n = BIP32Node.from_wallet_key(value) - - if 'Format' not in got: - assert addr_fmt == 'p2sh' - got.add('Format') - - assert len(got) == 4 + N - - # test delete while we're here - pick_menu_item('Delete') - - time.sleep(.2) - title, story = cap_story() - where = title if is_q1 else story - assert 'you SURE' in where - assert name in story - - press_select() - time.sleep(.1) - menu = cap_menu() - assert not [i for i in menu if name in i] - assert '(none setup yet)' in menu - @pytest.mark.parametrize('N', [ 3, 15]) -def test_overflow(N, import_ms_wallet, clear_ms, press_select, cap_story, mk_num, is_q1): +def test_overflow(N, import_ms_wallet, clear_miniscript, press_select, cap_story, mk_num, is_q1): - clear_ms() + clear_miniscript() M = N - name = 'a'*20 # longest possible + name = 'a'*19 # longest possible for count in range(1, 10): - keys = import_ms_wallet(M, N, name=name, addr_fmt='p2wsh', unique=count, accept=0, - common="m/45h/0h/34h") - - time.sleep(.1) - press_select() + keys = import_ms_wallet(M, N, name=f"{name}{count}", addr_fmt='p2wsh', unique=count, + accept=True, common="m/45h/0h/34h") time.sleep(.2) title, story = cap_story() @@ -986,159 +719,108 @@ def test_overflow(N, import_ms_wallet, clear_ms, press_select, cap_story, mk_num assert 'No space left' in story break - if mk_num >= 4: - assert count == 9 # unlimited now - else: - if N == 3: - assert count == 9, "Expect fail at 9" - if N == 15: - assert count == 2, "Expect fail at 2" + assert count == 9 # unlimited now press_select() - clear_ms() + clear_miniscript() -@pytest.fixture -def test_make_example_file(microsd_path, make_multisig): - def doit(M, N, addr_fmt=None): - keys = make_multisig(M, N) - - # render as a file for import - name = f'sample-{M}-{N}' - config = f"name: {name}\npolicy: {M} / {N}\n\n" - - if addr_fmt: - config += f'format: {addr_fmt.upper()}\n' - - config += '\n'.join('%s: %s' % (xfp2str(xfp), sk.hwif(as_private=False)) - for xfp,m,sk in keys) - - fname = microsd_path(f'{name}.txt') - with open(fname, 'wt') as fp: - fp.write(config+'\n') - - print(f"Created: {fname}") - return fname - return doit @pytest.mark.parametrize('N', [ 5, 10]) -def test_import_dup_safe(N, clear_ms, make_multisig, offer_ms_import, +def test_import_dup_safe(N, clear_miniscript, make_multisig, offer_minsc_import, need_keypress, cap_story, goto_home, pick_menu_item, - cap_menu, is_q1, press_select, OK): + cap_menu, is_q1, press_select, OK, settings_get, enter_text): # import wallet, rename it, (check that indicated, works), attempt same w/ addr fmt different M = N - clear_ms() + clear_miniscript() keys = make_multisig(M, N) # render as a file for import - def make_named(name, af='p2sh', m=M): - config = f"name: {name}\npolicy: {m} / {N}\nformat: {af}\n\n" - config += '\n'.join('%s: %s' % (xfp2str(xfp), sk.hwif(as_private=False)) - for xfp,m,sk in keys) - return config + def make_named(name, af='sh', m=M): + k = ','.join('[%s/45h]%s' % (xfp2str(xfp), sk.hwif()) for xfp, m, sk in keys) + desc_obj = {"name": name, "desc": f"{af}(sortedmulti({m},{k}))"} + return json.dumps(desc_obj) def has_name(name, num_wallets=1): # check worked: look in menu for name goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') menu = cap_menu() - assert f'{M}/{N}: {name}' in menu - # depending if NFC enabled or not, and if Q (has QR) or whether EDGE - assert (len(menu) - num_wallets) in [6, 7, 8, 9] + assert name in menu + assert len(settings_get("miniscript")) == num_wallets - title, story = offer_ms_import(make_named('xxx-orig')) - assert 'Create new multisig wallet' in story - assert 'xxx-orig' in story + orig_name = "xxx-orig" + title, story = offer_minsc_import(make_named(orig_name)) + assert 'Create new miniscript wallet' in story + assert orig_name in story assert 'P2SH' in story press_select() - has_name('xxx-orig') + has_name(orig_name) + + new_name = "AAAA" + title, story = offer_minsc_import(make_named(new_name)) + assert 'Duplicate wallet' in story + assert f"'{orig_name}' is the same" + assert new_name in story + try: + has_name(new_name) + raise ValueError + except AssertionError: pass + has_name(orig_name, 1) # just simple rename - title, story = offer_ms_import(make_named('xxx-new')) - assert 'update name only' in story.lower() - assert 'xxx-new' in story + pick_menu_item(orig_name) + pick_menu_item("Rename") + for i in range(len(orig_name) if is_q1 else len(orig_name) - 1): + need_keypress(KEY_DELETE if is_q1 else "x") + + if not is_q1: + # below should yield AAAA + need_keypress("1") + for _ in range(3): + need_keypress("9") # next char + need_keypress("1") # letters + + press_select() + else: + enter_text(new_name) press_select() - has_name('xxx-new') + has_name(new_name) - assert N < 15, 'cant make more, no space' - - newer = make_named('xxx-newer', 'p2wsh') - title, story = offer_ms_import(newer) - assert 'update name only' not in story.lower() - assert 'address type' in story.lower() - assert 'will NOT replace it' in story - assert 'xxx-newer' in story - assert 'WARNING:' in story + newer_name = "xxx-newer" + newer = make_named(newer_name, 'wsh') + title, story = offer_minsc_import(newer) + assert newer_name in story assert 'P2WSH' in story # should be 2 now, slightly different press_select() - has_name('xxx-newer', 2) + has_name(newer_name, 2) - # TODO # repeat last one, should still be two for keys in ['yn', 'n']: - title, story = offer_ms_import(newer) - assert 'Duplicate wallet' in story + title, story = offer_minsc_import(newer) + assert 'unique names' in story assert f'{OK} to approve' not in story - assert 'xxx-newer' in story + assert newer_name in story for key in keys: need_keypress(key) - has_name('xxx-newer', 2) + has_name(newer_name, 2) - clear_ms() - -@pytest.mark.parametrize('N', [ 5]) -def test_import_dup_diff_xpub(N, clear_ms, make_multisig, offer_ms_import, - press_select, cap_story, goto_home, - pick_menu_item, cap_menu, is_q1): - # import wallet, tweak xpub only, check that change detected - clear_ms() - - M = N - keys = make_multisig(M, N) - - # render as a file for import - def make_named(name, af='p2sh', m=M, tweaked=False): - config = f"name: {name}\npolicy: {m} / {N}\nformat: {af}\n\n" - lines = [] - for idx, (xfp,m,sk) in enumerate(keys): - if idx == 1 and tweaked: - x = bytearray(sk.node.key) - x[9] = 254 - sk.node.key = bytes(x) - - hwif = sk.hwif() - lines.append('%s: %s' % (xfp2str(xfp), hwif) ) - config += '\n'.join(lines) - return config - - title, story = offer_ms_import(make_named('xxx-orig')) - assert 'Create new multisig wallet' in story - assert 'xxx-orig' in story - assert 'P2SH' in story - press_select() - - # change one key. - title, story = offer_ms_import(make_named('xxx-new', tweaked=True)) - assert 'WARNING:' in story - assert 'xxx-new' in story - assert 'xpubs' in story - - clear_ms() + clear_miniscript() @pytest.mark.bitcoind @pytest.mark.parametrize('m_of_n', [(2,2), (2,3), (15,15)]) @pytest.mark.parametrize('addr_fmt', ['p2sh-p2wsh', 'p2sh', 'p2wsh' ]) -def test_import_dup_xfp_fails(m_of_n, use_regtest, addr_fmt, clear_ms, +def test_import_dup_xfp_fails(m_of_n, use_regtest, addr_fmt, clear_miniscript, make_multisig, import_ms_wallet, test_ms_show_addr): M, N = m_of_n @@ -1152,73 +834,18 @@ def test_import_dup_xfp_fails(m_of_n, use_regtest, addr_fmt, clear_ms, keys[-1] = (simulator_fixed_xfp, pk, sub) with pytest.raises(Exception) as ee: - import_ms_wallet(M, N, addr_fmt, accept=1, keys=keys) + import_ms_wallet(M, N, addr_fmt, accept=True, keys=keys) #assert 'XFP' in str(ee) assert 'wrong pubkey' in str(ee) -@pytest.mark.parametrize('addr_fmt', [AF_P2SH, AF_P2WSH, AF_P2WSH_P2SH]) -@pytest.mark.parametrize('desc', ["multi", "sortedmulti"]) -def test_ms_cli(dev, addr_fmt, clear_ms, import_ms_wallet, addr_vs_path, desc): - # exercise the p2sh command of ckcc:cli ... hard to do manually. - from subprocess import check_output - - M, N = 2, 3 - clear_ms() - bip67, descriptor = (False, True) if desc == "multi" else (True, False) - keys = import_ms_wallet(M, N, name='cli-test', accept=True, - addr_fmt=addr_fmt_names[addr_fmt], - descriptor=descriptor, bip67=bip67) - - pmapper = lambda i: [HARD(45), i, 0,3] - - scr, pubkeys, xfp_paths = make_redeem(M, keys, pmapper, bip67=bip67) - - def decode_path(p): - return '/'.join(str(i) if i < 0x80000000 else "%d'"%(i& 0x7fffffff) for i in p) - - if 1: - args = ['ckcc'] - if dev.is_simulator: - args += ['-x'] - - args += ['p2sh', '-q'] - - if addr_fmt == AF_P2WSH: - args += ['-s'] - elif addr_fmt == AF_P2WSH_P2SH: - args += ['-s', '-w'] - - args += [B2A(scr)] - args += [xfp2str(x)+'/'+decode_path(path) for x,*path in xfp_paths] - - import shlex - print('CMD: ' + (' '.join(shlex.quote(i) for i in args))) - - addr = check_output(args, encoding='ascii').strip() - - print(addr) - addr_vs_path(addr, addr_fmt=addr_fmt, script=scr) - - # test case for make_ms_address really. - expect_addr, _, scr2, _ = make_ms_address(M, keys, path_mapper=pmapper, - addr_fmt=addr_fmt, bip67=bip67) - assert expect_addr == addr - assert scr2 == scr - - # need to re-start our connection once ckcc has talked to simulator - dev.start_encryption() - dev.check_mitm() - - clear_ms() - @pytest.fixture -def make_myself_wallet(dev, set_bip39_pw, offer_ms_import, press_select, clear_ms, +def make_myself_wallet(dev, set_bip39_pw, offer_minsc_import, press_select, clear_miniscript, reset_seed_words, is_q1): # construct a wallet (M of 4) using different bip39 passwords, and default sim - def doit(M, addr_fmt=None, do_import=True): + def doit(M, addr_fmt="p2wsh", do_import=True, desc="sortedmulti"): passwords = ['Me', 'Myself', 'And I', ''] @@ -1251,31 +878,39 @@ def make_myself_wallet(dev, set_bip39_pw, offer_ms_import, press_select, clear_m if do_import: # render as a file for import - config = f"name: Myself-{M}\npolicy: {M} / 4\n\n" + msc = {"name": f"Myself-{M}"} + kk = ','.join('[%s/45h]%s' % (xfp2str(xfp), sk.hwif()) for xfp, _, sk in keys) - if addr_fmt: - config += f'format: {addr_fmt.upper()}\n' + if addr_fmt == "p2wsh": + d = f"wsh({desc}({M},{kk}))" + elif addr_fmt == "p2sh-p2wsh": + d = f"sh(wsh({desc}({M},{kk})))" + elif addr_fmt == "p2sh": + d = f"sh({desc}({M},{kk}))" + else: + raise ValueError("Unknown address format: " + addr_fmt) - config += '\n'.join('%s: %s' % (xfp2str(xfp), sk.hwif()) for xfp, _, sk in keys) - #print(config) - - title, story = offer_ms_import(config) - #print(story) + msc["desc"] = d + config = json.dumps(msc) + title, story = offer_minsc_import(config) + assert "Create new miniscript wallet" in story # don't care if update or create; accept it. time.sleep(.1) press_select() - def select_wallet(idx): + def select_wallet(idx, no_import=False): # select to specific pw + print(f"--- switch to another leg of MS: {idx} ---") xfp = set_bip39_pw(passwords[idx]) - if do_import: - offer_ms_import(config) + if do_import and not no_import: + offer_minsc_import(config) time.sleep(.1) press_select() assert xfp == keys[idx][0] + return xfp - return (keys, select_wallet) + return keys, select_wallet yield doit @@ -1288,10 +923,10 @@ def fake_ms_txn(pytestconfig): # - but has UTXO's to match needs from struct import pack - def doit(num_ins, num_outs, M, keys, fee=10000, outvals=None, segwit_in=False, + def doit(num_ins, num_outs, M, keys, fee=10000, outvals=None, inp_addr_fmt="p2wsh", outstyles=['p2pkh'], change_outputs=[], incl_xpubs=False, hack_psbt=None, hack_change_out=False, input_amount=1E8, psbt_v2=None, bip67=True, - violate_script_key_order=False): + violate_script_key_order=False, path_mapper=None, netcode="XTN", force_outstyle=None): psbt = BasicPSBT() if psbt_v2 is None: @@ -1322,18 +957,32 @@ def fake_ms_txn(pytestconfig): psbt.inputs = [BasicPSBTInput(idx=i) for i in range(num_ins)] psbt.outputs = [BasicPSBTOutput(idx=i) for i in range(num_outs)] + if netcode == "XTN": + net = 1 + elif netcode == "XRT": + net = 2 + else: + net = 0 + + af = unmap_addr_fmt[inp_addr_fmt] for i in range(num_ins): # make a fake txn to supply each of the inputs # - each input is 1BTC - # addr where the fake money will be stored. - addr, scriptPubKey, script, details = make_ms_address(M, keys, idx=i, bip67=bip67, - violate_script_key_order=violate_script_key_order) - + addr, scriptPubKey, script, details = make_ms_address( + M, keys, idx=i, bip67=bip67, + violate_script_key_order=violate_script_key_order, + path_mapper=path_mapper, addr_fmt=af, testnet=net + ) # lots of supporting details needed for p2sh inputs - if segwit_in: + if inp_addr_fmt in ["p2wsh", "p2sh-p2wsh", "p2wsh-p2sh"]: + segwit_in = True psbt.inputs[i].witness_script = script + if "p2sh" in inp_addr_fmt: + psbt.inputs[i].redeem_script = b'\x00\x20' + sha256(script).digest() else: + # p2sh + segwit_in = False psbt.inputs[i].redeem_script = script for pubkey, xfp_path in details: @@ -1375,11 +1024,19 @@ def fake_ms_txn(pytestconfig): style = outstyles[i % len(outstyles)] if i in change_outputs: + # overwrite style, change can only be of THE style + if force_outstyle: + style = force_outstyle + else: + style = inp_addr_fmt + make_redeem_args = dict() if hack_change_out: make_redeem_args = hack_change_out(i) if violate_script_key_order: make_redeem_args["violate_script_key_order"] = True + if path_mapper: + make_redeem_args["path_mapper"] = path_mapper addr, scriptPubKey, scr, details = \ make_ms_address(M, keys, idx=i, addr_fmt=unmap_addr_fmt[style], @@ -1390,7 +1047,7 @@ def fake_ms_txn(pytestconfig): if 'w' in style: psbt.outputs[i].witness_script = scr - if style.endswith('p2sh'): + if 'p2sh' in style: psbt.outputs[i].redeem_script = b'\0\x20' + sha256(scr).digest() elif style.endswith('sh'): psbt.outputs[i].redeem_script = scr @@ -1429,40 +1086,67 @@ def fake_ms_txn(pytestconfig): @pytest.mark.veryslow @pytest.mark.unfinalized -@pytest.mark.parametrize('addr_fmt', [AF_P2SH, AF_P2WSH, AF_P2WSH_P2SH]) +@pytest.mark.parametrize('addr_fmt', ["p2wsh", "p2sh-p2wsh", "p2sh"]) @pytest.mark.parametrize('num_ins', [2, 15]) -@pytest.mark.parametrize('incl_xpubs', [False, True, 'no-import']) +@pytest.mark.parametrize('incl_xpubs', [True, False, None]) @pytest.mark.parametrize('transport', ['usb', 'sd']) @pytest.mark.parametrize('has_change', [True, False]) @pytest.mark.parametrize('M_N', [(2, 3), (5, 15)]) -@pytest.mark.parametrize('desc', ["multi", "sortedmulti"]) -def test_ms_sign_simple(M_N, num_ins, dev, addr_fmt, clear_ms, incl_xpubs, import_ms_wallet, +@pytest.mark.parametrize('desc', ["sortedmulti", "multi"]) +def test_ms_sign_simple(M_N, num_ins, dev, addr_fmt, clear_miniscript, import_ms_wallet, addr_vs_path, fake_ms_txn, try_sign, try_sign_microsd, transport, - has_change, settings_set, desc): + has_change, settings_set, desc, sim_root_dir, incl_xpubs): M, N = M_N num_outs = num_ins-1 - descriptor, bip67 = (True, False) if desc == "multi" else (False, True) + bip67 = False if desc == "multi" else True - # trust PSBT if we're doing "no-import" case + # TODO + # # trust PSBT if we're doing "no-import" case settings_set('pms', 2 if (incl_xpubs == 'no-import') else 0) - clear_ms() + clear_miniscript() - if incl_xpubs != "no-import": - do_import = True + if addr_fmt == AF_P2SH: + dd = "m/45h" + elif addr_fmt == AF_P2WSH: + dd = "m/48h/1h/0h/2h" else: + dd = "m/48h/1h/0h/1h" + + def path_mapper(idx): + kk = str_to_path(dd) + return kk + [0,0] + + if incl_xpubs: + # test enrolling xpubs form PSBT do_import = False + + def incl_xpubs(idx, xfp, m, sk): + kk = str_to_path(dd) + bp = pack('<%dI' % (dd.count("/")+1), xfp, *kk) + return sk.node.serialize_public(), bp + if not bip67: raise pytest.skip("cannot import unsorted multisig from PSBT") + elif incl_xpubs is None: + # test verification of PSBT xpubs against our enrolled wallet + do_import = True + incl_xpubs = True + else: + do_import = True - keys = import_ms_wallet(M, N, name='cli-test', accept=True, addr_fmt=addr_fmt, - do_import=do_import, descriptor=descriptor, bip67=bip67) + keys = import_ms_wallet(M, N, name='ms-sign-simple', accept=True, addr_fmt=addr_fmt, + do_import=do_import, bip67=bip67, common=dd) - psbt = fake_ms_txn(num_ins, num_outs, M, keys, incl_xpubs=incl_xpubs, - outstyles=ADDR_STYLES_MS, change_outputs=[1] if has_change else [], - bip67=bip67) + if do_import is False: + keys = keys[0] - open('debug/last.psbt', 'wb').write(psbt) + psbt = fake_ms_txn(num_ins, num_outs, M, keys, inp_addr_fmt=addr_fmt, incl_xpubs=incl_xpubs, + outstyles=[addr_fmt], change_outputs=[1] if has_change else [], + bip67=bip67, netcode="XRT") + + with open(f'{sim_root_dir}/debug/last.psbt', 'wb') as f: + f.write(psbt) if transport == 'sd': try_sign_microsd(psbt, encoding=('binary', 'hex', 'base64')[random.randint(0,2)]) @@ -1472,33 +1156,36 @@ def test_ms_sign_simple(M_N, num_ins, dev, addr_fmt, clear_ms, incl_xpubs, impor @pytest.mark.unfinalized @pytest.mark.bitcoind @pytest.mark.parametrize('num_ins', [ 15 ]) -@pytest.mark.parametrize('M', [ 2, 4, 1]) -@pytest.mark.parametrize('segwit', [True, False]) +@pytest.mark.parametrize('M', [ 2, 4]) @pytest.mark.parametrize('incl_xpubs', [ True, False ]) -def test_ms_sign_myself(M, use_regtest, make_myself_wallet, segwit, num_ins, dev, clear_ms, - fake_ms_txn, try_sign, incl_xpubs, bitcoind): +def test_ms_sign_myself(M, use_regtest, make_myself_wallet, num_ins, dev, incl_xpubs, + clear_miniscript, fake_ms_txn, try_sign, bitcoind, sim_root_dir): - # IMPORTANT: wont work if you start simulator with --ms flag. Use no args + # IMPORTANT: won't work if you start simulator with --ms flag. Use no args all_out_styles = [af for af in unmap_addr_fmt.keys() if af != "p2tr"] num_outs = len(all_out_styles) - clear_ms() + clear_miniscript() use_regtest() # create a wallet, with 3 bip39 pw's - keys, select_wallet = make_myself_wallet(M, do_import=(not incl_xpubs)) + keys, select_wallet = make_myself_wallet(M, addr_fmt="p2sh", do_import=(not incl_xpubs)) N = len(keys) assert M<=N - psbt = fake_ms_txn(num_ins, num_outs, M, keys, segwit_in=segwit, incl_xpubs=incl_xpubs, - outstyles=all_out_styles, change_outputs=list(range(1,num_outs))) + psbt = fake_ms_txn(num_ins, num_outs, M, keys, inp_addr_fmt="p2sh", incl_xpubs=incl_xpubs, + outstyles=["p2sh"], change_outputs=list(range(1,num_outs))) - open(f'debug/myself-before.psbt', 'w').write(b64encode(psbt).decode()) + with open(f'{sim_root_dir}/debug/myself-before.psbt', 'w') as f: + f.write(b64encode(psbt).decode()) for idx in range(M): select_wallet(idx) + if incl_xpubs: + clear_miniscript() _, updated = try_sign(psbt, accept_ms_import=incl_xpubs) - open(f'debug/myself-after.psbt', 'w').write(b64encode(updated).decode()) + with open(f'{sim_root_dir}/debug/myself-after.psbt', 'w') as f: + f.write(b64encode(updated).decode()) assert updated != psbt aft = BasicPSBT().parse(updated) @@ -1509,43 +1196,17 @@ def test_ms_sign_myself(M, use_regtest, make_myself_wallet, segwit, num_ins, dev # should be fully signed now. anal = bitcoind.rpc.analyzepsbt(b64encode(psbt).decode('ascii')) - try: - assert not any(inp.get('missing') for inp in anal['inputs']), "missing sigs: %r" % anal - assert all(inp['next'] in {'finalizer','updater'} for inp in anal['inputs']), "other issue: %r" % anal - except: - # XXX seems to be a bug in analyzepsbt function ... not fully studied - pprint(anal, stream=open('debug/analyzed.txt', 'wt')) - decode = bitcoind.rpc.decodepsbt(b64encode(psbt).decode('ascii')) - pprint(decode, stream=open('debug/decoded.txt', 'wt')) - - if M==N or segwit: - # as observed, bug not trigged, so raise if it *does* happen - raise - else: - print("ignoring bug in bitcoind") + assert not any(inp.get('missing') for inp in anal['inputs']), "missing sigs: %r" % anal + assert all(inp['next'] in {'finalizer','updater'} for inp in anal['inputs']), "other issue: %r" % anal - if 0: - # why doesn't this work? - # TODO this does NOT work only if parameter segwit is True - # TODO I have debuged bitcoin core to see why we're still in updater phase, not in desired finalizer - # relevant comment from core code: - # When we're taking our information from a witness UTXO, we can't verify it is actually data from - # the output being spent. This is safe in case a witness signature is produced (which includes this - # information directly in the hash), but not for non-witness signatures. Remember that we require - # a witness signature in this situation. - # - # In our case, witness signature was not produced (but was required) - rv = bitcoind.rpc.finalizepsbt(b64encode(aft.as_bytes()).decode('ascii'), True) - _, txn, is_complete = b64decode(rv.get('psbt', '')), rv.get('hex'), rv['complete'] - assert is_complete @pytest.mark.parametrize('addr_fmt', ['p2wsh', 'p2sh-p2wsh']) -@pytest.mark.parametrize('acct_num', [ 0, None, 4321]) +@pytest.mark.parametrize('acct_num', [None, 4321]) @pytest.mark.parametrize('M_N', [(2,3), (8,14)]) @pytest.mark.parametrize('way', ["sd", "qr"]) @pytest.mark.parametrize('incl_self', [True, False, None]) def test_make_airgapped(addr_fmt, acct_num, M_N, goto_home, cap_story, pick_menu_item, - need_keypress, microsd_path, set_bip39_pw, clear_ms, enter_number, + need_keypress, microsd_path, set_bip39_pw, clear_miniscript, enter_number, get_settings, load_export, is_q1, press_select, press_cancel, cap_screen, way, scan_a_qr, skip_if_useless_way, incl_self): # test UX and math for bip45 export @@ -1556,7 +1217,7 @@ def test_make_airgapped(addr_fmt, acct_num, M_N, goto_home, cap_story, pick_menu for fn in glob(microsd_path('ccxp-*.json')): assert fn os.unlink(fn) - clear_ms() + clear_miniscript() for idx in range(N - int(incl_self is None)): if not idx and (incl_self is True): @@ -1567,7 +1228,7 @@ def test_make_airgapped(addr_fmt, acct_num, M_N, goto_home, cap_story, pick_menu goto_home() time.sleep(0.1) pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') pick_menu_item('Export XPUB') time.sleep(.05) press_select() @@ -1591,12 +1252,12 @@ def test_make_airgapped(addr_fmt, acct_num, M_N, goto_home, cap_story, pick_menu goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') pick_menu_item('Create Airgapped') if is_q1: time.sleep(.1) title, story = cap_story() - assert "scan multisg XPUBs from QR codes" in story + assert "scan multisig XPUBs from QR codes" in story if way == "qr": need_keypress(KEY_QR) else: @@ -1618,22 +1279,6 @@ def test_make_airgapped(addr_fmt, acct_num, M_N, goto_home, cap_story, pick_menu assert 0, addr_fmt if way == "qr": - # first non-json garbage - scan_a_qr("aaaaaaaaaaaaaaaaaaaa") - time.sleep(1) - scr = cap_screen() - assert f"Expected JSON data" in scr - - # JSON but wrong - _, parts = split_qrs('{"json": "but wrong","missing": "important data"}', - 'J', max_version=20) - for p in parts: - scan_a_qr(p) - - time.sleep(1) - scr = cap_screen() - assert f"Missing value: xfp" in scr # missing xfp - # need to scan json XPUBs here for i, fname in enumerate(glob(microsd_path('ccxp-*.json'))): with open(fname, 'r') as f: @@ -1647,7 +1292,7 @@ def test_make_airgapped(addr_fmt, acct_num, M_N, goto_home, cap_story, pick_menu scr = cap_screen() assert f"Number of keys scanned: {i+1}" in scr - press_cancel() # quit QR animation + press_select() # quit QR animation if not incl_self: time.sleep(.1) @@ -1671,32 +1316,32 @@ def test_make_airgapped(addr_fmt, acct_num, M_N, goto_home, cap_story, pick_menu title, story = cap_story() if incl_self is not False: - assert "Create new multisig" in story + assert "Create new miniscript" in story press_select() - # we use clear_ms fixture at the begining of each test + # we use clear_miniscript fixture at the begining of each test # new multisig wallet is first menu item press_select() - pick_menu_item("Coldcard Export") - impf, fname = load_export("sd", label="Coldcard multisig setup", is_json=False, - sig_check=False, ret_fname=True) + pick_menu_item("Descriptors") + pick_menu_item("Export") + impf, fname = load_export("sd", label="Miniscript", is_json=False, + ret_fname=True) cc_fname = microsd_path(fname) - assert f'Policy: {M} of {N}' in impf - if addr_fmt != 'p2sh': - assert f'Format: {addr_fmt.upper()}' in impf + strt = "wsh(sortedmulti" if addr_fmt == 'p2wsh' else "sh(wsh(sortedmulti(" + strt += str(M) press_select() press_select() - clear_ms() + clear_miniscript() # test re-importing the wallet from export file goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') - pick_menu_item('Import from File') + pick_menu_item('Miniscript') + pick_menu_item('Import') time.sleep(0.5) _, story = cap_story() - if "Press (1) to import multisig wallet file from SD Card" in story: + if "Press (1) to import miniscript" in story: need_keypress("1") time.sleep(.05) @@ -1704,12 +1349,8 @@ def test_make_airgapped(addr_fmt, acct_num, M_N, goto_home, cap_story, pick_menu time.sleep(.05) title, story = cap_story() - assert "Create new multisig" in story + assert "Create new miniscript" in story assert f"Policy: {M} of {N}" in story - if acct_num is None: - assert ("Varies (%d)" % N) in story - else: - assert f"/{acct_num}h/" in story need_keypress('1') time.sleep(.1) @@ -1718,8 +1359,7 @@ def test_make_airgapped(addr_fmt, acct_num, M_N, goto_home, cap_story, pick_menu else: # own wallet not included in the mix, can only export resulting descriptor - desc = load_export(way, label="Descriptor multisig setup", - is_json=False, sig_check=False) + desc = load_export(way, label="Miniscript", is_json=False, sig_check=False) desc = desc.strip() do = MultisigDescriptor.parse(desc) assert do.M == M @@ -1743,164 +1383,21 @@ def test_make_airgapped(addr_fmt, acct_num, M_N, goto_home, cap_story, pick_menu press_cancel() press_cancel() -@pytest.mark.unfinalized -@pytest.mark.bitcoind -@pytest.mark.parametrize('addr_style', ["legacy", "p2sh-segwit", "bech32"]) -@pytest.mark.parametrize('cc_sign_first', [True, False]) -def test_bitcoind_cosigning(cc_sign_first, dev, bitcoind, import_ms_wallet, clear_ms, try_sign, - press_cancel, addr_style, use_regtest, is_q1): - # Make a P2SH wallet with local bitcoind as a co-signer (and simulator) - # - send an receive various - # - following text of - # - the constructed multisig walelt will only work for a single pubkey on core side - # - before starting this test, have some funds already deposited to bitcoind testnet wallet - - if not bitcoind.has_bdb: - # addmultisigaddress not supported by descriptor wallets - pytest.skip("Needs BDB legacy wallet") - - from bip32 import PubKeyNode - from binascii import a2b_hex - - use_regtest() - if addr_style == 'legacy': - addr_fmt = AF_P2SH - elif addr_style == 'p2sh-segwit': - addr_fmt = AF_P2WSH_P2SH - elif addr_style == 'bech32': - addr_fmt = AF_P2WSH - - addr = bitcoind.supply_wallet.getnewaddress("sim-cosign") - - info = bitcoind.supply_wallet.getaddressinfo(addr) - - assert info['address'] == addr - bc_xfp = swab32(int(info['hdmasterfingerprint'], 16)) - bc_deriv = info['hdkeypath'] # example: "m/0'/0'/3'" - bc_pubkey = info['pubkey'] # 02f75ae81199559c4aa... - - node = BIP32Node(PubKeyNode( - key=a2b_hex(bc_pubkey), - chain_code=b'\x23'*32, - depth=len(bc_deriv.split('/'))-1, - parent_fingerprint=a2b_hex('%08x' % bc_xfp), - testnet=True - )) - # No means to export XPUB from bitcoind! Still. In 2019. - # - this fake will only work for one pubkey value, the first/topmost - keys = [ - (bc_xfp, None, node), - (simulator_fixed_xfp, None, BIP32Node.from_hwif('tpubD8NXmKsmWp3a3DXhbihAYbYLGaRNVdTnr6JoSxxfXYQcmwVtW2hv8QoDwng6JtEonmJoL3cNEwfd2cLXMpGezwZ2vL2dQ7259bueNKj9C8n')), # simulator: m/45' - ] - - M,N=2,2 - - clear_ms() - import_ms_wallet(M, N, keys=keys, accept=1, name="core-cosign", - addr_fmt=addr_fmt_names[addr_fmt], derivs=[bc_deriv, "m/45h"]) - - cc_deriv = "m/45h/55" - cc_pubkey = B2A(BIP32Node.from_hwif(simulator_fixed_tprv).subkey_for_path(cc_deriv).sec()) - - # NOTE: bitcoind doesn't seem to implement pubkey sorting. We have to do it. - resp = bitcoind.supply_wallet.addmultisigaddress(M, list(sorted([cc_pubkey, bc_pubkey])), - 'shared-addr-'+addr_style, addr_style) - ms_addr = resp['address'] - bc_redeem = a2b_hex(resp['redeemScript']) - - assert bc_redeem[0] == 0x52 - - def mapper(cosigner_idx): - return list(str2ipath(cc_deriv if cosigner_idx else bc_deriv)) - - scr, pubkeys, xfp_paths = make_redeem(M, keys, mapper) - - assert scr == bc_redeem - - # check Coldcard calcs right address to match - got_addr = dev.send_recv(CCProtocolPacker.show_p2sh_address( - M, xfp_paths, scr, addr_fmt=addr_fmt), timeout=None) - assert got_addr == ms_addr - time.sleep(.1) - press_cancel() # clear screen / start over - - print(f"Will be signing an input from {ms_addr}") - - if xfp2str(bc_xfp) in ('5380D0ED', 'EDD08053'): - # my own expected values - assert ms_addr in ( '2NDT3ymKZc8iMfbWqsNd1kmZckcuhixT5U4', - '2N1hZJ5mazTX524GQTPKkCT4UFZn5Fqwdz6', - 'tb1qpcv2rkc003p5v8lrglrr6lhz2jg8g4qa9vgtrgkt0p5rteae5xtqn6njw9') - - # fund multisig address - bitcoind.supply_wallet.importaddress(ms_addr, 'shared-addr-'+addr_style, True) - bitcoind.supply_wallet.sendtoaddress(address=ms_addr, amount=5) - bitcoind.supply_wallet.generatetoaddress(101, bitcoind.supply_wallet.getnewaddress()) # mining - unspent = bitcoind.supply_wallet.listunspent(addresses=[ms_addr]) - ret_addr = bitcoind.supply_wallet.getrawchangeaddress() - - resp = bitcoind.supply_wallet.walletcreatefundedpsbt([dict(txid=unspent[0]["txid"], vout=unspent[0]["vout"])], - [{ret_addr: 2}], 0, - {'subtractFeeFromOutputs': [0], 'includeWatching': True}, True) - - if not cc_sign_first: - # signing first with bitcoind - resp = bitcoind.supply_wallet.walletprocesspsbt(resp["psbt"]) - - # assert resp['changepos'] == -1 - psbt = b64decode(resp['psbt']) - - open('debug/funded.psbt', 'wb').write(psbt) - - # patch up the PSBT a little ... bitcoind doesn't know the path for the CC's key - ex = BasicPSBT().parse(psbt) - cxpk = a2b_hex(cc_pubkey) - for i in ex.inputs: - # issues/47 in secret - from 24.0 core does not add out key into PSBT input bip32 paths - no need to check - # assert cxpk in i.bip32_paths, 'input not to be signed by CC?' - i.bip32_paths[cxpk] = pack('<3I', keys[1][0], *str2ipath(cc_deriv)) - - psbt = ex.as_bytes() - - open('debug/patched.psbt', 'wb').write(psbt) - - _, updated = try_sign(psbt, finalize=False) - - open('debug/cc-updated.psbt', 'wb').write(updated) - - if cc_sign_first: - # cc signed first - bitcoind is now second - rr = bitcoind.supply_wallet.walletprocesspsbt(b64encode(updated).decode('ascii'), True, "ALL") - assert rr["complete"] - both_signed = rr["psbt"] - else: - both_signed = b64encode(updated).decode('ascii') - - # finalize and send - rr = bitcoind.supply_wallet.finalizepsbt(both_signed, True) - open('debug/bc-final-txn.txn', 'wt').write(rr['hex']) - assert rr['complete'] - tx_hex = rr["hex"] - res = bitcoind.supply_wallet.testmempoolaccept([tx_hex]) - assert res[0]["allowed"] - txn_id = bitcoind.supply_wallet.sendrawtransaction(rr['hex']) - assert len(txn_id) == 64 - @pytest.mark.parametrize('addr_fmt', [AF_P2WSH] ) @pytest.mark.parametrize('num_ins', [ 3]) -@pytest.mark.parametrize('incl_xpubs', [ False]) @pytest.mark.parametrize('out_style', ['p2wsh']) @pytest.mark.parametrize('bitrot', list(range(0,6)) + [98, 99, 100] + list(range(-5, 0))) @pytest.mark.ms_danger -def test_ms_sign_bitrot(num_ins, dev, addr_fmt, clear_ms, incl_xpubs, import_ms_wallet, addr_vs_path, - fake_ms_txn, start_sign, end_sign, out_style, cap_story, bitrot, has_ms_checks): +def test_ms_sign_bitrot(num_ins, dev, addr_fmt, clear_miniscript, import_ms_wallet, + addr_vs_path, fake_ms_txn, start_sign, end_sign, out_style, cap_story, + bitrot, sim_root_dir): M = 1 N = 3 num_outs = 2 - clear_ms() - keys = import_ms_wallet(M, N, accept=1, addr_fmt=out_style) + clear_miniscript() + keys = import_ms_wallet(M, N, accept=True, addr_fmt=out_style) # given script, corrupt it a little or a lot def rotten(track, bitrot, scr): @@ -1918,45 +1415,45 @@ def test_ms_sign_bitrot(num_ins, dev, addr_fmt, clear_ms, incl_xpubs, import_ms_ return rv track = [] - psbt = fake_ms_txn(num_ins, num_outs, M, keys, incl_xpubs=incl_xpubs, - outstyles=[out_style], change_outputs=[0], - hack_change_out=lambda idx: dict(finalizer_hack= - lambda scr: rotten(track, bitrot, scr))) + psbt = fake_ms_txn( + num_ins, num_outs, M, keys, outstyles=[out_style], change_outputs=[0], + hack_change_out=lambda idx: dict(finalizer_hack=lambda scr: rotten(track, bitrot, scr)) + ) assert len(track) == 1 - open('debug/last.psbt', 'wb').write(psbt) + with open(f'{sim_root_dir}/debug/last.psbt', 'wb') as f: + f.write(psbt) start_sign(psbt) with pytest.raises(Exception) as ee: - signed = end_sign(accept=None) + end_sign(accept=None) assert 'Output#0:' in str(ee) - assert 'change output script' in str(ee) + assert 'p2wsh change output is fraudulent' in str(ee) # Check error details are shown time.sleep(.01) title, story = cap_story() - assert story.strip() in str(ee) - assert len(story.split(':')[-1].strip()), story + assert 'Output#0:' in story + assert 'p2wsh change output is fraudulent' -@pytest.mark.parametrize('addr_fmt', [AF_P2WSH, AF_P2SH] ) -@pytest.mark.parametrize('num_ins', [ 1]) -@pytest.mark.parametrize('incl_xpubs', [ True]) -@pytest.mark.parametrize('out_style', ['p2wsh']) -@pytest.mark.parametrize('pk_num', range(4)) +@pytest.mark.parametrize('addr_fmt', ["p2wsh", "p2sh-p2wsh", "p2sh"] ) +@pytest.mark.parametrize('pk_num', range(4)) @pytest.mark.parametrize('case', ['pubkey', 'path']) -def test_ms_change_fraud(case, pk_num, num_ins, dev, addr_fmt, clear_ms, incl_xpubs, make_multisig, - addr_vs_path, fake_ms_txn, start_sign, end_sign, out_style, cap_story): +def test_ms_change_fraud(case, pk_num, dev, addr_fmt, clear_miniscript, make_multisig, + addr_vs_path, fake_ms_txn, start_sign, end_sign, cap_story, + sim_root_dir): M = 1 N = 3 + num_ins = 1 num_outs = 2 - clear_ms() + clear_miniscript() keys = make_multisig(M, N) - # given + # given def tweak(case, pk_num, data): # added from make_redeem() as tweak_pubkeys option #(pk, xfp, path)) @@ -1977,157 +1474,77 @@ def test_ms_change_fraud(case, pk_num, num_ins, dev, addr_fmt, clear_ms, incl_xp data[pk_num] = (pk, xfp, path) psbt = fake_ms_txn(num_ins, num_outs, M, keys, incl_xpubs=True, - outstyles=[out_style], change_outputs=[0], + outstyles=[addr_fmt, "p2wpkh"], change_outputs=[0], hack_change_out=lambda idx: dict(tweak_pubkeys= lambda data: tweak(case, pk_num, data))) - open('debug/last.psbt', 'wb').write(psbt) + with open(f'{sim_root_dir}/debug/last.psbt', 'wb') as f: + f.write(psbt) with pytest.raises(Exception) as ee: start_sign(psbt) - signed = end_sign(accept=True, accept_ms_import=False) + end_sign(accept=True, accept_ms_import=False) assert 'Output#0:' in str(ee) - assert 'P2WSH or P2SH change output script' in str(ee) + assert f'{addr_fmt} change output is fraudulent' #assert 'Deception regarding change output' in str(ee) # Check error details are shown time.sleep(.5) title, story = cap_story() - assert story.strip() in str(ee.value.args[0]) - assert len(story.split(':')[-1].strip()), story + assert 'Output#0:' in story + assert f'{addr_fmt} change output is fraudulent' -@pytest.mark.parametrize('N', [ 3, 15]) -@pytest.mark.parametrize('xderiv', [ None, 'any', 'unknown', '*', '', 'none']) -def test_ms_import_nopath(N, xderiv, make_multisig, clear_ms, offer_ms_import): - # try various synonyms for unknown/any derivation styles - - keys = make_multisig(N, N, deriv="m/48h/0h/0h/1h/0", unique=1) - - # just fingerprints, no deriv paths - config = 'Format: p2sh-p2wsh\n' - for xfp,m,sk in keys: - config += '%s: %s\n' % (xfp2str(xfp), sk.hwif(as_private=False)) - if xderiv != None: - config += 'Derivation: %s\n' % xderiv - - with pytest.raises(BaseException) as ee: - title, story = offer_ms_import(config) - assert 'empty deriv' in str(ee) - -@pytest.mark.parametrize('N', [ 15]) -@pytest.mark.parametrize('M', [ 1, 15]) -@pytest.mark.parametrize('way', ["sd", "vdisk", "nfc"]) -def test_ms_import_many_derivs(M, N, way, make_multisig, clear_ms, offer_ms_import, press_select, - pick_menu_item, cap_story, microsd_path, virtdisk_path, nfc_read_text, - goto_home, load_export, is_q1, need_keypress): - # try config file with different derivation paths given, including None - # - also check we can convert those into Electrum wallets - - actual = "m/48h/0h/0h/1h/0" - derivs = [ actual, 'm', "m/45h/0h/99h", "m/45h/34/34h/34"] - - keys = make_multisig(M, N, deriv=actual, unique=1) - - # just fingerprints, no deriv paths - config = f'Format: p2sh-p2wsh\nName: impmany\n\npolicy: {M} of {N}\n' - for idx, (xfp,m,sk) in enumerate(keys): - if idx == len(keys)-1: - # last one always simulator's xfp, so can't lie about derivation - config += "Derivation: %s\n" % actual - else: - dp = derivs[idx % len(derivs)] - config += 'Derivation: %s\n' % dp - print('%s => %s was %d, gonna be %d' % ( - xfp2str(xfp), dp, sk.node.depth, dp.count('/'))) - sk.node.depth = dp.count('/') - config += '%s: %s\n' % (xfp2str(xfp), sk.hwif(as_private=False)) - - # need to disable checks for root paths with wrong xfp +@pytest.mark.ms_danger +def test_danger_warning(request, clear_miniscript, import_ms_wallet, cap_story, fake_ms_txn, + start_sign, sim_exec, sim_root_dir, goto_home, pick_menu_item, + need_keypress): goto_home() pick_menu_item("Settings") - pick_menu_item("Multisig Wallets") + pick_menu_item("Miniscript") pick_menu_item("Skip Checks?") need_keypress("4") pick_menu_item("Skip Checks") - title, story = offer_ms_import(config) - assert f'Policy: {M} of {N}\n' in story - assert f'P2SH-P2WSH' in story - assert 'Derivation:\n Varies' in story - assert f' Varies ({len(set(derivs))})\n' in story - press_select() + time.sleep(.1) - goto_home() - pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') - pick_menu_item(f'{M}/{N}: impmany') - - pick_menu_item('Coldcard Export') - contents = load_export(way, label="Coldcard multisig setup", sig_check=False, is_json=False) - lines = io.StringIO(contents).readlines() - - for xfp,_,_ in keys: - m = xfp2str(xfp) - assert any(m in ln for ln in lines) - - pick_menu_item('Electrum Wallet') - - time.sleep(.25) - title, story = cap_story() - assert 'This saves a skeleton Electrum wallet file' in story - press_select() - - el = load_export(way, label="Electrum multisig wallet", sig_check=False, is_json=True) - - assert el['seed_version'] == 17 - assert el['wallet_type'] == f"{M}of{N}" - for n in range(1, N+1): - kk = f'x{n}/' - assert kk in el - co = el[kk] - assert 'Coldcard' in co['label'] - dd = co['derivation'] - assert (dd in derivs) or (dd == actual) or ("42069h" in dd) or (dd == 'm') - - clear_ms() - - -@pytest.mark.ms_danger -@pytest.mark.parametrize('descriptor', [True, False]) -def test_danger_warning(request, descriptor, clear_ms, import_ms_wallet, cap_story, fake_ms_txn, start_sign, sim_exec): - # note: cant use has_ms_checks fixture here - danger_mode = (request.config.getoption('--ms-danger')) - sim_exec(f'from multisig import MultisigWallet; MultisigWallet.disable_checks={danger_mode}') - - clear_ms() + clear_miniscript() M,N = 2,3 - keys = import_ms_wallet(M, N, accept=1, descriptor=descriptor, addr_fmt="p2wsh") - psbt = fake_ms_txn(1, 1, M, keys, incl_xpubs=True) + keys = import_ms_wallet(M, N, accept=True, addr_fmt="p2wsh") + psbt = fake_ms_txn(1, 1, M, keys, inp_addr_fmt="p2wsh", incl_xpubs=True) - open('debug/last.psbt', 'wb').write(psbt) + with open(f'{sim_root_dir}/debug/last.psbt', 'wb') as f: + f.write(psbt) start_sign(psbt) title, story = cap_story() - if danger_mode: - assert 'WARNING' in story - assert 'Danger' in story - assert 'Some multisig checks are disabled' in story - else: - assert 'WARNING' not in story + assert 'WARNING' in story + assert 'Danger' in story + assert 'Some miniscript checks are disabled' in story + + goto_home() + pick_menu_item("Settings") + pick_menu_item("Miniscript") + pick_menu_item("Skip Checks?") + pick_menu_item("Normal") + + start_sign(psbt) + title, story = cap_story() + + assert 'WARNING' not in story @pytest.mark.parametrize('change', [True, False]) @pytest.mark.parametrize('desc', ["multi", "sortedmulti"]) @pytest.mark.parametrize('start_idx', [1000, MAX_BIP32_IDX, 0]) @pytest.mark.parametrize('M_N', [(2,3), (15,15)]) @pytest.mark.parametrize('addr_fmt', [AF_P2WSH, AF_P2SH, AF_P2WSH_P2SH] ) -def test_ms_addr_explorer(change, M_N, addr_fmt, start_idx, clear_ms, cap_menu, +def test_ms_addr_explorer(change, M_N, addr_fmt, start_idx, clear_miniscript, cap_menu, need_keypress, goto_home, pick_menu_item, cap_story, import_ms_wallet, make_multisig, settings_set, enter_number, set_addr_exp_start_idx, desc, cap_screen_qr, press_cancel, press_right): - clear_ms() + clear_miniscript() M, N = M_N wal_name = f"ax{M}-{N}-{addr_fmt}" @@ -2144,14 +1561,11 @@ def test_ms_addr_explorer(change, M_N, addr_fmt, start_idx, clear_ms, cap_menu, derivs = [deriv.format(idx=i) for i in range(N)] - clear_ms() - - descriptor = None bip67 = True if desc == "multi": - descriptor, bip67 = True, False - keys = import_ms_wallet(M, N, accept=1, keys=keys, name=wal_name, derivs=derivs, - addr_fmt=text_a_fmt, descriptor=descriptor, bip67=bip67) + bip67 = False + keys = import_ms_wallet(M, N, accept=True, keys=keys, name=wal_name, + derivs=derivs, addr_fmt=text_a_fmt, bip67=bip67) goto_home() pick_menu_item("Address Explorer") @@ -2159,12 +1573,7 @@ def test_ms_addr_explorer(change, M_N, addr_fmt, start_idx, clear_ms, cap_menu, set_addr_exp_start_idx(start_idx) - m = cap_menu() - if wal_name in m: - pick_menu_item(wal_name) - else: - # descriptor - pick_menu_item(f"{M}-of-{N}") + pick_menu_item(wal_name) time.sleep(.5) title, story = cap_story() @@ -2221,7 +1630,7 @@ def test_ms_addr_explorer(change, M_N, addr_fmt, start_idx, clear_ms, cap_menu, path_mapper=path_mapper, bip67=bip67) assert int(subpath.split('/')[-1]) == idx - assert int(subpath.split('/')[-2]) == chng_idx + # assert int(subpath.split('/')[-2]) == chng_idx #print('../0/%s => \n %s' % (idx, B2A(script))) addr = addr_from_display_format(addr) @@ -2230,66 +1639,86 @@ def test_ms_addr_explorer(change, M_N, addr_fmt, start_idx, clear_ms, cap_menu, def test_dup_ms_wallet_bug(goto_home, pick_menu_item, press_select, import_ms_wallet, - clear_ms, is_q1): + clear_miniscript, is_q1): M = 2 N = 3 deriv = ["m/48h/1h/0h/69h/1"]*N fmts = [ 'p2wsh', 'p2sh-p2wsh'] - clear_ms() + clear_miniscript() for n, ty in enumerate(fmts): - import_ms_wallet(M, N, name=f'name-{n}', accept=1, derivs=deriv, addr_fmt=ty) + import_ms_wallet(M, N, name=f'name-{n}', accept=True, derivs=deriv, addr_fmt=ty) goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') # drill down to second one time.sleep(.1) - pick_menu_item('2/3: name-1') + pick_menu_item('name-1') pick_menu_item('Delete') press_select() # BUG: pre v4.0.3, would be showing a "Yikes" referencing multisig:419 at this point - pick_menu_item('2/3: name-0') + pick_menu_item('name-0') pick_menu_item('Delete') press_select() - clear_ms() + clear_miniscript() -@pytest.mark.parametrize('M_N', [(2, 3), (2, 2), (3, 5), (15, 15)]) -@pytest.mark.parametrize('addr_fmt', [ AF_P2SH, AF_P2WSH, AF_P2WSH_P2SH ]) +@pytest.mark.parametrize('M_N', [(2, 3), (3, 5), (15, 15)]) +@pytest.mark.parametrize('addr_fmt', ["p2wsh", "p2sh-p2wsh", "p2sh"]) @pytest.mark.parametrize('int_ext_desc', [True, False]) +@pytest.mark.parametrize('json_wrapped', [True, False]) @pytest.mark.parametrize('way', ["sd", "vdisk", "nfc"]) @pytest.mark.parametrize('desc', ["multi", "sortedmulti"]) -def test_import_desciptor(M_N, addr_fmt, int_ext_desc, way, import_ms_wallet, goto_home, pick_menu_item, - press_select, clear_ms, cap_story, microsd_path, virtdisk_path, - nfc_read_text, load_export, is_q1, desc): - clear_ms() +def test_import_descriptor(M_N, addr_fmt, int_ext_desc, way, import_ms_wallet, goto_home, pick_menu_item, + press_select, clear_miniscript, cap_story, microsd_path, virtdisk_path, + nfc_read_text, load_export, is_q1, desc, sim_root_dir, skip_if_useless_way, + json_wrapped): + skip_if_useless_way(way) M, N = M_N - import_ms_wallet(M, N, addr_fmt=addr_fmt, accept=1, descriptor=True, - int_ext_desc=int_ext_desc, bip67=False if desc == "multi" else True) + if (way == "nfc") and (M == N == 15): + raise pytest.skip("too big for simulated NFC") + + clear_miniscript() goto_home() - pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') - press_select() # only one enrolled multisig - choose it + + name = None + if json_wrapped: + # descriptor wrapped in JSON with name key + name = "aaa" + + import_ms_wallet( + M, N, addr_fmt=addr_fmt, accept=True, way=way, name=name, + int_ext_desc=int_ext_desc, bip67=False if desc == "multi" else True, + ) + with open(f'{sim_root_dir}/debug/last-ms.txt', 'r') as f: + desc_import = f.read().strip() + + if json_wrapped: + desc_obj = json.loads(desc_import) + desc_import = desc_obj["desc"] + pick_menu_item(name) + else: + press_select() # only one enrolled multisig - choose it + pick_menu_item('Descriptors') pick_menu_item('Export') - contents = load_export(way, label="Descriptor multisig setup", is_json=False, sig_check=False) + contents = load_export(way, label="Miniscript", is_json=False) desc_export = contents.strip() - with open("debug/last-ms.txt", "r") as f: - desc_import = f.read().strip() + normalized = parse_desc_str(desc_export) - # as new format is not widely supported we only allow to import it - no export yet + # needs bitcoin core client at least on 29.0 if int_ext_desc: - # checksum will differ - ignore it - assert desc_import.split("#")[0] == normalized.split("#")[0].replace("0/*", "<0;1>/*") - else: assert desc_import == normalized + else: + # we always export with multipath + assert normalized.split("#")[0] == desc_import.split("#")[0].replace("/0/*", "/<0;1>/*") starts_with = MULTI_FMT_TO_SCRIPT[addr_fmt].split("%")[0] assert normalized.startswith(starts_with) assert f"{desc}(" in desc_export @@ -2301,25 +1730,25 @@ def test_import_desciptor(M_N, addr_fmt, int_ext_desc, way, import_ms_wallet, go @pytest.mark.parametrize("start_idx", [2147483540, MAX_BIP32_IDX, 0]) @pytest.mark.parametrize('M_N', [(2, 2), (3, 5), (15, 15)]) @pytest.mark.parametrize('addr_fmt', [AF_P2WSH, AF_P2SH, AF_P2WSH_P2SH]) -@pytest.mark.parametrize('way', ["sd", "vdisk", "nfc"]) -def test_bitcoind_ms_address(change, M_N, addr_fmt, clear_ms, goto_home, need_keypress, +@pytest.mark.parametrize('way', ["sd", "nfc"]) # vdisk +def test_bitcoind_ms_address(change, M_N, addr_fmt, clear_miniscript, goto_home, need_keypress, pick_menu_item, cap_menu, cap_story, make_multisig, import_ms_wallet, microsd_path, bitcoind_d_wallet_w_sk, use_regtest, load_export, way, is_q1, press_select, start_idx, settings_set, set_addr_exp_start_idx, - desc, garbage_collector, virtdisk_path): + desc, garbage_collector, virtdisk_path, skip_if_useless_way): + skip_if_useless_way(way) use_regtest() - clear_ms() + clear_miniscript() bitcoind = bitcoind_d_wallet_w_sk M, N = M_N path_f = microsd_path if way == "sd" else virtdisk_path - # whether to import as descriptor or old school to CC - descriptor = random.choice([True, False]) + bip67 = True if desc == "multi": bip67 = False - descriptor = True settings_set("aei", True if start_idx else False) + # adding this as parameter doubles the time this runs wal_name = f"ax{M}-{N}-{addr_fmt}" @@ -2334,9 +1763,9 @@ def test_bitcoind_ms_address(change, M_N, addr_fmt, clear_ms, goto_home, need_ke derivs = [deriv.format(idx=i) for i in range(N)] - clear_ms() - import_ms_wallet(M, N, accept=1, keys=keys, name=wal_name, derivs=derivs, - addr_fmt=text_a_fmt, descriptor=descriptor, bip67=bip67) + clear_miniscript() + import_ms_wallet(M, N, accept=True, keys=keys, name=wal_name, derivs=derivs, + addr_fmt=text_a_fmt, bip67=bip67) goto_home() pick_menu_item("Address Explorer") @@ -2344,10 +1773,7 @@ def test_bitcoind_ms_address(change, M_N, addr_fmt, clear_ms, goto_home, need_ke set_addr_exp_start_idx(start_idx) m = cap_menu() - if descriptor: - wal_name = m[-2 if start_idx else -1] - else: - assert wal_name in m + assert wal_name in m pick_menu_item(wal_name) time.sleep(0.2) @@ -2363,38 +1789,33 @@ def test_bitcoind_ms_address(change, M_N, addr_fmt, clear_ms, goto_home, need_ke assert "(0)" not in story if way != "nfc": - contents, exp_fname = load_export(way, label="Address summary", is_json=False, - sig_check=False, ret_fname=True) + contents, exp_fname = load_export(way, label="Address summary", + is_json=False, ret_fname=True) garbage_collector.append(path_f(exp_fname)) else: - contents = load_export(way, label="Address summary", is_json=False, sig_check=False) + contents = load_export(way, label="Address summary", is_json=False) addr_cont = contents.strip() goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') press_select() # only one enrolled multisig - choose it pick_menu_item('Descriptors') pick_menu_item("Bitcoin Core") if way != "nfc": - contents, exp_fname = load_export(way, label="Bitcoin Core multisig setup", is_json=False, - sig_check=False, ret_fname=True) + contents, exp_fname = load_export(way, label="Bitcoin Core miniscript", is_json=False, + ret_fname=True) garbage_collector.append(path_f(exp_fname)) else: - contents = load_export(way, label="Bitcoin Core multisig setup", is_json=False, sig_check=False) + contents = load_export(way, label="Bitcoin Core miniscript", is_json=False) text = contents.replace("importdescriptors ", "").strip() # remove junk r1 = text.find("[") r2 = text.find("]", -1, 0) text = text[r1: r2] core_desc_object = json.loads(text) - if change: - # in descriptor.py we always append external descriptor first - desc_export = core_desc_object[1]["desc"] - else: - desc_export = core_desc_object[0]["desc"] + desc_core = core_desc_object[0]["desc"] - if descriptor: - assert f"({desc}(" in desc_export + assert f"({desc}(" in desc_core if way == "nfc": end_idx = start_idx + 9 @@ -2413,7 +1834,8 @@ def test_bitcoind_ms_address(change, M_N, addr_fmt, clear_ms, goto_home, need_ke cc_addrs = addr_cont.split("\n")[1:] part_addr_index = 1 - bitcoind_addrs = bitcoind.deriveaddresses(desc_export, addr_range) + ea, ia = bitcoind.deriveaddresses(desc_core, addr_range) + bitcoind_addrs = ia if change else ea for idx, cc_item in enumerate(cc_addrs): cc_item = cc_item.split(",") address = cc_item[part_addr_index] @@ -2422,136 +1844,12 @@ def test_bitcoind_ms_address(change, M_N, addr_fmt, clear_ms, goto_home, need_ke assert bitcoind_addrs[idx] == address -@pytest.fixture -def bitcoind_multisig(bitcoind, bitcoind_d_sim_watch, need_keypress, cap_story, load_export, pick_menu_item, goto_home, - cap_menu, microsd_path, use_regtest, press_select): - def doit(M, N, script_type, cc_account=0, funded=True): - use_regtest() - bitcoind_signers = [ - bitcoind.create_wallet(wallet_name=f"bitcoind--signer{i}", disable_private_keys=False, blank=False, - passphrase=None, avoid_reuse=False, descriptors=True) - for i in range(N - 1) - ] - for signer in bitcoind_signers: - signer.keypoolrefill(10) - # watch only wallet where multisig descriptor will be imported - ms = bitcoind.create_wallet( - wallet_name=f"watch_only_{script_type}_{M}of{N}", disable_private_keys=True, - blank=True, passphrase=None, avoid_reuse=False, descriptors=True - ) - goto_home() - pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') - pick_menu_item('Export XPUB') - time.sleep(0.5) - title, story = cap_story() - assert "extended public keys (XPUB) you would need to join a multisig wallet" in story - press_select() - need_keypress(str(cc_account)) # account - press_select() - xpub_obj = load_export("sd", label="Multisig XPUB", is_json=True, sig_check=False) - template = xpub_obj[script_type +"_desc"] - # get keys from bitcoind signers - bitcoind_signers_xpubs = [] - for signer in bitcoind_signers: - target_desc = "" - bitcoind_descriptors = signer.listdescriptors()["descriptors"] - for desc in bitcoind_descriptors: - if desc["desc"].startswith("pkh(") and desc["internal"] is False: - target_desc = desc["desc"] - core_desc, checksum = target_desc.split("#") - # remove pkh(....) - core_key = core_desc[4:-1] - bitcoind_signers_xpubs.append(core_key) - desc = template.replace("M", str(M), 1).replace("...", ",".join(bitcoind_signers_xpubs)) - - if script_type == 'p2wsh': - name = f"core{M}of{N}_native.txt" - elif script_type == "p2sh_p2wsh": - name = f"core{M}of{N}_wrapped.txt" - else: - name = f"core{M}of{N}_legacy.txt" - with open(microsd_path(name), "w") as f: - f.write(desc + "\n") - goto_home() - pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') - pick_menu_item('Import from File') - time.sleep(0.3) - _, story = cap_story() - if "Press (1) to import multisig wallet file from SD Card" in story: - # in case Vdisk is enabled - need_keypress("1") - time.sleep(0.5) - pick_menu_item(name) - _, story = cap_story() - assert "Create new multisig wallet?" in story - assert name.split(".")[0] in story - assert f"{M} of {N}" in story - if M == N: - assert f"All {N} co-signers must approve spends" in story - else: - assert f"{M} signatures, from {N} possible" in story - if script_type == "p2wsh": - assert "P2WSH" in story - elif script_type == "p2sh": - assert "P2SH" in story - else: - assert "P2SH-P2WSH" in story - assert "Derivation:\n Varies (2)" in story - press_select() # approve multisig import - goto_home() - pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') - menu = cap_menu() - pick_menu_item(menu[0]) # pick imported descriptor multisig wallet - pick_menu_item("Descriptors") - pick_menu_item("Bitcoin Core") - text = load_export("sd", label="Bitcoin Core multisig setup", is_json=False, sig_check=False) - text = text.replace("importdescriptors ", "").strip() - # remove junk - r1 = text.find("[") - r2 = text.find("]", -1, 0) - text = text[r1: r2] - core_desc_object = json.loads(text) - # import descriptors to watch only wallet - res = ms.importdescriptors(core_desc_object) - assert res[0]["success"] - assert res[1]["success"] - - if funded: - if script_type == "p2wsh": - addr_type = "bech32" - elif script_type == "p2tr": - addr_type = "bech32m" - elif script_type == "p2sh": - addr_type = "legacy" - else: - addr_type = "p2sh-segwit" - - addr = ms.getnewaddress("", addr_type) - if script_type == "p2wsh": - sw = "bcrt1q" - elif script_type == "p2tr": - sw = "bcrt1p" - else: - sw = "2" - assert addr.startswith(sw) - # get some coins and fund above multisig address - bitcoind.supply_wallet.sendtoaddress(addr, 49) - bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) # mine above - - return ms, bitcoind_signers - - return doit - - @pytest.mark.bitcoind -def test_legacy_multisig_witness_utxo_in_psbt(bitcoind, use_regtest, clear_ms, microsd_wipe, goto_home, need_keypress, +def test_legacy_multisig_witness_utxo_in_psbt(bitcoind, use_regtest, clear_miniscript, microsd_wipe, goto_home, need_keypress, pick_menu_item, cap_story, load_export, microsd_path, cap_menu, try_sign, is_q1, press_select): use_regtest() - clear_ms() + clear_miniscript() microsd_wipe() M,N = 2,2 cosigner = bitcoind.create_wallet(wallet_name=f"bitcoind--signer-wit-utxo", disable_private_keys=False, blank=False, @@ -2562,7 +1860,7 @@ def test_legacy_multisig_witness_utxo_in_psbt(bitcoind, use_regtest, clear_ms, m ) goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') pick_menu_item('Export XPUB') time.sleep(0.5) title, story = cap_story() @@ -2570,8 +1868,8 @@ def test_legacy_multisig_witness_utxo_in_psbt(bitcoind, use_regtest, clear_ms, m press_select() need_keypress("0") # account press_select() - xpub_obj = load_export("sd", label="Multisig XPUB", is_json=True, sig_check=False) - template = xpub_obj["p2sh_desc"] + xpub_obj = load_export("sd", label="Multisig XPUB", is_json=True) + cc_key = xpub_obj["p2sh_key_exp"] # get key from bitcoind cosigner target_desc = "" bitcoind_descriptors = cosigner.listdescriptors()["descriptors"] @@ -2581,7 +1879,7 @@ def test_legacy_multisig_witness_utxo_in_psbt(bitcoind, use_regtest, clear_ms, m core_desc, checksum = target_desc.split("#") # remove pkh(....) core_key = core_desc[4:-1] - desc = template.replace("M", str(M), 1).replace("...", core_key) + desc = f"sh(sortedmulti({M},{core_key},{cc_key}))" desc_info = ms.getdescriptorinfo(desc) desc_w_checksum = desc_info["descriptor"] # with checksum name = f"core{M}of{N}_legacy.txt" @@ -2589,32 +1887,30 @@ def test_legacy_multisig_witness_utxo_in_psbt(bitcoind, use_regtest, clear_ms, m f.write(desc_w_checksum + "\n") goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') - pick_menu_item('Import from File') + pick_menu_item('Miniscript') + pick_menu_item('Import') time.sleep(0.3) _, story = cap_story() - if "Press (1) to import multisig wallet file from SD Card" in story: + if "Press (1) to import miniscript" in story: # in case Vdisk is enabled need_keypress("1") time.sleep(0.5) pick_menu_item(name) _, story = cap_story() - assert "Create new multisig wallet?" in story + assert "Create new miniscript wallet?" in story assert name.split(".")[0] in story assert f"{M} of {N}" in story - assert f"All {N} co-signers must approve spends" in story assert "P2SH" in story - assert "Derivation:\n Varies (2)" in story press_select() # approve multisig import goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') menu = cap_menu() pick_menu_item(menu[0]) # pick imported descriptor multisig wallet pick_menu_item("Descriptors") pick_menu_item("Bitcoin Core") - text = load_export("sd", label="Bitcoin Core multisig setup", is_json=False, sig_check=False) + text = load_export("sd", label="Bitcoin Core miniscript", is_json=False) text = text.replace("importdescriptors ", "").strip() # remove junk r1 = text.find("[") @@ -2655,165 +1951,260 @@ def test_legacy_multisig_witness_utxo_in_psbt(bitcoind, use_regtest, clear_ms, m try_sign(updated) +@pytest.fixture +def get_cc_key(dev): + def doit(path, subderiv=None): + # cc device key + cc_key = dev.send_recv(CCProtocolPacker.get_xpub(path), timeout=None) + if subderiv is None: + cc_key = cc_key + "/<0;1>/*" + + if not path: + return cc_key + + master_xfp_str = struct.pack('/* allowed", "wsh(sortedmulti(2,[0f056943/48'/1'/0'/2']tpubDF2rnouQaaYrXF4noGTv6rQYmx87cQ4GrUdhpvXkhtChwQPbdGTi8GA88NUaSrwZBwNsTkC9bFkkC8vDyGBVVAQTZ2AS6gs68RQXtXcCvkP/1/*,[c463f778/44'/0'/0']tpubDD8pw7eZ9bUzYUR1LK5wpkA69iy3BpuLxPzsE6FFNdtTnJDySduc1VJdFEhEJQDKjYktznKdJgHwaQDRfQDQJpceDxH22c1ZKUMjrarVs7M/0/*))#sj7lxn0l"), + ("need multipath", "wsh(sortedmulti(2,[0f056943/48'/1'/0'/2']tpubDF2rnouQaaYrXF4noGTv6rQYmx87cQ4GrUdhpvXkhtChwQPbdGTi8GA88NUaSrwZBwNsTkC9bFkkC8vDyGBVVAQTZ2AS6gs68RQXtXcCvkP/1/*,[c463f778/44'/0'/0']tpubDD8pw7eZ9bUzYUR1LK5wpkA69iy3BpuLxPzsE6FFNdtTnJDySduc1VJdFEhEJQDKjYktznKdJgHwaQDRfQDQJpceDxH22c1ZKUMjrarVs7M/0/*))#sj7lxn0l"), ("All keys must be ranged", "wsh(sortedmulti(2,[0f056943/48'/1'/0'/2']tpubDF2rnouQaaYrXF4noGTv6rQYmx87cQ4GrUdhpvXkhtChwQPbdGTi8GA88NUaSrwZBwNsTkC9bFkkC8vDyGBVVAQTZ2AS6gs68RQXtXcCvkP/0/0,[c463f778/44'/0'/0']tpubDD8pw7eZ9bUzYUR1LK5wpkA69iy3BpuLxPzsE6FFNdtTnJDySduc1VJdFEhEJQDKjYktznKdJgHwaQDRfQDQJpceDxH22c1ZKUMjrarVs7M/0/*))#9h02aqg5"), - ("Key derivation too long", "wsh(sortedmulti(2,[0f056943/48'/1'/0'/2']tpubDF2rnouQaaYrXF4noGTv6rQYmx87cQ4GrUdhpvXkhtChwQPbdGTi8GA88NUaSrwZBwNsTkC9bFkkC8vDyGBVVAQTZ2AS6gs68RQXtXcCvkP/0/0/*,[c463f778/44'/0'/0']tpubDD8pw7eZ9bUzYUR1LK5wpkA69iy3BpuLxPzsE6FFNdtTnJDySduc1VJdFEhEJQDKjYktznKdJgHwaQDRfQDQJpceDxH22c1ZKUMjrarVs7M/0/*))#fy9mm8dt"), + ("need multipath", "wsh(sortedmulti(2,[0f056943/48'/1'/0'/2']tpubDF2rnouQaaYrXF4noGTv6rQYmx87cQ4GrUdhpvXkhtChwQPbdGTi8GA88NUaSrwZBwNsTkC9bFkkC8vDyGBVVAQTZ2AS6gs68RQXtXcCvkP/0/0/*,[c463f778/44'/0'/0']tpubDD8pw7eZ9bUzYUR1LK5wpkA69iy3BpuLxPzsE6FFNdtTnJDySduc1VJdFEhEJQDKjYktznKdJgHwaQDRfQDQJpceDxH22c1ZKUMjrarVs7M/0/*))#fy9mm8dt"), # ("Key origin info is required", "wsh(sortedmulti(2,tpubDF2rnouQaaYrXF4noGTv6rQYmx87cQ4GrUdhpvXkhtChwQPbdGTi8GA88NUaSrwZBwNsTkC9bFkkC8vDyGBVVAQTZ2AS6gs68RQXtXcCvkP/0/*,[c463f778/44'/0'/0']tpubDD8pw7eZ9bUzYUR1LK5wpkA69iy3BpuLxPzsE6FFNdtTnJDySduc1VJdFEhEJQDKjYktznKdJgHwaQDRfQDQJpceDxH22c1ZKUMjrarVs7M))#ypuy22nw"), - ("xpub xfp wrong 0F056943", "wsh(sortedmulti(2,[0f056943]tpubDF2rnouQaaYrXF4noGTv6rQYmx87cQ4GrUdhpvXkhtChwQPbdGTi8GA88NUaSrwZBwNsTkC9bFkkC8vDyGBVVAQTZ2AS6gs68RQXtXcCvkP/0/*,[c463f778/44'/0'/0']tpubDD8pw7eZ9bUzYUR1LK5wpkA69iy3BpuLxPzsE6FFNdtTnJDySduc1VJdFEhEJQDKjYktznKdJgHwaQDRfQDQJpceDxH22c1ZKUMjrarVs7M))#nhjvt4wd"), - ("xpub depth", "wsh(sortedmulti(2,[0f056943/0h]tpubDF2rnouQaaYrXF4noGTv6rQYmx87cQ4GrUdhpvXkhtChwQPbdGTi8GA88NUaSrwZBwNsTkC9bFkkC8vDyGBVVAQTZ2AS6gs68RQXtXcCvkP/0/*,[c463f778/44'/0'/0']tpubDD8pw7eZ9bUzYUR1LK5wpkA69iy3BpuLxPzsE6FFNdtTnJDySduc1VJdFEhEJQDKjYktznKdJgHwaQDRfQDQJpceDxH22c1ZKUMjrarVs7M))"), - ("Key derivation too long", "wsh(sortedmulti(2,[0f056943/48'/1'/0'/2']tpubDF2rnouQaaYrXF4noGTv6rQYmx87cQ4GrUdhpvXkhtChwQPbdGTi8GA88NUaSrwZBwNsTkC9bFkkC8vDyGBVVAQTZ2AS6gs68RQXtXcCvkP/0/*,[c463f778/44'/0'/0']tpubDD8pw7eZ9bUzYUR1LK5wpkA69iy3BpuLxPzsE6FFNdtTnJDySduc1VJdFEhEJQDKjYktznKdJgHwaQDRfQDQJpceDxH22c1ZKUMjrarVs7M/0))#s487stua"), + ("wrong pubkey", "wsh(sortedmulti(2,[0f056943]tpubDF2rnouQaaYrXF4noGTv6rQYmx87cQ4GrUdhpvXkhtChwQPbdGTi8GA88NUaSrwZBwNsTkC9bFkkC8vDyGBVVAQTZ2AS6gs68RQXtXcCvkP/0/*,[c463f778/44'/0'/0']tpubDD8pw7eZ9bUzYUR1LK5wpkA69iy3BpuLxPzsE6FFNdtTnJDySduc1VJdFEhEJQDKjYktznKdJgHwaQDRfQDQJpceDxH22c1ZKUMjrarVs7M))#nhjvt4wd"), + ("deriv len != xpub depth", "wsh(sortedmulti(2,[0f056943/0h]tpubDF2rnouQaaYrXF4noGTv6rQYmx87cQ4GrUdhpvXkhtChwQPbdGTi8GA88NUaSrwZBwNsTkC9bFkkC8vDyGBVVAQTZ2AS6gs68RQXtXcCvkP/0/*,[c463f778/44'/0'/0']tpubDD8pw7eZ9bUzYUR1LK5wpkA69iy3BpuLxPzsE6FFNdtTnJDySduc1VJdFEhEJQDKjYktznKdJgHwaQDRfQDQJpceDxH22c1ZKUMjrarVs7M))"), + ("All keys must be ranged", "wsh(sortedmulti(2,[0f056943/48'/1'/0'/2']tpubDF2rnouQaaYrXF4noGTv6rQYmx87cQ4GrUdhpvXkhtChwQPbdGTi8GA88NUaSrwZBwNsTkC9bFkkC8vDyGBVVAQTZ2AS6gs68RQXtXcCvkP/0/*,[c463f778/44'/0'/0']tpubDD8pw7eZ9bUzYUR1LK5wpkA69iy3BpuLxPzsE6FFNdtTnJDySduc1VJdFEhEJQDKjYktznKdJgHwaQDRfQDQJpceDxH22c1ZKUMjrarVs7M/0))#s487stua"), ("Cannot use hardened sub derivation path", "wsh(sortedmulti(2,[0f056943/48'/1'/0'/2']tpubDF2rnouQaaYrXF4noGTv6rQYmx87cQ4GrUdhpvXkhtChwQPbdGTi8GA88NUaSrwZBwNsTkC9bFkkC8vDyGBVVAQTZ2AS6gs68RQXtXcCvkP/0/*,[c463f778/44'/0'/0']tpubDD8pw7eZ9bUzYUR1LK5wpkA69iy3BpuLxPzsE6FFNdtTnJDySduc1VJdFEhEJQDKjYktznKdJgHwaQDRfQDQJpceDxH22c1ZKUMjrarVs7M/0'/*))#3w6hpha3"), ("M must be <= N", "wsh(sortedmulti(3,[0f056943/48'/1'/0'/2']tpubDF2rnouQaaYrXF4noGTv6rQYmx87cQ4GrUdhpvXkhtChwQPbdGTi8GA88NUaSrwZBwNsTkC9bFkkC8vDyGBVVAQTZ2AS6gs68RQXtXcCvkP/0/*,[c463f778/44'/0'/0']tpubDD8pw7eZ9bUzYUR1LK5wpkA69iy3BpuLxPzsE6FFNdtTnJDySduc1VJdFEhEJQDKjYktznKdJgHwaQDRfQDQJpceDxH22c1ZKUMjrarVs7M/0/*))#uueddtsy"), ]) -def test_exotic_descriptors(desc, clear_ms, goto_home, need_keypress, pick_menu_item, cap_menu, +def test_exotic_descriptors(desc, clear_miniscript, goto_home, need_keypress, pick_menu_item, cap_menu, cap_story, make_multisig, microsd_path, use_regtest, is_q1, press_select): use_regtest() - clear_ms() + clear_miniscript() msg, desc = desc name = "exotic.txt" if os.path.exists(microsd_path(name)): @@ -2944,22 +2377,22 @@ def test_exotic_descriptors(desc, clear_ms, goto_home, need_keypress, pick_menu_ f.write(desc + "\n") goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') - pick_menu_item('Import from File') + pick_menu_item('Miniscript') + pick_menu_item('Import') time.sleep(0.1) _, story = cap_story() - if "Press (1) to import multisig wallet file from SD Card" in story: + if "Press (1) to import miniscript wallet file from SD Card" in story: need_keypress("1") time.sleep(0.1) pick_menu_item(name) _, story = cap_story() - assert "Failed to import" in story + assert "Failed to import miniscript" in story assert msg in story press_select() -def test_ms_wallet_ordering(clear_ms, import_ms_wallet, try_sign_microsd, fake_ms_txn): - clear_ms() +def test_ms_wallet_ordering(clear_miniscript, import_ms_wallet, try_sign_microsd, fake_ms_txn): + clear_miniscript() all_out_styles = list(unmap_addr_fmt.keys()) index = all_out_styles.index("p2sh-p2wsh") all_out_styles[index] = "p2wsh-p2sh" @@ -2971,21 +2404,20 @@ def test_ms_wallet_ordering(clear_ms, import_ms_wallet, try_sign_microsd, fake_m # WHY: as we store wallets in list, they are ordered by their addition/import. Iterating over # wallet candindates in psbt.py M are equal N differs --> assertion error name = f'ms1' - import_ms_wallet(3, 6, name=name, accept=1, do_import=True, addr_fmt="p2wsh") + import_ms_wallet(3, 6, name=name, accept=True, do_import=True, addr_fmt="p2wsh") name = f'ms2' - keys3 = import_ms_wallet(3, 5, name=name, accept=1, do_import=True, addr_fmt="p2wsh") + keys3 = import_ms_wallet(3, 5, name=name, accept=True, do_import=True, addr_fmt="p2wsh") - psbt = fake_ms_txn(5, 5, 3, keys3, outstyles=all_out_styles, segwit_in=True, incl_xpubs=True) - - open('debug/last.psbt', 'wb').write(psbt) + psbt = fake_ms_txn(5, 5, 3, keys3, outstyles=all_out_styles, inp_addr_fmt="p2wsh", incl_xpubs=True) try_sign_microsd(psbt, encoding='base64') @pytest.mark.parametrize("descriptor", [True, False]) @pytest.mark.parametrize("m_n", [(2, 3), (3, 5), (5, 10)]) -def test_ms_xpub_ordering(descriptor, m_n, clear_ms, make_multisig, import_ms_wallet, try_sign_microsd, fake_ms_txn): - clear_ms() +def test_ms_xpub_ordering(descriptor, m_n, clear_miniscript, make_multisig, import_ms_wallet, + try_sign_microsd, fake_ms_txn): + clear_miniscript() M, N = m_n all_out_styles = list(unmap_addr_fmt.keys()) index = all_out_styles.index("p2sh-p2wsh") @@ -2994,17 +2426,14 @@ def test_ms_xpub_ordering(descriptor, m_n, clear_ms, make_multisig, import_ms_wa keys = make_multisig(M, N) all_options = list(itertools.combinations(keys, len(keys))) for opt in all_options: - import_ms_wallet(M, N, keys=opt, name=name, accept=1, do_import=True, - addr_fmt="p2wsh", descriptor=descriptor) + import_ms_wallet(M, N, keys=opt, name=name, accept=True, do_import=True, addr_fmt="p2wsh") psbt = fake_ms_txn(5, 5, M, opt, outstyles=all_out_styles, - segwit_in=True, incl_xpubs=True) - open('debug/last.psbt', 'wb').write(psbt) + inp_addr_fmt="p2wsh", incl_xpubs=True) try_sign_microsd(psbt, encoding='base64') for opt_1 in all_options: # create PSBT with original keys order psbt = fake_ms_txn(5, 5, M, opt_1, outstyles=all_out_styles, - segwit_in=True, incl_xpubs=True) - open('debug/last.psbt', 'wb').write(psbt) + inp_addr_fmt="p2wsh", incl_xpubs=True) try_sign_microsd(psbt, encoding='base64') @@ -3013,7 +2442,7 @@ def test_ms_xpub_ordering(descriptor, m_n, clear_ms, make_multisig, import_ms_wa @pytest.mark.parametrize('M_N', [(2, 3), (3, 5), (15, 15)]) @pytest.mark.parametrize('desc', ["multi", "sortedmulti"]) @pytest.mark.parametrize('addr_fmt', [AF_P2WSH, AF_P2SH, AF_P2WSH_P2SH]) -def test_multisig_descriptor_export(M_N, way, addr_fmt, cmn_pth_from_root, clear_ms, make_multisig, +def test_multisig_descriptor_export(M_N, way, addr_fmt, cmn_pth_from_root, clear_miniscript, make_multisig, import_ms_wallet, goto_home, pick_menu_item, cap_menu, nfc_read_text, microsd_path, cap_story, need_keypress, load_export, desc): @@ -3021,12 +2450,12 @@ def test_multisig_descriptor_export(M_N, way, addr_fmt, cmn_pth_from_root, clear def choose_multisig_wallet(): goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') menu = cap_menu() pick_menu_item(menu[0]) M, N = M_N - wal_name = f"reexport_{M}-{N}-{addr_fmt}" + wal_name = f"reexport" dd = { AF_P2WSH: ("m/48h/1h/0h/2h/{idx}", 'p2wsh'), @@ -3036,37 +2465,23 @@ def test_multisig_descriptor_export(M_N, way, addr_fmt, cmn_pth_from_root, clear deriv, text_a_fmt = dd[addr_fmt] keys = make_multisig(M, N, unique=1, deriv=None if cmn_pth_from_root else deriv) derivs = [deriv.format(idx=i) for i in range(N)] - clear_ms() - import_ms_wallet(M, N, accept=1, keys=keys, name=wal_name, derivs=None if cmn_pth_from_root else derivs, - addr_fmt=text_a_fmt, descriptor=True, common="m/45h" if cmn_pth_from_root else None, + clear_miniscript() + import_ms_wallet(M, N, accept=True, keys=keys, name=wal_name, + derivs=None if cmn_pth_from_root else derivs, + addr_fmt=text_a_fmt, common="m/45h" if cmn_pth_from_root else None, bip67=False if desc == "multi" else True) # get bare descriptor choose_multisig_wallet() pick_menu_item("Descriptors") pick_menu_item("Export") - contents = load_export(way, label="Descriptor multisig setup", is_json=False, sig_check=False) + contents = load_export(way, label="Miniscript", is_json=False) bare_desc = contents.strip() - # get pretty descriptor - choose_multisig_wallet() - pick_menu_item("Descriptors") - pick_menu_item("View Descriptor") - for _ in range(5): - _, story = cap_story() - if "Press (1) to export" in story: - need_keypress("1") - break - else: - time.sleep(1) - - contents = load_export(way, label="Descriptor multisig setup", is_json=False, sig_check=False) - pretty_desc = contents.strip() - # get core descriptor json choose_multisig_wallet() pick_menu_item("Descriptors") pick_menu_item("Bitcoin Core") - core_desc_text = load_export(way, label="Bitcoin Core multisig setup", is_json=False, sig_check=False) + core_desc_text = load_export(way, label="Bitcoin Core miniscript", is_json=False) # remove junk text = core_desc_text.replace("importdescriptors ", "").strip() @@ -3075,87 +2490,64 @@ def test_multisig_descriptor_export(M_N, way, addr_fmt, cmn_pth_from_root, clear text = text[r1: r2] core_desc_object = json.loads(text) - # get descriptor from view descriptor - choose_multisig_wallet() - pick_menu_item("Descriptors") - pick_menu_item("View Descriptor") - for _ in range(5): - try: - _, story = cap_story() - if "Press (1)" in story: - break - except: - time.sleep(1) - - view_desc = story.strip().split("\n\n")[1] - # assert that bare and pretty are the same after parse assert f"({desc}(" in bare_desc - assert bare_desc == view_desc - assert parse_desc_str(pretty_desc) == bare_desc - for obj in core_desc_object: - if obj["internal"]: - pass - else: - assert obj["desc"] == bare_desc - clear_ms() + assert core_desc_object[0]["desc"] == bare_desc + clear_miniscript() def test_chain_switching(use_mainnet, use_regtest, settings_get, settings_set, - clear_ms, goto_home, cap_menu, pick_menu_item, + clear_miniscript, goto_home, cap_menu, pick_menu_item, need_keypress, import_ms_wallet): - clear_ms() + clear_miniscript() use_regtest() # cannot import XPUBS when testnet/regtest enabled with pytest.raises(Exception): - import_ms_wallet(3, 3, addr_fmt="p2wsh", accept=1, descriptor=True, chain="BTC") + import_ms_wallet(3, 3, addr_fmt="p2wsh", accept=True, chain="BTC") - import_ms_wallet(2, 2, addr_fmt="p2wsh", accept=1, descriptor=True, chain="XTN") - # assert that wallets created at XRT always store XTN anywas (key_chain) - res = settings_get("multisig") + on_regtest = "xtn0" + import_ms_wallet(2, 2, name=on_regtest, addr_fmt="p2wsh", accept=True, chain="XRT") + res = settings_get("miniscript") assert len(res) == 1 - assert res[0][-1]["ch"] == "XTN" + assert res[0][-1]["ct"] == "XRT" goto_home() pick_menu_item("Settings") - pick_menu_item("Multisig Wallets") + pick_menu_item("Miniscript") time.sleep(0.1) m = cap_menu() assert "(none setup yet)" not in m - assert "2/2:" in m[0] + assert on_regtest == m[0] goto_home() settings_set("chain", "BTC") pick_menu_item("Settings") - pick_menu_item("Multisig Wallets") + pick_menu_item("Miniscript") time.sleep(0.1) m = cap_menu() - # asterisk hints that some wallets are already stored - # but not on current active chain - assert "(none setup yet)*" in m - import_ms_wallet(3, 3, addr_fmt="p2wsh", accept=1, descriptor=True, chain="BTC") + assert "(none setup yet)" in m + on_mainnet = "btc0" + import_ms_wallet(3, 3, addr_fmt="p2wsh", accept=True, chain="BTC", name=on_mainnet) goto_home() pick_menu_item("Settings") - pick_menu_item("Multisig Wallets") + pick_menu_item("Miniscript") time.sleep(0.1) m = cap_menu() - assert "3/3:" in m[0] - for mi in m: - assert not mi.startswith("2/2:") + assert on_mainnet == m[0] + assert on_regtest not in m goto_home() settings_set("chain", "XTN") - import_ms_wallet(4, 4, addr_fmt="p2wsh", accept=1, descriptor=True, chain="XTN") + import_ms_wallet(4, 4, addr_fmt="p2wsh", accept=True, chain="XTN", name="xtn1") pick_menu_item("Settings") - pick_menu_item("Multisig Wallets") + pick_menu_item("Miniscript") time.sleep(0.1) m = cap_menu() assert "(none setup yet)" not in m - assert "2/2:" in m[0] - assert "4/4:" in m[1] - for mi in m: - assert not mi.startswith("3/3:") + assert on_regtest == m[0] + assert "xtn1" == m[1] + assert on_mainnet not in m @pytest.mark.parametrize("desc", [ @@ -3169,111 +2561,102 @@ def test_chain_switching(use_mainnet, use_regtest, settings_get, settings_set, "))"), ]) def test_same_key_account_based_multisig(goto_home, need_keypress, pick_menu_item, cap_story, - clear_ms, microsd_path, load_export, desc, - offer_ms_import): - clear_ms() - try: - _, story = offer_ms_import(desc) - except Exception as e: - assert "my key included more than once" in str(e) + clear_miniscript, microsd_path, load_export, desc, + offer_minsc_import): + clear_miniscript() + _, story = offer_minsc_import(desc) + # this is allowed now + assert "Create new miniscript wallet" in story -def test_multisig_name_validation(microsd_path, offer_ms_import): - with open("data/multisig/export-p2wsh-myself.txt", "r") as f: +def test_multisig_name_validation(microsd_path, offer_minsc_import): + with open("data/multisig/desc-p2wsh-myself.txt", "r") as f: config = f.read() - c0 = config.replace("Name: CC-2-of-4", "Name: eê") - with pytest.raises(Exception) as e: - offer_ms_import(c0, allow_non_ascii=True) + offer_minsc_import(json.dumps({"name": "eê", "desc": config}), allow_non_ascii=True) assert "must be ascii" in e.value.args[0] - c0 = config.replace("Name: CC-2-of-4", "Name: eee\teee") - with pytest.raises(Exception) as e: - offer_ms_import(c0, allow_non_ascii=True) + offer_minsc_import(json.dumps({"name": "eee\teee", "desc": config}), allow_non_ascii=True) assert "must be ascii" in e.value.args[0] -def test_multisig_deriv_path_migration(settings_set, clear_ms, import_ms_wallet, - press_cancel, settings_get, make_multisig, - goto_home, start_sign, cap_story, end_sign, - pick_menu_item, cap_menu): - # this test case simulates multisig wallets imported to CC before 5.3.0 - # release; these wallets, saved in user settings, still have "'" in derivation - # paths; 5.3.1 firmware implements migration to "h" in MultisigWallet.deserialize - - clear_ms() - - deriv, text_a_fmt = ("m/48h/1h/0h/2h/{idx}", 'p2wsh') - keys = make_multisig(2, 3, unique=1, deriv=deriv) - derivs = [deriv.format(idx=i) for i in range(3)] - import_ms_wallet(2, 3, accept=True, keys=keys, name="ms1", - derivs=derivs, addr_fmt=text_a_fmt) - time.sleep(.1) - - import_ms_wallet(3, 5, name="ms2", addr_fmt='p2wsh-p2sh', accept=True) - time.sleep(.1) - - ms = settings_get("multisig") - pths0 = ms[0][3]["d"] - new_pths0 = [p.replace("h", "'") for p in pths0] - ms[0][3]["d"] = new_pths0 - - ms[1][3]["pp"] = ms[1][3]["pp"].replace("h", "'") - - # this matches data/PSBT - ms.append( - ( - 'ms', - (2, 2), - [(2285969762, 0, 'tpubDEy2hd2VTrqbBS8cS2svq12UmjGM2j7FHmocjHzAXfVhmJdhBFVVbmAi13humi49esaAuSmz36NEJ6GL3u58RzNuUkExP9vL4d81PM3s8u6'), - (1130956047, 1, 'tpubDEFX3QojMWh7x4vSAHN17wpsywpP78aSs2t6nyELHuq1k34gub9mQ7QiaHNCBAYjSQ4UCMMpfBkf5np1cTQaStrvvRCxwxZ7kZaGHqYxUv3')], - {'ch': 'XTN', 'ft': 14, 'd': ["m/48'/0'/99'/2'", "m/48'/0'/33'/2'"]} - ) - ) - settings_set("multisig", ms) - - # psbt from nunchuk, with global xpubs belonging to above ms wallet - b64_psbt = "cHNidP8BAF4CAAAAAfkDjXlS32gzOjVhSRArKxvkAecMTnp1g8wwMJTtq74/AAAAAAD9////AekaAAAAAAAAIgAgzs2e4h4vctbFvvauK+QVFAPzCFnMi1H9hTacH7498P8AAAAATwEENYfPBC7g3O2AAAACLvzTgnL7V0DNOnISJdvOgq/6Pw6DAtkPflmZ+Hc04qwC5CShG0rDIlh8gu7gH2NMBLfrIzYSzoSomnVHeMxtxVQUDwVpQzAAAIAAAACAIQAAgAIAAIBPAQQ1h88EkEB8moAAAALv/1L+Cfeg2EPc01pS00f18DIdU5BOeExlGsXyEFOKGwL71tcAiRuL4Bs+uT1JJjU6AbR3j3X60/rI+rTMJmnOgRRiIUGIMAAAgAAAAIBjAACAAgAAgAABAIkCAAAAAZ5Im3CxbYDyByyrr4luss5vr+s0r7Vt8pK+OvicPLO7AAAAAAD9////AnM2AAAAAAAAIgAgvZi0zfKCeBasTet1hNKm73GA4MEkwiSVwCB9cN0/EnTmvqUXAAAAACJRIJF/VcIeZ3E4f+ZEjwiUl5AUUxBJgoaEaPaHHJecq18lq+4qAAEBK3M2AAAAAAAAIgAgvZi0zfKCeBasTet1hNKm73GA4MEkwiSVwCB9cN0/EnQiAgNRdmGxEwsP88xu9rl/tGAXq7kPm/730yTyQ6XHQL/D3kcwRAIgHNmbk4J9wu4ljq6UouY132eX1i/2jWvJjuuWWyLRFScCIBPyPCuZ/Hmd06h9KtVkSropBonIuqIc/BK8JZ50YKp/AQEDBAEAAAABBUdSIQMBr34TVHrqSk8K6505//5YTOkHmHqF83J8iUURtL/ptCEDUXZhsRMLD/PMbva5f7RgF6u5D5v+99Mk8kOlx0C/w95SriIGAwGvfhNUeupKTwrrnTn//lhM6QeYeoXzcnyJRRG0v+m0HA8FaUMwAACAAAAAgCEAAIACAACAAAAAAAAAAAAiBgNRdmGxEwsP88xu9rl/tGAXq7kPm/730yTyQ6XHQL/D3hxiIUGIMAAAgAAAAIBjAACAAgAAgAAAAAAAAAAAAAEBR1IhAscIZVvBcy3Q0GKO4UqR3gDB3pm/tWas8siH3Ej8MmuCIQN8lTj0MMTpT+Dlk2MbMdAaL93hezzNP3WDsRn/gwlVQlKuIgICxwhlW8FzLdDQYo7hSpHeAMHemb+1ZqzyyIfcSPwya4IcYiFBiDAAAIAAAACAYwAAgAIAAIAAAAAAAQAAACICA3yVOPQwxOlP4OWTYxsx0Bov3eF7PM0/dYOxGf+DCVVCHA8FaUMwAACAAAAAgCEAAIACAACAAAAAAAEAAAAA" - - goto_home() - # in time of creatin of PSBT, lopp was making testnet3 unusable... - settings_set("fee_limit", -1) - start_sign(base64.b64decode(b64_psbt)) - title, story = cap_story() - assert title == "OK TO SEND?" - end_sign() - settings_set("fee_limit", 10) # rollback - pick_menu_item("Settings") - pick_menu_item("Multisig Wallets") - m = cap_menu() - for msi in m[:3]: # three wallets imported - pick_menu_item(msi) - pick_menu_item("View Details") - time.sleep(.1) - _, story = cap_story() - assert "'" not in story - press_cancel() - press_cancel() +# def test_multisig_deriv_path_migration(settings_set, clear_miniscript, import_ms_wallet, +# press_cancel, settings_get, make_multisig, +# goto_home, start_sign, cap_story, end_sign, +# pick_menu_item, cap_menu): +# # this test case simulates multisig wallets imported to CC before 5.3.0 +# # release; these wallets, saved in user settings, still have "'" in derivation +# # paths; 5.3.1 firmware implements migration to "h" in MultisigWallet.deserialize +# +# clear_miniscript() +# +# deriv, text_a_fmt = ("m/48h/1h/0h/2h/{idx}", 'p2wsh') +# keys = make_multisig(2, 3, unique=1, deriv=deriv) +# derivs = [deriv.format(idx=i) for i in range(3)] +# import_ms_wallet(2, 3, accept=True, keys=keys, name="ms1", +# derivs=derivs, addr_fmt=text_a_fmt) +# time.sleep(.1) +# +# import_ms_wallet(3, 5, name="ms2", addr_fmt='p2wsh-p2sh', accept=True) +# time.sleep(.1) +# +# ms = settings_get("multisig") +# pths0 = ms[0][3]["d"] +# new_pths0 = [p.replace("h", "'") for p in pths0] +# ms[0][3]["d"] = new_pths0 +# +# ms[1][3]["pp"] = ms[1][3]["pp"].replace("h", "'") +# +# # this matches data/PSBT +# ms.append( +# ( +# 'ms', +# (2, 2), +# [(2285969762, 0, 'tpubDEy2hd2VTrqbBS8cS2svq12UmjGM2j7FHmocjHzAXfVhmJdhBFVVbmAi13humi49esaAuSmz36NEJ6GL3u58RzNuUkExP9vL4d81PM3s8u6'), +# (1130956047, 1, 'tpubDEFX3QojMWh7x4vSAHN17wpsywpP78aSs2t6nyELHuq1k34gub9mQ7QiaHNCBAYjSQ4UCMMpfBkf5np1cTQaStrvvRCxwxZ7kZaGHqYxUv3')], +# {'ch': 'XTN', 'ft': 14, 'd': ["m/48'/0'/99'/2'", "m/48'/0'/33'/2'"]} +# ) +# ) +# settings_set("multisig", ms) +# +# # psbt from nunchuk, with global xpubs belonging to above ms wallet +# b64_psbt = "cHNidP8BAF4CAAAAAfkDjXlS32gzOjVhSRArKxvkAecMTnp1g8wwMJTtq74/AAAAAAD9////AekaAAAAAAAAIgAgzs2e4h4vctbFvvauK+QVFAPzCFnMi1H9hTacH7498P8AAAAATwEENYfPBC7g3O2AAAACLvzTgnL7V0DNOnISJdvOgq/6Pw6DAtkPflmZ+Hc04qwC5CShG0rDIlh8gu7gH2NMBLfrIzYSzoSomnVHeMxtxVQUDwVpQzAAAIAAAACAIQAAgAIAAIBPAQQ1h88EkEB8moAAAALv/1L+Cfeg2EPc01pS00f18DIdU5BOeExlGsXyEFOKGwL71tcAiRuL4Bs+uT1JJjU6AbR3j3X60/rI+rTMJmnOgRRiIUGIMAAAgAAAAIBjAACAAgAAgAABAIkCAAAAAZ5Im3CxbYDyByyrr4luss5vr+s0r7Vt8pK+OvicPLO7AAAAAAD9////AnM2AAAAAAAAIgAgvZi0zfKCeBasTet1hNKm73GA4MEkwiSVwCB9cN0/EnTmvqUXAAAAACJRIJF/VcIeZ3E4f+ZEjwiUl5AUUxBJgoaEaPaHHJecq18lq+4qAAEBK3M2AAAAAAAAIgAgvZi0zfKCeBasTet1hNKm73GA4MEkwiSVwCB9cN0/EnQiAgNRdmGxEwsP88xu9rl/tGAXq7kPm/730yTyQ6XHQL/D3kcwRAIgHNmbk4J9wu4ljq6UouY132eX1i/2jWvJjuuWWyLRFScCIBPyPCuZ/Hmd06h9KtVkSropBonIuqIc/BK8JZ50YKp/AQEDBAEAAAABBUdSIQMBr34TVHrqSk8K6505//5YTOkHmHqF83J8iUURtL/ptCEDUXZhsRMLD/PMbva5f7RgF6u5D5v+99Mk8kOlx0C/w95SriIGAwGvfhNUeupKTwrrnTn//lhM6QeYeoXzcnyJRRG0v+m0HA8FaUMwAACAAAAAgCEAAIACAACAAAAAAAAAAAAiBgNRdmGxEwsP88xu9rl/tGAXq7kPm/730yTyQ6XHQL/D3hxiIUGIMAAAgAAAAIBjAACAAgAAgAAAAAAAAAAAAAEBR1IhAscIZVvBcy3Q0GKO4UqR3gDB3pm/tWas8siH3Ej8MmuCIQN8lTj0MMTpT+Dlk2MbMdAaL93hezzNP3WDsRn/gwlVQlKuIgICxwhlW8FzLdDQYo7hSpHeAMHemb+1ZqzyyIfcSPwya4IcYiFBiDAAAIAAAACAYwAAgAIAAIAAAAAAAQAAACICA3yVOPQwxOlP4OWTYxsx0Bov3eF7PM0/dYOxGf+DCVVCHA8FaUMwAACAAAAAgCEAAIACAACAAAAAAAEAAAAA" +# +# goto_home() +# # in time of creatin of PSBT, lopp was making testnet3 unusable... +# settings_set("fee_limit", -1) +# start_sign(base64.b64decode(b64_psbt)) +# title, story = cap_story() +# assert title == "OK TO SEND?" +# end_sign() +# settings_set("fee_limit", 10) # rollback +# pick_menu_item("Settings") +# pick_menu_item("Multisig Wallets") +# m = cap_menu() +# for msi in m[:3]: # three wallets imported +# pick_menu_item(msi) +# pick_menu_item("View Details") +# time.sleep(.1) +# _, story = cap_story() +# assert "'" not in story +# press_cancel() +# press_cancel() @pytest.mark.parametrize("fpath", [ - # CC export format - "data/multisig/export-p2sh-myself.txt", - "data/multisig/export-p2sh-p2wsh-myself.txt", - "data/multisig/export-p2wsh-myself.txt", # descriptors "data/multisig/desc-p2sh-myself.txt", "data/multisig/desc-p2sh-p2wsh-myself.txt", "data/multisig/desc-p2wsh-myself.txt", ]) -def test_scan_any_qr(fpath, is_q1, scan_a_qr, clear_ms, goto_home, +def test_scan_any_qr(fpath, is_q1, scan_a_qr, clear_miniscript, goto_home, pick_menu_item, cap_story, press_cancel): if not is_q1: pytest.skip("No QR support for Mk4") - clear_ms() + clear_miniscript() goto_home() pick_menu_item("Scan Any QR Code") @@ -3289,74 +2672,22 @@ def test_scan_any_qr(fpath, is_q1, scan_a_qr, clear_ms, goto_home, time.sleep(.1) title, story = cap_story() - assert "Create new multisig wallet?" in story + assert "Create new miniscript wallet?" in story press_cancel() -@pytest.mark.parametrize("N", [3, 15]) -def test_bare_cc_ms_qr_import(N, make_multisig, scan_a_qr, clear_ms, goto_home, - pick_menu_item, cap_story, press_cancel, is_q1): - # bare: - # - no fingerprints - # - no xfps - # - no meta data - - if not is_q1: - raise pytest.skip("No QR support for Mk4") - - keys = make_multisig(N, N) - config = '\n'.join(sk.hwif(as_private=False) for xfp,m,sk in keys) - actual_vers, parts = split_qrs(config, 'U', max_version=20) - random.shuffle(parts) - - # will not work in scan any qr in main menu (no xfp) - clear_ms() - goto_home() - pick_menu_item("Scan Any QR Code") - - for p in parts: - scan_a_qr(p) - time.sleep(2.0 / len(parts)) - - title, story = cap_story() - assert title == 'Simple Text' - assert "We can't do any more with it." in story - - press_cancel() - - # if someone uses this bare format with keys of depth 1 - # multisig import path needs to be used - pick_menu_item("Settings") - pick_menu_item("Multisig Wallets") - pick_menu_item("Import from QR") - for p in parts: - scan_a_qr(p) - time.sleep(2.0 / len(parts)) - - title, story = cap_story() - assert "Create new multisig wallet?" in story - assert f"{N}-of-{N}" in story - press_cancel() - - -@pytest.mark.parametrize("psbtv2", [True, False]) @pytest.mark.parametrize("desc", ["multi", "sortedmulti"]) -@pytest.mark.parametrize("data", [ +@pytest.mark.parametrize("data,af", [ # (out_style, amount, is_change) - [("p2wsh", 1000000, 0)] * 99, - [("p2sh", 1000000, 1)] * 33, - [("p2wsh-p2sh", 1000000, 1)] * 18 + [("p2wsh", 50000000, 0)] * 12, - [("p2sh", 1000000, 1), ("p2wsh-p2sh", 50000000, 0), ("p2wsh", 800000, 1)] * 14, + # change can only be of the same address type as imported wallet + ([("p2wsh", 1000000, 0)] * 99, "p2wsh"), + ([("p2sh", 1000000, 1)] * 33, "p2sh"), + ([("p2wsh-p2sh", 1000000, 1)] * 18 + [("p2wsh", 50000000, 0)] * 12, "p2sh-p2wsh"), + ([("p2sh", 1000000, 0), ("p2wsh-p2sh", 50000000, 0), ("p2wsh", 800000, 1)] * 14, "p2wsh"), ]) -def test_txout_explorer(psbtv2, data, clear_ms, import_ms_wallet, fake_ms_txn, - start_sign, txout_explorer, desc): - clear_ms() - M, N = 2, 3 - descriptor, bip67 = False, True - if desc == "multi": - descriptor, bip67 = True, False - keys = import_ms_wallet(2, 3, name='ms-test', accept=True, - descriptor=descriptor, bip67=bip67) +def test_txout_explorer(data, af, desc, clear_miniscript, import_ms_wallet, fake_ms_txn, + start_sign, txout_explorer, pytestconfig): + # TODO This test MUST be run with --psbt2 flag on and off outstyles = [] outvals = [] @@ -3368,54 +2699,38 @@ def test_txout_explorer(psbtv2, data, clear_ms, import_ms_wallet, fake_ms_txn, if is_change: change_outputs.append(i) + clear_miniscript() + M, N = 2, 3 + bip67 = True if desc == "multi" else False + keys = import_ms_wallet(2, 3, name='ms-test', accept=True, bip67=bip67, addr_fmt=af) + inp_amount = sum(outvals) + 100000 # 100k sat fee - psbt = fake_ms_txn(1, len(data), M, keys, outstyles=outstyles, + psbt = fake_ms_txn(1, len(data), M, keys, outstyles=outstyles, inp_addr_fmt=af, outvals=outvals, change_outputs=change_outputs, - input_amount=inp_amount, psbt_v2=psbtv2, bip67=bip67) + input_amount=inp_amount, psbt_v2=pytestconfig.getoption('psbt2'), + bip67=bip67) start_sign(psbt) txout_explorer(data) -def test_import_duplicate_shuffled_keys_legacy(clear_ms, make_multisig, import_ms_wallet, - cap_story, press_cancel, OK): - clear_ms() - M, N = 2, 3 - wname = "ms02" - keys = make_multisig(M, N) - import_ms_wallet(M, N, addr_fmt="p2wsh", name=wname, accept=True, keys=keys, - descriptor=False) - # shuffle - keys[0], keys[1] = keys[1], keys[0] - - with pytest.raises(AssertionError): - import_ms_wallet(M, N, addr_fmt="p2wsh", name=wname, accept=True, keys=keys, - descriptor=False) - - time.sleep(.1) - title, story = cap_story() - assert 'Duplicate wallet' in story - assert f'{OK} to approve' not in story - press_cancel() @pytest.mark.parametrize("order", list(itertools.product([True, False], repeat=2))) -def test_import_duplicate_shuffled_keys(clear_ms, make_multisig, import_ms_wallet, +def test_import_duplicate_shuffled_keys(clear_miniscript, make_multisig, import_ms_wallet, cap_story, press_cancel, order, OK): # DO NOT allow to import both wsh(sortedmulti(2,A,B,C)) and wsh(sortedmulti(2,B,C,A)) # DO NOT allow to import both wsh(multi(2,A,B,C)) and wsh(multi(2,B,C,A)) # DO NOT allow to import both wsh(sortedmulti(2,A,B,C)) and wsh(multi(2,B,C,A)) # MUST BE treated as duplicates - clear_ms() + clear_miniscript() M, N = 2, 3 A, B = order # defines bip67 - wname = "ms02" keys = make_multisig(M, N) - import_ms_wallet(M, N, addr_fmt="p2wsh", name=wname, accept=True, keys=keys, - descriptor=True, bip67=A) + import_ms_wallet(M, N, addr_fmt="p2wsh", name="ms0", accept=True, keys=keys, bip67=A) # shuffle keys[0], keys[1] = keys[1], keys[0] with pytest.raises(AssertionError): - import_ms_wallet(M, N, addr_fmt="p2wsh", name=wname, accept=True, keys=keys, - descriptor=True, bip67=B) + import_ms_wallet(M, N, addr_fmt="p2wsh", name="ms1", accept=True, keys=keys, bip67=B) + time.sleep(.1) title, story = cap_story() assert 'Duplicate wallet' in story @@ -3427,9 +2742,10 @@ def test_import_duplicate_shuffled_keys(clear_ms, make_multisig, import_ms_walle @pytest.mark.parametrize("int_ext", [True, False]) -def test_multi_sortedmulti_duplicate(clear_ms, make_multisig, import_ms_wallet, OK, - cap_story, press_cancel, int_ext, offer_ms_import): - clear_ms() +def test_multi_sortedmulti_duplicate(clear_miniscript, make_multisig, import_ms_wallet, OK, + cap_story, press_cancel, int_ext, offer_minsc_import, + settings_set): + clear_miniscript() M, N = 3, 5 wname = "ms001" fstr = "m/48h/1h/0h/2h/{idx}" @@ -3444,72 +2760,23 @@ def test_multi_sortedmulti_duplicate(clear_ms, make_multisig, import_ms_wallet, d = MultisigDescriptor(M, N, obj_keys, addr_fmt=AF_P2WSH, is_sorted=False) ser_desc = d.serialize(int_ext=int_ext) - title, story = offer_ms_import(ser_desc) + title, story = offer_minsc_import(ser_desc) assert 'Duplicate wallet' in story assert f'{OK} to approve' not in story assert "BIP-67 clash" in story press_cancel() -def test_unsort_multisig_setting(settings_set, import_ms_wallet, goto_home, - pick_menu_item, cap_story, need_keypress, - settings_get, clear_ms, press_select, is_q1): - clear_ms() - mi = "Unsorted Multisig?" if is_q1 else "Unsorted Multi?" - settings_set("unsort_ms", 0) # OFF by default - with pytest.raises(Exception) as e: - import_ms_wallet(2, 3, "p2wsh", descriptor=True, bip67=False, - accept=True, force_unsort_ms=False) - assert '"multi(...)" not allowed' in e.value.args[0] - - goto_home() - pick_menu_item("Settings") - pick_menu_item("Multisig Wallets") - pick_menu_item(mi) - time.sleep(.1) - title, story = cap_story() - assert '"multi(...)" unsorted multisig wallets that DO NOT follow BIP-67.' in story - assert ("CRUCIAL importance to backup multisig descriptor" - " for unsorted wallets in order to preserve key ordering") in story - assert 'USE AT YOUR OWN RISK' in story - assert 'Press (4)' in story - need_keypress("4") - time.sleep(.1) - pick_menu_item("Allow") - time.sleep(.3) - assert settings_get("unsort_ms") == 1 - import_ms_wallet(2, 3, "p2wsh", descriptor=True, bip67=False, - accept=True, force_unsort_ms=False) - assert len(settings_get("multisig")) == 1 - pick_menu_item("Settings") - pick_menu_item("Multisig Wallets") - pick_menu_item(mi) - time.sleep(.1) - title, story = cap_story() - assert "Remove already saved multi(...) wallets first" in story - assert "2-of-3" in story # wallet that needs to be removed - press_select() - assert len(settings_get("multisig")) == 1 - clear_ms() - pick_menu_item(mi) - pick_menu_item("Do Not Allow") - time.sleep(.3) - with pytest.raises(Exception) as e: - import_ms_wallet(2, 3, "p2wsh", descriptor=True, bip67=False, - accept=True, force_unsort_ms=False) - assert '"multi(...)" not allowed' in e.value.args[0] - - @pytest.mark.bitcoind @pytest.mark.parametrize("cs", [True, False]) @pytest.mark.parametrize("way", ["usb", "nfc", "sd", "vdisk", "qr"]) -def test_import_multisig_usb_json(use_regtest, cs, way, cap_menu, clear_ms, +def test_import_multisig_usb_json(use_regtest, cs, way, cap_menu, clear_miniscript, pick_menu_item, goto_home, need_keypress, - offer_ms_import, bitcoind, microsd_path, - virtdisk_path, import_multisig): + offer_minsc_import, bitcoind, microsd_path, + virtdisk_path, import_miniscript): name = "my_ms_wal" use_regtest() - clear_ms() + clear_miniscript() with open("data/multisig/desc-p2wsh-myself.txt", "r") as f: desc = f.read().strip() @@ -3522,7 +2789,7 @@ def test_import_multisig_usb_json(use_regtest, cs, way, cap_menu, clear_ms, data = None fname = None if way == "usb": - title, story = offer_ms_import(val) + title, story = offer_minsc_import(val) else: if way in ["nfc", "qr"]: data = val @@ -3536,15 +2803,15 @@ def test_import_multisig_usb_json(use_regtest, cs, way, cap_menu, clear_ms, with open(fpath, "w") as f: f.write(val) - title, story = import_multisig(fname=fname, way=way, data=data) + title, story = import_miniscript(fname=fname, way=way, data=data) - assert "Create new multisig wallet?" in story + assert "Create new miniscript wallet?" in story assert name in story need_keypress("y") time.sleep(.2) goto_home() pick_menu_item("Settings") - pick_menu_item("Multisig Wallets") + pick_menu_item("Miniscript") m = cap_menu() assert name in m[0] @@ -3572,27 +2839,19 @@ def test_import_multisig_usb_json(use_regtest, cs, way, cap_menu, clear_ms, {"name": "ab", "desc": None, "random": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"} ), ]) -def test_json_import_failures(err, config, offer_ms_import): +def test_json_import_failures(err, config, offer_minsc_import): with pytest.raises(Exception) as e: - offer_ms_import(json.dumps(config)) + offer_minsc_import(json.dumps(config)) assert err in e.value.args[0] -@pytest.mark.parametrize("desc", [True, False]) -def test_root_keys_import(desc, import_ms_wallet, clear_ms, fake_ms_txn, try_sign): - clear_ms() - M, N = 2, 3 - import_ms_wallet(M, N, "p2wsh", accept=True, name="root", - common="m", descriptor=desc) - - @pytest.mark.bitcoind -def test_cc_root_key(import_ms_wallet, bitcoind, use_regtest, clear_ms, microsd_wipe, goto_home, - pick_menu_item, cap_story, press_select, need_keypress, offer_ms_import, +def test_cc_root_key(import_ms_wallet, bitcoind, use_regtest, clear_miniscript, microsd_wipe, goto_home, + pick_menu_item, cap_story, press_select, need_keypress, offer_minsc_import, cap_menu, load_export, try_sign, goto_address_explorer, settings_set): # only CC has root key here, not practical to attempt get xpub from core, if possible use_regtest() - clear_ms() + clear_miniscript() microsd_wipe() M, N = 2, 2 cosigner = bitcoind.create_wallet(wallet_name=f"bds", disable_private_keys=False, blank=False, @@ -3602,6 +2861,7 @@ def test_cc_root_key(import_ms_wallet, bitcoind, use_regtest, clear_ms, microsd_ blank=True, passphrase=None, avoid_reuse=False, descriptors=True ) goto_home() + target_first_der = [] # get key from bitcoind cosigner target_desc = "" @@ -3612,30 +2872,48 @@ def test_cc_root_key(import_ms_wallet, bitcoind, use_regtest, clear_ms, microsd_ core_desc, checksum = target_desc.split("#") # remove pkh(....) core_key = core_desc[4:-1] + + _idx = core_key.find("]") + assert _idx != -1 + inner = core_key[1:_idx].split("/") + # xfp to upper + inner[0] = inner[0].upper() + core_der_base = f"[{'/'.join(inner)}/0/%d]" + cc_der_base = f"[{xfp2str(simulator_fixed_xfp)}/0/%d]" + target_first_der.append(core_der_base % 0) + target_first_der.append(cc_der_base % 0) + desc = f"wsh(sortedmulti(2,{core_key},[{xfp2str(simulator_fixed_xfp).lower()}]{simulator_fixed_tpub}/0/*))" desc_info = ms.getdescriptorinfo(desc) desc_w_checksum = desc_info["descriptor"] # with checksum - title, story = offer_ms_import(desc_w_checksum) + name = "cc_root_key" + title, story = offer_minsc_import(json.dumps({"name": name, "desc": desc_w_checksum})) - assert "Create new multisig wallet?" in story - assert f"All {N} co-signers must approve spends" in story + assert "Create new miniscript wallet?" in story + assert name in story + # assert f"All {N} co-signers must approve spends" in story assert "P2WSH" in story press_select() # approve multisig import goto_home() pick_menu_item('Settings') - pick_menu_item('Multisig Wallets') + pick_menu_item('Miniscript') menu = cap_menu() pick_menu_item(menu[0]) # pick imported descriptor multisig wallet pick_menu_item("Descriptors") pick_menu_item("Bitcoin Core") - text = load_export("sd", label="Bitcoin Core multisig setup", is_json=False, sig_check=False) + text = load_export("sd", label="Bitcoin Core miniscript", is_json=False) text = text.replace("importdescriptors ", "").strip() # remove junk r1 = text.find("[") r2 = text.find("]", -1, 0) text = text[r1: r2] core_desc_object = json.loads(text) + # bump range to be able to verify multisig scripts against bitcoind + # default exported range from us is just 100 addresses + for i in range(len(core_desc_object)): + core_desc_object[i]["range"] = [0,250] + # import descriptors to watch only wallet res = ms.importdescriptors(core_desc_object) for obj in res: @@ -3667,20 +2945,62 @@ def test_cc_root_key(import_ms_wallet, bitcoind, use_regtest, clear_ms, microsd_ bitcoind_addrs = ms.deriveaddresses(desc_w_checksum, [0,250]) goto_address_explorer() - pick_menu_item("2-of-2") + pick_menu_item(name) + # TODO + # _, story = cap_story() + # # 2of2 - full paths shown for first address + # der_paths = story.split("\n\n")[1].split("\n")[:N] + # assert der_paths == target_first_der + need_keypress('1') # SD - contents = load_export("sd", label="Address summary", is_json=False, sig_check=False) + contents = load_export("sd", label="Address summary", is_json=False) cc_addrs = contents.strip().split("\n")[1:] # Generate the addresses file and get each line in a list for i, line in enumerate(cc_addrs): - addr = line.split(",")[1][1:-1] + split_line = line.split(",") + addr = split_line[1][1:-1] + # TODO + # script_hex = split_line[2][1:-1] + # cc_der = split_line[-1][1:-1] + # core_der = split_line[-2][1:-1] + # assert cc_der == (cc_der_base % i) + # assert core_der == (core_der_base % i) assert addr == bitcoind_addrs[i] + addr_info = ms.getaddressinfo(addr) + assert addr_info["ismine"] + # assert addr_info["hex"] == script_hex + + +@pytest.mark.parametrize("way", ["nfc", "qr"]) +def test_multisig_nfc_qr_finalization(way, clear_miniscript, make_multisig, import_ms_wallet, + cap_story, press_cancel, OK, settings_set, + fake_ms_txn, try_sign_nfc, settings_remove, + try_sign_bbqr): + clear_miniscript() + settings_remove("ptxurl") # tesing above parameter, ptxurl needs to be off + M, N = 1, 2 + wname = "finms-%s" % way + keys = import_ms_wallet(M, N, addr_fmt="p2wsh", name=wname, accept=True) + + psbt = fake_ms_txn(2, 2, M, keys, outstyles=['p2wsh', 'p2wsh-p2sh'], + change_outputs=[0], inp_addr_fmt="p2wsh") + + if way == "nfc": + ip, result, txid = try_sign_nfc(psbt, expect_finalize=True, + nfc_tools=True, encoding="hex") + is_fin = bool(txid) + else: + assert way == "qr" + ip, ft, result = try_sign_bbqr(psbt) + is_fin = (ft == "T") + + assert is_fin @pytest.mark.parametrize("has_orig", [False, True]) -def test_originless_keys(get_cc_key, bitcoin_core_signer, bitcoind, offer_ms_import, - pick_menu_item, load_export, goto_home, cap_menu, clear_ms, +def test_originless_keys(get_cc_key, bitcoin_core_signer, bitcoind, offer_minsc_import, + pick_menu_item, load_export, goto_home, cap_menu, clear_miniscript, use_regtest, press_select, start_sign, end_sign, cap_story, has_orig, need_keypress): # can be both: @@ -3688,7 +3008,7 @@ def test_originless_keys(get_cc_key, bitcoin_core_signer, bitcoind, offer_ms_imp # b.) ranged xpub with its fp -> [xpub1_fp]xpub1/<0;1>/* use_regtest() - clear_ms() + clear_miniscript() af = "bech32" name = "originless_multlisig" @@ -3705,7 +3025,7 @@ def test_originless_keys(get_cc_key, bitcoin_core_signer, bitcoind, offer_ms_imp desc = tmplt.replace("@0", cc_key) desc = desc.replace("@1", originless_ck) to_import = {"desc": desc, "name": name} - offer_ms_import(json.dumps(to_import)) + offer_minsc_import(json.dumps(to_import)) press_select() wo = bitcoind.create_wallet(wallet_name=name, disable_private_keys=True, blank=True, @@ -3713,13 +3033,11 @@ def test_originless_keys(get_cc_key, bitcoin_core_signer, bitcoind, offer_ms_imp goto_home() pick_menu_item("Settings") - pick_menu_item("Multisig Wallets") - menu = cap_menu() - assert menu[0] == f"2/2: {name}" - pick_menu_item(menu[0]) # pick imported descriptor miniscript wallet + pick_menu_item("Miniscript") + pick_menu_item(name) # pick imported descriptor miniscript wallet pick_menu_item("Descriptors") pick_menu_item("Bitcoin Core") - text = load_export("sd", label="Bitcoin Core multisig setup", is_json=False, sig_check=False) + text = load_export("sd", label="Bitcoin Core miniscript", is_json=False) text = text.replace("importdescriptors ", "").strip() # remove junk r1 = text.find("[") @@ -3768,4 +3086,374 @@ def test_originless_keys(get_cc_key, bitcoin_core_signer, bitcoind, offer_ms_imp res = wo.sendrawtransaction(tx_hex) assert len(res) == 64 # tx id + +def test_input_script_type(clear_miniscript, import_ms_wallet, start_sign, end_sign, cap_story, + press_cancel, settings_set, fake_ms_txn): + + def sign_check(psbt): + # start sign MUST raise scriptPubKey mismatch on inputs or change outputs + # it does not in current master + start_sign(psbt) + _, story = cap_story() + try: + end_sign() + assert False, story + except Exception as e: + assert e.args[0] == 'Coldcard Error: Nothing to sign here' + return + + clear_miniscript() + M, N = 2, 3 + wname = "bugg" + # import wallet with script type p2wsh + keys = import_ms_wallet(M, N, addr_fmt="p2wsh", name=wname, accept=True) + + # create txn with p2sh inputs + # we shouldn't even recognize these input as ours + psbt = fake_ms_txn(2, 2, M, keys, inp_addr_fmt="p2sh", + change_outputs=[0,1]) + sign_check(psbt) + + # create txn with p2sh-p2wsh + # we shouldn't even recognize these input as ours + psbt = fake_ms_txn(2, 2, M, keys, + change_outputs=[0,1], inp_addr_fmt="p2sh-p2wsh") + + sign_check(psbt) + + # ============================ + + clear_miniscript() + # import wallet with script type p2sh-p2wsh + keys = import_ms_wallet(M, N, addr_fmt="p2sh-p2wsh", name=wname, accept=True) + + # create txn with p2wsh inputs + # we shouldn't even recognize these input as ours + psbt = fake_ms_txn(2, 2, M, keys, + change_outputs=[0,1], inp_addr_fmt="p2wsh") + + sign_check(psbt) + + # create txn with p2sh inputs + # we shouldn't even recognize these input as ours + psbt = fake_ms_txn(2, 2, M, keys, + change_outputs=[0,1], inp_addr_fmt="p2sh") + + sign_check(psbt) + + # ============================ + + clear_miniscript() + # import wallet with script type p2sh + keys = import_ms_wallet(M, N, addr_fmt="p2sh", name=wname, accept=True) + + # create txn with p2wsh inputs + # we shouldn't even recognize these input as ours + psbt = fake_ms_txn(2, 2, M, keys, + change_outputs=[0,1], inp_addr_fmt="p2wsh") + + sign_check(psbt) + + # create txn with p2sh-p2wsh inputs + # we shouldn't even recognize these input as ours + psbt = fake_ms_txn(2, 2, M, keys, + change_outputs=[0,1], inp_addr_fmt="p2sh-p2wsh") + + sign_check(psbt) + + +def test_change_output_script_type(clear_miniscript, import_ms_wallet, start_sign, end_sign, + cap_story, press_cancel, settings_set, fake_ms_txn): + + def sign_check(psbt): + # start sign MUST raise scriptPubKey mismatch on inputs or change outputs + # it does not in current master + start_sign(psbt) + _, story = cap_story() + assert "change output is fraudulent" in story + assert "spk mismatch" in story + + clear_miniscript() + M, N = 2, 3 + wname = "bugg" + # import wallet with script type p2wsh + keys = import_ms_wallet(M, N, addr_fmt="p2wsh", name=wname, accept=True) + + # inputs correct, change outputs wrong address format + psbt = fake_ms_txn(2, 2, M, keys, force_outstyle="p2sh", inp_addr_fmt="p2wsh", + change_outputs=[0,1]) + sign_check(psbt) + + psbt = fake_ms_txn(2, 2, M, keys, force_outstyle="p2sh-p2wsh", + change_outputs=[0,1], inp_addr_fmt="p2wsh") + + sign_check(psbt) + + # ============================ + + clear_miniscript() + # import wallet with script type p2sh-p2wsh + keys = import_ms_wallet(M, N, addr_fmt="p2sh-p2wsh", name=wname, accept=True) + + # inputs correct, change outputs wrong address format + psbt = fake_ms_txn(2, 2, M, keys, force_outstyle="p2wsh", + change_outputs=[0,1], inp_addr_fmt="p2sh-p2wsh") + + sign_check(psbt) + + psbt = fake_ms_txn(2, 2, M, keys, force_outstyle="p2sh", + change_outputs=[0,1], inp_addr_fmt="p2sh-p2wsh") + + sign_check(psbt) + + # ============================ + + clear_miniscript() + M, N = 2, 3 + wname = "bugg" + # import wallet with script type p2sh + keys = import_ms_wallet(M, N, addr_fmt="p2sh", name=wname, accept=True) + + # inputs correct, change outputs wrong address format + psbt = fake_ms_txn(2, 2, M, keys, force_outstyle="p2wsh", + change_outputs=[0,1], inp_addr_fmt="p2sh") + + sign_check(psbt) + + psbt = fake_ms_txn(2, 2, M, keys, force_outstyle="p2sh-p2wsh", + change_outputs=[0,1], inp_addr_fmt="p2sh") + + sign_check(psbt) + + +def test_sh_vs_wrapped_segwit_psbt(clear_miniscript, import_ms_wallet, start_sign, end_sign, + cap_story, press_cancel, settings_set, fake_ms_txn): + + clear_miniscript() + M, N = 2, 3 + wname = "spk_check_sh_shwsh" + # import wallet with script type p2sh + keys = import_ms_wallet(M, N, addr_fmt="p2sh", name=wname, accept=True) + + def hack(psbt_in): + for inp in psbt_in.inputs: + # switch scripts so it looks like bare p2sh instead wrapped segwit script hash + # it even has our keys, and script is correct + inp.redeem_script = inp.witness_script + inp.witness_script = None + + # PSBT has p2sh-p2wsh inputs & outputs + # but PSBT creator made a mistake and filled redeem/witness like in p2sh (see hack) + psbt = fake_ms_txn(2, 2, M, keys, inp_addr_fmt="p2sh-p2wsh", hack_psbt=hack) + + start_sign(psbt) + time.sleep(.1) + title, story = cap_story() + assert "OK TO SEND?" not in title + assert "spk mismatch" in story + + +def test_wrapped_segwit_vs_sh_psbt(clear_miniscript, import_ms_wallet, start_sign, end_sign, + cap_story, press_cancel, settings_set, fake_ms_txn): + + clear_miniscript() + M, N = 2, 3 + wname = "spk_check_shwsh_sh" + # import wallet with script type p2sh-p2wsh + keys = import_ms_wallet(M, N, addr_fmt="p2sh-p2wsh", name=wname, accept=True) + + def hack(psbt_in): + for inp in psbt_in.inputs: + # switch scripts so it looks like bare p2sh instead wrapped segwit script hash + # it even has our keys, and script is correct + inp.witness_script = inp.redeem_script + inp.redeem_script = b"\x00\x20" + sha256(inp.witness_script).digest() + + # PSBT has p2sh inputs & outputs + # but PSBT creator made a mistake and filled redeem/witness like in p2sh (see hack) + psbt = fake_ms_txn(2, 2, M, keys, inp_addr_fmt="p2sh", hack_psbt=hack) + + start_sign(psbt) + time.sleep(.1) + title, story = cap_story() + assert "OK TO SEND?" not in title + assert "spk mismatch" in story + + +@pytest.mark.parametrize("pms", [0, 1, 2]) +def test_psbt_xpubs_slip132(pms, clear_miniscript, settings_set, start_sign, end_sign, cap_story, + set_seed_words, press_select, offer_minsc_import): + + set_seed_words("cannon budget unknown inhale select virtual absurd chapter inch firm inquiry valley") + clear_miniscript() + settings_set("pms", pms) + # got this PSBT directly form Casa (part of their test suite) + psbt = 'cHNidP8BAFMBAAAAAeB18EjWQ2J8kHcbWSOWLZ4XG9TROiK2EqIAn2a5pe+PAAAAAAD9////AS9EAgAAAAAAF6kURuQXuB5Udus5+DWGg/ZP1bK5/5mHAAAAAE8BAkKJ7wM+PJ4JAAAAAOIDwvV5ejMJ0rSyNey8cKbskf4kk73yRvCe8cUEiNhiA4E0IkUc+Xmx5ndEYFbZ9sHkOnOXJWeSjxIN6Go1AMfiEM3yQGYxAAAAAQAAAAAAAABPAQJCie8DR+pdIQAADTESbO7YkHNCwPnMVS6sXbxDRiMahe6Eil9h9RzUx1aiKQL+RIAGlCJ8PIu+x5O+oSdz9kSY/1vbnZxjm99fMRYWuRAS1W01MQAAAAEAAAAAAAAATwECQonvA+HsXFkAAAAAsdd6QnUkHTmhRlBNy/VQOWcZHfdPJSf4tX6LWUj1VWMCYWPVp4pXPi5mg/AC9ZP4sdbLtwyRwvalwzNO6KfrzaIQXbGC5jEAAAABAAAAAAAAAAABAPgBAAAAAAEB+Qe27L6aqLnQJ4sbxsWvQR6mhcNk0Y1DIbARPdJjSd4BAAAAFxYAFCU3KVhnuRLNeMk85jv3FgbOR9PH/f///wIrcgIAAAAAABepFJanKkFHtvWWwbHNOjPR6NP7RPfqhwoxrQUAAAAAF6kU5xbgzlw1qmkUVzLnuWp6lOPJpImHAkgwRQIhAMtF6v3RgUOxfTs9uGKAV6jjFb3TPlcZSrhRqgO8QlQ2AiANiNAi5rEGfAR0cAp8AadOOIlcQFH+X0Pf98Nz0KF5vQEhAqiLyMuk2fePxFgctRiB5QB/jwBA7q/zWtHgUbskc3rQAAAAAAEBICtyAgAAAAAAF6kUlqcqQUe29ZbBsc06M9Ho0/tE9+qHAQQiACDHvYHyHI3mL9BOaF+AgriPtki9tfeDyUhVBytva0dqmgEFaVIhAnJjmbStmsYp7bb8aAN/aN2hKiLk+6SzNpcjJftG5703IQKO3IofMd3egH0WqIpjS/M3iusXuFuAHA06s2eLBSCs+CECpbdrv+ihGqUyCBYU+K7QgpXuMD7sOt0zcltPV04PJz1TriIGAnJjmbStmsYp7bb8aAN/aN2hKiLk+6SzNpcjJftG5703GM3yQGYxAAAAAQAAAAAAAAAAAAAAAAAAACIGAo7cih8x3d6AfRaoimNL8zeK6xe4W4AcDTqzZ4sFIKz4GBLVbTUxAAAAAQAAAAAAAAAAAAAAAAAAACIGAqW3a7/ooRqlMggWFPiu0IKV7jA+7DrdM3JbT1dODyc9GF2xguYxAAAAAQAAAAAAAAAAAAAAAAAAAAAA' + bpsbt = base64.b64decode(psbt) + start_sign(bpsbt) + time.sleep(.1) + title, story = cap_story() + if pms == 0: + # verify only + assert "Invalid PSBT" in story + assert "XPUBs in PSBT do not match any existing wallet" + press_select() + title, story = offer_minsc_import("sh(wsh(sortedmulti(2,[cdf24066/49/1/0]Upub5QWbdFzCKPujKUZWDF9mST5iE4VJpaqAqXiS85jYUEaSBtwbFcJwswU2DeWGC6rNBnoKs8rQC9oKGdNTSqKwseHDeaE68YAx2QbgcqX84z6/<0;1>/*,[12d56d35/49/1/0]Upub5QaiwZWYcoJwBw26hGguMiUgmKvqpnzrBR92uVEmmwdAtS5LnpBEUPPavjQgxdakT8MKb96FE2Pn61ogKFT3r6obPZiH8q9Y3NPCFRswq6F/<0;1>/*,[5db182e6/49/1/0]Upub5RiNwTn4EVpghGJx1CWjbt9jfL5d792JRyccZxgtWVhbPDwf1o6A4vK9AyTY4VgGBMvEgM3qHM3mhAKxCiF4idL3nMjdskZNP1hQXD8XPq3/<0;1>/*)))") + assert "Create new miniscript wallet" in story + assert "P2SH-P2WSH" + press_select() + start_sign(bpsbt) + time.sleep(.1) + title, story = cap_story() + + elif pms == 1: + # offer import + assert "Create new miniscript wallet" in story + assert "P2SH-P2WSH" + press_select() + start_sign(bpsbt) + time.sleep(.1) + title, story = cap_story() + + assert "Invalid PSBT" not in story + res = end_sign(bpsbt) + po = BasicPSBT().parse(res) + assert len(po.inputs[0].part_sigs) == 1 + + +@pytest.mark.parametrize("af", ["p2sh", "p2wsh", "p2sh-p2wsh"]) +def test_af_psbt_input_matching(af, clear_miniscript, fake_ms_txn, import_ms_wallet, goto_home, + cap_story, start_sign, end_sign, settings_set): + M, N = 3, 5 + clear_miniscript() + goto_home() + + # all is matched properly even without pms_af as we're checking PSBT inputs + # assuming PSBT only has own wallets input - matching will always work + settings_set("pms", 2) # Trust PSBT + + # random path that does not match anything + path = "m/21/21/21" + + def path_mapper(idx): + kk = str_to_path(path) + return kk + [0, 0] + + def incl_xpubs(idx, xfp, m, sk): + kk = str_to_path(path) + bp = pack('<%dI' % (path.count("/") + 1), xfp, *kk) + return sk.node.serialize_public(), bp + + keys = import_ms_wallet(M, N, name='psbt_af_match', accept=True, addr_fmt=af, + common=path, do_import=False)[0] + + psbt = fake_ms_txn(1, 2, M, keys, incl_xpubs=incl_xpubs, inp_addr_fmt=af, + outstyles=ADDR_STYLES_MS, change_outputs=[0], path_mapper=path_mapper) + start_sign(psbt) + time.sleep(.1) + title, story = cap_story() + assert "Invalid PSBT" not in story + res = end_sign(accept=True) + po = BasicPSBT().parse(res) + assert len(po.inputs[0].part_sigs) == 1 + + +def test_casa_case(clear_miniscript, settings_set, start_sign, end_sign, cap_story, set_seed_words): + clear_miniscript() + set_seed_words("cannon budget unknown inhale select virtual absurd chapter inch firm inquiry valley") + settings_set("pms", 2) # Trust PSBT + # got this PSBT directly form Casa (part of their test suite) + psbt = 'cHNidP8BAFMBAAAAAeB18EjWQ2J8kHcbWSOWLZ4XG9TROiK2EqIAn2a5pe+PAAAAAAD9////AS9EAgAAAAAAF6kURuQXuB5Udus5+DWGg/ZP1bK5/5mHAAAAAE8BAkKJ7wM+PJ4JAAAAAOIDwvV5ejMJ0rSyNey8cKbskf4kk73yRvCe8cUEiNhiA4E0IkUc+Xmx5ndEYFbZ9sHkOnOXJWeSjxIN6Go1AMfiEM3yQGYxAAAAAQAAAAAAAABPAQJCie8DR+pdIQAADTESbO7YkHNCwPnMVS6sXbxDRiMahe6Eil9h9RzUx1aiKQL+RIAGlCJ8PIu+x5O+oSdz9kSY/1vbnZxjm99fMRYWuRAS1W01MQAAAAEAAAAAAAAATwECQonvA+HsXFkAAAAAsdd6QnUkHTmhRlBNy/VQOWcZHfdPJSf4tX6LWUj1VWMCYWPVp4pXPi5mg/AC9ZP4sdbLtwyRwvalwzNO6KfrzaIQXbGC5jEAAAABAAAAAAAAAAABAPgBAAAAAAEB+Qe27L6aqLnQJ4sbxsWvQR6mhcNk0Y1DIbARPdJjSd4BAAAAFxYAFCU3KVhnuRLNeMk85jv3FgbOR9PH/f///wIrcgIAAAAAABepFJanKkFHtvWWwbHNOjPR6NP7RPfqhwoxrQUAAAAAF6kU5xbgzlw1qmkUVzLnuWp6lOPJpImHAkgwRQIhAMtF6v3RgUOxfTs9uGKAV6jjFb3TPlcZSrhRqgO8QlQ2AiANiNAi5rEGfAR0cAp8AadOOIlcQFH+X0Pf98Nz0KF5vQEhAqiLyMuk2fePxFgctRiB5QB/jwBA7q/zWtHgUbskc3rQAAAAAAEBICtyAgAAAAAAF6kUlqcqQUe29ZbBsc06M9Ho0/tE9+qHAQQiACDHvYHyHI3mL9BOaF+AgriPtki9tfeDyUhVBytva0dqmgEFaVIhAnJjmbStmsYp7bb8aAN/aN2hKiLk+6SzNpcjJftG5703IQKO3IofMd3egH0WqIpjS/M3iusXuFuAHA06s2eLBSCs+CECpbdrv+ihGqUyCBYU+K7QgpXuMD7sOt0zcltPV04PJz1TriIGAnJjmbStmsYp7bb8aAN/aN2hKiLk+6SzNpcjJftG5703GM3yQGYxAAAAAQAAAAAAAAAAAAAAAAAAACIGAo7cih8x3d6AfRaoimNL8zeK6xe4W4AcDTqzZ4sFIKz4GBLVbTUxAAAAAQAAAAAAAAAAAAAAAAAAACIGAqW3a7/ooRqlMggWFPiu0IKV7jA+7DrdM3JbT1dODyc9GF2xguYxAAAAAQAAAAAAAAAAAAAAAAAAAAAA' + start_sign(base64.b64decode(psbt)) + time.sleep(.1) + title, story = cap_story() + assert "Invalid PSBT" not in story + res = end_sign(psbt) + po = BasicPSBT().parse(res) + assert len(po.inputs[0].part_sigs) == 1 + + +@pytest.mark.parametrize("af", ["p2sh", "p2wsh", "p2sh-p2wsh"]) +@pytest.mark.parametrize("psbt_v2", [True, False]) +def test_af_matching_convoluted_case(af, psbt_v2, clear_miniscript, fake_ms_txn, import_ms_wallet, + goto_home, pick_menu_item, cap_story, press_select, start_sign, + end_sign, is_q1, settings_set): + # merge two multisig PSBTs, each with one input (two inputs after merge) + # first input is not ours, but has same M, N + # second is ours, but address format matching will be based on first + M, N = 3, 5 + clear_miniscript() + goto_home() + settings_set("pms", 2) # TRUST PSBT + + # random path that does not match anything + path = "m/21/21/21" + + def path_mapper(idx): + kk = str_to_path(path) + return kk + [0, 0] + + def incl_xpubs(idx, xfp, m, sk): + kk = str_to_path(path) + bp = pack('<%dI' % (path.count("/") + 1), xfp, *kk) + return sk.node.serialize_public(), bp + + keys0 = import_ms_wallet(M, N, name='00', accept=True, addr_fmt=af, + common=path, do_import=False)[0] + + psbt0 = fake_ms_txn(1, 2, M, keys0, incl_xpubs=incl_xpubs, inp_addr_fmt=af, + outstyles=ADDR_STYLES_MS, change_outputs=[0], path_mapper=path_mapper) + # max confusion + af1 = { + "p2sh": "p2sh-p2wsh", + "p2wsh": "p2sh-p2wsh", + "p2sh-p2wsh": "p2sh" + }[af] + + keys1 = import_ms_wallet(M, N+1, name='11', accept=True, addr_fmt=af1, + common=path, do_import=False)[0] + + # last key is ours - drop it - as if it has our key, we will fail + keys1 = keys1[:-1] + + psbt1 = fake_ms_txn(1, 2, M, keys1, incl_xpubs=incl_xpubs, inp_addr_fmt=af1, + outstyles=ADDR_STYLES_MS, change_outputs=[0], path_mapper=path_mapper) + + # now combine above PSBT so that one that we wanna sign (and preserve XPUBS is only the second input) + # aka trick our matching algo to be wrong + p0 = BasicPSBT().parse(psbt0) + p1 = BasicPSBT().parse(psbt1) + + # change to PSBT v2 to not need handle txn + p00 = BasicPSBT().parse(p0.to_v2()) + p11 = BasicPSBT().parse(p1.to_v2()) + + combined = BasicPSBT() + combined.version = 2 + combined.txn_version = 2 + + combined.xpubs = p0.xpubs + + combined.input_count = p00.input_count + p11.input_count + combined.output_count = p00.output_count + p11.output_count + combined.fallback_locktime = 0 + + # put the one that we will not be signig first (i.e no matching PSBT_XPUBS) + combined.inputs = p11.inputs + p00.inputs + combined.outputs = p11.outputs + p00.outputs + + # drop xfp paths for input 0 - otherwise failure - correct + combined.inputs[0].bip32_paths = {} + + psbt = combined.to_v2() if psbt_v2 else combined.to_v0() + start_sign(psbt) + time.sleep(.1) + title, story = cap_story() + assert "(1 warning below)" in story + assert "Limited Signing" in story + res = end_sign(accept=True) + po = BasicPSBT().parse(res) + assert len(po.inputs[0].part_sigs) == 0 # considered not ours + assert len(po.inputs[1].part_sigs) == 1 # signature added + # EOF diff --git a/testing/test_nfc.py b/testing/test_nfc.py index 29a9389a..5a0ef8c8 100644 --- a/testing/test_nfc.py +++ b/testing/test_nfc.py @@ -5,17 +5,18 @@ # - many test "sync" issues here; case is right but gets outs of sync with DUT # - use `./simulator.py --eff --set nfc=1` # -import pytest, time, io, shutil, json, os +import pytest, time, io, shutil, json, os, random from binascii import b2a_hex, a2b_hex from struct import pack, unpack import ndef from hashlib import sha256 from txn import * -from charcodes import KEY_NFC, KEY_QR +from constants import unmap_addr_fmt +from charcodes import KEY_NFC @pytest.mark.parametrize('case', range(6)) -def test_ndef(case, load_shared_mod): +def test_ndef(case, load_shared_mod, src_root_dir): # NDEF unit tests -- runs in cpython def get_body(efile): @@ -36,7 +37,7 @@ def test_ndef(case, load_shared_mod): def decode(msg): return list(ndef.message_decoder(get_body(msg))) - cc_ndef = load_shared_mod('cc_ndef', '../shared/ndef.py') + cc_ndef = load_shared_mod('cc_ndef', f'{src_root_dir}/shared/ndef.py') n = cc_ndef.ndefMaker() if case == 0: @@ -101,13 +102,13 @@ def test_ndef(case, load_shared_mod): 'short', 'long', ]) -def test_ndef_ccfile(ccfile, load_shared_mod): +def test_ndef_ccfile(ccfile, load_shared_mod, src_root_dir): # NDEF unit tests def decode(body): return list(ndef.message_decoder(body)) - cc_ndef = load_shared_mod('cc_ndef', '../shared/ndef.py') + cc_ndef = load_shared_mod('cc_ndef', f'{src_root_dir}/shared/ndef.py') txt_msg = None if ccfile == 'rx': @@ -149,7 +150,8 @@ def test_ndef_ccfile(ccfile, load_shared_mod): @pytest.fixture def try_sign_nfc(cap_story, pick_menu_item, goto_home, need_keypress, sim_exec, nfc_read, nfc_write, nfc_block4rf, press_select, - press_cancel, press_nfc): + press_cancel, press_nfc, nfc_read_txn, ndef_parse_txn_psbt, + sim_root_dir): # like "try_sign" but use NFC to send/receive PSBT/results @@ -172,17 +174,18 @@ def try_sign_nfc(cap_story, pick_menu_item, goto_home, need_keypress, ip = b2a_hex(ip) recs = [ndef.TextRecord(ip)] elif encoding == 'base64': - from base64 import b64encode, b64decode + from base64 import b64encode ip = b64encode(ip) recs = [ndef.TextRecord(ip)] else: assert encoding == 'binary' recs = [ndef.Record(type='urn:nfc:ext:bitcoin.org:psbt', data=ip), ndef.Record(type='urn:nfc:ext:bitcoin.org:sha256', data=sha256(ip).digest()), - ndef.TextRecord('some text here about situ'), + ndef.TextRecord('some text'), ] - open('debug/nfc-sent.psbt', 'wb').write(ip) + with open(f'{sim_root_dir}/debug/nfc-sent.psbt', 'wb') as f: + f.write(ip) # wrap in a CCFile serialized = b''.join(ndef.message_encoder(recs)) @@ -243,7 +246,7 @@ def try_sign_nfc(cap_story, pick_menu_item, goto_home, need_keypress, for r in range(10): time.sleep(0.1) title, story = cap_story() - if title == 'PSBT Signed': break + if "shared via NFC" in story: break else: assert False, 'timed out' @@ -262,6 +265,20 @@ def try_sign_nfc(cap_story, pick_menu_item, goto_home, need_keypress, press_select() txid = None + got_psbt, got_txn, got_txid = ndef_parse_txn_psbt(contents, txid, ip, expect_finalize) + + return ip, (got_psbt or got_txn), (txid or got_txid) + + + yield doit + + # cleanup / restore + sim_exec('from pyb import SDCard; SDCard.ejected = False') + +@pytest.fixture +def ndef_parse_txn_psbt(press_cancel, sim_root_dir): + def doit(contents, txid=None, orig=None, expect_finalized=True): + # from NFC data read, what did we get? got_txid = None got_txn = None got_psbt = None @@ -270,7 +287,7 @@ def try_sign_nfc(cap_story, pick_menu_item, goto_home, need_keypress, if got.type == 'urn:nfc:wkt:T': assert 'Transaction' in got.text or 'PSBT' in got.text if 'Transaction' in got.text and txid: - assert b2a_hex(txid).decode() in got.text + assert txid in got.text elif got.type == 'urn:nfc:ext:bitcoin.org:txid': got_txid = b2a_hex(got.data).decode('ascii') elif got.type == 'urn:nfc:ext:bitcoin.org:txn': @@ -293,23 +310,16 @@ def try_sign_nfc(cap_story, pick_menu_item, goto_home, need_keypress, if got_txid: assert got_txn assert got_txid == txid - assert expect_finalize + assert expect_finalized result = got_txn - open("debug/nfc-result.txn", 'wb').write(result) + with open(f"{sim_root_dir}/debug/nfc-result.txn", 'wb') as f: + f.write(result) else: - assert not expect_finalize + assert not expect_finalized result = got_psbt - open("debug/nfc-result.psbt", 'wb').write(result) - - if 0: - # check output encoding matches input - if encoding == 'hex' or finalize: - result = a2b_hex(result.strip()) - elif encoding == 'base64': - result = b64decode(result) - else: - assert encoding == 'binary' + with open(f"{sim_root_dir}/debug/nfc-result.psbt", 'wb') as f: + f.write(result) # read back final product if got_txn: @@ -325,45 +335,45 @@ def try_sign_nfc(cap_story, pick_menu_item, goto_home, need_keypress, assert got_psbt[0:5] == b'psbt\xff' from psbt import BasicPSBT - was = BasicPSBT().parse(ip) + was = BasicPSBT().parse(orig) now = BasicPSBT().parse(got_psbt) assert was.txn == now.txn assert was != now - return ip, (got_psbt or got_txn), txid + press_cancel() # exit re-export animation - yield doit + return got_psbt, got_txn, got_txid - # cleanup / restore - sim_exec('from pyb import SDCard; SDCard.ejected = False') + return doit @pytest.mark.parametrize('num_outs', [ 1, 20, 250]) def test_nfc_after(num_outs, fake_txn, try_sign, nfc_read, need_keypress, cap_story, is_q1, press_nfc, press_cancel): # Read signing result (transaction) over NFC, decode it. psbt = fake_txn(1, num_outs) - orig, result = try_sign(psbt, accept=True, finalize=True) + orig, result = try_sign(psbt, accept=True, finalize=True, exit_export_loop=False) too_big = len(result) > 8000 if too_big: assert num_outs > 100 - if num_outs > 100: assert too_big time.sleep(.1) title, story = cap_story() - assert 'TXID' in title, story - txid = a2b_hex(story.split()[0]) - assert f'Press {KEY_NFC if is_q1 else "(3)"}' in story + assert 'TXID' in story, story + txid = a2b_hex(story.split("\n")[3]) + assert f'press {KEY_NFC if is_q1 else "(3)"}' in story press_nfc() time.sleep(.2) if too_big: title, story = cap_story() assert 'is too large' in story + press_cancel() return contents = nfc_read() press_cancel() + press_cancel() #print("contents = " + B2A(contents)) for got in ndef.message_decoder(contents): @@ -380,10 +390,15 @@ def test_nfc_after(num_outs, fake_txn, try_sign, nfc_read, need_keypress, raise ValueError(got.type) @pytest.mark.unfinalized # iff partial=1 +@pytest.mark.reexport @pytest.mark.parametrize('encoding', ['binary', 'hex', 'base64']) @pytest.mark.parametrize('num_outs', [1,2]) @pytest.mark.parametrize('partial', [1, 0]) -def test_nfc_signing(encoding, num_outs, partial, try_sign_nfc, fake_txn, dev): +def test_nfc_signing(encoding, num_outs, partial, try_sign_nfc, fake_txn, dev, + signing_artifacts_reexport, microsd_wipe): + # clear any possible files on SD - that are created by signing_artifacts_reexport + microsd_wipe() + xp = dev.master_xpub def hack(psbt): @@ -393,9 +408,15 @@ def test_nfc_signing(encoding, num_outs, partial, try_sign_nfc, fake_txn, dev): pp = psbt.inputs[0].bip32_paths[pk] psbt.inputs[0].bip32_paths[pk] = b'what' + pp[4:] - psbt = fake_txn(2, num_outs, xp, segwit_in=True, psbt_hacker=hack) + psbt = fake_txn([["p2wpkh"],["p2pkh"]], num_outs, xp, psbt_hacker=hack) - _, txn, txid = try_sign_nfc(psbt, expect_finalize=not partial, encoding=encoding) + got_psbt, txn, txid = try_sign_nfc(psbt, expect_finalize=not partial, encoding=encoding) + _psbt, _txn = signing_artifacts_reexport("nfc", tx_final=not partial, txid=txid, + encoding=encoding) + if partial: + assert _psbt == txn + else: + assert _txn == txn def test_rf_uid(rf_interface, cap_story, goto_home, pick_menu_item): # read UID of NFC chip over the air @@ -416,23 +437,25 @@ def test_rf_uid(rf_interface, cap_story, goto_home, pick_menu_item): print(uid) -def test_ndef_roundtrip(load_shared_mod): +def test_ndef_roundtrip(load_shared_mod, src_root_dir): # specific failing case - cc_ndef = load_shared_mod('cc_ndef', '../shared/ndef.py') + cc_ndef = load_shared_mod('cc_ndef', f'{src_root_dir}/shared/ndef.py') r = open('data/ms-import.ndef', 'rb').read() assert cc_ndef.ccfile_decode(r) == (12, 399, False, 4096) +@pytest.mark.parametrize('multisig', [True, False]) @pytest.mark.parametrize('num_outs', [2, 5, 100, 250]) @pytest.mark.parametrize('chain', ['BTC', 'XTN']) @pytest.mark.parametrize('way', ['sd', 'nfc', 'usb', 'qr']) def test_nfc_pushtx(num_outs, chain, enable_nfc, settings_set, settings_remove, - try_sign, fake_txn, nfc_block4rf, nfc_read, press_cancel, + try_sign, fake_txn, nfc_block4rf, nfc_read_url, press_cancel, cap_story, cap_screen, has_qwerty, way, try_sign_microsd, try_sign_nfc, scan_a_qr, need_keypress, press_select, - goto_home): + goto_home, multisig, fake_ms_txn, import_ms_wallet, + clear_miniscript, try_sign_bbqr): # check the NFC push Tx feature, validating the URL's it makes # - not the UX # - 100 outs => 5000 or so @@ -441,6 +464,7 @@ def test_nfc_pushtx(num_outs, chain, enable_nfc, settings_set, settings_remove, from base64 import urlsafe_b64decode from urllib.parse import urlsplit, parse_qsl, unquote + clear_miniscript() settings_set('chain', chain) enable_nfc() @@ -451,33 +475,28 @@ def test_nfc_pushtx(num_outs, chain, enable_nfc, settings_set, settings_remove, prefix = 'http://10.0.0.10/pushtx#' settings_set('ptxurl', prefix) - psbt = fake_txn(2, num_outs) + if multisig: + goto_home() + # create 1 of 3 multiig wallet - no need for another signers to make tx final + M, N = 1, 3 + af = random.choice(["p2wsh", "p2sh-p2wsh", "p2sh"]) + keys = import_ms_wallet(M, N, af, name="ms_pushtx", accept=True, way=way, chain=chain) + psbt = fake_ms_txn(2, num_outs, M, keys, inp_addr_fmt=af) + else: + psbt = fake_txn(2, num_outs) + if way == "usb": - _, result = try_sign(psbt, finalize=True) + _, result = try_sign(psbt, finalize=True, exit_export_loop=False) elif way == "sd": ip, result, txid = try_sign_microsd(psbt, finalize=True, nfc_push_tx=True) elif way == "nfc": + if len(psbt) > 1000: + pytest.skip("too big") + ip, result, txid = try_sign_nfc(psbt, expect_finalize=True, nfc_tools=True, - nfc_push_tx=True) + nfc_push_tx=True, encoding="hex") elif way == "qr": - goto_home() - need_keypress(KEY_QR) - from bbqr import split_qrs - actual_vers, parts = split_qrs(psbt, 'P') - for p in parts: - scan_a_qr(p) - time.sleep(4.0 / len(parts)) # just so we can watch - - for r in range(20): - title, story = cap_story() - if 'OK TO SEND' in title: - break - time.sleep(.1) - else: - raise pytest.fail('never saw it?') - - # approve it - press_select() + try_sign_bbqr(psbt, nfc_push_tx=True) # print(f'len = {len(result)}') # @@ -486,10 +505,9 @@ def test_nfc_pushtx(num_outs, chain, enable_nfc, settings_set, settings_remove, time.sleep(.1) title, story = cap_story() if way == "usb": - assert title == 'Final TXID' - assert 'to share signed txn' in story + assert 'TXID' in story elif way == "sd": - assert title == "PSBT Signed" + assert ('Updated PSBT' in story) or ('Finalized transaction' in story) else: assert False return @@ -501,20 +519,12 @@ def test_nfc_pushtx(num_outs, chain, enable_nfc, settings_set, settings_remove, scr = cap_screen() assert 'TXID:' in scr - contents = nfc_read() + uri = nfc_read_url() - print(f'nfc contents = {len(contents)}') + assert uri.startswith(prefix) + assert uri.startswith(prefix + 't') - press_cancel() # exit NFC animation - - # expect a single record, a URL - got, = ndef.message_decoder(contents) - - assert got.type == 'urn:nfc:wkt:U' - assert got.uri.startswith(prefix) - assert got.uri.startswith(prefix + 't') - - parts = urlsplit(got.uri) + parts = urlsplit(uri) args = parse_qsl(unquote(parts.fragment)) assert args[0][0] == 't', 'txn must be first' @@ -597,10 +607,11 @@ def test_share_by_pushtx(goto_home, cap_story, pick_menu_item, settings_set, ]) def test_nfc_share_files(fname, mode, ftype, nfc_read_json, nfc_read_text, need_keypress, goto_home, pick_menu_item, is_q1, - cap_menu, nfc_read, nfc_block4rf, press_select): + cap_menu, nfc_read, nfc_block4rf, press_select, + src_root_dir, sim_root_dir): goto_home() - fpath = "data/" + fname - shutil.copy2(fpath, '../unix/work/MicroSD') + fpath = f"{src_root_dir}/testing/data/" + fname + shutil.copy2(fpath, f'{sim_root_dir}/MicroSD') pick_menu_item("Advanced/Tools") pick_menu_item("File Management") pick_menu_item("NFC File Share") @@ -651,6 +662,6 @@ def test_nfc_share_files(fname, mode, ftype, nfc_read_json, nfc_read_text, res = json.loads(res) assert res == contents - os.remove('../unix/work/MicroSD/' + fname) + os.remove(f'{sim_root_dir}/MicroSD/' + fname) # EOF diff --git a/testing/test_notes.py b/testing/test_notes.py index 56dd6238..b5441328 100644 --- a/testing/test_notes.py +++ b/testing/test_notes.py @@ -6,7 +6,6 @@ import pytest, time, json, random, os, pdb from helpers import prandom from charcodes import * from constants import AF_CLASSIC, AF_P2WPKH_P2SH, AF_P2WPKH -from test_bbqr import readback_bbqr from bbqr import split_qrs @@ -41,12 +40,14 @@ def goto_notes(cap_story, cap_menu, press_select, goto_home, pick_menu_item): return doit @pytest.fixture -def need_some_notes(settings_get, settings_set): +def need_some_notes(is_q1, settings_get, settings_set): # create a note or use what's there, provide as obj def doit(title='Title Here', body='Body'): + assert is_q1 notes = settings_get('notes', []) if not notes: settings_set('notes', [dict(misc=body, title=title)]) + settings_set('secnap', True) return notes return doit @@ -54,8 +55,8 @@ def need_some_notes(settings_get, settings_set): def need_some_passwords(settings_get, settings_set): def doit(): notes = settings_get('notes', []) - if any(n.get('password', False) for n in notes): - settings_set('notes', [ + if not any(1 for n in notes if n.get('password', False)): + notes.extend([ {'misc': 'More Notes AAAA', 'password': 'fds65fd5f1sd51s', 'site': 'https://a.com', @@ -67,6 +68,8 @@ def need_some_passwords(settings_get, settings_set): 'title': 'B-Title', 'user': 'Buzzer'} ]) + settings_set('notes', notes) + settings_set('secnap', True) return notes return doit diff --git a/testing/test_ownership.py b/testing/test_ownership.py index 51936d50..d6530de4 100644 --- a/testing/test_ownership.py +++ b/testing/test_ownership.py @@ -6,6 +6,7 @@ import pytest, time, io, csv, json from txn import fake_address from base58 import encode_base58_checksum from helpers import hash160, taptweak, addr_from_display_format +from bech32 import encode as bech32_encode from bip32 import BIP32Node from constants import AF_P2WSH, AF_P2SH, AF_P2WSH_P2SH, AF_CLASSIC, AF_P2WPKH, AF_P2WPKH_P2SH, AF_P2TR from constants import simulator_fixed_xprv, simulator_fixed_tprv, addr_fmt_names @@ -52,22 +53,24 @@ def test_negative(addr_fmt, testnet, sim_exec): (AF_P2SH, "XTN"), (AF_P2WSH_P2SH, "XTN"), ]) -@pytest.mark.parametrize('offset', [ 3, 760] ) +@pytest.mark.parametrize('offset', [ 3, 760, 763] ) @pytest.mark.parametrize('subaccount', [ 0, 34] ) @pytest.mark.parametrize('change_idx', [ 0, 1] ) @pytest.mark.parametrize('from_empty', [ True, False] ) def test_positive(addr_fmt, offset, subaccount, chain, from_empty, change_idx, sim_exec, wipe_cache, make_myself_wallet, use_testnet, goto_home, pick_menu_item, - enter_number, press_cancel, settings_set, import_ms_wallet, clear_ms + enter_number, press_cancel, settings_set, import_ms_wallet, clear_miniscript, is_q1, ): - from bech32 import encode as bech32_encode # API/Unit test, limited UX + ms_addr_fmts = { AF_P2WSH, AF_P2SH, AF_P2WSH_P2SH } + if (addr_fmt in ms_addr_fmts) and subaccount: + raise pytest.skip('multisig with subaccount') if chain == "BTC": use_testnet(False) testnet = False - if addr_fmt in { AF_P2WSH, AF_P2SH, AF_P2WSH_P2SH }: + if addr_fmt in ms_addr_fmts: # multisig jigs assume testnet raise pytest.skip('testnet only') @@ -77,23 +80,22 @@ def test_positive(addr_fmt, offset, subaccount, chain, from_empty, change_idx, coin_type = 1 testnet = True - if from_empty: - wipe_cache() # very different codepaths - settings_set('accts', []) + wipe_cache() # very different codepaths + settings_set('accts', []) if addr_fmt in { AF_P2WSH, AF_P2SH, AF_P2WSH_P2SH }: from test_multisig import make_ms_address, HARD M, N = 1, 3 expect_name = f'search-test-{addr_fmt}' - clear_ms() - keys = import_ms_wallet(M, N, name=expect_name, accept=1, addr_fmt=addr_fmt_names[addr_fmt]) + clear_miniscript() + keys = import_ms_wallet(M, N, name=expect_name, accept=True, addr_fmt=addr_fmt_names[addr_fmt]) # iffy: no cosigner index in this wallet, so indicated that w/ path_mapper - addr, scriptPubKey, script, details = make_ms_address(M, keys, - is_change=change_idx, idx=offset, addr_fmt=addr_fmt, testnet=int(testnet), - path_mapper=lambda cosigner: [HARD(45), change_idx, offset]) - + addr, scriptPubKey, script, details = make_ms_address( + M, keys, addr_fmt=addr_fmt, testnet=int(testnet), + is_change=change_idx, idx=offset + ) path = f'.../{change_idx}/{offset}' else: @@ -103,7 +105,7 @@ def test_positive(addr_fmt, offset, subaccount, chain, from_empty, change_idx, elif addr_fmt == AF_P2WPKH_P2SH: menu_item = expect_name = 'P2SH-Segwit' path = "m/49h/{ct}h/{acc}h" - clear_ms() + clear_miniscript() elif addr_fmt == AF_P2WPKH: menu_item = expect_name = 'Segwit P2WPKH' path = "m/84h/{ct}h/{acc}h" @@ -145,48 +147,65 @@ def test_positive(addr_fmt, offset, subaccount, chain, from_empty, change_idx, pick_menu_item(menu_item) press_cancel() - cmd = f'from ownership import OWNERSHIP; w,path=OWNERSHIP.search({addr!r}); '\ - 'RV.write(repr([w.name, path]))' - lst = sim_exec(cmd) - if 'candidates without finding a match' in lst: - # some kinda timing issue, but don't want big delays, so just retry - print("RETRY search!") - lst = sim_exec(cmd) - + cmd = (f'from ownership import OWNERSHIP;' + f'c,w,path=OWNERSHIP.search({addr!r});' + f'RV.write(repr([c, w.name, path]))') + + if not from_empty: + # we expect here to find address from cache + # so we first need to generate proper cache + lst = sim_exec(cmd, timeout=None) + assert 'Traceback' not in lst, lst + lst = eval(lst) + assert len(lst) == 3 + assert lst[0] is False # not from cache, needed to build it + + + lst = sim_exec(cmd, timeout=None) assert 'Traceback' not in lst, lst - lst = eval(lst) - assert len(lst) == 2 + assert len(lst) == 3 - got_name, got_path = lst - assert expect_name in got_name - if subaccount and '...' not in path: + from_cache, got_name, got_path = lst + + assert from_cache == (not from_empty) + if is_q1: + assert expect_name in got_name + else: + assert expect_name.split(" ")[-1] in got_name + if subaccount: # not expected for multisig, since we have proper wallet name - assert f'Account#{subaccount}' in got_name + if is_q1: + assert f'Account#{subaccount}' in got_name + else: + assert f'Acct#{subaccount}' in got_name assert got_path == (change_idx, offset) @pytest.mark.parametrize('valid', [ True, False] ) -@pytest.mark.parametrize('testnet', [ True, False] ) +@pytest.mark.parametrize('netcode', [ "BTC", "XTN"] ) @pytest.mark.parametrize('method', [ 'qr', 'nfc'] ) @pytest.mark.parametrize('multisig', [ True, False] ) -def test_ux(valid, testnet, method, +def test_ux(valid, netcode, method, sim_exec, wipe_cache, make_myself_wallet, use_testnet, goto_home, pick_menu_item, press_cancel, press_select, settings_set, is_q1, nfc_write, need_keypress, cap_screen, cap_story, load_shared_mod, scan_a_qr, skip_if_useless_way, - sign_msg_from_address, multisig, import_ms_wallet, clear_ms, verify_qr_address + sign_msg_from_address, multisig, import_ms_wallet, clear_miniscript, verify_qr_address, + src_root_dir, sim_root_dir ): skip_if_useless_way(method) addr_fmt = AF_CLASSIC + testnet = (netcode == "XTN") + if valid: if multisig: from test_multisig import make_ms_address, HARD M, N = 2, 3 expect_name = f'own_ux_test' - clear_ms() - keys = import_ms_wallet(M, N, AF_P2WSH, name=expect_name, accept=1) + clear_miniscript() + keys = import_ms_wallet(M, N, "p2wsh", name=expect_name, accept=1) # iffy: no cosigner index in this wallet, so indicated that w/ path_mapper addr, scriptPubKey, script, details = make_ms_address( @@ -198,7 +217,7 @@ def test_ux(valid, testnet, method, mk = BIP32Node.from_wallet_key(simulator_fixed_tprv if testnet else simulator_fixed_xprv) path = "m/44h/{ct}h/{acc}h/0/3".format(acc=0, ct=(1 if testnet else 0)) sk = mk.subkey_for_path(path) - addr = sk.address(chain="XTN" if testnet else "BTC") + addr = sk.address(chain=netcode) else: addr = fake_address(addr_fmt, testnet) @@ -216,7 +235,7 @@ def test_ux(valid, testnet, method, elif method == 'nfc': - cc_ndef = load_shared_mod('cc_ndef', '../shared/ndef.py') + cc_ndef = load_shared_mod('cc_ndef', f'{src_root_dir}/shared/ndef.py') n = cc_ndef.ndefMaker() n.add_text(addr) ccfile = n.bytes() @@ -226,7 +245,8 @@ def test_ux(valid, testnet, method, pick_menu_item('Advanced/Tools') pick_menu_item('NFC Tools') pick_menu_item('Verify Address') - open('debug/nfc-addr.ndef', 'wb').write(ccfile) + with open(f'{sim_root_dir}/debug/nfc-addr.ndef', 'wb') as f: + f.write(ccfile) nfc_write(ccfile) #press_select() @@ -258,25 +278,27 @@ def test_ux(valid, testnet, method, assert "Press (0) to sign message with this key" in story need_keypress('0') msg = "coinkite CC the most solid HWW" - sign_msg_from_address(msg, addr, path, addr_fmt, method, testnet) + sign_msg_from_address(msg, addr, path, addr_fmt, method, netcode) else: assert title == 'Unknown Address' - assert 'Searched ' in story - assert 'candidates without finding a match' in story + assert 'Searched 1528' in story # max + assert "1 wallet(s)" in story + assert 'without finding a match' in story @pytest.mark.parametrize("af", ["P2SH-Segwit", "Segwit P2WPKH", "Classic P2PKH", "Taproot P2TR", "ms0", "msc0", "msc2"]) def test_address_explorer_saver(af, wipe_cache, settings_set, goto_address_explorer, - pick_menu_item, need_keypress, sim_exec, clear_ms, + pick_menu_item, need_keypress, sim_exec, clear_miniscript, import_ms_wallet, press_select, goto_home, nfc_write, load_shared_mod, load_export_and_verify_signature, - cap_story, load_export, offer_minsc_import, is_q1): + cap_story, load_export, offer_minsc_import, is_q1, + src_root_dir, sim_root_dir): goto_home() wipe_cache() settings_set('accts', []) if af == "ms0": - clear_ms() + clear_miniscript() import_ms_wallet(2, 3, name=af) press_select() # accept ms import elif "msc" in af: @@ -297,11 +319,7 @@ def test_address_explorer_saver(af, wipe_cache, settings_set, goto_address_explo assert lst title, body = cap_story() - if af in ("Taproot P2TR", "ms0", "msc0", "msc2"): - # p2tr - no signature file - contents = load_export("sd", label="Address summary", is_json=False, sig_check=False) - else: - contents, _ = load_export_and_verify_signature(body, "sd", label="Address summary") + contents, _, _ = load_export_and_verify_signature(body, "sd", label="Address summary") addr_dump = io.StringIO(contents) cc = csv.reader(addr_dump) @@ -313,6 +331,285 @@ def test_address_explorer_saver(af, wipe_cache, settings_set, goto_address_explo if idx == 200: addr = addr + cc_ndef = load_shared_mod('cc_ndef', f'{src_root_dir}/shared/ndef.py') + n = cc_ndef.ndefMaker() + n.add_text(addr) + ccfile = n.bytes() + + # run simulator w/ --set nfc=1 --eff + goto_home() + pick_menu_item('Advanced/Tools') + pick_menu_item('NFC Tools') + pick_menu_item('Verify Address') + with open(f'{sim_root_dir}/debug/nfc-addr.ndef', 'wb') as f: + f.write(ccfile) + + nfc_write(ccfile) + + time.sleep(1) + title, story = cap_story() + + assert addr == addr_from_display_format(story.split("\n\n")[0]) + assert title == ('Verified Address' if is_q1 else "Verified!") + assert 'Found in wallet' in story + assert 'Derivation path' in story + if is_q1: + assert af in story + else: + if "ms" in af: + assert af in story + elif af == "P2SH-Segwit": + assert af in story + else: + part = af.split(" ")[1] + assert part in story + + +def test_ae_saver(wipe_cache, settings_set, goto_address_explorer, cap_story, + pick_menu_item, need_keypress, sim_exec, is_q1, + import_ms_wallet, press_select, goto_home, nfc_write, + load_shared_mod, load_export_and_verify_signature, + set_addr_exp_start_idx, use_testnet): + + cmd = lambda a: ( + f'from ownership import OWNERSHIP;' + f'c,w,path=OWNERSHIP.search({a!r});' + f'RV.write(repr([c, w.name, path]))') + + def cache_check(a, from_cache): + l = sim_exec(cmd(a), timeout=None) + assert 'Traceback' not in l, l + assert eval(l)[0] == from_cache + + use_testnet() + goto_home() + wipe_cache() + settings_set('accts', []) + settings_set('aei', True) + + goto_address_explorer() + set_addr_exp_start_idx(7) # starting from index 7 + pick_menu_item("Segwit P2WPKH") + need_keypress("1") # save to SD + + time.sleep(.1) + title, body = cap_story() + contents, sig_addr, _ = load_export_and_verify_signature(body, "sd", label="Address summary") + addr_dump = io.StringIO(contents) + cc = csv.reader(addr_dump) + hdr = next(cc) + assert hdr == ['Index', 'Payment Address', 'Derivation'] + addrs = {} + for idx, addr, deriv in cc: + addrs[int(idx)] = addr + + # nothing was created from above as start index was 7 + cache_check(addrs[7], False) + # now we have cached addresses up to 27 + for i in range(8, 28): + cache_check(addrs[i], True) + + # cache file position at 27 (aka count) + goto_address_explorer() + set_addr_exp_start_idx(1) # starting from index 1 + pick_menu_item("Segwit P2WPKH") + need_keypress("1") # save to SD + + time.sleep(.1) + title, body = cap_story() + load_export_and_verify_signature(body, "sd", label="Address summary") + + # after above we must have first 250 addresses cached + cache_check(addrs[249], True) + + # cache file position at 250 (aka count) + goto_address_explorer() + set_addr_exp_start_idx(250) # starting from index 250 + pick_menu_item("Segwit P2WPKH") + need_keypress("1") # save to SD + + time.sleep(.1) + title, body = cap_story() + contents, sig_addr, _ = load_export_and_verify_signature(body, "sd", label="Address summary") + addr_dump = io.StringIO(contents) + cc = csv.reader(addr_dump) + hdr = next(cc) + assert hdr == ['Index', 'Payment Address', 'Derivation'] + addrs = {} + for idx, addr, deriv in cc: + addrs[int(idx)] = addr + + # after above we must have first 500 addresses cached + cache_check(addrs[300], True) + cache_check(addrs[400], True) + cache_check(addrs[499], True) + + # now addresses that we already have, does nothing + goto_address_explorer() + set_addr_exp_start_idx(100) # starting from index 100 + pick_menu_item("Segwit P2WPKH") + need_keypress("1") # save to SD + + time.sleep(.1) + title, body = cap_story() + load_export_and_verify_signature(body, "sd", label="Address summary") + cache_check(addrs[499], True) + + # now move count up via ownership + mk = BIP32Node.from_wallet_key(simulator_fixed_tprv) + sk = mk.subkey_for_path("84h/1h/0h/0/580") + addr = bech32_encode('tb', 0, sk.hash160()) + cache_check(addr, False) + # now count at 600 (580+20) + + # now over the max but with some we already have + goto_address_explorer() + set_addr_exp_start_idx(550) # starting from index 550 (would go up to 800) + pick_menu_item("Segwit P2WPKH") + need_keypress("1") # save to SD + + time.sleep(.1) + title, body = cap_story() + contents, sig_addr, _ = load_export_and_verify_signature(body, "sd", label="Address summary") + addr_dump = io.StringIO(contents) + cc = csv.reader(addr_dump) + hdr = next(cc) + assert hdr == ['Index', 'Payment Address', 'Derivation'] + addrs = {} + for idx, addr, deriv in cc: + addrs[int(idx)] = addr + + assert 799 in addrs + cache_check(addrs[763], True) # max + + # start idx over max stored addresses + goto_address_explorer() + set_addr_exp_start_idx(764) # starting from index 764 + pick_menu_item("Segwit P2WPKH") + need_keypress("1") # save to SD + + time.sleep(.1) + title, body = cap_story() + load_export_and_verify_signature(body, "sd", label="Address summary") + # does notthing harmful, nothing added + + cache_check(addrs[763], True) # max + l = sim_exec(cmd(addrs[764]), timeout=None) + assert 'Traceback' in l + assert 'Searched 1528' in l # max + assert "1 wallet(s)" in l + assert 'without finding a match' in l + + +def test_regtest_addr_on_mainnet(goto_home, is_q1, pick_menu_item, scan_a_qr, nfc_write, cap_story, + need_keypress, load_shared_mod, use_mainnet, src_root_dir, sim_root_dir): + # testing bug in chains.possible_address_fmt + # allowed regtest addresses to be allowed on main chain + goto_home() + use_mainnet() + addr = "bcrt1qmff7njttlp6tqtj0nq7svcj2p9takyqm3mfl06" + if is_q1: + pick_menu_item('Scan Any QR Code') + scan_a_qr(addr) + time.sleep(1) + + title, story = cap_story() + + assert addr == addr_from_display_format(story.split("\n\n")[0]) + assert '(1) to verify ownership' in story + need_keypress('1') + + else: + cc_ndef = load_shared_mod('cc_ndef', f'{src_root_dir}/shared/ndef.py') + n = cc_ndef.ndefMaker() + n.add_text(addr) + ccfile = n.bytes() + + # run simulator w/ --set nfc=1 --eff + pick_menu_item('Advanced/Tools') + pick_menu_item('NFC Tools') + pick_menu_item('Verify Address') + with open(f'{sim_root_dir}/debug/nfc-addr.ndef', 'wb') as f: + f.write(ccfile) + nfc_write(ccfile) + # press_select() + + time.sleep(1) + title, story = cap_story() + assert addr == addr_from_display_format(story.split("\n\n")[0]) + + assert title == 'Unknown Address' + assert "not valid on Bitcoin Mainnet" in story + + +def test_20_more_build_after_match(sim_exec, import_ms_wallet, clear_miniscript, wipe_cache, + settings_set): + from test_multisig import make_ms_address, HARD + + cmd = lambda a: ( + f'from ownership import OWNERSHIP;' + f'c,w,path=OWNERSHIP.search({a!r});' + f'RV.write(repr([c, w.name, path]))') + + # create multisig wallet + M, N = 2, 3 + expect_name = 'test20more' + clear_miniscript() + keys = import_ms_wallet(M, N, name=expect_name, accept=True, addr_fmt="p2wsh") + + make_a = lambda index: make_ms_address( + M, keys, + is_change=False, idx=index, addr_fmt=AF_P2WSH, testnet=True, + path_mapper=lambda cosigner: [HARD(45), 0, index]) + + def cache_check(index, from_cache): + a = make_a(index)[0] + l = sim_exec(cmd(a), timeout=None) + assert 'Traceback' not in l, l + assert eval(l)[0] == from_cache + + # clean slate + wipe_cache() + settings_set('accts', []) + + # generate 10th (idx=9) address (external) + # first run, generated first 10 addresses + 20 + cache_check(9, False) + + # now we can go up to index 29 - all must come from cache + for i in range(10, 30): + cache_check(i, True) + + # idx 30 - not in cache + # but will cache next 20 addrs + cache_check(30, False) + + # now we can go up to index 51 - all must come from cache + for i in range(31, 51): + cache_check(i, True) + + # idx 51 - not in cache + # but will cache next 20 addrs + cache_check(51, False) + + cache_check(760, False) + cache_check(761, True) + cache_check(762, True) + cache_check(763, True) + + # after max - not gonna find + addr = make_a(764)[0] + l = sim_exec(cmd(addr), timeout=None) + assert 'Traceback' in l + assert 'Searched 1528' in l # max + assert "1 wallet(s)" in l + assert 'without finding a match' in l + + +def test_named_wallet_search_fail(load_shared_mod, goto_home, pick_menu_item, nfc_write, + cap_story, sim_root_dir): + addr = fake_address(AF_P2WSH, True) + addr = f"{addr}?wallet=unknown" cc_ndef = load_shared_mod('cc_ndef', '../shared/ndef.py') n = cc_ndef.ndefMaker() n.add_text(addr) @@ -323,20 +620,105 @@ def test_address_explorer_saver(af, wipe_cache, settings_set, goto_address_explo pick_menu_item('Advanced/Tools') pick_menu_item('NFC Tools') pick_menu_item('Verify Address') - open('debug/nfc-addr.ndef', 'wb').write(ccfile) + with open(f'{sim_root_dir}/debug/nfc-addr.ndef', 'wb') as f: + f.write(ccfile) nfc_write(ccfile) time.sleep(1) title, story = cap_story() + assert addr.split("?", 1)[0] == addr_from_display_format(story.split("\n\n")[0]) + assert "Wallet 'unknown' not defined." in story - assert addr == addr_from_display_format(story.split("\n\n")[0]) - assert title == ('Verified Address' if is_q1 else "Verified!") - assert 'Found in wallet' in story - if "msc" not in af: - assert 'Derivation path' in story - if af == "Segwit P2WPKH": - assert " P2WPKH " in story + +@pytest.mark.parametrize('valid', [True, False]) +@pytest.mark.parametrize('method', ["qr", "nfc"]) +@pytest.mark.parametrize('wname', ["msnm", "Longer Wallet Name"]) +def test_named_wallet_search(wname, valid, method, clear_miniscript, import_ms_wallet, is_q1, + load_shared_mod, goto_home, pick_menu_item, scan_a_qr, + cap_story, need_keypress, nfc_write, use_testnet, + wipe_cache, settings_set, sim_root_dir): + + from test_multisig import make_ms_address, HARD + + if method == "qr" and (not is_q1): + raise pytest.skip("QR Mk") + + wipe_cache() # very different codepaths + settings_set('accts', []) + use_testnet() + M, N = 2, 3 + clear_miniscript() + ms_data = {} + # all ms wallets have same address format, different M/N + for i in range(3): + idx = 5 + if i == 2: + idx = 763 + name = f'{wname}{i}' + keys = import_ms_wallet(M+i, N+i, "p2wsh", name=name, accept=True) + # last address + addr, scriptPubKey, script, details = make_ms_address( + M+i, keys, is_change=0, idx=idx, addr_fmt=AF_P2WSH, + testnet=True, path_mapper=lambda cosigner: [HARD(45), 0, idx] + ) + ms_data[name] = (addr, scriptPubKey, script, keys) + + if valid: + # msnw2 -> last added wallet + addr, *_ = ms_data[f"{wname}{i}"] else: - assert af in story + # will fail, even tho address is present in different wallet + # with wallet= only specified wallet is searched + addr, *_ = ms_data[f"{wname}0"] + + # will only search specified wallet + addr = f"{addr}?wallet={wname}{i}".replace(' ', '%20') + + if method == 'qr': + goto_home() + pick_menu_item('Scan Any QR Code') + scan_a_qr(addr) + time.sleep(1) + + title, story = cap_story() + + assert addr.split("?", 1)[0] == addr_from_display_format(story.split("\n\n")[0]) + assert '(1) to verify ownership' in story + need_keypress('1') + + elif method == 'nfc': + cc_ndef = load_shared_mod('cc_ndef', '../shared/ndef.py') + n = cc_ndef.ndefMaker() + n.add_text(addr) + ccfile = n.bytes() + + # run simulator w/ --set nfc=1 --eff + goto_home() + pick_menu_item('Advanced/Tools') + pick_menu_item('NFC Tools') + pick_menu_item('Verify Address') + with open(f'{sim_root_dir}/debug/nfc-addr.ndef', 'wb') as f: + f.write(ccfile) + nfc_write(ccfile) + # press_select() + + else: + raise ValueError(method) + + time.sleep(1) + title, story = cap_story() + assert addr.split("?", 1)[0] == addr_from_display_format(story.split("\n\n")[0]) + + if valid: + assert title == ('Verified Address' if is_q1 else "Verified!") + assert 'Found in wallet' in story + assert 'Derivation path' in story + assert f"{wname}" in story + + else: + assert title == 'Unknown Address' + assert 'Searched 1528' in story # max + assert "1 wallet(s)" in story + assert 'without finding a match' in story # EOF diff --git a/testing/test_paper.py b/testing/test_paper.py index 18333be3..c6c59d34 100644 --- a/testing/test_paper.py +++ b/testing/test_paper.py @@ -18,7 +18,7 @@ from ckcc_protocol.constants import * @pytest.mark.parametrize('netcode', ["XRT", "BTC", "XTN"]) def test_generate(mode, pdf, netcode, dev, cap_menu, pick_menu_item, goto_home, cap_story, need_keypress, microsd_path, verify_detached_signature_file, settings_set, - press_select, validate_address, bitcoind): + press_select, validate_address, bitcoind, src_root_dir): # test UX and operation of the 'bitcoin core' wallet export mx = "Don't make PDF" @@ -49,7 +49,7 @@ def test_generate(mode, pdf, netcode, dev, cap_menu, pick_menu_item, goto_home, if pdf: assert mx in cap_menu() - shutil.copy('../docs/paperwallet.pdf', microsd_path('paperwallet.pdf')) + shutil.copy(f'{src_root_dir}/docs/paperwallet.pdf', microsd_path('paperwallet.pdf')) pick_menu_item(mx) time.sleep(0.2) diff --git a/testing/test_pwsave.py b/testing/test_pwsave.py index 41b335ee..2e158af6 100644 --- a/testing/test_pwsave.py +++ b/testing/test_pwsave.py @@ -3,11 +3,15 @@ # tests for ../shared/pwsave.py # import pytest, time, os, shutil -from test_ux import word_menu_entry from binascii import a2b_hex from constants import simulator_fixed_tprv -SIM_FNAME = '../unix/work/MicroSD/.tmp.tmp' + +@pytest.fixture +def simulator_db_file(sim_root_dir): + def doit(): + return sim_root_dir + "/MicroSD/.tmp.tmp" + return doit @pytest.fixture def set_pw_phrase(pick_menu_item, word_menu_entry): @@ -32,8 +36,9 @@ def set_pw_phrase(pick_menu_item, word_menu_entry): 'ab'*25, ]) def test_first_time(pws, need_keypress, cap_story, pick_menu_item, enter_complex, - cap_menu, go_to_passphrase, reset_seed_words, press_select): - try: os.unlink(SIM_FNAME) + cap_menu, go_to_passphrase, reset_seed_words, press_select, + simulator_db_file): + try: os.unlink(simulator_db_file()) except: pass pws = pws.split() @@ -86,7 +91,7 @@ def test_first_time(pws, need_keypress, cap_story, pick_menu_item, enter_complex reset_seed_words() -def test_crypto_unittest(sim_eval, sim_exec, simulator): +def test_crypto_unittest(sim_exec, simulator, simulator_db_file): # unit test for AES key generation from SDCard and master secret card = sim_exec('import files; from h import b2a_hex; cs = files.CardSlot().__enter__(); RV.write(b2a_hex(cs.get_id_hash())); cs.__exit__()') @@ -122,7 +127,7 @@ p=PassphraseSaver(); p._calc_key(cs); RV.write(b2a_hex(p.key)); cs.__exit__()''' # check that key works for decrypt and that the file was actually encrypted - with open(SIM_FNAME, 'rb') as fd: + with open(simulator_db_file(), 'rb') as fd: raw = fd.read() import pyaes @@ -138,7 +143,7 @@ p=PassphraseSaver(); p._calc_key(cs); RV.write(b2a_hex(p.key)); cs.__exit__()''' assert j[0]['xfp'] def test_delete_one_by_one(go_to_passphrase, pick_menu_item, cap_menu, - cap_story, press_select): + cap_story, press_select, src_root_dir, sim_root_dir): # delete it one by one # when all deleted - we must be back in Passphrase # menu without Restore Saved option visible @@ -146,7 +151,7 @@ def test_delete_one_by_one(go_to_passphrase, pick_menu_item, cap_menu, time.sleep(.1) m = cap_menu() if 'Restore Saved' not in m: - shutil.copy2('data/pwsave.tmp', '../unix/work/MicroSD/.tmp.tmp') + shutil.copy2(f'{src_root_dir}/testing/data/pwsave.tmp', f'{sim_root_dir}/MicroSD/.tmp.tmp') go_to_passphrase() pick_menu_item('Restore Saved') m = cap_menu() diff --git a/testing/test_se2.py b/testing/test_se2.py index 092ea215..ec6a77ff 100644 --- a/testing/test_se2.py +++ b/testing/test_se2.py @@ -65,7 +65,7 @@ def decode_slot(data): assert len(data) == 128 return SlotInfo(*struct.unpack(TRICK_FMT, data)) -@pytest.fixture(scope='function') +@pytest.fixture def se2_gate(sim_exec): # not-so-low-level method: include auth data for main PIN def doit(method_num, obj=None, buf=None): @@ -252,7 +252,7 @@ def test_ux_trick_menus(goto_trick_menu, pick_menu_item, cap_menu, # all clear now -@pytest.fixture(scope='function') +@pytest.fixture def new_trick_pin(goto_trick_menu, pick_menu_item, cap_menu, press_select, cap_story, enter_pin, se2_gate, is_simulator, is_q1): # using menus and UX, setup a new trick PIN @@ -301,8 +301,10 @@ def new_trick_pin(goto_trick_menu, pick_menu_item, cap_menu, press_select, time.sleep(.1) m = cap_menu() assert m[0] == f'[{new_pin}]' - assert set(m[1:]) == {'Duress Wallet', 'Just Reboot', 'Wipe Seed', \ - 'Delta Mode', 'Look Blank', 'Brick Self', 'Login Countdown'} + assert set(m[1:]) == {'Duress Wallet', 'Just Reboot', 'Wipe Seed', 'Delta Mode', + 'Look Blank', 'Policy Unlock', + 'Policy Unlock & Wipe' if is_q1 else 'P.U. & Wipe', + 'Brick Self', 'Login Countdown'} pick_menu_item(op_mode) @@ -515,7 +517,7 @@ def test_ux_countdown_choices(subchoice, expect, xflags, new_trick_pin, new_pin_ # ( 'Blank Coldcard', 'freshly wiped Coldcard', TC_WIPE|TC_BLANK_WALLET, 0 ), ]) def test_ux_duress_choices(with_wipe, subchoice, expect, xflags, xargs, words12, - reset_seed_words, repl, clear_all_tricks, import_ms_wallet, get_setting, clear_ms, + reset_seed_words, repl, clear_all_tricks, import_ms_wallet, get_setting, clear_miniscript, new_trick_pin, new_pin_confirmed, cap_menu, pick_menu_item, cap_story, need_keypress, press_select, press_cancel, seed_story_to_words, is_q1, set_seed_words, stop_after_activated=False, @@ -529,11 +531,11 @@ def test_ux_duress_choices(with_wipe, subchoice, expect, xflags, xargs, words12, xargs += 1000 # import multisig - clear_ms() + clear_miniscript() import_ms_wallet(2, 2, dev_key=words12) press_select() time.sleep(.1) - assert len(get_setting('multisig')) == 1 + assert len(get_setting('miniscript')) == 1 # after Wipe Seed -> Wipe->Wallet choice, another level clear_all_tricks() @@ -611,7 +613,7 @@ def test_ux_duress_choices(with_wipe, subchoice, expect, xflags, xargs, words12, xp = repl.eval("settings.get('xpub')") assert xp == wallet.hwif(as_private=False) - assert not get_setting('multisig') # multisig is not copied + assert not get_setting('miniscript') # multisig is not copied # re-login to recover normal seed reset_seed_words() @@ -879,7 +881,7 @@ def build_duress_wallets(request, seed_vault=False): # fixtures I need in test_ux_duress_choices args = {f: request.getfixturevalue(f) - for f in ['reset_seed_words', 'repl', 'clear_all_tricks', 'new_trick_pin', 'clear_ms', + for f in ['reset_seed_words', 'repl', 'clear_all_tricks', 'new_trick_pin', 'clear_miniscript', 'import_ms_wallet', 'get_setting', 'press_select', 'press_cancel', 'is_q1', 'new_pin_confirmed', 'cap_menu', 'pick_menu_item', 'cap_story', 'need_keypress', 'seed_story_to_words', 'set_seed_words']} @@ -914,6 +916,14 @@ def build_duress_wallets(request, seed_vault=False): return 4 +def test_deltamode_toggle(get_deltamode, set_deltamode): + # check test fixture works. + assert get_deltamode() == False + set_deltamode(True) + assert get_deltamode() == True + set_deltamode(False) + assert get_deltamode() == False + # TODO # - make trick and do login, check arrives right state? diff --git a/testing/test_seed_xor.py b/testing/test_seed_xor.py index bdd2f929..ec823905 100644 --- a/testing/test_seed_xor.py +++ b/testing/test_seed_xor.py @@ -3,12 +3,11 @@ # test Seed XOR features # -import pytest, time, itertools +import pytest, time, itertools, random from mnemonic import Mnemonic from constants import simulator_fixed_words from xor import prepare_test_pairs, xor from bip32 import BIP32Node -from test_ux import word_menu_entry, pass_word_quiz from charcodes import KEY_QR, KEY_RIGHT, KEY_DOWN wordlist = Mnemonic('english').wordlist @@ -55,7 +54,7 @@ def restore_seed_xor(set_seed_words, goto_home, pick_menu_item, cap_story, word_menu_entry, verify_ephemeral_secret_ui, confirm_tmp_seed, seed_vault_enable, press_select, scan_a_qr, is_q1, cap_screen_qr, cap_screen, OK): - def doit(parts, expect, incl_self=False, save_to_vault=False, + def doit(parts, expect, incl_self=False, save_to_vault=None, is_master_tmp_fail=False, way=None): if expect is None: parts, expect = prepare_test_pairs(*parts) @@ -67,6 +66,9 @@ def restore_seed_xor(set_seed_words, goto_home, pick_menu_item, cap_story, elif incl_self is False: set_seed_words(proper[num_words]) + if save_to_vault is None: + save_to_vault = random.getrandbits(1) + seed_vault_enable(save_to_vault) time.sleep(.2) @@ -172,7 +174,6 @@ def restore_seed_xor(set_seed_words, goto_home, pick_menu_item, cap_story, @pytest.mark.parametrize('way', ["qr", "seedqr", "classic"]) @pytest.mark.parametrize('incl_self', [False, True]) -@pytest.mark.parametrize('seed_vault', [False, True]) @pytest.mark.parametrize('parts, expect', [ # 24words - 3 parts (['romance wink lottery autumn shop bring dawn tongue range crater truth ability miss spice fitness easy legal release recall obey exchange recycle dragon room', @@ -192,10 +193,10 @@ def restore_seed_xor(set_seed_words, goto_home, pick_menu_item, cap_story, # random generated *random_test_cases() ]) -def test_import_xor(seed_vault, incl_self, parts, expect, restore_seed_xor, way, is_q1): +def test_import_xor(incl_self, parts, expect, restore_seed_xor, way, is_q1): if not is_q1 and "qr" in way: raise pytest.skip("Q only") - restore_seed_xor(parts, expect, incl_self, seed_vault, way=way) + restore_seed_xor(parts, expect, incl_self, way=way) @pytest.mark.parametrize('incl_self', [False, True]) diff --git a/testing/test_sign.py b/testing/test_sign.py index 9f2bc821..c8977335 100644 --- a/testing/test_sign.py +++ b/testing/test_sign.py @@ -16,7 +16,7 @@ from helpers import B2A, fake_dest_addr, parse_change_back, addr_from_display_fo from helpers import xfp2str, seconds2human_readable, hash160 from msg import verify_message from bip32 import BIP32Node -from constants import ADDR_STYLES, ADDR_STYLES_SINGLE, SIGHASH_MAP +from constants import ADDR_STYLES, ADDR_STYLES_SINGLE, SIGHASH_MAP, simulator_fixed_xfp, SIGHASH_MAP_NON_TAPROOT from txn import * from ctransaction import CTransaction, CTxOut, CTxIn, COutPoint from ckcc_protocol.constants import STXN_VISUALIZE, STXN_SIGNED @@ -40,7 +40,7 @@ def test_sign1(dev, finalize): #assert 'None of the keys' in str(ee) #assert 'require subpaths' in str(ee) - assert 'PSBT does not contain any key path information' in str(ee) + assert 'PSBT inputs do not contain any key path information' in str(ee) @pytest.mark.parametrize('fn', [ @@ -87,7 +87,7 @@ def test_psbt_parse_good(try_sign, fn, accept): assert ('Missing UTXO' in msg) \ or ('None of the keys' in msg) \ or ('completely signed already' in msg) \ - or ('PSBT does not contain any key path information' in msg) \ + or ('PSBT inputs do not contain any key path information' in msg) \ or ('require subpaths' in msg), msg @@ -119,22 +119,23 @@ def xxx_test_sign_truncated(dev): 'data/worked-combined.psbt', 'data/worked-7.psbt', ]) -def test_psbt_proxy_parsing(fn, sim_execfile, sim_exec): +def test_psbt_proxy_parsing(fn, sim_execfile, sim_exec, src_root_dir, sim_root_dir): # unit test: parsing by the psbt proxy object - sim_exec('import main; main.FILENAME = %r; ' % ('../../testing/'+fn)) + sim_exec('import main; main.FILENAME = %r; ' % (f'{src_root_dir}/testing/'+fn)) rv = sim_execfile('devtest/unit_psbt.py') assert not rv, rv - rb = '../unix/work/readback.psbt' + rb = f'{sim_root_dir}/readback.psbt' oo = BasicPSBT().parse(open(fn, 'rb').read()) rb = BasicPSBT().parse(open(rb, 'rb').read()) assert oo == rb @pytest.mark.unfinalized -@pytest.mark.parametrize("taproot", [True, False]) -def test_speed_test(dev, taproot, fake_txn, is_mark3, is_mark4, start_sign, end_sign, press_select): +@pytest.mark.parametrize("addr_fmt", ["p2tr", "p2wpkh"]) +def test_speed_test(dev, addr_fmt, fake_txn, is_mark3, is_mark4, start_sign, end_sign, + press_select, press_cancel, sim_root_dir): # measure time to sign a larger txn if is_mark4: # Mk4: expect @@ -149,12 +150,11 @@ def test_speed_test(dev, taproot, fake_txn, is_mark3, is_mark4, start_sign, end_ num_in = 9 num_out = 100 - if taproot: - psbt = fake_txn(num_in, num_out, dev.master_xpub, taproot_in=True) - else: - psbt = fake_txn(num_in, num_out, dev.master_xpub, segwit_in=True) + psbt = fake_txn(num_in, num_out, dev.master_xpub, addr_fmt=addr_fmt) + + with open(f'{sim_root_dir}/debug/speed.psbt', 'wb') as f: + f.write(psbt) - open('debug/speed.psbt', 'wb').write(psbt) dt = time.time() start_sign(psbt, finalize=False) @@ -172,6 +172,7 @@ def test_speed_test(dev, taproot, fake_txn, is_mark3, is_mark4, start_sign, end_ print(" Tx time: %.1f" % tx_time) print("Sign time: %.1f" % ready_time) + press_cancel() if 0: # TODO: attempt to re-create the mega transaction: 5,569 inputs, one out @@ -193,10 +194,9 @@ if 0: @pytest.mark.bitcoind @pytest.mark.veryslow -@pytest.mark.parametrize('segwit', [True, False]) -@pytest.mark.parametrize('taproot', [True, False]) -def test_io_size(request, use_regtest, decode_with_bitcoind, fake_txn, is_mark3, is_mark4, - start_sign, end_sign, dev, segwit, taproot, accept=True): +@pytest.mark.parametrize('addr_fmt', ["p2wpkh", "p2tr", "p2pkh"]) +def test_io_size(request, use_regtest, decode_with_bitcoind, fake_txn, + start_sign, end_sign, dev, addr_fmt, sim_root_dir): # try a bunch of different bigger sized txns # - important to test on real device, due to it's limited memory @@ -213,10 +213,11 @@ def test_io_size(request, use_regtest, decode_with_bitcoind, fake_txn, is_mark3, num_in = 250 num_out = 2000 - psbt = fake_txn(num_in, num_out, dev.master_xpub, segwit_in=segwit, - taproot_in=taproot, outstyles=ADDR_STYLES) + psbt = fake_txn(num_in, num_out, dev.master_xpub, addr_fmt=addr_fmt, + force_full_tx_utxo=True, supply_num_ins=10, supply_num_outs=10) - open('debug/last.psbt', 'wb').write(psbt) + with open(f'{sim_root_dir}/debug/last.psbt', 'wb') as f: + f.write(psbt) start_sign(psbt, finalize=True) @@ -229,9 +230,10 @@ def test_io_size(request, use_regtest, decode_with_bitcoind, fake_txn, is_mark3, except: cap_story = None - signed = end_sign(accept, finalize=True) + signed = end_sign(True, finalize=True) - open('debug/signed.txn', 'wb').write(signed) + with open(f'{sim_root_dir}/debug/signed.txn', 'wb') as f: + f.write(signed) decoded = decode_with_bitcoind(signed) @@ -266,15 +268,16 @@ def test_io_size(request, use_regtest, decode_with_bitcoind, fake_txn, is_mark3, @pytest.mark.bitcoind @pytest.mark.parametrize('num_ins', [ 2, 7, 15 ]) -@pytest.mark.parametrize('segwit', [True, False]) -@pytest.mark.parametrize('taproot', [True, False]) -def test_real_signing(fake_txn, use_regtest, try_sign, dev, num_ins, segwit,taproot, - decode_with_bitcoind): +def test_real_signing(fake_txn, use_regtest, try_sign, dev, num_ins, + decode_with_bitcoind, sim_root_dir): # create a TXN using actual addresses that are correct for DUT xp = dev.master_xpub - psbt = fake_txn(num_ins, 1, xp, segwit_in=segwit, taproot_in=taproot) - open('debug/real-%d.psbt' % num_ins, 'wb').write(psbt) + inputs = [["p2tr"] if i % 2 == 0 else ["p2wpkh"] for i in range(num_ins)] + + psbt = fake_txn(inputs, 1, xp) + with open(f'{sim_root_dir}/debug/real-%d.psbt' % num_ins, 'wb') as f: + f.write(psbt) _, txn = try_sign(psbt, accept=True, finalize=True) @@ -285,8 +288,7 @@ def test_real_signing(fake_txn, use_regtest, try_sign, dev, num_ins, segwit,tapr #pprint(decoded) assert len(decoded['vin']) == num_ins - if segwit: - assert all(x['txinwitness'] for x in decoded['vin']) + assert all(x['txinwitness'] for x in decoded['vin']) @pytest.mark.unfinalized # iff we_finalize=F @@ -294,7 +296,7 @@ def test_real_signing(fake_txn, use_regtest, try_sign, dev, num_ins, segwit,tapr @pytest.mark.parametrize('num_dests', [ 1, 10, 25 ]) @pytest.mark.bitcoind def test_vs_bitcoind(match_key, use_regtest, check_against_bitcoind, bitcoind, - start_sign, end_sign, we_finalize, num_dests): + start_sign, end_sign, we_finalize, num_dests, sim_root_dir): wallet_xfp = match_key use_regtest() @@ -350,7 +352,8 @@ def test_vs_bitcoind(match_key, use_regtest, check_against_bitcoind, bitcoind, fee = resp['fee'] chg_pos = resp['changepos'] - open('debug/vs.psbt', 'wb').write(psbt) + with open(f'{sim_root_dir}/debug/vs.psbt', 'wb') as f: + f.write(psbt) # check some basics mine = BasicPSBT().parse(psbt) @@ -372,14 +375,17 @@ def test_vs_bitcoind(match_key, use_regtest, check_against_bitcoind, bitcoind, assert mine.version == 2 signed = end_sign(accept=True, finalize=we_finalize) - open('debug/vs-signed.psbt', 'wb').write(signed) + with open(f'{sim_root_dir}/debug/vs-signed.psbt', 'wb') as f: + f.write(signed) if not we_finalize: b4 = BasicPSBT().parse(psbt) aft = BasicPSBT().parse(signed) assert b4 != aft, "signing didn't change anything?" - open('debug/signed.psbt', 'wb').write(signed) + with open(f'{sim_root_dir}/debug/signed.psbt', 'wb') as f: + f.write(signed) + resp = bitcoind.supply_wallet.finalizepsbt(str(b64encode(signed), 'ascii'), True) #combined_psbt = b64decode(resp['psbt']) @@ -391,7 +397,8 @@ def test_vs_bitcoind(match_key, use_regtest, check_against_bitcoind, bitcoind, # assert resp['complete'] print("Final txn: %r" % network) - open('debug/finalized-by-btcd.txn', 'wb').write(network) + with open(f'{sim_root_dir}/debug/finalized-by-btcd.txn', 'wb') as f: + f.write(network) # try to send it txed = bitcoind.supply_wallet.sendrawtransaction(B2A(network)) @@ -400,7 +407,8 @@ def test_vs_bitcoind(match_key, use_regtest, check_against_bitcoind, bitcoind, else: assert signed[0:4] != b'psbt', "expecting raw bitcoin txn" #print("Final txn: %s" % B2A(signed)) - open('debug/finalized-by-cc.txn', 'wb').write(signed) + with open(f'{sim_root_dir}/debug/finalized-by-cc.txn', 'wb') as f: + f.write(signed) txed = bitcoind.supply_wallet.sendrawtransaction(B2A(signed)) print("Final txn hash: %r" % txed) @@ -432,7 +440,7 @@ def test_sign_example(set_master_key, sim_execfile, start_sign, end_sign): @pytest.mark.bitcoind @pytest.mark.unfinalized -def test_sign_p2sh_p2wpkh(match_key, use_regtest, start_sign, end_sign, bitcoind): +def test_sign_p2sh_p2wpkh(match_key, use_regtest, start_sign, end_sign, bitcoind, sim_root_dir): # Check we can finalize p2sh_p2wpkh inputs right. # TODO fix this @@ -448,7 +456,8 @@ def test_sign_p2sh_p2wpkh(match_key, use_regtest, start_sign, end_sign, bitcoind start_sign(psbt, finalize=True) signed = end_sign(accept=True) #signed = end_sign(None) - open('debug/p2sh-signed.psbt', 'wb').write(signed) + with open(f'{sim_root_dir}/debug/p2sh-signed.psbt', 'wb') as f: + f.write(signed) #print('my finalization: ' + B2A(signed)) @@ -456,7 +465,9 @@ def test_sign_p2sh_p2wpkh(match_key, use_regtest, start_sign, end_sign, bitcoind signed_psbt = end_sign(accept=True) # use bitcoind to combine - open('debug/signed.psbt', 'wb').write(signed_psbt) + with open(f'{sim_root_dir}/debug/signed.psbt', 'wb') as f: + f.write(signed_psbt) + resp = bitcoind.rpc.finalizepsbt(str(b64encode(signed_psbt), 'ascii'), True) assert resp['complete'] == True, "bitcoind wasn't able to finalize it" @@ -469,7 +480,8 @@ def test_sign_p2sh_p2wpkh(match_key, use_regtest, start_sign, end_sign, bitcoind @pytest.mark.bitcoind @pytest.mark.unfinalized def test_sign_p2sh_example(set_master_key, use_regtest, sim_execfile, start_sign, end_sign, - decode_psbt_with_bitcoind, offer_ms_import, press_select, clear_ms): + decode_psbt_with_bitcoind, offer_minsc_import, press_select, clear_miniscript, + sim_root_dir): # Use the private key given in BIP 174 and do similar signing # as the examples. @@ -493,8 +505,8 @@ def test_sign_p2sh_example(set_master_key, use_regtest, sim_execfile, start_sign xfp = '4F6A0CD9' config += f'{xfp}: {n1}\n{xfp}: {n2}\n' - clear_ms() - offer_ms_import(config) + clear_miniscript() + offer_minsc_import(config) time.sleep(.1) press_select() @@ -510,7 +522,8 @@ def test_sign_p2sh_example(set_master_key, use_regtest, sim_execfile, start_sign start_sign(psbt) part_signed = end_sign(True) - open('debug/ex-signed-part.psbt', 'wb').write(part_signed) + with open(f'{sim_root_dir}/debug/ex-signed-part.psbt', 'wb') as f: + f.write(part_signed) b4 = BasicPSBT().parse(psbt) aft = BasicPSBT().parse(part_signed) @@ -520,7 +533,9 @@ def test_sign_p2sh_example(set_master_key, use_regtest, sim_execfile, start_sign start_sign(part_signed, finalize=False) signed = end_sign(True, finalize=False) - open('debug/ex-signed.psbt', 'wb').write(signed) + with open(f'{sim_root_dir}/debug/ex-signed.psbt', 'wb') as f: + f.write(signed) + aft2 = BasicPSBT().parse(signed) decode = decode_psbt_with_bitcoind(signed) @@ -548,7 +563,8 @@ def test_sign_p2sh_example(set_master_key, use_regtest, sim_execfile, start_sign @pytest.mark.bitcoind -def test_change_case(start_sign, use_regtest, end_sign, check_against_bitcoind, cap_story): +def test_change_case(start_sign, use_regtest, end_sign, check_against_bitcoind, cap_story, + sim_root_dir): # is change shown/hidden at right times. no fraud checks # NOTE: out#1 is change: @@ -568,7 +584,8 @@ def test_change_case(start_sign, use_regtest, end_sign, check_against_bitcoind, check_against_bitcoind(B2A(b4.txn), Decimal('0.00000294'), change_outs=[1,]) signed = end_sign(True) - open('debug/chg-signed.psbt', 'wb').write(signed) + with open(f'{sim_root_dir}/debug/chg-signed.psbt', 'wb') as f: + f.write(signed) # modify it: remove bip32 path b4.outputs[1].bip32_paths = {} @@ -587,14 +604,17 @@ def test_change_case(start_sign, use_regtest, end_sign, check_against_bitcoind, check_against_bitcoind(B2A(b4.txn), Decimal('0.00000294'), change_outs=[]) signed2 = end_sign(True) - open('debug/chg-signed2.psbt', 'wb').write(signed) + with open(f'{sim_root_dir}/debug/chg-signed2.psbt', 'wb') as f: + f.write(signed) + aft = BasicPSBT().parse(signed) aft2 = BasicPSBT().parse(signed2) assert aft.txn == aft2.txn @pytest.mark.parametrize('case', [ 1, 2]) @pytest.mark.bitcoind -def test_change_fraud_path(start_sign, use_regtest, end_sign, case, check_against_bitcoind, cap_story): +def test_change_fraud_path(start_sign, use_regtest, end_sign, case, check_against_bitcoind, + cap_story, sim_root_dir): # fraud: BIP-32 path of output doesn't lead to pubkey indicated # NOTE: out#1 is change: @@ -618,7 +638,8 @@ def test_change_fraud_path(start_sign, use_regtest, end_sign, case, check_agains b4.serialize(fd) mod_psbt = fd.getvalue() - open('debug/mod-%d.psbt' % case, 'wb').write(mod_psbt) + with open(f'{sim_root_dir}/debug/mod-%d.psbt' % case, 'wb') as f: + f.write(mod_psbt) if case == 1: start_sign(mod_psbt) @@ -637,7 +658,8 @@ def test_change_fraud_path(start_sign, use_regtest, end_sign, case, check_agains end_sign(True) @pytest.mark.bitcoind -def test_change_fraud_addr(start_sign, end_sign, use_regtest, check_against_bitcoind, cap_story): +def test_change_fraud_addr(start_sign, end_sign, use_regtest, check_against_bitcoind, cap_story, + sim_root_dir): # fraud: BIP-32 path of output doesn't match TXO address # NOTE: out#1 is change: #chg_addr = 'mvBGHpVtTyjmcfSsy6f715nbTGvwgbgbwo' @@ -659,24 +681,27 @@ def test_change_fraud_addr(start_sign, end_sign, use_regtest, check_against_bitc b4.serialize(fd) mod_psbt = fd.getvalue() - open('debug/mod-addr.psbt', 'wb').write(mod_psbt) + with open(f'{sim_root_dir}/debug/mod-addr.psbt', 'wb') as f: + f.write(mod_psbt) start_sign(mod_psbt) with pytest.raises(CCProtoError) as ee: signed = end_sign(True) - assert 'Change output is fraud' in str(ee) + assert 'p2pkh change output is fraud' in str(ee) @pytest.mark.parametrize('case', ['p2sh-p2wpkh', 'p2wpkh', 'p2sh', 'p2sh-p2pkh']) @pytest.mark.bitcoind def test_change_p2sh_p2wpkh(start_sign, end_sign, check_against_bitcoind, use_regtest, - cap_story, case): + cap_story, case, sim_root_dir): # not fraud: output address encoded in various equiv forms use_regtest() # NOTE: out#1 is change: #chg_addr = 'mvBGHpVtTyjmcfSsy6f715nbTGvwgbgbwo' - psbt = open('data/example-change.psbt', 'rb').read() + with open('data/example-change.psbt', 'rb') as f: + psbt = f.read() + b4 = BasicPSBT().parse(psbt) t = CTransaction() @@ -726,7 +751,8 @@ def test_change_p2sh_p2wpkh(start_sign, end_sign, check_against_bitcoind, use_re b4.serialize(fd) mod_psbt = fd.getvalue() - open('debug/mod-%s.psbt' % case, 'wb').write(mod_psbt) + with open(f'{sim_root_dir}/debug/mod-%s.psbt' % case, 'wb') as f: + f.write(mod_psbt) start_sign(mod_psbt) @@ -734,7 +760,7 @@ def test_change_p2sh_p2wpkh(start_sign, end_sign, check_against_bitcoind, use_re _, story = cap_story() if case in ["p2sh", "p2sh-p2pkh"]: - assert "Output#1: Change output is fraudulent" == story + assert f"Output#1: p2sh-p2wpkh change output is fraudulent" in story return check_against_bitcoind(B2A(b4.txn), Decimal('0.00000294'), change_outs=[1,], @@ -788,7 +814,7 @@ def test_wrong_p2sh_p2wpkh(bitcoind, start_sign, end_sign, bitcoind_d_sim_watch, try: fin = end_sign(True) except Exception as e: - assert "Change output is fraudulent" in e.args[0] + assert "p2sh-p2wpkh change output is fraudulent" in e.args[0] # this is the correct ending return @@ -823,7 +849,8 @@ def test_sign_multisig_partial_fail(start_sign, end_sign): assert 'None of the keys involved' in str(ee) @pytest.mark.unfinalized -def test_sign_wutxo(start_sign, set_seed_words, end_sign, cap_story, sim_exec, sim_execfile): +def test_sign_wutxo(start_sign, set_seed_words, end_sign, cap_story, sim_exec, sim_execfile, + sim_root_dir): # Example from SomberNight: we can sign it, but signature won't be accepted by # network because the PSBT lies about the UTXO amount and tries to give away to miners, @@ -846,7 +873,7 @@ def test_sign_wutxo(start_sign, set_seed_words, end_sign, cap_story, sim_exec, s assert 'Network fee 0.00000500 XTN' in story # check we understood it right - ex = dict( had_witness=False, num_inputs=1, num_outputs=1, sw_inputs=[None], + ex = dict( had_witness=False, num_inputs=1, num_outputs=1, sw_inputs=[False], miner_fee=500, warnings_expected=0, lock_time=1442308, total_value_out=99500, total_value_in=100000) @@ -858,11 +885,13 @@ def test_sign_wutxo(start_sign, set_seed_words, end_sign, cap_story, sim_exec, s signed = end_sign(True, finalize=fin) - open('debug/sn-signed.'+ ('txn' if fin else 'psbt'), 'wt').write(B2A(signed)) + with open(f'{sim_root_dir}/debug/sn-signed.'+ ('txn' if fin else 'psbt'), 'wt') as f: + f.write(B2A(signed)) @pytest.mark.parametrize('fee_max', [ 10, 25, 50]) @pytest.mark.parametrize('under', [ False, True]) -def test_network_fee_amts(fee_max, under, fake_txn, try_sign, start_sign, dev, settings_set, sim_exec, cap_story): +def test_network_fee_amts(fee_max, under, fake_txn, try_sign, start_sign, dev, settings_set, + sim_exec, cap_story, sim_root_dir): settings_set('fee_limit', fee_max) @@ -870,9 +899,10 @@ def test_network_fee_amts(fee_max, under, fake_txn, try_sign, start_sign, dev, s target = (fee_max - 2) if under else fee_max outval = int(1E8 / ((target/100.) + 1.)) - psbt = fake_txn(1, 1, dev.master_xpub, fee=None, outvals=[outval]) + psbt = fake_txn(1, [["p2pkh", outval]], dev.master_xpub, fee=0) - open('debug/fee.psbt', 'wb').write(psbt) + with open(f'{sim_root_dir}/debug/fee.psbt', 'wb') as f: + f.write(psbt) if not under: with pytest.raises(CCProtoError) as ee: @@ -891,16 +921,16 @@ def test_network_fee_amts(fee_max, under, fake_txn, try_sign, start_sign, dev, s settings_set('fee_limit', 10) -def test_network_fee_unlimited(fake_txn, start_sign, end_sign, dev, settings_set, cap_story): +def test_network_fee_unlimited(fake_txn, start_sign, end_sign, dev, settings_set, cap_story, + sim_root_dir): settings_set('fee_limit', -1) # creat a txn with single 1BTC input, and tiny one output; the rest is fee - outval = 100 + psbt = fake_txn(1, [["p2wpkh", 100]], dev.master_xpub) - psbt = fake_txn(1, 1, dev.master_xpub, fee=None, outvals=[outval]) - - open('debug/fee-un.psbt', 'wb').write(psbt) + with open(f'{sim_root_dir}/debug/fee-un.psbt', 'wb') as f: + f.write(psbt) # should be able to sign, but get warning start_sign(psbt, False) @@ -918,21 +948,21 @@ def test_network_fee_unlimited(fake_txn, start_sign, end_sign, dev, settings_set @pytest.mark.parametrize('num_outs', [ 2, 7, 15 ]) @pytest.mark.parametrize('act_outs', [ 2, 1, -1]) -@pytest.mark.parametrize('segwit', [True, False]) -@pytest.mark.parametrize('taproot', [True, False]) -@pytest.mark.parametrize('add_xpub', [True, False]) +# @pytest.mark.parametrize('add_xpub', [True, False]) # TODO create test and verify @pytest.mark.parametrize('out_style', ADDR_STYLES_SINGLE) @pytest.mark.parametrize('visualized', [0, STXN_VISUALIZE, STXN_VISUALIZE|STXN_SIGNED]) def test_change_outs(fake_txn, start_sign, end_sign, cap_story, dev, num_outs, master_xpub, - act_outs, segwit, taproot, out_style, visualized, add_xpub, num_ins=3): + act_outs, out_style, visualized, sim_root_dir): # create a TXN which has change outputs, which shouldn't be shown to user, and also not fail. + num_ins = 3 xp = dev.master_xpub couts = num_outs if act_outs == -1 else num_ins-act_outs - psbt = fake_txn(num_ins, num_outs, xp, segwit_in=segwit, taproot_in=taproot, - outstyles=[out_style], change_outputs=range(couts), add_xpub=add_xpub) + outs = [[out_style, None, True] for _ in range(couts)] + [[out_style] for _ in range(num_outs-couts)] + psbt = fake_txn(num_ins, outs, xp, addr_fmt=out_style) - open('debug/change.psbt', 'wb').write(psbt) + with open(f'{sim_root_dir}/debug/change.psbt', 'wb') as f: + f.write(psbt) # should be able to sign, but get warning if not visualized: @@ -978,8 +1008,12 @@ def test_change_outs(fake_txn, start_sign, end_sign, cap_story, dev, num_outs, m assert all((i[0] in 'mn') for i in addrs) elif out_style == 'p2wpkh': assert set(i[0:4] for i in addrs) == {'tb1q'} - elif out_style == 'p2wpkh-p2sh': + elif out_style in ('p2wpkh-p2sh', 'p2sh-p2wpkh'): assert set(i[0] for i in addrs) == {'2'} + else: + assert out_style == "p2tr" + assert set(i[0:4] for i in addrs) == {'tb1p'} + def KEEP_test_random_psbt(try_sign, sim_exec, fname="data/ .psbt"): # allow almost any PSBT to run on simulator, at least up until wrong pubkeys detected @@ -1008,7 +1042,8 @@ def KEEP_test_random_psbt(try_sign, sim_exec, fname="data/ .psbt"): @pytest.mark.bitcoind @pytest.mark.unfinalized @pytest.mark.parametrize('num_dests', [ 1, 10, 25 ]) -def test_finalization_vs_bitcoind(match_key, use_regtest, check_against_bitcoind, bitcoind, start_sign, end_sign, num_dests): +def test_finalization_vs_bitcoind(match_key, use_regtest, check_against_bitcoind, bitcoind, + start_sign, end_sign, num_dests, sim_root_dir): # Compare how we finalize vs bitcoind ... should be exactly the same txn wallet_xfp = match_key # has to be after match key @@ -1037,7 +1072,8 @@ def test_finalization_vs_bitcoind(match_key, use_regtest, check_against_bitcoind fee = resp['fee'] chg_pos = resp['changepos'] - open('debug/vs.psbt', 'wb').write(psbt) + with open(f'{sim_root_dir}/debug/vs.psbt', 'wb') as f: + f.write(psbt) # check some basics mine = BasicPSBT().parse(psbt) @@ -1060,13 +1096,15 @@ def test_finalization_vs_bitcoind(match_key, use_regtest, check_against_bitcoind signed_final = end_sign(accept=True, finalize=True) assert signed_final[0:4] != b'psbt', "expecting raw bitcoin txn" - open('debug/finalized-by-ckcc.txn', 'wt').write(B2A(signed_final)) + with open(f'{sim_root_dir}/debug/finalized-by-ckcc.txn', 'wt') as f: + f.write(B2A(signed_final)) # Sign again, but don't finalize it. start_sign(psbt, finalize=False) signed = end_sign(accept=True) - open('debug/vs-signed-unfin.psbt', 'wb').write(signed) + with open(f'{sim_root_dir}/debug/vs-signed-unfin.psbt', 'wb') as f: + f.write(signed) # Use bitcoind to finalize it this time. resp = bitcoind.supply_wallet.finalizepsbt(str(b64encode(signed), 'ascii'), True) @@ -1076,7 +1114,8 @@ def test_finalization_vs_bitcoind(match_key, use_regtest, check_against_bitcoind # assert resp['complete'] #print("Final txn: %r" % network) - open('debug/finalized-by-btcd.txn', 'wt').write(B2A(network)) + with open(f'{sim_root_dir}/debug/finalized-by-btcd.txn', 'wt') as f: + f.write(B2A(network)) assert network == signed_final, "Finalized differently" @@ -1098,7 +1137,7 @@ def test_finalization_vs_bitcoind(match_key, use_regtest, check_against_bitcoind # ("44'/1'/0'/3000/5", '2nd last component'), # ("44'/1'/0'/3/5", '2nd last component'), ]) -def test_change_troublesome(dev, start_sign, cap_story, try_path, expect): +def test_change_troublesome(dev, start_sign, cap_story, try_path, expect, sim_root_dir): # NOTE: out#1 is change: # addr = 'mvBGHpVtTyjmcfSsy6f715nbTGvwgbgbwo' # path = (m=4369050F)/44'/1'/0'/1/5 @@ -1122,7 +1161,8 @@ def test_change_troublesome(dev, start_sign, cap_story, try_path, expect): b4.serialize(fd) mod_psbt = fd.getvalue() - open('debug/troublesome.psbt', 'wb').write(mod_psbt) + with open(f'{sim_root_dir}/debug/troublesome.psbt', 'wb') as f: + f.write(mod_psbt) start_sign(mod_psbt) time.sleep(0.1) @@ -1207,46 +1247,61 @@ def spend_outputs(funding_psbt, finalized_txn, tweaker=None): with BytesIO() as rv: nn.serialize(rv) raw = rv.getvalue() - - open('debug/spend_outs.psbt', 'wb').write(raw) return nn, raw @pytest.fixture -def hist_count(sim_exec): +def history_data(sim_exec): def doit(): - return int(sim_exec( - 'import history; RV.write(str(len(history.OutptValueCache.runtime_cache)));')) + return eval(sim_exec( + 'import history; RV.write(str(history.OutptValueCache.runtime_cache));')) + return doit + +@pytest.fixture +def txid_from_export_prompt(cap_story, cap_screen_qr, cap_screen, need_keypress): + def doit(): + time.sleep(.1) + title, story = cap_story() + assert "(6) for QR Code of TXID" in story + need_keypress("6") + time.sleep(.1) + screen_txid = cap_screen().strip().replace("\n", "").replace("~", "") + qr_txid = cap_screen_qr().decode().strip().lower() + assert qr_txid == screen_txid + return qr_txid + return doit @pytest.mark.parametrize('num_utxo', [9, 100]) -@pytest.mark.parametrize('segwit_in', [False, True]) -@pytest.mark.parametrize('taproot_in', [False, True]) -def test_bip143_attack_data_capture(num_utxo, segwit_in, taproot_in, try_sign, fake_txn, +def test_bip143_attack_data_capture(num_utxo, try_sign, fake_txn, press_cancel, settings_set, settings_get, cap_story, sim_exec, - hist_count): + history_data, txid_from_export_prompt, sim_root_dir): # cleanup prev runs, if very first time thru sim_exec('import history; history.OutptValueCache.clear()') - hist_b4 = hist_count() - assert hist_b4 == 0 + assert len(history_data()) == 0 # make a txn, capture the outputs of that as inputs for another txn - psbt = fake_txn(1, num_utxo+3, segwit_in=segwit_in, change_outputs=range(num_utxo+2), - taproot_in=taproot_in, - outstyles=(['p2wpkh']*num_utxo) + ['p2wpkh-p2sh', 'p2pkh']) - _, txn = try_sign(psbt, accept=True, finalize=True) + outputs = [] + for i in range(num_utxo): + if i: + # change + outputs.append(["p2wpkh", None, True]) + else: + outputs.append(["p2pkh", None, True]) - open('debug/funding.psbt', 'wb').write(psbt) + psbt = fake_txn(1, outputs, addr_fmt="p2wpkh") + _, txn = try_sign(psbt, accept=True, finalize=True, exit_export_loop=False) - num_inp_utxo = (1 if (segwit_in or taproot_in) else 0) + with open(f'{sim_root_dir}/debug/funding.psbt', 'wb') as f: + f.write(psbt) - time.sleep(.1) - title, story = cap_story() - assert 'TXID' in title, story - txid = story.strip().split()[0] + txid = txid_from_export_prompt() + press_cancel() + press_cancel() - assert hist_count() in {128, hist_b4+num_utxo+num_inp_utxo} + curr = history_data() + assert len(curr) in {128, num_utxo} t = CTransaction() t.deserialize(BytesIO(txn)) @@ -1255,12 +1310,14 @@ def test_bip143_attack_data_capture(num_utxo, segwit_in, taproot_in, try_sign, f # expect all of new "change outputs" to be recorded (none of the non-segwit change tho) # plus the one input we "revealed" after1 = settings_get('ovc') - assert len(after1) == min(30, num_utxo + num_inp_utxo) + assert len(after1) == min(30, num_utxo) - all_utxo = hist_count() - assert all_utxo == hist_b4+num_utxo+num_inp_utxo + all_utxo = history_data() + assert len(all_utxo) == num_utxo # build a new PSBT based on those change outputs psbt2, raw = spend_outputs(psbt, txn) + with open(f'{sim_root_dir}/debug/spend_outs.psbt', 'wb') as f: + f.write(raw) # try to sign that ... should work fine try_sign(raw, accept=True, finalize=True) @@ -1276,56 +1333,51 @@ def test_bip143_attack_data_capture(num_utxo, segwit_in, taproot_in, try_sign, f spendables[0][1].nValue += amt psbt3, raw = spend_outputs(psbt, txn, tweaker=value_tweak) + with open(f'{sim_root_dir}/debug/spend_outs.psbt', 'wb') as f: + f.write(raw) with pytest.raises(CCProtoError) as ee: orig, result = try_sign(raw, accept=True, finalize=True) assert 'but PSBT claims' in str(ee), ee -@pytest.mark.parametrize('segwit', [False, True]) -@pytest.mark.parametrize('taproot', [False, True]) +@pytest.mark.parametrize('addr_fmt', ADDR_STYLES_SINGLE) @pytest.mark.parametrize('num_ins', [1, 17]) @pytest.mark.parametrize('num_outs', [1, 17]) -def test_txid_calc(num_ins, fake_txn, try_sign, dev, segwit, decode_with_bitcoind, - cap_story, taproot, num_outs): +def test_txid_calc(num_ins, fake_txn, try_sign, dev, decode_with_bitcoind, cap_story, + txid_from_export_prompt, press_cancel, num_outs, addr_fmt): # verify correct txid for transactions is being calculated xp = dev.master_xpub - psbt = fake_txn(num_ins, num_outs, xp, segwit_in=segwit, taproot_in=taproot) + psbt = fake_txn(num_ins, num_outs, xp, addr_fmt=addr_fmt) - _, txn = try_sign(psbt, accept=True, finalize=True) + _, txn = try_sign(psbt, accept=True, finalize=True, exit_export_loop=False) + txid = txid_from_export_prompt() + press_cancel() # exit QR + press_cancel() # exit re-export loop - #print('Signed; ' + B2A(txn)) + t = CTransaction() + t.deserialize(BytesIO(txn)) + assert t.txid().hex() == txid - time.sleep(.1) - title, story = cap_story() - assert '0' in story - assert 'TXID' in title, story - txid = story.strip().split()[0] + # compare to bitcoin core + decoded = decode_with_bitcoind(txn) + pprint(decoded) - if 1: - t = CTransaction() - t.deserialize(BytesIO(txn)) - assert t.txid().hex() == txid + assert len(decoded['vin']) == num_ins + if "w" in addr_fmt: + assert all(x['txinwitness'] for x in decoded['vin']) + assert decoded['txid'] == txid - if 1: - # compare to bitcoin core - decoded = decode_with_bitcoind(txn) - pprint(decoded) - - assert len(decoded['vin']) == num_ins - if segwit: - assert all(x['txinwitness'] for x in decoded['vin']) - - assert decoded['txid'] == txid @pytest.mark.unfinalized # iff partial=1 +@pytest.mark.reexport @pytest.mark.parametrize('encoding', ['binary', 'hex', 'base64']) -#@pytest.mark.parametrize('num_outs', [1,2,3,4,5,6,7,8]) @pytest.mark.parametrize('num_outs', [1,15]) @pytest.mark.parametrize('del_after', [1, 0]) @pytest.mark.parametrize('partial', [1, 0]) -def test_sdcard_signing(encoding, num_outs, del_after, partial, try_sign_microsd, fake_txn, try_sign, dev, settings_set): +def test_sdcard_signing(encoding, num_outs, del_after, partial, try_sign_microsd, fake_txn, + dev, settings_set, signing_artifacts_reexport): # exercise the txn encode/decode from sdcard xp = dev.master_xpub @@ -1338,15 +1390,22 @@ def test_sdcard_signing(encoding, num_outs, del_after, partial, try_sign_microsd pp = psbt.inputs[0].bip32_paths[pk] psbt.inputs[0].bip32_paths[pk] = b'what' + pp[4:] - psbt = fake_txn(3, num_outs, xp, segwit_in=True, taproot_in=True, psbt_hacker=hack) + psbt = fake_txn([["p2pkh"], ["p2wpkh"], ["p2tr"]], num_outs, xp, psbt_hacker=hack) _, txn, txid = try_sign_microsd(psbt, finalize=not partial, - encoding=encoding, del_after=del_after) + encoding=encoding, del_after=del_after) + _psbt, _txn = signing_artifacts_reexport("sd", tx_final=not partial, txid=txid, + encoding=encoding, del_after=del_after) + if partial: + assert _psbt == txn + else: + assert _txn == txn @pytest.mark.unfinalized @pytest.mark.parametrize('num_ins', [2,3,8]) @pytest.mark.parametrize('num_outs', [1,2,8]) -def test_payjoin_signing(num_ins, num_outs, fake_txn, try_sign, start_sign, end_sign, cap_story): +def test_payjoin_signing(num_ins, num_outs, fake_txn, try_sign, start_sign, end_sign, + cap_story, sim_root_dir): # Try to simulate a PSBT that might be involved in a Payjoin (BIP-78 txn) @@ -1354,9 +1413,10 @@ def test_payjoin_signing(num_ins, num_outs, fake_txn, try_sign, start_sign, end_ # change an input to be "not ours" ... but with utxo details psbt.inputs[num_ins-1].bip32_paths.clear() - psbt = fake_txn(num_ins, num_outs, segwit_in=True, psbt_hacker=hack) + psbt = fake_txn(num_ins, num_outs, addr_fmt="p2wpkh", psbt_hacker=hack) - open('debug/payjoin.psbt', 'wb').write(psbt) + with open(f'{sim_root_dir}/debug/payjoin.psbt', 'wb') as f: + f.write(psbt) ip = start_sign(psbt, finalize=False) time.sleep(.1) @@ -1364,14 +1424,14 @@ def test_payjoin_signing(num_ins, num_outs, fake_txn, try_sign, start_sign, end_ assert 'warning below' in story assert 'Limited Signing' in story - assert 'because we do not know the key' in story + assert "don't know the key" in story + assert "different wallet" in story assert ': %s' % (num_ins-1) in story txn = end_sign(True, finalize=False) -@pytest.mark.parametrize('segwit', [False, True]) -@pytest.mark.parametrize('taproot', [False, True]) -def test_fully_unsigned(fake_txn, try_sign, segwit, taproot): +@pytest.mark.parametrize('addr_fmt', ["p2wpkh", "p2tr"]) +def test_fully_unsigned(fake_txn, try_sign, addr_fmt): # A PSBT which is unsigned but all inputs lack keypaths @@ -1381,16 +1441,15 @@ def test_fully_unsigned(fake_txn, try_sign, segwit, taproot): i.bip32_paths.clear() i.taproot_bip32_paths.clear() - psbt = fake_txn(7, 2, segwit_in=segwit, taproot_in=taproot, psbt_hacker=hack) + psbt = fake_txn(7, 2, addr_fmt=addr_fmt, psbt_hacker=hack) with pytest.raises(CCProtoError) as ee: orig, result = try_sign(psbt, accept=True) - assert 'does not contain any key path information' in str(ee) + assert 'PSBT inputs do not contain any key path information' in str(ee) -@pytest.mark.parametrize('segwit', [False, True]) -@pytest.mark.parametrize('taproot', [False, True]) -def test_wrong_xfp(fake_txn, try_sign, segwit, taproot): +@pytest.mark.parametrize('addr_fmt', ["p2wpkh", "p2tr"]) +def test_wrong_xfp(fake_txn, try_sign, addr_fmt): # A PSBT which is unsigned and doesn't involve our XFP value @@ -1404,17 +1463,16 @@ def test_wrong_xfp(fake_txn, try_sign, segwit, taproot): for xonly_pubkey in i.taproot_bip32_paths: i.taproot_bip32_paths[xonly_pubkey] = b"\x00" + wrong_xfp + i.taproot_bip32_paths[xonly_pubkey][5:] - psbt = fake_txn(7, 2, segwit_in=segwit, taproot_in=taproot, psbt_hacker=hack) + psbt = fake_txn(7, 2, addr_fmt=addr_fmt, psbt_hacker=hack) with pytest.raises(CCProtoError) as ee: orig, result = try_sign(psbt, accept=True) assert 'None of the keys' in str(ee) - assert 'found 12345678' in str(ee) + assert 'need 0F056943' in str(ee) -@pytest.mark.parametrize('segwit', [False, True]) -@pytest.mark.parametrize('taproot', [False, True]) -def test_wrong_xfp_multi(fake_txn, try_sign, segwit, taproot): +@pytest.mark.parametrize('addr_fmt', ["p2wpkh", "p2tr"]) +def test_wrong_xfp_multi(fake_txn, try_sign, addr_fmt, sim_root_dir): # A PSBT which is unsigned and doesn't involve our XFP value # - but multiple wrong XFP values @@ -1433,9 +1491,11 @@ def test_wrong_xfp_multi(fake_txn, try_sign, segwit, taproot): i.taproot_bip32_paths[xonly_pubkey] = b"\x00" + here + i.taproot_bip32_paths[xonly_pubkey][5:] wrongs.add(xfp2str(idx + 73)) - psbt = fake_txn(7, 2, segwit_in=segwit, taproot_in=taproot, psbt_hacker=hack) + psbt = fake_txn(7, 2, addr_fmt=addr_fmt, psbt_hacker=hack) + + with open(f'{sim_root_dir}/debug/wrong-xfp.psbt', 'wb') as f: + f.write(psbt) - open('debug/wrong-xfp.psbt', 'wb').write(psbt) with pytest.raises(CCProtoError) as ee: orig, result = try_sign(psbt, accept=True) @@ -1443,23 +1503,21 @@ def test_wrong_xfp_multi(fake_txn, try_sign, segwit, taproot): pass else: assert 'None of the keys' in str(ee) - # WEAK: device keeps them in order, but that's chance/impl defined... - assert 'found '+', '.join(sorted(wrongs)) in str(ee) + assert "need 0F056943" in str(ee) + @pytest.mark.parametrize('out_style', ADDR_STYLES_SINGLE) -@pytest.mark.parametrize('segwit', [False, True]) -@pytest.mark.parametrize('taproot', [False, True]) @pytest.mark.parametrize('outval', ['.5', '.788888', '0.92640866']) -def test_render_outs(out_style, segwit, outval, fake_txn, start_sign, end_sign, dev, taproot): +def test_render_outs(out_style, outval, fake_txn, start_sign, end_sign, dev, sim_root_dir): # check how we render the value of outputs # - works on simulator and connected USB real-device - xp = dev.master_xpub oi = int(Decimal(outval) * int(1E8)) - psbt = fake_txn(1, 2, dev.master_xpub, segwit_in=segwit, outvals=[oi, int(1E8-oi)], - taproot_in=taproot, outstyles=[out_style], change_outputs=[1]) + psbt = fake_txn(1, [[out_style, oi],[out_style, int(1E8 -oi), True]], dev.master_xpub, + addr_fmt="p2wpkh") - open('debug/render.psbt', 'wb').write(psbt) + with open(f'{sim_root_dir}/debug/render.psbt', 'wb') as f: + f.write(psbt) # should be able to sign, but get warning @@ -1497,7 +1555,7 @@ def test_render_outs(out_style, segwit, outval, fake_txn, start_sign, end_sign, def test_negative_fee(dev, fake_txn, try_sign): # Silly to sign a psbt the network won't accept, but anyway... with pytest.raises(CCProtoError) as ee: - psbt = fake_txn(1, 1, dev.master_xpub, outvals=[int(2E8)]) + psbt = fake_txn(1, [["p2pkh", int(2E8)]], dev.master_xpub) orig, result = try_sign(psbt, accept=False) msg = ee.value.args[0] @@ -1508,30 +1566,33 @@ def test_negative_fee(dev, fake_txn, try_sign): ( 5, 'mXTN'), ( 2, 'bits'), ( 0, 'sats')]) -def test_value_render(dev, units, fake_txn, start_sign, cap_story, settings_set, settings_remove): +def test_value_render(dev, units, fake_txn, start_sign, cap_story, settings_set, + settings_remove, sim_root_dir): # Check we are rendering values in right units. decimal, units = units settings_set('rz', decimal) - outputs = [int(i) for i in [ + outputs = [[random.choice(ADDR_STYLES_SINGLE), int(i)] for i in [ 10E8, 3E8, 1.2345678E8, 1, 12, 123, 123456, 1234567, 12345678, 123456789012, ]] - need = sum(outputs) - psbt = fake_txn(1, len(outputs), dev.master_xpub, segwit_in=True, outvals=outputs, invals=[need]) + need = sum([r[1] for r in outputs]) + psbt = fake_txn(1, outputs, dev.master_xpub, + input_amount=need) - open('debug/values.psbt', 'wb').write(psbt) + with open(f'{sim_root_dir}/debug/values.psbt', 'wb') as f: + f.write(psbt) ip = start_sign(psbt, finalize=False) time.sleep(.1) _, story = cap_story() lines = story.split('\n') - for v in outputs: + for af, v in outputs: div = int(10**decimal) #expect = '%d %s' % ((v//div), units) if decimal == 0: @@ -1547,41 +1608,41 @@ def test_value_render(dev, units, fake_txn, start_sign, cap_story, settings_set, @pytest.mark.qrcode @pytest.mark.parametrize('num_in', [1,2,3]) @pytest.mark.parametrize('num_out', [1,2,3]) -def test_qr_txn(num_in, num_out, request, fake_txn, try_sign, dev, cap_screen_qr, qr_quality_check, cap_story, need_keypress): - segwit=True +@pytest.mark.parametrize('addr_fmt', ["p2wpkh", "p2tr"]) +def test_qr_txn(num_in, num_out, addr_fmt, fake_txn, try_sign, dev, cap_screen_qr, + qr_quality_check, cap_story, need_keypress, is_q1, press_cancel, sim_root_dir): - psbt = fake_txn(num_in, num_out, dev.master_xpub, segwit_in=False) + psbt = fake_txn(num_in, num_out, dev.master_xpub, addr_fmt=addr_fmt) - - _, txn = try_sign(psbt, accept=True, finalize=True) - open('debug/last.txn', 'wb').write(txn) - - print("txn len = %d bytes" % len(txn)) + _, txn = try_sign(psbt, accept=True, finalize=True, exit_export_loop=False) + with open(f'{sim_root_dir}/debug/last.txn', 'wb') as f: + f.write(txn) title, story = cap_story() - assert 'QR Code' in story + assert '(6) for QR Code of TXID' in story - if 1: - # check TXID qr code - need_keypress('1') + # check TXID qr code + need_keypress('6') + qr = cap_screen_qr().decode() + press_cancel() - qr = cap_screen_qr().decode() + t = CTransaction() + t.deserialize(BytesIO(txn)) + assert t.txid().hex() == qr.lower() - t = CTransaction() - t.deserialize(BytesIO(txn)) - assert t.txid().hex() == qr.lower() - - else: - # TODO: QR for txn itself yet - need_keypress('2') + if is_q1: + need_keypress(KEY_QR) qr = cap_screen_qr().decode() assert qr.lower() == txn.hex() + press_cancel() + + press_cancel() def test_missing_keypaths(dev, try_sign, fake_txn): # make valid psbt - psbt = fake_txn(3, 1, dev.master_xpub, segwit_in=False) + psbt = fake_txn(3, 1, dev.master_xpub, addr_fmt="p2pkh") # strip keypaths oo = BasicPSBT().parse(psbt) @@ -1596,12 +1657,12 @@ def test_missing_keypaths(dev, try_sign, fake_txn): orig, result = try_sign(mod_psbt, accept=False) msg = ee.value.args[0] - assert ('does not contain any key path information' in msg) + assert ('PSBT inputs do not contain any key path information' in msg) def test_wrong_pubkey(dev, try_sign, fake_txn): # psbt input gives a pubkey+subkey path, but that pubkey doesn't map to utxo pubkey - psbt = fake_txn(1, 1, dev.master_xpub, segwit_in=False) + psbt = fake_txn(1, 1, dev.master_xpub, addr_fmt="p2pkh") # tweak the pubkey of first input oo = BasicPSBT().parse(psbt) @@ -1628,7 +1689,7 @@ def test_wrong_pubkey(dev, try_sign, fake_txn): def test_incomplete_signing(dev, try_sign, fake_txn, cap_story): # psbt where we only sign one input # - must not allow finalization - psbt = fake_txn(3, 1, dev.master_xpub, segwit_in=False) + psbt = fake_txn(3, 1, dev.master_xpub, addr_fmt="p2pkh") oo = BasicPSBT().parse(psbt) oo.inputs[1].bip32_paths = { k: b'\x01\x02\x03\x04'+v[4:] @@ -1648,7 +1709,8 @@ def test_incomplete_signing(dev, try_sign, fake_txn, cap_story): def test_zero_xfp(dev, start_sign, end_sign, fake_txn, cap_story): # will sign PSBT with zero values for XFP in ins and outs - psbt = fake_txn(2, 3, dev.master_xpub, segwit_in=False, change_outputs=[1,2]) + psbt = fake_txn(2, [["p2pkh", None],["p2pkh", None, True],["p2pkh", None, True]], + dev.master_xpub, addr_fmt="p2pkh") oo = BasicPSBT().parse(psbt) for i in oo.inputs: @@ -1669,12 +1731,12 @@ def test_zero_xfp(dev, start_sign, end_sign, fake_txn, cap_story): assert 'Zero XFP' in story # and then signing should work. - signed = end_sign(True, finalize=True) + end_sign(True, finalize=True) -@pytest.mark.parametrize("segwit_in", [True, False]) +@pytest.mark.parametrize("addr_fmt", ["p2pkh", "p2wpkh"]) @pytest.mark.parametrize('num_not_ours', [1, 3, 4]) -def test_foreign_utxo_missing(segwit_in, num_not_ours, dev, fake_txn, start_sign, +def test_foreign_utxo_missing(addr_fmt, num_not_ours, dev, fake_txn, start_sign, cap_story, end_sign): def hack(psbt): # change first input to not be ours @@ -1686,29 +1748,29 @@ def test_foreign_utxo_missing(segwit_in, num_not_ours, dev, fake_txn, start_sign psbt.inputs[i].utxo = None psbt.inputs[i].witness_utxo = None - psbt = fake_txn(5, 2, dev.master_xpub, segwit_in=segwit_in, psbt_hacker=hack) + psbt = fake_txn(5, 2, dev.master_xpub, addr_fmt=addr_fmt, psbt_hacker=hack) start_sign(psbt) time.sleep(.1) _, story = cap_story() no = ", ".join(str(i) for i in list(range(num_not_ours))) assert "warnings" in story - assert f"Limited Signing: We are not signing these inputs, because we do not know the key: {no}" in story + assert f"Limited Signing:" in story + assert f": {no}" in story assert f"Unable to calculate fee: Some input(s) haven't provided UTXO(s): {no}" in story signed = end_sign(accept=True) assert signed != psbt -@pytest.mark.parametrize("segwit_in", [True, False]) -@pytest.mark.parametrize("taproot_in", [True, False]) +@pytest.mark.parametrize("addr_fmt", ["p2pkh", "p2wpkh", "p2tr"]) @pytest.mark.parametrize("num_missing", [1, 3, 4]) -def test_own_utxo_missing(segwit_in, num_missing, dev, fake_txn, start_sign, cap_story, end_sign, - press_cancel, taproot_in): +def test_own_utxo_missing(num_missing, dev, fake_txn, start_sign, cap_story, end_sign, + press_cancel, addr_fmt): def hack(psbt): for i in range(num_missing): # no utxo provided for our input psbt.inputs[i].utxo = None psbt.inputs[i].witness_utxo = None - psbt = fake_txn(5, 2, dev.master_xpub, segwit_in=segwit_in, taproot_in=taproot_in, psbt_hacker=hack) + psbt = fake_txn(5, 2, dev.master_xpub, addr_fmt=addr_fmt, psbt_hacker=hack) start_sign(psbt) time.sleep(.1) title, story = cap_story() @@ -1736,8 +1798,9 @@ def test_bitcoind_missing_foreign_utxo(bitcoind, bitcoind_d_sim_watch, microsd_p tap_dave_addr = tap_dave.getnewaddress("", "bech32m") # fund all addresses for addr in (alice_addr, bob_addr, cc_addr, tap_dave_addr): - bitcoind.supply_wallet.sendtoaddress(addr, 2) + bitcoind.supply_wallet.sendtoaddress(addr, 2.0) + # mine above sends bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) psbt_list = [] @@ -1745,6 +1808,7 @@ def test_bitcoind_missing_foreign_utxo(bitcoind, bitcoind_d_sim_watch, microsd_p assert w.listunspent() psbt = w.walletcreatefundedpsbt([], [{dest_address: 1.0}], 0, {"fee_rate": 20})["psbt"] psbt_list.append(psbt) + # join PSBTs to one the_psbt = bitcoind.supply_wallet.joinpsbts(psbt_list) the_psbt_obj = BasicPSBT().parse(the_psbt.encode()) @@ -1779,6 +1843,10 @@ def test_bitcoind_missing_foreign_utxo(bitcoind, bitcoind_d_sim_watch, microsd_p @pytest.mark.bitcoind @pytest.mark.parametrize("op_return_data", [ + 81 * b"a", + 255 * b"b", # biggest possible with PUSHDATA1 + 256 * b"c", # PUSHDATA2 + 4000 * b"d", # PUSHDATA2 b"Coldcard is the best signing device", # to test with both pushdata opcodes b"Coldcard, the best signing deviceaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", # len 80 max b"\x80" * 80, @@ -1787,29 +1855,54 @@ def test_bitcoind_missing_foreign_utxo(bitcoind, bitcoind_d_sim_watch, microsd_p b"$$$$$$$$$$$$$$ Bitcoin", b"\xeb\x97\xf7\xb7\xf78\x9a';\x90F_\xfc\xe2b\xa4\x93)\xea\xac\xacR\xff\x9c\xbe\x1c\xf1\xad\xe9!\xee\xd9t1\x1f\x92\x83\x97\xb3\x98/\xff\xc8\xff\xc1\xc0\xdd\x1et\x00L\x13\xe0\xe3\x90\xe4\xd4\xf2x:\xf7Ab\x04\x91\x1e\xa8R\x92\xd3\x96OK\xc6I\x06\x9e\xce=\xb3", ]) -def test_op_return_signing(op_return_data, dev, fake_txn, bitcoind_d_sim_watch, bitcoind, start_sign, end_sign, cap_story): +def test_op_return_signing(op_return_data, dev, fake_txn, bitcoind_d_sim_watch, bitcoind, + start_sign, end_sign, cap_story): cc = bitcoind_d_sim_watch dest_address = cc.getnewaddress() - bitcoind.supply_wallet.sendtoaddress(dest_address, 49) + bitcoind.supply_wallet.sendtoaddress(dest_address, 2) bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) psbt = cc.walletcreatefundedpsbt([], [{dest_address: 1.0}, {"data": op_return_data.hex()}], 0, {"fee_rate": 20})["psbt"] - start_sign(base64.b64decode(psbt)) + start_sign(base64.b64decode(psbt), finalize=True) time.sleep(.1) title, story = cap_story() assert title == "OK TO SEND?" # in older implementations, one would see a warning for OP_RETURN --> not now - assert "warning" not in story + if len(op_return_data) > 80: + assert "(1 warning below)" in story # looking for warning at the top + assert "OP_RETURN > 80 bytes" in story + else: + assert "warning" not in story + assert "OP_RETURN" in story + assert "Multiple OP_RETURN outputs:" not in story # always just one - core restriction + try: - expect = op_return_data.decode("ascii") + assert len(op_return_data) <= 160 + try: + expect = op_return_data.decode("ascii") + except: + # not ascii + expect = op_return_data.hex() except: expect = binascii.hexlify(op_return_data).decode() + expect = expect[:160] + "\n ⋯\n" + expect[-160:] + assert expect in story - signed = end_sign(accept=True) - tx = cc.finalizepsbt(base64.b64encode(signed).decode())["hex"] - assert cc.testmempoolaccept([tx])[0]["allowed"] is True - tx_id = cc.sendrawtransaction(tx) - assert isinstance(tx_id, str) and len(tx_id) == 64 + tx = end_sign(accept=True, finalize=True).hex() + + # tx is final at this point and consensus valid + # tx = cc.finalizepsbt(base64.b64encode(signed).decode())["hex"] + res = cc.testmempoolaccept([tx])[0] + + if (bitcoind.version < 300000) and (len(op_return_data) > 80): + # policy + assert res["allowed"] is False + assert res["reject-reason"] == "scriptpubkey" + else: + assert res["allowed"] is True + tx_id = cc.sendrawtransaction(tx) + assert isinstance(tx_id, str) and len(tx_id) == 64 + @pytest.mark.parametrize("unknowns", [ # tuples (unknown_global, unknown_ins, unknown_outs) @@ -1821,7 +1914,7 @@ def test_op_return_signing(op_return_data, dev, fake_txn, bitcoind_d_sim_watch, ({b"x" * 64: b"y" * 128}, {b"q" * 64: b"p" * 128}, {b"w" * 90: b"z" * 256}), ({b"x" * 32: b"y" * 256}, {b"q" * 32: b"p" * 256, b"f" * 15: 32 * b"\x01"}, {b"w": b"z"}), ]) -def test_unknow_values_in_psbt(unknowns, dev, start_sign, end_sign, fake_txn): +def test_unknow_values_in_psbt(unknowns, dev, start_sign, end_sign, fake_txn, sim_root_dir): unknown_global, unknown_ins, unknown_outs = unknowns def hack(psbt): psbt.unknown = unknown_global @@ -1830,8 +1923,9 @@ def test_unknow_values_in_psbt(unknowns, dev, start_sign, end_sign, fake_txn): for o in psbt.outputs: o.unknown = unknown_outs - psbt = fake_txn(5, 5, dev.master_xpub, segwit_in=True, psbt_hacker=hack) - open('debug/last.psbt', 'wb').write(psbt) + psbt = fake_txn(5, 5, dev.master_xpub, addr_fmt="p2wpkh", psbt_hacker=hack) + with open(f'{sim_root_dir}/debug/last.psbt', 'wb') as f: + f.write(psbt) psbt_o = BasicPSBT().parse(psbt) assert psbt_o.unknown == unknown_global for inp in psbt_o.inputs: @@ -1848,7 +1942,7 @@ def test_unknow_values_in_psbt(unknowns, dev, start_sign, end_sign, fake_txn): for out in res.outputs: assert out.unknown == unknown_outs -def test_read_write_prop_attestation_keys(try_sign, fake_txn): +def test_read_write_prop_attestation_keys(try_sign, fake_txn, sim_root_dir): from psbt import ser_prop_key, PSBT_PROP_CK_ID def attach_attest_to_outs(psbt): for idx, o in enumerate(psbt.outputs): @@ -1857,7 +1951,8 @@ def test_read_write_prop_attestation_keys(try_sign, fake_txn): o.proprietary[key] = value psbt = fake_txn(2, 2, psbt_hacker=attach_attest_to_outs) - open('debug/propkeys.psbt', 'wb').write(psbt) + with open(f'{sim_root_dir}/debug/propkeys.psbt', 'wb') as f: + f.write(psbt) orig, signed = try_sign(psbt) res = BasicPSBT().parse(signed) @@ -1871,7 +1966,7 @@ def test_duplicate_unknow_values_in_psbt(dev, start_sign, end_sign, fake_txn): # duplicate keys for global unknowns def hack(psbt): psbt.unknown = [(b"xxx", 32 * b"\x00"), (b"xxx", 32 * b"\x01")] - psbt = fake_txn(5, 5, dev.master_xpub, segwit_in=True, psbt_hacker=hack) + psbt = fake_txn(5, 5, dev.master_xpub, addr_fmt="p2wpkh", psbt_hacker=hack) start_sign(psbt) with pytest.raises(Exception): end_sign() @@ -1880,7 +1975,7 @@ def test_duplicate_unknow_values_in_psbt(dev, start_sign, end_sign, fake_txn): def hack(psbt): for i in psbt.inputs: i.unknown = [(b"xxx", 32 * b"\x00"), (b"xxx", 32 * b"\x01")] - psbt = fake_txn(5, 5, dev.master_xpub, segwit_in=True, psbt_hacker=hack) + psbt = fake_txn(5, 5, dev.master_xpub, addr_fmt="p2pkh", psbt_hacker=hack) start_sign(psbt) with pytest.raises(Exception): end_sign() @@ -1889,7 +1984,7 @@ def test_duplicate_unknow_values_in_psbt(dev, start_sign, end_sign, fake_txn): def hack(psbt): for o in psbt.outputs: o.unknown = [(b"xxx", 32 * b"\x00"), (b"xxx", 32 * b"\x01")] - psbt = fake_txn(5, 5, dev.master_xpub, segwit_in=True, psbt_hacker=hack) + psbt = fake_txn(5, 5, dev.master_xpub, addr_fmt="p2tr", psbt_hacker=hack) start_sign(psbt) with pytest.raises(Exception): end_sign() @@ -1897,12 +1992,19 @@ def test_duplicate_unknow_values_in_psbt(dev, start_sign, end_sign, fake_txn): @pytest.fixture def _test_single_sig_sighash(cap_story, press_select, start_sign, end_sign, dev, - bitcoind, bitcoind_d_dev_watch, settings_set, finalize_v2_v0_convert): + bitcoind, bitcoind_d_dev_watch, settings_set, + finalize_v2_v0_convert, pytestconfig, sim_root_dir): def doit(addr_fmt, sighash, num_inputs=2, num_outputs=2, consolidation=False, sh_checks=False, - psbt_v2=False): + psbt_v2=None, tx_check=True): from decimal import Decimal, ROUND_DOWN + if psbt_v2 is None: + # anything passed directly to this function overrides + # pytest flag --psbt2 - only care about pytest flag + # if psbt_v2 is not specified (None) + psbt_v2 = pytestconfig.getoption('psbt2') + if dev.is_simulator: # if running against real HW you need to set CC to correct sighshchk mode # Below test need to run with sighshchk disabled: @@ -1916,9 +2018,10 @@ def _test_single_sig_sighash(cap_story, press_select, start_sign, end_sign, dev, settings_set("sighshchk", int(not sh_checks)) - not_all_ALL = any(sh != "ALL" for sh in sighash) + not_all_ALL = any(sh not in ["ALL", "DEFAULT"] for sh in sighash) - stranger = bitcoind.create_wallet(f"{os.urandom(10).hex()}") + # this is needed as supply wallet is still legacy bitcoind wallet (no tr support) + dest_wal = bitcoind.create_wallet("dest_wal") bitcoind_d_dev_watch.keypoolrefill(num_inputs + num_outputs) input_val = bitcoind.supply_wallet.getbalance() / num_inputs @@ -1938,7 +2041,7 @@ def _test_single_sig_sighash(cap_story, press_select, start_sign, end_sign, dev, unspent = bitcoind_d_dev_watch.listunspent() output_val = bitcoind_d_dev_watch.getbalance() / num_outputs # consolidation or not? - dest_wal = bitcoind_d_dev_watch if consolidation else stranger # using stranger here as supply+wallet is legacy and has no tr addresses + dest_wal = bitcoind_d_dev_watch if consolidation else dest_wal destinations = [ {dest_wal.getnewaddress("", addr_fmt): Decimal(output_val).quantize(Decimal('.0000001'), rounding=ROUND_DOWN)} for _ in range(num_outputs) @@ -1967,8 +2070,9 @@ def _test_single_sig_sighash(cap_story, press_select, start_sign, end_sign, dev, psbt_sh = x.as_b64_str() # make useful reference psbt along the way - open(f'debug/sighash-{sighash[0] if len(sighash) == 1 else "MIX"}.psbt'\ - .replace('|', '-'), 'wt').write(psbt_sh) + with open(f'{sim_root_dir}/debug/sighash-{sighash[0] if len(sighash) == 1 else "MIX"}.psbt'\ + .replace('|', '-'), 'wt') as f: + f.write(psbt_sh) # get story out of CC via visualize feature start_sign(psbt_sh_bytes, False, stxn_flags=STXN_VISUALIZE) @@ -1978,7 +2082,7 @@ def _test_single_sig_sighash(cap_story, press_select, start_sign, end_sign, dev, with pytest.raises(Exception) as e: end_sign(accept=None, expect_txn=False).decode() # assert title == "Failure" - assert "Only sighash ALL is allowed for pure consolidation transaction" in e.value.args[0] + assert "Only sighash ALL/DEFAULT is allowed for pure consolidation transaction" in e.value.args[0] return elif not consolidation and any("NONE" in sh for sh in sighash if isinstance(sh, str)): @@ -1996,7 +2100,7 @@ def _test_single_sig_sighash(cap_story, press_select, start_sign, end_sign, dev, assert "---WARNING---" in story assert "Danger" in story assert "Destination address can be changed after signing (sighash NONE)." in story - elif any(sh != "ALL" for sh in sighash): + elif any(sh not in ["ALL", "DEFAULT"] for sh in sighash): assert "(1 warning below)" in story assert "---WARNING---" in story assert "Caution" in story @@ -2022,6 +2126,11 @@ def _test_single_sig_sighash(cap_story, press_select, start_sign, end_sign, dev, target = sighash[0] sh_num = SIGHASH_MAP[target] if target == "ALL": + if addr_fmt == "bech32m": + assert i.sighash == sh_num + else: + assert i.sighash is None + elif target == "DEFAULT": assert i.sighash is None else: assert i.sighash == sh_num @@ -2029,6 +2138,11 @@ def _test_single_sig_sighash(cap_story, press_select, start_sign, end_sign, dev, target = sighash[idx] sh_num = SIGHASH_MAP[target] if target == "ALL": + if addr_fmt == "bech32m": + assert i.sighash == sh_num + else: + assert i.sighash is None + elif target == "DEFAULT": assert i.sighash is None else: assert i.sighash == sh_num @@ -2041,13 +2155,15 @@ def _test_single_sig_sighash(cap_story, press_select, start_sign, end_sign, dev, assert resp["complete"] is True tx_hex = resp["hex"] - # sign again - this time get finalized tx ready for broadcast out - start_sign(psbt_sh_bytes, finalize=True) - cc_tx_hex = end_sign(accept=True, finalize=True).hex() - if addr_fmt != "bech32m": - # schnorr signatures are not deterministic - # any subsequent sign will produce different witness - assert tx_hex == cc_tx_hex + if tx_check: + # sign and get finalized tx ready for broadcast out + start_sign(psbt_sh_bytes, finalize=True) + cc_tx_hex = end_sign(accept=True, finalize=True) + cc_tx_hex = cc_tx_hex.hex() + if addr_fmt != "bech32m": + # schnorr signatures are not deterministic + # any subsequent sign will produce different witness + assert tx_hex == cc_tx_hex if psbt_v2: # check txn_modifiable properly set @@ -2080,42 +2196,51 @@ def _test_single_sig_sighash(cap_story, press_select, start_sign, end_sign, dev, return doit +# TODO Sighash test MUST be run with --psbt2 flag on and off +# pytest test_sign.py -k sighash {--psbt2,} @pytest.mark.bitcoind @pytest.mark.parametrize("addr_fmt", ["legacy", "p2sh-segwit", "bech32", "bech32m"]) -@pytest.mark.parametrize("sighash", [sh for sh in SIGHASH_MAP if sh != 'ALL']) -@pytest.mark.parametrize("num_outs", [1, 3, 5]) -@pytest.mark.parametrize("num_ins", [2, 5]) -@pytest.mark.parametrize("psbt_v2", [True, False]) -def test_sighash_same(addr_fmt, sighash, num_ins, num_outs, psbt_v2, _test_single_sig_sighash): +@pytest.mark.parametrize("sighash", [sh for sh in SIGHASH_MAP if sh not in ['ALL', 'DEFAULT']]) +def test_sighash_same(addr_fmt, sighash, _test_single_sig_sighash): # sighash is the same among all inputs - _test_single_sig_sighash(addr_fmt, [sighash], num_inputs=num_ins, num_outputs=num_outs, - psbt_v2=psbt_v2) + _test_single_sig_sighash(addr_fmt, [sighash], num_inputs=4, num_outputs=2) @pytest.mark.bitcoind -@pytest.mark.parametrize("addr_fmt", ["legacy", "p2sh-segwit", "bech32", "bech32m"]) -@pytest.mark.parametrize("sighash", list(itertools.combinations(SIGHASH_MAP.keys(), 2))) -@pytest.mark.parametrize("num_outs", [2, 3, 5]) -@pytest.mark.parametrize("psbt_v2", [True, False]) -def test_sighash_different(addr_fmt, sighash, num_outs, psbt_v2, _test_single_sig_sighash): +@pytest.mark.parametrize("addr_fmt", ["legacy", "p2sh-segwit", "bech32"]) +@pytest.mark.parametrize("sighash", list(itertools.combinations(SIGHASH_MAP_NON_TAPROOT.keys(), 2))) +def test_sighash_different(addr_fmt, sighash, _test_single_sig_sighash): # sighash differ among all inputs - _test_single_sig_sighash(addr_fmt, sighash, num_inputs=2, num_outputs=num_outs, - psbt_v2=psbt_v2) + _test_single_sig_sighash(addr_fmt, sighash, num_inputs=2, num_outputs=5) + + +@pytest.mark.bitcoind +@pytest.mark.parametrize("sighash", [ + ('ALL', 'DEFAULT', 'NONE'), ('ALL', 'DEFAULT', 'SINGLE'), ('ALL', 'DEFAULT', 'ALL|ANYONECANPAY'), + ('DEFAULT', 'ALL', 'NONE|ANYONECANPAY'), ('DEFAULT', 'ALL', 'SINGLE|ANYONECANPAY') +]) +@pytest.mark.parametrize("num_outs", [1, 5]) +def test_sighash_different_taproot(sighash, num_outs, _test_single_sig_sighash): + # sighash differ among all inputs + _test_single_sig_sighash("bech32m", sighash, num_inputs=3, num_outputs=num_outs) @pytest.mark.bitcoind @pytest.mark.parametrize("addr_fmt", ["legacy", "p2sh-segwit", "bech32", "bech32m"]) -@pytest.mark.parametrize("num_outs", [5, 8]) -@pytest.mark.parametrize("psbt_v2", [True, False]) -def test_sighash_fullmix(addr_fmt, num_outs, psbt_v2, _test_single_sig_sighash): +def test_sighash_fullmix(addr_fmt, _test_single_sig_sighash): # tx with 6 inputs representing all possible sighashes - _test_single_sig_sighash(addr_fmt, tuple(SIGHASH_MAP.keys()), num_inputs=6, - num_outputs=num_outs, psbt_v2=psbt_v2) + _test_single_sig_sighash(addr_fmt, tuple(SIGHASH_MAP_NON_TAPROOT.keys()), num_inputs=6, num_outputs=8) @pytest.mark.bitcoind -@pytest.mark.parametrize("sighash", [sh for sh in SIGHASH_MAP if sh != 'ALL']) +def test_sighash_fullmix_taproot(_test_single_sig_sighash): + # tx with 6 inputs representing all possible sighashes + _test_single_sig_sighash("bech32m", tuple(SIGHASH_MAP.keys()), num_inputs=7, num_outputs=5) + + +@pytest.mark.bitcoind +@pytest.mark.parametrize("sighash", [sh for sh in SIGHASH_MAP if sh not in ['ALL', 'DEFAULT']]) def test_sighash_disallowed_consolidation(sighash, _test_single_sig_sighash): # sighash != ALL blocked for pure consolidations _test_single_sig_sighash("bech32", [sighash], num_inputs=2, num_outputs=2, @@ -2124,10 +2249,11 @@ def test_sighash_disallowed_consolidation(sighash, _test_single_sig_sighash): @pytest.mark.bitcoind @pytest.mark.parametrize("sighash", ["NONE", "NONE|ANYONECANPAY"]) -def test_sighash_disallowed_NONE(sighash, _test_single_sig_sighash): +@pytest.mark.parametrize("num_outs", [1, 3]) +def test_sighash_disallowed_NONE(sighash, num_outs, _test_single_sig_sighash): # sighash is the same among all inputs - _test_single_sig_sighash("bech32", [sighash], num_inputs=2, num_outputs=2, - consolidation=False, sh_checks=True) + _test_single_sig_sighash("bech32", [sighash], num_inputs=2, + num_outputs=num_outs, consolidation=False, sh_checks=True) @pytest.mark.bitcoind @@ -2163,19 +2289,25 @@ def test_no_outputs_tx(fake_txn, microsd_path, goto_home, press_select, pick_men try: os.remove(fpath) except: pass - -def test_send2taproot_addresss(fake_txn , start_sign, end_sign, cap_story, use_testnet): +@pytest.mark.parametrize("num_unknown", [1,3]) +def test_send2unknown_script(fake_txn , start_sign, end_sign, cap_story, use_testnet, num_unknown): use_testnet() - psbt = fake_txn(2, 2, segwit_in=True, change_outputs=[0], outstyles=["p2tr"]) + unknowns = ["unknown"] * num_unknown + num_out = 2 if num_unknown == 1 else 4 + + # OP_CHECKLOCKTIMEVERIFY OP_DROP OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG + hex_str = "049f7b2a5cb17576a914371c20fb2e9899338ce5e99908e64fd30b78931388ac" + + outs = [["p2tr", None, True] if not i else ["unknown", None, False, hex_str] for i in range(num_out)] + psbt = fake_txn(2, outs, addr_fmt="p2tr") start_sign(psbt) title, story = cap_story() assert title == "OK TO SEND?" # we do not understand change in taproot (taproot not supported) + assert "(1 warning below)" in story # unknown script + assert ("Sending to %d not well understood script(s)" % num_unknown) in story assert "Consolidating" not in story - assert "Change back" in story - # but we should show address - assert "to script" not in story - assert "tb1p" in story + assert "to script" in story signed = end_sign(accept=True, finalize=False) assert signed @@ -2191,7 +2323,7 @@ def test_batch_sign(num_tx, ui_path, action, fake_txn, need_keypress, microsd_wipe() for i in range(num_tx): - psbt = fake_txn(2, 2, segwit_in=random.getrandbits(1)) + psbt = fake_txn(2, 2, addr_fmt=random.choice(["p2tr", "p2wpkh", "p2pkh"])) with open(microsd_path(f"{i}.psbt"), "wb") as f: f.write(psbt) @@ -2243,7 +2375,7 @@ def test_batch_sign(num_tx, ui_path, action, fake_txn, need_keypress, time.sleep(.5) title, story = cap_story() assert "-signed.psbt" in story - press_select() + press_cancel() time.sleep(.5) title, story = cap_story() @@ -2283,12 +2415,9 @@ def test_v2_psbt_bip370_invalid(desc_psbt_hex, start_sign, cap_story): @pytest.mark.bitcoind @pytest.mark.parametrize("outstyle", ADDR_STYLES_SINGLE) -@pytest.mark.parametrize("segwit_in", [True, False]) -@pytest.mark.parametrize("wrapped_segwit_in", [True, False]) -def test_psbt_v2(outstyle, segwit_in, wrapped_segwit_in, fake_txn , start_sign, end_sign, cap_story, +def test_psbt_v2(outstyle, fake_txn , start_sign, end_sign, cap_story, microsd_path, bitcoind, finalize_v2_v0_convert): - psbt = fake_txn(2, 2, segwit_in=segwit_in, wrapped=wrapped_segwit_in, change_outputs=[0], - outstyles=[outstyle], psbt_v2=True) + psbt = fake_txn(2, [[outstyle, None, True], [outstyle]], addr_fmt=outstyle, psbt_v2=True) start_sign(psbt) title, story = cap_story() @@ -2317,8 +2446,7 @@ def test_psbt_v2(outstyle, segwit_in, wrapped_segwit_in, fake_txn , start_sign, assert resp["complete"] is True def test_psbt_v2_tx_modifiable_parse(fake_txn, start_sign, end_sign): - psbt = fake_txn(2, 2, segwit_in=True, wrapped=True, - change_outputs=[0], psbt_v2=True) + psbt = fake_txn(2, [["p2tr", None, True],["p2wpkh"]], addr_fmt="p2tr", psbt_v2=True) p = BasicPSBT().parse(psbt) # 3 = both inputs and outputs are modifiable # need just some value instead of None, in that case flag is ommited @@ -2352,9 +2480,8 @@ def test_psbt_v2_global_quantities(way, fake_txn, start_sign, end_sign, cap_stor psbt.output_count = actual_len_o + 1 - psbt = fake_txn(2, 2, segwit_in=True, wrapped=True, change_outputs=[0], - outstyles=["p2pkh", "p2wpkh"], psbt_v2=True, - psbt_hacker=lambda psbt: hacker(psbt, way)) + psbt = fake_txn(2, [["p2pkh", None, True],["p2wpkh"]], addr_fmt="p2sh-p2wpkh", + psbt_v2=True, psbt_hacker=lambda psbt: hacker(psbt, way)) start_sign(psbt) title, story = cap_story() @@ -2373,7 +2500,7 @@ def test_psbt_v2_global_quantities(way, fake_txn, start_sign, end_sign, cap_stor ]) def test_locktime_ux(use_regtest, bitcoind_d_sim_watch, start_sign, end_sign, microsd_path, cap_story, goto_home, press_select, - pick_menu_item, bitcoind, locktime): + pick_menu_item, bitcoind, locktime, file_tx_signing_done): use_regtest() sim = bitcoind_d_sim_watch addr = sim.getnewaddress() @@ -2402,12 +2529,15 @@ def test_locktime_ux(use_regtest, bitcoind_d_sim_watch, start_sign, end_sign, psbt_fname = "locktime.psbt" with open(microsd_path(psbt_fname), "w") as f: f.write(psbt) + goto_home() pick_menu_item('Ready To Sign') time.sleep(0.1) - pick_menu_item(psbt_fname) - time.sleep(0.1) title, story = cap_story() + if 'OK TO SEND' not in title: + pick_menu_item(psbt_fname) + time.sleep(0.1) + title, story = cap_story() assert "WARNING" not in story if locktime != 0: @@ -2426,18 +2556,10 @@ def test_locktime_ux(use_regtest, bitcoind_d_sim_watch, start_sign, end_sign, press_select() # confirm signing time.sleep(0.1) title, story = cap_story() - assert title == 'PSBT Signed' assert "Updated PSBT is:" in story assert "Finalized transaction (ready for broadcast)" in story assert "TXID" in story - split_story = story.split("\n\n") - story_txid = split_story[-1].split("\n")[-1] - signed_psbt_fname = split_story[1] - with open(microsd_path(signed_psbt_fname), "r") as f: - signed_psbt = f.read().strip() - signed_txn_fname = split_story[3] - with open(microsd_path(signed_txn_fname), "r") as f: - signed_txn = f.read().strip() + signed_psbt, signed_txn, story_txid = file_tx_signing_done(story) assert signed_psbt != psbt finalize_res = sim.finalizepsbt(signed_psbt) bitcoind_signed_txn = finalize_res["hex"] @@ -2462,7 +2584,7 @@ def test_locktime_ux(use_regtest, bitcoind_d_sim_watch, start_sign, end_sign, def test_nsequence_blockheight_relative_locktime_ux(sequence, use_regtest, bitcoind_d_sim_watch, start_sign, end_sign, microsd_path, cap_story, goto_home, press_select, pick_menu_item, - bitcoind, num_ins, differ): + bitcoind, num_ins, differ, file_tx_signing_done): if differ and (sequence == 0): # this case makes no sense return @@ -2511,12 +2633,15 @@ def test_nsequence_blockheight_relative_locktime_ux(sequence, use_regtest, bitco psbt_fname = "rtl-blockheight.psbt" with open(microsd_path(psbt_fname), "w") as f: f.write(psbt) + goto_home() pick_menu_item('Ready To Sign') time.sleep(0.1) - pick_menu_item(psbt_fname) - time.sleep(0.1) title, story = cap_story() + if 'OK TO SEND' not in title: + pick_menu_item(psbt_fname) + time.sleep(0.1) + title, story = cap_story() assert "WARNING" not in story if sequence: @@ -2538,18 +2663,11 @@ def test_nsequence_blockheight_relative_locktime_ux(sequence, use_regtest, bitco press_select() # confirm signing time.sleep(0.1) title, story = cap_story() - assert title == 'PSBT Signed' assert "Updated PSBT is:" in story assert "Finalized transaction (ready for broadcast)" in story assert "TXID" in story - split_story = story.split("\n\n") - story_txid = split_story[-1].split("\n")[-1] - signed_psbt_fname = split_story[1] - with open(microsd_path(signed_psbt_fname), "r") as f: - signed_psbt = f.read().strip() - signed_txn_fname = split_story[3] - with open(microsd_path(signed_txn_fname), "r") as f: - signed_txn = f.read().strip() + press_select() # exit saved story + signed_psbt, signed_txn, story_txid = file_tx_signing_done(story) assert signed_psbt != psbt finalize_res = sim.finalizepsbt(signed_psbt) bitcoind_signed_txn = finalize_res["hex"] @@ -2574,13 +2692,13 @@ def test_nsequence_blockheight_relative_locktime_ux(sequence, use_regtest, bitco @pytest.mark.bitcoind -@pytest.mark.veryslow @pytest.mark.parametrize("num_ins", [1, 4, 11]) @pytest.mark.parametrize("differ", [True, False]) -@pytest.mark.parametrize("seconds", [512, 10000, 1000000, 33554431]) +@pytest.mark.parametrize("seconds", [512, 10240, 1024000, 33554431]) def test_nsequence_timebased_relative_locktime_ux(seconds, use_regtest, bitcoind_d_sim_watch, start_sign, microsd_path, cap_story, goto_home, press_select, - pick_menu_item, bitcoind, end_sign, num_ins, differ): + pick_menu_item, bitcoind, end_sign, num_ins, differ, + file_tx_signing_done): sequence = SEQUENCE_LOCKTIME_TYPE_FLAG | (seconds >> 9) use_regtest() sim = bitcoind_d_sim_watch @@ -2598,18 +2716,22 @@ def test_nsequence_timebased_relative_locktime_ux(seconds, use_regtest, bitcoind ins = [] num_ins_locked = 0 + locked_indexes = [] for i, utxo in enumerate(utxos): # time-based RTL - if i and differ: - nSeq = sequence - (sequence * i) + if i and differ and (seconds > 512): + secs = seconds // i + nSeq = SEQUENCE_LOCKTIME_TYPE_FLAG | (secs >> 9) if nSeq < 0: nSeq = 0 else: + secs = seconds nSeq = sequence if nSeq > 0: num_ins_locked += 1 + locked_indexes.append((i, secs)) inp = { "txid": utxo["txid"], @@ -2623,12 +2745,15 @@ def test_nsequence_timebased_relative_locktime_ux(seconds, use_regtest, bitcoind psbt_fname = "rtl-time.psbt" with open(microsd_path(psbt_fname), "w") as f: f.write(psbt) + goto_home() - pick_menu_item('Ready To Sign') - time.sleep(0.1) - pick_menu_item(psbt_fname) + pick_menu_item("Ready To Sign") time.sleep(0.1) title, story = cap_story() + if 'OK TO SEND' not in title: + pick_menu_item(psbt_fname) + time.sleep(0.1) + title, story = cap_story() assert "WARNING" not in story assert "TX LOCKTIMES" in story @@ -2638,9 +2763,9 @@ def test_nsequence_timebased_relative_locktime_ux(seconds, use_regtest, bitcoind if num_ins_locked == 1: assert ("has " + base_msg) in story else: - if differ: + if differ and (seconds > 512): assert ("%d inputs have relative time-based timelock." % num_ins_locked) in story - for i in range(num_ins_locked): + for i, _ in sorted(locked_indexes, key=lambda i: i[1], reverse=True)[:10]: assert ("%d. " % i) in story else: msg1 = "%d inputs have " % num_ins_locked @@ -2649,18 +2774,10 @@ def test_nsequence_timebased_relative_locktime_ux(seconds, use_regtest, bitcoind press_select() # confirm signing time.sleep(0.1) title, story = cap_story() - assert title == 'PSBT Signed' assert "Updated PSBT is:" in story assert "Finalized transaction (ready for broadcast)" in story assert "TXID" in story - split_story = story.split("\n\n") - story_txid = split_story[-1].split("\n")[-1] - signed_psbt_fname = split_story[1] - with open(microsd_path(signed_psbt_fname), "r") as f: - signed_psbt = f.read().strip() - signed_txn_fname = split_story[3] - with open(microsd_path(signed_txn_fname), "r") as f: - signed_txn = f.read().strip() + signed_psbt, signed_txn, story_txid = file_tx_signing_done(story) assert signed_psbt != psbt finalize_res = sim.finalizepsbt(signed_psbt) bitcoind_signed_txn = finalize_res["hex"] @@ -2685,13 +2802,13 @@ def test_nsequence_timebased_relative_locktime_ux(seconds, use_regtest, bitcoind assert txid == story_txid -@pytest.mark.bitcoind @pytest.mark.veryslow +@pytest.mark.bitcoind @pytest.mark.parametrize("abs_lock", [True, False]) -@pytest.mark.parametrize("num_rtl", [(2,3),(4,7),(8,3),(6,7)]) -def test_mixed_locktimes(num_rtl, use_regtest, bitcoind_d_sim_watch, start_sign, - microsd_path, cap_story, goto_home, press_select, - pick_menu_item, bitcoind, end_sign, abs_lock): +@pytest.mark.parametrize("num_rtl", [(2,3),(4,7),(6,7)]) +def test_mixed_locktimes(num_rtl, use_regtest, bitcoind_d_sim_watch, start_sign, microsd_path, + cap_story, goto_home, press_select, pick_menu_item, bitcoind, end_sign, + abs_lock, file_tx_signing_done): tb, bb = num_rtl num_ins = tb + bb sequence = SEQUENCE_LOCKTIME_TYPE_FLAG | (512 >> 9) @@ -2739,9 +2856,11 @@ def test_mixed_locktimes(num_rtl, use_regtest, bitcoind_d_sim_watch, start_sign, goto_home() pick_menu_item('Ready To Sign') time.sleep(0.1) - pick_menu_item(psbt_fname) - time.sleep(0.1) title, story = cap_story() + if 'OK TO SEND' not in title: + pick_menu_item(psbt_fname) + time.sleep(0.1) + title, story = cap_story() assert "WARNING" not in story assert "TX LOCKTIMES" in story @@ -2762,18 +2881,10 @@ def test_mixed_locktimes(num_rtl, use_regtest, bitcoind_d_sim_watch, start_sign, press_select() # confirm signing time.sleep(0.1) title, story = cap_story() - assert title == 'PSBT Signed' assert "Updated PSBT is:" in story assert "Finalized transaction (ready for broadcast)" in story assert "TXID" in story - split_story = story.split("\n\n") - story_txid = split_story[-1].split("\n")[-1] - signed_psbt_fname = split_story[1] - with open(microsd_path(signed_psbt_fname), "r") as f: - signed_psbt = f.read().strip() - signed_txn_fname = split_story[3] - with open(microsd_path(signed_txn_fname), "r") as f: - signed_txn = f.read().strip() + signed_psbt, signed_txn, story_txid = file_tx_signing_done(story) assert signed_psbt != psbt finalize_res = sim.finalizepsbt(signed_psbt) bitcoind_signed_txn = finalize_res["hex"] @@ -2826,65 +2937,65 @@ def random_nLockTime_test_cases(num=10): *random_nLockTime_test_cases() ]) def test_timelocks_visualize(start_sign, end_sign, dev, bitcoind, use_regtest, - bitcoind_d_sim_watch, nLockTime): - # - works on simulator and connected USB real-device - nLockTime, expect_ux = nLockTime - num_ins = 10 - use_regtest() - bitcoind_d_sim_watch.keypoolrefill(20) - for i in range(num_ins): - addr = bitcoind_d_sim_watch.getnewaddress() - bitcoind.supply_wallet.sendtoaddress(addr, 1) + bitcoind_d_sim_watch, nLockTime, sim_root_dir): + # - works on simulator and connected USB real-device + nLockTime, expect_ux = nLockTime + num_ins = 10 + use_regtest() + bitcoind_d_sim_watch.keypoolrefill(20) + for i in range(num_ins): + addr = bitcoind_d_sim_watch.getnewaddress() + bitcoind.supply_wallet.sendtoaddress(addr, 1) - bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) - dest_addr = bitcoind_d_sim_watch.getnewaddress() # self-spend - utxos = bitcoind_d_sim_watch.listunspent() - assert len(utxos) == num_ins + bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) + dest_addr = bitcoind_d_sim_watch.getnewaddress() # self-spend + utxos = bitcoind_d_sim_watch.listunspent() + assert len(utxos) == num_ins - ins = [] - for i, utxo in enumerate(utxos): - if i % 2 == 0: - nSeq = (SEQUENCE_LOCKTIME_TYPE_FLAG | i) - else: - confirmations = utxo["confirmations"] - nSeq = confirmations + (20*i) + ins = [] + for i, utxo in enumerate(utxos): + if i % 2 == 0: + nSeq = (SEQUENCE_LOCKTIME_TYPE_FLAG | i) + else: + confirmations = utxo["confirmations"] + nSeq = confirmations + (20*i) - inp = { - "txid": utxo["txid"], - "vout": utxo["vout"], - "sequence": nSeq, - } - ins.append(inp) + inp = { + "txid": utxo["txid"], + "vout": utxo["vout"], + "sequence": nSeq, + } + ins.append(inp) - psbt_resp = bitcoind_d_sim_watch.walletcreatefundedpsbt( - ins, [{dest_addr: (num_ins - 0.1)}], - nLockTime, {"fee_rate": 20} - ) - psbt = base64.b64decode(psbt_resp.get("psbt")) + psbt_resp = bitcoind_d_sim_watch.walletcreatefundedpsbt( + ins, [{dest_addr: (num_ins - 0.1)}], + nLockTime, {"fee_rate": 20} + ) + psbt = base64.b64decode(psbt_resp.get("psbt")) - open('debug/locktimes.psbt', 'wb').write(psbt) + with open(f'{sim_root_dir}/debug/locktimes.psbt', 'wb') as f: + f.write(psbt) - # should be able to sign, but get warning + # should be able to sign, but get warning - # use new feature to have Coldcard return the 'visualization' of transaction - start_sign(psbt, False, stxn_flags=STXN_VISUALIZE) - story = end_sign(accept=None, expect_txn=False) + # use new feature to have Coldcard return the 'visualization' of transaction + start_sign(psbt, False, stxn_flags=STXN_VISUALIZE) + story = end_sign(accept=None, expect_txn=False) - story = story.decode('ascii') - assert datetime.datetime.utcfromtimestamp(nLockTime).strftime("%Y-%m-%d %H:%M:%S") == expect_ux - assert f"Abs Locktime: This tx can only be spent after {expect_ux} UTC (MTP)" in story - assert "Block height RTL: 5 inputs have relative block height timelock" in story - # when i=0 in loop time based RTL is zero - assert "Time-based RTL: 4 inputs have relative time-based timelock" in story + story = story.decode('ascii') + assert datetime.datetime.utcfromtimestamp(nLockTime).strftime("%Y-%m-%d %H:%M:%S") == expect_ux + assert f"Abs Locktime: This tx can only be spent after {expect_ux} UTC (MTP)" in story + assert "Block height RTL: 5 inputs have relative block height timelock" in story + # when i=0 in loop time based RTL is zero + assert "Time-based RTL: 4 inputs have relative time-based timelock" in story @pytest.mark.parametrize('in_out', [(4,1),(2,2),(2,1)]) @pytest.mark.parametrize('partial', [False, True]) -@pytest.mark.parametrize('segwit', [True, False]) -def test_base64_psbt_qr(in_out, partial, segwit, scan_a_qr, readback_bbqr, +def test_base64_psbt_qr(in_out, partial, scan_a_qr, readback_bbqr, goto_home, use_regtest, cap_story, fake_txn, dev, decode_psbt_with_bitcoind, decode_with_bitcoind, - press_cancel, press_select, need_keypress): + press_cancel, press_select, need_keypress, sim_root_dir): def hack(psbt): if partial: # change first input to not be ours @@ -2894,15 +3005,12 @@ def test_base64_psbt_qr(in_out, partial, segwit, scan_a_qr, readback_bbqr, num_in, num_out = in_out - if not segwit: - psbt = fake_txn(num_in, num_out, dev.master_xpub, psbt_hacker=hack) - else: - psbt = fake_txn(num_in, num_out, dev.master_xpub, psbt_hacker=hack, - segwit_in=True, outstyles=['p2wpkh']) + psbt = fake_txn(num_in, num_out, dev.master_xpub, addr_fmt="p2wpkh", psbt_hacker=hack) psbt = base64.b64encode(psbt).decode() - open('debug/last.psbt', 'w').write(psbt) + with open(f'{sim_root_dir}/debug/last.psbt', 'w') as f: + f.write(psbt) goto_home() need_keypress(KEY_QR) @@ -2958,8 +3066,7 @@ def test_sorting_outputs_by_size(fake_txn, start_sign, cap_story, use_testnet, 9000000, 179989995, 11000000, 12000000, 13000000, 14000000, 15000000] max_display_num = 10 rest_num = len(out_vals) - max_display_num - psbt = fake_txn(3, 15, segwit_in=True, outstyles=ADDR_STYLES_SINGLE, - outvals=out_vals) + psbt = fake_txn(3, [[random.choice(ADDR_STYLES_SINGLE), i] for i in out_vals], addr_fmt="p2wpkh") start_sign(psbt) time.sleep(.1) title, story = cap_story() @@ -2983,7 +3090,6 @@ def test_sorting_outputs_by_size(fake_txn, start_sign, cap_story, use_testnet, press_cancel() -@pytest.mark.parametrize("psbtv2", [True, False]) @pytest.mark.parametrize("chain", ["BTC", "XTN"]) @pytest.mark.parametrize("data", [ # (out_style, amount, is_change) @@ -2993,41 +3099,48 @@ def test_sorting_outputs_by_size(fake_txn, start_sign, cap_story, use_testnet, [("p2pkh", 1000000, 1)] * 11 + [("p2wpkh", 50000000, 0)] * 16, [("p2pkh", 1000000, 1), ("p2wpkh", 50000000, 0), ("p2wpkh-p2sh", 800000, 1), ("p2tr", 100000, 0)] * 11, ]) -def test_txout_explorer(psbtv2, chain, data, fake_txn, start_sign, - settings_set, txout_explorer, cap_story): +def test_txout_explorer(chain, data, fake_txn, start_sign, settings_set, txout_explorer, + cap_story, pytestconfig): + # TODO This test MUST be run with --psbt2 flag on and off settings_set("chain", chain) - outstyles = [] - outvals = [] - change_outputs = [] - for i in range(len(data)): - os, ov, is_change = data[i] - outstyles.append(os) - outvals.append(ov) - if is_change: - change_outputs.append(i) - inp_amount = sum(outvals) + 100000 # 100k sat fee - psbt = fake_txn(1, len(data), segwit_in=True, outstyles=outstyles, - outvals=outvals, change_outputs=change_outputs, - psbt_v2=psbtv2, input_amount=inp_amount) + out_val = sum(d[1] for d in data) # zero fee + psbt = fake_txn(1, data, addr_fmt="p2tr", input_amount=out_val, + psbt_v2=pytestconfig.getoption('psbt2')) start_sign(psbt) txout_explorer(data, chain) - -def test_txout_explorer_op_return(fake_txn, start_sign, cap_story, is_q1, - need_keypress, press_cancel): - d = [ - (1, b"Coinkite"), - (0, b"Mk1 Mk2 Mk3 Mk4 Q"), - (100, b"binarywatch.org"), - (100, b"a" * 75), - ] - psbt = fake_txn(1, 20, segwit_in=False, op_return=d) - start_sign(psbt) +@pytest.mark.parametrize("finalize", [True, False]) +@pytest.mark.parametrize("data", [ + [(1, b"Coinkite"), (0, b"Mk1 Mk2 Mk3 Mk4 Q"), (100, b"binarywatch.org"), (100, b"a" * 75)], + [(0, b"W"*160), (10000, b"W"*153)], + [(0, b"a" * 300), (10, b"x" * 1000), (0, b"anchor output")], + [(0, b""), (10, b"")], + [(0, os.urandom(32)), (10, os.urandom(64)), (1000, os.urandom(160)), (0, os.urandom(161))], +]) +def test_txout_explorer_op_return(finalize, data, fake_txn, start_sign, cap_story, is_q1, + need_keypress, press_cancel, press_select, end_sign, + cap_screen_qr, cap_screen): + outputs = [["p2tr", 50000, not i] for i in range(20)] + outputs += [["op_return", am, None, d] for am, d in data] + out_val = sum(o[1] for o in outputs) + psbt = fake_txn(1, outputs, addr_fmt="p2tr", input_amount=out_val) + start_sign(psbt, finalize=finalize) time.sleep(.1) title, story = cap_story() assert title == 'OK TO SEND?' + assert "(1 warning below)" in story + if len(data) > 1: + assert ("Multiple OP_RETURN outputs: %d" % len(data)) in story + else: + assert "Multiple OP_RETURN outputs" not in story + + if sum(int(len(x[1]) > 80) for x in data): + assert "OP_RETURN > 80 bytes" in story + else: + assert "OP_RETURN > 80 bytes" not in story + assert "Press (2) to explore txn" in story need_keypress("2") time.sleep(.1) @@ -3039,63 +3152,260 @@ def test_txout_explorer_op_return(fake_txn, start_sign, cap_story, is_q1, time.sleep(.1) _, story = cap_story() ss = story.split("\n\n") - for i, (sa, sb, (amount, data)) in enumerate(zip(ss[:-1:2], ss[1::2], d), start=20): + + # collect QR codes first + need_keypress(KEY_QR if is_q1 else "4") + qr_list = [] + for v, d in data: + try: + qr = cap_screen_qr().decode() + qr_list.append(qr) + except RuntimeError: + scr = cap_screen() + if is_q1: + too_big = 650 + assert "QR too big" in scr + else: + too_big = 158 + assert "QR too" in scr + assert "big" in scr + + assert len(d) > too_big + qr_list.append(None) + + need_keypress(KEY_RIGHT if is_q1 else "9") + time.sleep(.5) + + press_cancel() # QR code on screen - exit + + for i, (sa, sb, (amount, data)) in enumerate(zip(ss[:-1:2], ss[1::2], data), start=20): assert f"Output {i}:" == sa - val, name, dd = sb.split("\n") + try: + val, name, dd = sb.split("\n") + except: + dd = None + val, name, dd0, _, dd1 = sb.split("\n") assert "OP_RETURN" in name assert f'{amount / 100000000:.8f} XTN' == val - hex_str, ascii_str = dd.split(" ", 1) - assert f"(ascii: {data.decode()})" == ascii_str - assert data.hex() == hex_str + if dd == "null-data": + assert qr_list[i - 20] == "" + elif dd: + is_ascii = False + try: + data.decode("ascii") + is_ascii = True + except UnicodeDecodeError: pass + if is_ascii: + hex_str, ascii_str = dd.split(" ", 1) + else: + hex_str = dd - press_cancel() - press_cancel() - - -def test_low_R_grinding(dev, goto_home, microsd_path, press_select, offer_ms_import, - cap_story, try_sign, reset_seed_words, clear_ms): - reset_seed_words() - clear_ms() - desc = "sh(sortedmulti(2,[6ba6cfd0/45h]tpubD9429UXFGCTKJ9NdiNK4rC5ygqSUkginycYHccqSg5gkmyQ7PZRHNjk99M6a6Y3NY8ctEUUJvCu6iCCui8Ju3xrHRu3Ez1CKB4ZFoRZDdP9/0/*,[747b698e/45h]tpubD97nVL37v5tWyMf9ofh5rznwhh1593WMRg6FT4o6MRJkKWANtwAMHYLrcJFsFmPfYbY1TE1LLQ4KBb84LBPt1ubvFwoosvMkcWJtMwvXgSc/0/*,[7bb026be/45h]tpubD9ArfXowvGHnuECKdGXVKDMfZVGdephVWg8fWGWStH3VKHzT4ph3A4ZcgXWqFu1F5xGTfxncmrnf3sLC86dup2a8Kx7z3xQ3AgeNTQeFxPa/0/*,[0f056943/45h]tpubD8NXmKsmWp3a3DXhbihAYbYLGaRNVdTnr6JoSxxfXYQcmwVtW2hv8QoDwng6JtEonmJoL3cNEwfd2cLXMpGezwZ2vL2dQ7259bueNKj9C8n/0/*))#up0sw2xp" - # PSBT created via fake_ms_txn, grinded in test_ms_sign_myself - psbt_fname = "myself-72sig.psbt" - with open(f"data/{psbt_fname}", "r") as f: - b64psbt = f.read() - - goto_home() - passphrase = "Myself" - dev.send_recv(CCProtocolPacker.bip39_passphrase(passphrase), timeout=None) - press_select() - time.sleep(.1) - title, story = cap_story() - - assert "[747B698E]" in title - press_select() - - time.sleep(.1) - _, story = offer_ms_import(desc) - assert "Create new multisig wallet?" in story - time.sleep(.1) - press_select() - - # below raises for 72 bytes long signature - # only on firmware versions that do only 10 grinding iterations - try_sign(base64.b64decode(b64psbt), accept=True) + qr_target = qr_list[i-20] + if qr_target: + assert hex_str in qr_target + assert qr_target.startswith("6a") # OP_RETURN + assert data.hex() == hex_str + if is_ascii: + assert f"(ascii: {data.decode()})" == ascii_str + else: + s = data[:80].hex() + e = data[-80:].hex() + assert s == dd0 + assert e == dd1 + press_cancel() # exit txn out explorer + end_sign(finalize=finalize) def test_null_data_op_return(fake_txn, start_sign, end_sign, reset_seed_words): reset_seed_words() - psbt = fake_txn(1, 1, op_return=[(50, b"")]) + psbt = fake_txn(1, [["p2pkh", 99_999_800], ["op_return", 50, None, b""]]) start_sign(psbt, False, stxn_flags=STXN_VISUALIZE) story = end_sign(accept=None, expect_txn=False).decode() assert "null-data" in story assert "OP_RETURN" in story +def test_smallest_txn(fake_txn, start_sign, end_sign, reset_seed_words, settings_set): + # serialized txn has just 62 bytes and is the smallest that we support + # 1 input (iregardless of script type) and 1 zero value null OP_RETURN + reset_seed_words() + settings_set("fee_limit", -1) + psbt = fake_txn(1, [["op_return", 10, None, b""]], addr_fmt="p2tr", input_amount=10) + start_sign(psbt, False, stxn_flags=STXN_VISUALIZE) + story = end_sign(accept=None, expect_txn=False).decode() + assert "null-data" in story + assert "OP_RETURN" in story + + +@pytest.mark.parametrize("num_outs", [1, 12]) +@pytest.mark.parametrize("change", [True, False]) +def test_zero_value_outputs(num_outs, change, fake_txn, start_sign, end_sign, reset_seed_words, + settings_set): + reset_seed_words() + # user needs to disable fee limit checks to be able to do this + settings_set("fee_limit", -1) + psbt = fake_txn(1, num_outs * [[random.choice(ADDR_STYLES_SINGLE), 0, change]], input_amount=1) + start_sign(psbt, False, stxn_flags=STXN_VISUALIZE) + story = end_sign(accept=None, expect_txn=False).decode() + assert "Zero Value: Non-standard zero value output(s)." in story + assert "1 input" in story + assert f"{num_outs} output{'' if num_outs == 1 else 's'}" in story + assert 'Network fee 0.00000001 XTN' in story + + if change: + assert "0.00000000 XTN" in story.split("\n\n")[4] # change back is zero + assert "Consolidating 0.00000000 XTN" in story + assert "Change back" in story + if num_outs > 1: + assert "to addresses" in story + else: + assert "to address" in story + else: + # even + if num_outs == 12: + # even tho we do not see 2 outputs, fee is also 0 and 2 smaller not shown here have also value o 0 + assert story.count('0.00000000 XTN') == 12 + else: + assert story.count('0.00000000 XTN') == 2 + assert "Change back" not in story + + +@pytest.mark.parametrize("change", [True, False]) +@pytest.mark.parametrize("num_ins", [True, False]) +def test_zero_value_input(change, num_ins, fake_txn, start_sign, end_sign, reset_seed_words, + cap_story): + # 0 value inputs - not allowed + reset_seed_words() + af = random.choice(ADDR_STYLES_SINGLE) + psbt = fake_txn([[af, None, 0]], [[af, 0, change]], addr_fmt=af, fee=0) + start_sign(psbt, False, stxn_flags=STXN_VISUALIZE) + with pytest.raises(Exception): + end_sign(accept=None, expect_txn=False).decode() + + _, story = cap_story() + assert "zero value txn" in story + + +@pytest.mark.parametrize("num_ins", [1, 12]) +@pytest.mark.parametrize("foreign", [True, False]) +@pytest.mark.parametrize("change", [True, False]) +def test_zero_value_inputs(num_ins, foreign, change, fake_txn, start_sign, end_sign, + reset_seed_words): + # one input is-non zero + # others are zero --> allowed + reset_seed_words() + af = random.choice(ADDR_STYLES_SINGLE) + + inputs = (num_ins - 1 -int(foreign)) * [[af, None, 0]] + if foreign: + inputs += [[af, None, 0, False]] + + inputs += [[af, None, 10000]] # always one input mine + + psbt = fake_txn(inputs, [[af, 9980, change]], addr_fmt=af, fee=20) + start_sign(psbt, False, stxn_flags=STXN_VISUALIZE) + end_sign(accept=None, expect_txn=False).decode() + + +def test_negative_amount_inputs(reset_seed_words, fake_txn, start_sign, end_sign, cap_story): + reset_seed_words() + af = random.choice(ADDR_STYLES_SINGLE) + psbt = fake_txn([[af, None, -1000]], [[af, 200]], addr_fmt=af, fee=0) + start_sign(psbt, False, stxn_flags=STXN_VISUALIZE) + with pytest.raises(Exception): + end_sign(accept=None, expect_txn=False).decode() + + _, story = cap_story() + assert "negative input value: i0" in story + +def test_negative_amount_outputs(reset_seed_words, fake_txn, start_sign, end_sign, cap_story): + reset_seed_words() + af = random.choice(ADDR_STYLES_SINGLE) + psbt = fake_txn([[af, None, 1000]], [[af, -200]], addr_fmt=af, fee=0) + start_sign(psbt, False, stxn_flags=STXN_VISUALIZE) + with pytest.raises(Exception): + end_sign(accept=None, expect_txn=False).decode() + + _, story = cap_story() + assert "negative output value: o0" in story + +def test_mk4_done_signing_infinite_loop(goto_home, try_sign, fake_txn, enable_hw_ux, + settings_get, is_q1): + if is_q1: + raise pytest.skip("Irrelevant on Q as it always provides QR option") + + goto_home() + had_nfc = settings_get("nfc", None) + had_vdisk = settings_get("vidsk", None) + enable_hw_ux("nfc", disable=True) + enable_hw_ux("vdisk", disable=True) + psbt = fake_txn(1, [["p2wpkh", None, True], []], addr_fmt="p2wpkh") + try_sign(psbt, accept=True) + # above never returns in unpatched version and fills up the disk + if had_nfc: + enable_hw_ux("nfc") + if had_vdisk: + enable_hw_ux("vdisk") + + +@pytest.mark.bitcoind +def test_finalize_with_foreign_inputs(bitcoind, bitcoind_d_sim_watch, start_sign, end_sign, + cap_story, try_sign_microsd): + # foreign inputs that have partial sigs filled + # we still do not care about final_scriptsig & final_scriptwitness PSBT fields + dest_address = bitcoind.supply_wallet.getnewaddress() + alice = bitcoind.create_wallet(wallet_name="alice") + bob = bitcoind.create_wallet(wallet_name="bob") + cc = bitcoind_d_sim_watch + alice_addr = alice.getnewaddress() + bob_addr = bob.getnewaddress() + cc_addr = cc.getnewaddress() + # fund all addresses + for addr in (alice_addr, bob_addr, cc_addr): + bitcoind.supply_wallet.sendtoaddress(addr, 2.0) + + # mine above sends + bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) + + psbt_list = [] + for w in (alice, bob, cc): + assert w.listunspent() + psbt = w.walletcreatefundedpsbt([], [{dest_address: 1.0}], 0, {"fee_rate": 20})["psbt"] + psbt_list.append(psbt) + + # join PSBTs to one + the_psbt = bitcoind.supply_wallet.joinpsbts(psbt_list) + + # bitcoin core would just fill finalscriptwitness, we need partial signatures + # just add dummy signatures and remove + pp = BasicPSBT().parse(base64.b64decode(the_psbt)) + for i in pp.inputs: + assert len(i.bip32_paths) == 1 # single sigs + der = list(i.bip32_paths.values())[0] + if der[:4].hex().upper() == xfp2str(simulator_fixed_xfp): + # our key + continue + pubkey = list(i.bip32_paths.keys())[0] + assert not i.part_sigs # empty + i.part_sigs[pubkey] = os.urandom(71) # dummy sig + + # USB works and our signature is added (but only if we do not finalize) + psbt = pp.as_bytes() + start_sign(psbt) + signed = end_sign(accept=True) + assert signed != psbt + for i in BasicPSBT().parse(signed).inputs: + assert i.part_sigs + + try_sign_microsd(psbt, finalize=True, accept=True) + title, story = cap_story() + assert title == "PSBT Signed" + assert "Finalized transaction (ready for broadcast)" in story + # EOF @pytest.mark.bitcoind -def test_taproot_keyspend(use_regtest, bitcoind_d_sim_watch, start_sign, end_sign, microsd_path, cap_story, goto_home, - press_select, pick_menu_item, bitcoind): +def test_taproot_keyspend(use_regtest, bitcoind_d_sim_watch, start_sign, end_sign, microsd_path, + cap_story, goto_home, press_select, pick_menu_item, bitcoind, sim_root_dir): use_regtest() sim = bitcoind_d_sim_watch sim.keypoolrefill(10) @@ -3106,7 +3416,8 @@ def test_taproot_keyspend(use_regtest, bitcoind_d_sim_watch, start_sign, end_sig psbt_resp = sim.walletcreatefundedpsbt([], [{dest_addr: 1.0}], 0, {"fee_rate": 20}) psbt = psbt_resp.get("psbt") psbt_fname = "tr.psbt" - open('debug/last.psbt', 'w').write(psbt) + with open(f'{sim_root_dir}/debug/last.psbt', 'w')as f: + f.write(psbt) with open(microsd_path(psbt_fname), "w") as f: f.write(psbt) goto_home() @@ -3132,11 +3443,12 @@ def test_taproot_keyspend(use_regtest, bitcoind_d_sim_watch, start_sign, end_sig assert "Finalized transaction (ready for broadcast)" in story assert "TXID" in story split_story = story.split("\n\n") - story_txid = split_story[-1].split("\n")[-1] + story_txid = split_story[4].split("\n")[-1] signed_psbt_fname = split_story[1] with open(microsd_path(signed_psbt_fname), "r") as f: signed_psbt = f.read().strip() - open('debug/last.psbt', 'w').write(psbt) + with open(f'{sim_root_dir}/debug/last.psbt', 'w') as f: + f.write(psbt) signed_txn_fname = split_story[3] with open(microsd_path(signed_txn_fname), "r") as f: signed_txn = f.read().strip() @@ -3167,7 +3479,8 @@ def test_taproot_keyspend(use_regtest, bitcoind_d_sim_watch, start_sign, end_sig 0, {'subtractFeeFromOutputs': [0], "fee_rate": 20}) psbt = psbt_resp.get("psbt") psbt_fname = "tr-all.psbt" - open('debug/last.psbt', 'w').write(psbt) + with open(f'{sim_root_dir}/debug/last.psbt', 'w') as f: + f.write(psbt) with open(microsd_path(psbt_fname), "w") as f: f.write(psbt) goto_home() @@ -3189,11 +3502,12 @@ def test_taproot_keyspend(use_regtest, bitcoind_d_sim_watch, start_sign, end_sig assert "Finalized transaction (ready for broadcast)" in story assert "TXID" in story split_story = story.split("\n\n") - story_txid = split_story[-1].split("\n")[-1] + story_txid = split_story[4].split("\n")[-1] signed_psbt_fname = split_story[1] with open(microsd_path(signed_psbt_fname), "r") as f: signed_psbt = f.read().strip() - open('debug/last.psbt', 'w').write(psbt) + with open(f'{sim_root_dir}/debug/last.psbt', 'w') as f: + f.write(psbt) signed_txn_fname = split_story[3] with open(microsd_path(signed_txn_fname), "r") as f: signed_txn = f.read().strip() @@ -3238,11 +3552,12 @@ def test_taproot_keyspend(use_regtest, bitcoind_d_sim_watch, start_sign, end_sig assert "Finalized transaction (ready for broadcast)" in story assert "TXID" in story split_story = story.split("\n\n") - story_txid = split_story[-1].split("\n")[-1] + story_txid = split_story[4].split("\n")[-1] signed_psbt_fname = split_story[1] with open(microsd_path(signed_psbt_fname), "r") as f: signed_psbt = f.read().strip() - open('debug/last.psbt', 'w').write(psbt) + with open(f'{sim_root_dir}/debug/last.psbt', 'w') as f: + f.write(psbt) signed_txn_fname = split_story[3] with open(microsd_path(signed_txn_fname), "r") as f: signed_txn = f.read().strip() @@ -3287,7 +3602,7 @@ def test_taproot_keyspend(use_regtest, bitcoind_d_sim_watch, start_sign, end_sig assert "Finalized transaction (ready for broadcast)" in story assert "TXID" in story split_story = story.split("\n\n") - story_txid = split_story[-1].split("\n")[-1] + story_txid = split_story[4].split("\n")[-1] signed_psbt_fname = split_story[1] with open(microsd_path(signed_psbt_fname), "r") as f: signed_psbt = f.read().strip() @@ -3328,8 +3643,8 @@ def test_invalid_input_taproot_psbt(start_sign, fn_err_msg, cap_story): # assert err_msg in story -def test_invalid_output_tapproot_psbt(fake_txn, start_sign, cap_story, dev): - psbt = fake_txn(3, 2, master_xpub=dev.master_xpub, taproot_in=True, outstyles=["p2tr"], change_outputs=[1]) +def test_invalid_output_taproot_psbt(fake_txn, start_sign, cap_story, dev): + psbt = fake_txn(3, [[],["p2tr", None, True]], master_xpub=dev.master_xpub, addr_fmt="p2tr") # invalid internal key length psbt_obj = BasicPSBT().parse(psbt) for o in psbt_obj.outputs: @@ -3355,3 +3670,74 @@ def test_invalid_output_tapproot_psbt(fake_txn, start_sign, cap_story, dev): assert 'Invalid PSBT' in story # error messages are disabled to save some space - problem file line is still included # assert "PSBT_IN_TAP_BIP32_DERIVATION xonly-pubkey length != 32" in story + +@pytest.mark.parametrize("multi", [False, True]) +@pytest.mark.parametrize("ss_af", ["p2wpkh", "p2tr", "p2pkh", "p2sh-p2wpkh"]) +@pytest.mark.parametrize("ms_af", ["p2wsh", "p2sh-p2wsh"]) # p2tr +def test_single_multi_psbt(multi, ss_af, ms_af, dev, fake_txn, fake_ms_txn, import_ms_wallet, + start_sign, end_sign, cap_story, clear_miniscript, use_testnet): + clear_miniscript() + use_testnet() + psbt = fake_txn(1, [[ss_af, int(5E6)], [ss_af, int(1E8 - 5E6), True]], + fee=0, addr_fmt=ss_af) + + wal_name = "msw" + keys = import_ms_wallet(2, 3, ms_af, name=wal_name, accept=True) + ms_psbt = fake_ms_txn(1, 2, 2, keys, outstyles=[ms_af], change_outputs=[0], inp_addr_fmt=ms_af) + + ssp = BasicPSBT().parse(psbt) + msp = BasicPSBT().parse(ms_psbt) + + # change to PSBT v2 to not need handle txn + sspv2 = BasicPSBT().parse(ssp.to_v2()) + mspv2 = BasicPSBT().parse(msp.to_v2()) + + combined = BasicPSBT() + combined.version = 2 + combined.txn_version = 2 + + combined.input_count = sspv2.input_count + mspv2.input_count + combined.output_count = sspv2.output_count + mspv2.output_count + combined.fallback_locktime = 0 + if multi: + cha = render_address(mspv2.outputs[0].script) + combined.inputs = mspv2.inputs + sspv2.inputs + combined.outputs = sspv2.outputs + mspv2.outputs + else: + cha = render_address(sspv2.outputs[1].script) + combined.inputs = sspv2.inputs + mspv2.inputs + combined.outputs = mspv2.outputs + sspv2.outputs + + for psbt in [combined.to_v2(), combined.to_v0()]: + + start_sign(psbt) + + time.sleep(.1) + _, story = cap_story() + + change_story = story.split("\n\n")[7 if multi else 6] + assert "Change back:" in change_story + split_chstory = change_story.split("\n") + assert len(split_chstory) == 4 # just one address + got = addr_from_display_format(split_chstory[-1]) + assert cha == got, f"{cha} target\n{got} got" + + if multi: + assert f"Wallet: {wal_name}" in story + else: + assert wal_name not in story + + assert "(1 warning below)" in story + assert 'Limited Signing' in story + assert ("We are not signing these inputs, because we either don't " + "know the key, inputs belong to different wallet," + " or we have already signed: 1") in story + + res = end_sign() + r = BasicPSBT().parse(res) + # check only desired signatures were added + if ss_af == "p2tr" and not multi: + assert r.inputs[0].taproot_key_sig + else: + assert r.inputs[0].part_sigs + assert not r.inputs[1].part_sigs \ No newline at end of file diff --git a/testing/test_sssp.py b/testing/test_sssp.py new file mode 100644 index 00000000..36089ab2 --- /dev/null +++ b/testing/test_sssp.py @@ -0,0 +1,783 @@ +# (c) Copyright 2025 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# +# tests related to Single Signer Spending Policy feature (SSSP) +# +# run simulator without --eff +# +# +import pytest, time, base64, random, json +from psbt import BasicPSBT +from ckcc.protocol import CCProtocolPacker + + +@pytest.fixture +def goto_sssp_menu(goto_home, pick_menu_item, is_mark4): + def doit(): + goto_home() + pick_menu_item("Advanced/Tools") + pick_menu_item("Spending Policy") + pick_menu_item("Single-Signer") + + return doit + + +@pytest.fixture +def setup_sssp(goto_sssp_menu, pick_menu_item, cap_story, press_select, pass_word_quiz, is_q1, + seed_story_to_words, cap_menu, OK, word_menu_entry, press_cancel, press_delete, + enter_number, scan_a_qr, cap_screen, settings_get, need_keypress, microsd_path, + master_settings_get, enter_pin, settings_remove, sim_exec): + + def doit(pin=None, mag=None, vel=None, whitelist=None, w2fa=None, has_violation=None, + word_check=None, notes_and_pws=None, rel_keys=None): + + goto_sssp_menu() + time.sleep(.1) + title, story = cap_story() + + # it is possible that PIN was set beforehand + if title == "Spending Policy": + assert "stops you from signing transactions unless conditions are met" in story + assert "locked into a special mode" in story + assert "First step is to define a new PIN" in story + press_select() + time.sleep(.1) + scr = cap_screen() + if "Spending Policy" in scr: + what = "Enter first part of PIN" if is_q1 else "Enter PIN Prefix" + assert what in scr + + enter_pin(pin) + time.sleep(.1) + scr = cap_screen() + what = "Confirm PIN value"if is_q1 else "CONFIRM PIN VALUE" + assert what in scr + enter_pin(pin) + time.sleep(.1) + + m = cap_menu() + + assert "Edit Policy..." in m + if has_violation is not None: + if has_violation: + assert "Last Violation" in m + else: + assert "last Violation" not in m + + assert "Word Check" in m + assert ("Allow Notes" in m) or not is_q1 + assert "Related Keys" in m + assert "Remove Policy" in m + assert "Test Drive" in m + assert "ACTIVATE" in m + + pick_menu_item("Edit Policy...") + + whitelist_mi = "Whitelist Addresses" if is_q1 else "Whitelist" + mag_mi = "Max Magnitude" + vel_mi = "Limit Velocity" + mi_2fa = "Web 2FA" + + time.sleep(.1) + m = cap_menu() + assert mag_mi in m + assert vel_mi in m + assert whitelist_mi in m + assert mi_2fa in m + + # setting above values here + if mag: + pick_menu_item(mag_mi) + enter_number(mag) + time.sleep(.1) + title, story = cap_story() + assert f"{mag} {'BTC' if int(mag) < 1000 else 'SATS'}" in story + press_select() + + time.sleep(.1) + assert settings_get("sssp")["pol"]["mag"] == mag + + if vel: + if not settings_get("sssp")["pol"].get("mag", None): + pick_menu_item(vel_mi) + title, story = cap_story() + assert 'Velocity limit requires' in story + assert 'starting value' in story + press_select() + else: + pick_menu_item(vel_mi) + + if vel == "Unlimited": + target = 0 + else: + target = int(vel.split()[0]) + + pick_menu_item(vel) # actually a full menu item + time.sleep(.3) + assert settings_get("sssp")["pol"]["vel"] == target + + if whitelist: + pick_menu_item(whitelist_mi) + time.sleep(.1) + m = cap_menu() + assert "(none yet)" in m + assert "Import from File" in m + if is_q1: + assert "Scan QR" in m + pick_menu_item("Scan QR") + for i, addr in enumerate(whitelist, start=1): + scan_a_qr(addr) + + for _ in range(10): + scr = cap_screen() + if (f"Got {i} so far" in scr) and ("ENTER to apply" in scr): + break + time.sleep(.2) + else: + assert False, "updating whitelist failed" + + press_select() + else: + assert "Scan QR" not in m + fname = "ccc_addrs.txt" + with open(microsd_path(fname), "w") as f: + for a in whitelist: + f.write(f"{a}\n") + + pick_menu_item("Import from File") + time.sleep(.1) + _, story = cap_story() + if "Press (1)" in story: + need_keypress("1") + pick_menu_item(fname) + + time.sleep(.1) + _, story = cap_story() + if len(whitelist) == 1: + assert "Added new address to whitelist" in story + else: + assert f"Added {len(whitelist)} new addresses to whitelist" in story + + for addr in whitelist: + assert addr in story + + # check menu correct + press_select() + time.sleep(.1) + m = cap_menu() + mi_addrs = [a for a in m if '⋯' in a] + for mia, addr in zip(mi_addrs, reversed(whitelist)): + _start, _end = mia.split('⋯') + assert addr.startswith(_start) + assert addr.endswith(_end) + + press_cancel() + + assert settings_get("sssp")["pol"]["addrs"] == whitelist + + if w2fa: + pick_menu_item(mi_2fa) + + press_cancel() # leave Edit Policy... (shared settings with CCC) + + # now rest of sssp specific settings + if word_check is not None: + pick_menu_item("Word Check") + time.sleep(.1) + title, story = cap_story() + assert "addition to special PIN" in story + assert "provide the first and last seed words" in story + if word_check: + assert "Enable?" in story + press_select() # confirm action + time.sleep(.1) + assert settings_get("sssp")["words"] + else: + assert "Disable?" in story + pol = settings_get("sssp") + if "words" in pol: + assert not pol["words"] + + if notes_and_pws is not None: + assert is_q1 + pick_menu_item("Allow Notes") + time.sleep(.1) + title, story = cap_story() + assert "Allow (read-only) access to secure notes and passwords?" in story + if notes_and_pws: + assert "Enable?" in story + press_select() # confirm action + time.sleep(.1) + assert settings_get("sssp")["notes"] + else: + assert "Disable?" in story + pol = settings_get("sssp") + if "notes" in pol: + assert not pol["notes"] + + if rel_keys is not None: + pick_menu_item("Related Keys") + time.sleep(.1) + title, story = cap_story() + assert "Allow access to BIP-39 passphrase wallets" in story + assert "and Seed Vault (read-only)" in story + if rel_keys: + assert "Enable?" in story + press_select() # confirm action + time.sleep(.1) + assert settings_get("sssp")["okeys"] + else: + assert "Disable?" in story + pol = settings_get("sssp") + if "okeys" in pol: + assert not pol["okeys"] + + yield doit + + # cleanup code -- all users of this fixture will get this code + + settings_remove("sssp") + sim_exec('from pincodes import pa;pa.hobbled_mode = False; from actions import goto_top_menu; goto_top_menu()') + + + +@pytest.fixture +def policy_sign(start_sign, end_sign, cap_story, get_last_violation): + def doit(wallet, psbt, violation=None): + start_sign(base64.b64decode(psbt)) + time.sleep(.1) + title, story = cap_story() + + if violation: + # assume SSSP cases + assert title == "Failure" + assert 'warning' not in story + assert "Spending Policy violation." in story + assert violation in get_last_violation() + return + + assert 'OK TO SEND?' == title + assert "warning" not in story + + signed = end_sign(accept=True) + po = BasicPSBT().parse(signed) + + tx_hex = None + if violation is None: + assert not get_last_violation() + assert len(po.inputs[0].part_sigs) or po.inputs[0].taproot_key_sig or len(po.inputs[0].taproot_script_sigs) + res = wallet.finalizepsbt(base64.b64encode(signed).decode()) + assert res["complete"] + tx_hex = res["hex"] + res = wallet.testmempoolaccept([tx_hex]) + assert res[0]["allowed"] + res = wallet.sendrawtransaction(tx_hex) + assert len(res) == 64 # tx id + + return signed, tx_hex + + return doit + + +@pytest.mark.bitcoind +@pytest.mark.parametrize("mag_ok", [True, False]) +@pytest.mark.parametrize("mag", [1000000, 2]) +def test_magnitude(mag_ok, mag, setup_sssp, bitcoind, settings_set, pick_menu_item, + bitcoind_d_sim_watch, policy_sign, press_select, + reset_seed_words, settings_path): + + wo = bitcoind_d_sim_watch + + settings_set("chain", "XRT") + + if mag_ok: + # always try limit/border value + if mag is None: + to_send = 1 + else: + to_send = mag / 100000000 if mag > 1000 else mag + else: + if mag is None: + to_send = 1.1 + else: + to_send = ((mag / 100000000)+1) if mag > 1000 else (mag+0.001) + + setup_sssp("11-11", mag=mag) + + pick_menu_item("ACTIVATE") + press_select() + + addr = wo.getnewaddress() + bitcoind.supply_wallet.sendtoaddress(address=addr, amount=5.0) + bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) + # create funded PSBT + psbt_resp = wo.walletcreatefundedpsbt( + [], [{bitcoind.supply_wallet.getnewaddress(): to_send}], 0, {"fee_rate": 2} + ) + psbt = psbt_resp.get("psbt") + + policy_sign(wo, psbt, violation=None if mag_ok else "magnitude") + + +@pytest.mark.bitcoind +@pytest.mark.parametrize("whitelist_ok", [True, False]) +def test_whitelist(whitelist_ok, setup_sssp, bitcoind, settings_set, policy_sign, + bitcoind_d_sim_watch, pick_menu_item, press_select): + + wo = bitcoind_d_sim_watch + + settings_set("chain", "XRT") + + whitelist = [ + "bcrt1qqca9eefwz8tzn7rk6aumhwhapyf5vsrtrddxxp", + "bcrt1q7nck280nje50gzjja3gyguhp2ds6astu5ndhkj", + "bcrt1qhexpvdhwuerqq0h24j06g8y5eumjjdr28ng4vv", + "bcrt1q3ylr55pk7rl0rc06d8th7h25zmcuvvg8wt0yl3", + ] + + if whitelist_ok: + send_to = whitelist[0] + else: + send_to = bitcoind.supply_wallet.getnewaddress() + + setup_sssp("11-11", whitelist=whitelist) + pick_menu_item("ACTIVATE") + press_select() + + multi_addr = wo.getnewaddress() + bitcoind.supply_wallet.sendtoaddress(address=multi_addr, amount=5.0) + bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) + # create funded PSBT + psbt_resp = wo.walletcreatefundedpsbt( + [], [{send_to: 1}], 0, {"fee_rate": 2} + ) + psbt = psbt_resp.get("psbt") + policy_sign(wo, psbt, violation=None if whitelist_ok else "whitelist") + + +@pytest.mark.bitcoind +@pytest.mark.parametrize("velocity_mi", ['6 blocks (hour)', '48 blocks (8h)']) +def test_velocity(velocity_mi, setup_sssp, bitcoind, settings_set, pick_menu_item, + policy_sign, settings_get, bitcoind_d_sim_watch, press_select): + + wo = bitcoind_d_sim_watch + wo.keypoolrefill(20) + settings_set("chain", "XRT") + + blocks = int(velocity_mi.split()[0]) + + setup_sssp("11-11", vel=velocity_mi) + pick_menu_item("ACTIVATE") + press_select() + + assert "block_h" not in settings_get("sssp")["pol"] + + multi_addr = wo.getnewaddress() + bitcoind.supply_wallet.sendtoaddress(address=multi_addr, amount=49) + bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) + # create funded PSBT, first tx + init_block_height = bitcoind.supply_wallet.getblockchaininfo()["blocks"] # block height + psbt_resp = wo.walletcreatefundedpsbt([], [{bitcoind.supply_wallet.getnewaddress(): 1}], + init_block_height) # nLockTime set to current block height + psbt = psbt_resp.get("psbt") + po = BasicPSBT().parse(base64.b64decode(psbt)) + assert po.parsed_txn.nLockTime == init_block_height + policy_sign(wo, psbt) # success as this is first tx that sets block height from 0 + + assert settings_get("sssp")["pol"]["block_h"] == init_block_height + + # mine some, BUT not enough to satisfy velocity policy + # - check velocity is exactly right to block number vs. required gap + bitcoind.supply_wallet.generatetoaddress(blocks - 1, bitcoind.supply_wallet.getnewaddress()) + block_height = bitcoind.supply_wallet.getblockchaininfo()["blocks"] + psbt_resp = wo.walletcreatefundedpsbt([], [{bitcoind.supply_wallet.getnewaddress(): 1}], + block_height) + psbt = psbt_resp.get("psbt") + po = BasicPSBT().parse(base64.b64decode(psbt)) + assert po.parsed_txn.nLockTime == block_height + policy_sign(wo, psbt, violation="velocity") + + assert settings_get("sssp")["pol"]["block_h"] == init_block_height # still initial block height as above failed + + # mine the remaining one block to satisfy velocity policy + bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) + block_height = bitcoind.supply_wallet.getblockchaininfo()["blocks"] + psbt_resp = wo.walletcreatefundedpsbt([], [{bitcoind.supply_wallet.getnewaddress(): 1}], + block_height) + psbt = psbt_resp.get("psbt") + po = BasicPSBT().parse(base64.b64decode(psbt)) + assert po.parsed_txn.nLockTime == block_height + policy_sign(wo, psbt) # success + + assert settings_get("sssp")["pol"]["block_h"] == block_height # updated block height + + # check txn re-sign fails (if velocity in effect) + policy_sign(wo, psbt, violation="rewound") + # check decreasing nLockTime + policy_sign( + wo, + wo.walletcreatefundedpsbt( + [], [{bitcoind.supply_wallet.getnewaddress(): 1}], block_height - 1 + )["psbt"], + violation="rewound" + ) + # check nLockTime disabled when velocity enabled - fail + policy_sign( + wo, + wo.walletcreatefundedpsbt( + [], [{bitcoind.supply_wallet.getnewaddress(): 1}], 0 + )["psbt"], + violation="no nLockTime" + ) + # unix timestamp + policy_sign( + wo, + wo.walletcreatefundedpsbt( + [], [{bitcoind.supply_wallet.getnewaddress(): 1}], 500000000 + )["psbt"], + violation="nLockTime not height" + ) + + +@pytest.mark.bitcoind +@pytest.mark.parametrize("active", [True, False]) +def test_warnings(setup_sssp, bitcoind, settings_set, policy_sign, pick_menu_item, + bitcoind_d_sim_watch, settings_get, press_select, active): + + wo = bitcoind_d_sim_watch + wo.keypoolrefill(20) + + settings_set("chain", "XRT") + + whitelist = ["bcrt1qlk39jrclgnawa42tvhu2n7se987qm96qg8v76e", + "2Mxp1Dy2MyR4w36J2VaZhrFugNNFgh6LC1j", + "mjR14oKxYzRg9RAZdpu3hrw8zXfFgGzLKm"] + + setup_sssp("11-11", mag=10000000, vel='6 blocks (hour)', whitelist=whitelist) + if active: + pick_menu_item("ACTIVATE") + press_select() + else: + # demonstration that policy is in effect from configuration + # user does not need to activate (or test-drive) and policy in effect already + pass + + bitcoind.supply_wallet.sendtoaddress(address=wo.getnewaddress(), amount=2) + bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) + # create funded PSBT, first tx + # whitelist OK, velocity OK, & magnitude OK - but fee high + init_block_height = bitcoind.supply_wallet.getblockchaininfo()["blocks"] # block height + psbt_resp = wo.walletcreatefundedpsbt([], [{whitelist[0]: 0.06},{whitelist[1]: 0.01},{whitelist[2]: 0.03}], + init_block_height, {"fee_rate":48000}) + psbt = psbt_resp.get("psbt") + po = BasicPSBT().parse(base64.b64decode(psbt)) + assert po.parsed_txn.nLockTime == init_block_height + policy_sign(wo, psbt, violation="has warnings") + + # invalidate nLockTime with use of nSequence max values + utxos = wo.listunspent() + ins = [] + for i, utxo in enumerate(utxos): + # block height based RTL + inp = { + "txid": utxo["txid"], + "vout": utxo["vout"], + "sequence": 0xffffffff, + } + ins.append(inp) + + psbt_resp = wo.walletcreatefundedpsbt(ins, [{whitelist[0]: 0.06},{whitelist[1]: 0.01},{whitelist[2]: 0.03}], + 0, {"fee_rate":2, "replaceable": False}) # locktime needs to be zero, otherwise exception from core (contradicting parameters) + po = BasicPSBT().parse(base64.b64decode(psbt_resp.get("psbt"))) + assert po.parsed_txn.nLockTime == 0 + po.parsed_txn.nLockTime = init_block_height # add locktime + po.txn = po.parsed_txn.serialize_with_witness() + # num_warn=2, warn_list=["Bad Locktime"] + policy_sign(wo, po.as_b64_str(), violation="has warnings") + + # exotic sighash warning + settings_set("sighshchk", 1) # needed to only get warning instead of failure + psbt_resp = wo.walletcreatefundedpsbt([], [{whitelist[0]: 0.06},{whitelist[1]: 0.01},{whitelist[2]: 0.03}], + init_block_height, {"fee_rate":2, "replaceable": True}) + po = BasicPSBT().parse(base64.b64decode(psbt_resp.get("psbt"))) + for idx, i in enumerate(po.inputs): + i.sighash = 2 # NONE + + # num_warn=2, warn_list=["sighash NONE"] + policy_sign(wo, po.as_b64_str(), violation="has warnings") + + +def test_remove_sssp(setup_sssp, pick_menu_item, press_select, cap_story, cap_menu, settings_get): + setup_sssp("11-11", mag=10000000, vel='6 blocks (hour)') + + # check test drive + pick_menu_item("Test Drive") + time.sleep(.1) + _, story = cap_story() + assert "COLDCARD operation will look like with Spending Policy" in story + press_select() + + time.sleep(.1) + m = cap_menu() + assert "EXIT TEST DRIVE" in m + assert "Settings" not in m + + pick_menu_item("EXIT TEST DRIVE") + time.sleep(.1) + m = cap_menu() + assert "Edit Policy..." in m # back in policy settings + + pick_menu_item("Remove Policy") + time.sleep(.1) + _, story = cap_story() + assert "Bypass PIN will be removed" in story + assert "spending policy settings forgotten" in story + press_select() + + time.sleep(.1) + assert not settings_get("sssp") + + tps = settings_get("tp") + if tps: + assert "11-11" not in tps + + assert not settings_get("sssp") + + +def test_use_main_pin_as_unlock(setup_sssp, cap_story): + # not allowed + # simulator PIN + with pytest.raises(Exception): + setup_sssp("12-12") + + _, story = cap_story() + assert "already in use" in story + assert "PIN codes must be unique" in story + + +@pytest.mark.parametrize("hide", [True, False]) +def test_use_trick_pin_as_unlock(hide, setup_sssp, cap_story, new_trick_pin, pick_menu_item, + press_select, clear_all_tricks): + clear_all_tricks() + pin = "11-11" + new_trick_pin(pin, 'Wipe Seed', 'Wipe the seed and maybe do more') + pick_menu_item('Wipe & Reboot') + press_select() + press_select() + if hide: + pick_menu_item(f"↳{pin}") + pick_menu_item("Hide Trick") + press_select() # confirm + + with pytest.raises(Exception): + setup_sssp(pin) + + _, story = cap_story() + assert "already in use" in story + assert "PIN codes must be unique" in story + + + +@pytest.mark.parametrize("active_policy", [False, True]) +def test_deltamode_signature(active_policy, setup_sssp, bitcoind, settings_set, + start_sign, end_sign, pick_menu_item, press_select, + set_deltamode, bitcoind_d_sim_watch, settings_get): + + # verify that "deltamode" trick pins will work in SSSP mode + # - and that resulting signature is bad + # - device should **not** wipe itself + + dest = "bcrt1qlk39jrclgnawa42tvhu2n7se987qm96qg8v76e" + wo = bitcoind_d_sim_watch + wo.keypoolrefill(20) + + settings_set("chain", "XRT") + + if active_policy: + setup_sssp(f"{random.randint(0,99)}-11", mag=100) + pick_menu_item("ACTIVATE") + press_select() + + bitcoind.supply_wallet.sendtoaddress(address=wo.getnewaddress(), amount=2) + bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) + + # create funded PSBT, first tx + # - within active policy. + init_block_height = bitcoind.supply_wallet.getblockchaininfo()["blocks"] # block height + psbt_resp = wo.walletcreatefundedpsbt([], [{dest: 0.06}], + init_block_height, {"fee_rate":2, "replaceable": False}) + psbt = psbt_resp.get("psbt") + + po = BasicPSBT().parse(base64.b64decode(psbt)) + assert po.parsed_txn.nLockTime == init_block_height + + start_sign(base64.b64decode(psbt), finalize=True) + signed = end_sign(accept=True, finalize=True) + + set_deltamode(True) + + start_sign(base64.b64decode(psbt), finalize=True) + signed2 = end_sign(accept=True, finalize=True) + + # check wrong signature happened + assert signed != signed2 + probs = wo.testmempoolaccept([signed2.hex()])[0] + try: + # old bitcoind + assert 'Signature must be zero' in probs['reject-reason'], probs + except AssertionError: + assert 'mandatory-script-verify-flag-failed' in probs['reject-reason'], probs + assert not probs['allowed'] + + # check right signature + no_probs = wo.testmempoolaccept([signed.hex()])[0] + assert no_probs['allowed'] + + +@pytest.mark.bitcoind +def test_sssp_enforce_tmp_seed(setup_sssp, bitcoind, settings_set, settings_get, press_select, + pick_menu_item, cap_menu, go_to_passphrase, enter_complex, + need_keypress, word_menu_entry, fake_txn, start_sign, dev, + cap_story): + tmp_words = "style car win bomb plug raccoon predict warm wrap flush usual seminar" + blocks = 6 # ~1 hour + settings_set("chain", "XRT") + setup_sssp("11-11", mag=2, vel='6 blocks (hour)', rel_keys=True) + assert "block_h" not in settings_get("sssp")["pol"] + pick_menu_item("ACTIVATE") + press_select() + time.sleep(.1) + m = cap_menu() + # check we are in hobbled mode & okeys is respected + assert "Passphrase" in m + assert "Settings" not in m + + # import word-based seed as tmp and check that sssp is enforced + pick_menu_item("Advanced/Tools") + pick_menu_item("Temporary Seed") + need_keypress("4") + pick_menu_item("Import Words") + pick_menu_item("12 Words") + word_menu_entry(tmp_words.split()) + press_select() + time.sleep(.1) + m = cap_menu() + assert "Passphrase" in m # word based + okeys + assert "Settings" not in m + + xpub = dev.send_recv(CCProtocolPacker.get_xpub("m"), timeout=None) + psbt = fake_txn(2,2, input_amount=200000000, master_xpub=xpub) + start_sign(psbt) + time.sleep(.1) + _, story = cap_story() + assert "Spending Policy violation" in story + press_select() + + # recurse deeper, to passphrase wallet, on top of word-based tmp seed + go_to_passphrase() + enter_complex("AAA", apply=True) + + press_select() + m = cap_menu() + assert "Passphrase" not in m # xprv based + assert "Settings" not in m # still in hobbled + + xpub = dev.send_recv(CCProtocolPacker.get_xpub("m"), timeout=None) + psbt = fake_txn(2, 2, input_amount=200000000, master_xpub=xpub) + start_sign(psbt) + time.sleep(.1) + _, story = cap_story() + assert "Spending Policy violation" in story + press_select() + time.sleep(.1) + + pick_menu_item("Restore Master") + press_select() + + time.sleep(.1) + m = cap_menu() + assert "Passphrase" in m + assert "Settings" not in m # still in hobbled + psbt = fake_txn(2, 2, input_amount=200000000) + start_sign(psbt) + time.sleep(.1) + _, story = cap_story() + assert "Spending Policy violation" in story + press_select() + +def test_sssp_notes_enable(only_q1, setup_sssp): + # just test menu item works + setup_sssp("11-11", mag=2, vel='6 blocks (hour)', notes_and_pws=True) + +def test_sssp_word_check(setup_sssp): + # just test menu item works + setup_sssp("11-11", mag=2, vel='6 blocks (hour)', word_check=True) + +@pytest.mark.parametrize("af", ["bech32", "bech32m"]) +def test_miniscript_enforce(af, settings_set, clear_miniscript, goto_home, get_cc_key, bitcoind, + offer_minsc_import, press_select, cap_menu, pick_menu_item, cap_story, + start_sign, end_sign, create_core_wallet, policy_sign, setup_sssp): + sequence = 10 + goto_home() + clear_miniscript() + + settings_set("chain", "XRT") + policy = "and_v(v:pk(@0/<0;1>/*),older(10))" + + if af == "bech32m": + tmplt = f"tr(tpubD6NzVbkrYhZ4XgXS51CV3bhoP5dJeQqPhEyhKPDXBgEs64VdSyAfku99gtDXQzY6HEXY5Dqdw8Qud1fYiyewDmYjKe9gGJeDx7x936ur4Ju/<0;1>/*,{policy})" + else: + tmplt = f"wsh({policy})" + + cc_key = get_cc_key("m/666h/1h/0h").replace('/<0;1>/*', '') + desc = tmplt.replace("@0", cc_key) + + wname = "single_k_mini" + + _, story = offer_minsc_import(json.dumps(dict(name=wname, desc=desc))) + assert "Create new miniscript wallet?" in story + # do some checks on policy --> helper function to replace keys with letters + press_select() + + wo = create_core_wallet(wname, af, "sd", True) + + whitelisted_addr = bitcoind.supply_wallet.getnewaddress() + setup_sssp("11-11", mag=10000000, vel='6 blocks (hour)', whitelist=[whitelisted_addr]) + pick_menu_item("ACTIVATE") + press_select() + + unspent = wo.listunspent() + assert len(unspent) == 1 + + # mines 10 blocks to release script lock (not related to SSSP) + bitcoind.supply_wallet.generatetoaddress(sequence, bitcoind.supply_wallet.getnewaddress()) + + inp = {"txid": unspent[0]["txid"], "vout": unspent[0]["vout"], "sequence": sequence} + psbt_resp = wo.walletcreatefundedpsbt( + [inp], + [{bitcoind.supply_wallet.getnewaddress(): 5}], # magnitude violation + wo.getblockchaininfo()["blocks"], + {"fee_rate": 3, "change_type": af}, + ) + psbt = psbt_resp.get("psbt") + + policy_sign(wo, psbt, violation="magnitude") + + psbt_resp = wo.walletcreatefundedpsbt( + [inp], + [{bitcoind.supply_wallet.getnewaddress(): 0.09}], # whitelist violation + wo.getblockchaininfo()["blocks"], + {"fee_rate": 3, "change_type": af}, + ) + psbt = psbt_resp.get("psbt") + policy_sign(wo, psbt, violation="whitelist") + + psbt_resp = wo.walletcreatefundedpsbt( + [inp], + [{whitelisted_addr: 0.09}], + wo.getblockchaininfo()["blocks"], + {"fee_rate": 3, "change_type": af}, + ) + psbt = psbt_resp.get("psbt") + policy_sign(wo, psbt) # good - in accordance with policy + +# EOF diff --git a/testing/test_teleport.py b/testing/test_teleport.py new file mode 100644 index 00000000..05fc5657 --- /dev/null +++ b/testing/test_teleport.py @@ -0,0 +1,991 @@ +# (c) Copyright 2024 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# +# Key Teleport (a Q-only feature) +# +# - you'll need v1.0.1 of bbqr library for this to work +# +import pytest, time, re, pdb, os, json, base64 +from mnemonic import Mnemonic +from bip32 import BIP32Node +from helpers import prandom, xfp2str, str2xfp, str_to_path +from bbqr import join_qrs +from charcodes import KEY_QR, KEY_NFC +from base64 import b32encode +from constants import * +from test_ephemeral import SEEDVAULT_TEST_DATA +from test_backup import make_big_notes +from ckcc.protocol import CCProtocolPacker +from test_hobble import set_hobble + +# All tests in this file are exclusively meant for Q +# +@pytest.fixture(autouse=True) +def THIS_FILE_requires_q1(is_q1, is_headless): + if not is_q1 or is_headless: + raise pytest.skip('Q1 only (not headless)') + +@pytest.fixture +def rx_start(grab_payload, goto_home, pick_menu_item): + def doit(**kws): + goto_home() + pick_menu_item('Advanced/Tools') + pick_menu_item('Key Teleport (start)') + + return grab_payload('R', **kws)[0:2] + + return doit + +@pytest.fixture +def main_do_over(unit_test, settings_get, settings_set): + # reset all contents, including master secret ... except ktrx + # - so you can test backup-restore onto blank unit + def doit(): + kp = settings_get('ktrx') + unit_test('devtest/clear_seed.py') + settings_set('ktrx', kp) + + return doit + +@pytest.fixture +def grab_payload(press_select, need_keypress, press_cancel, nfc_read_url, cap_story, nfc_block4rf, + cap_screen_qr, readback_bbqr): + + # started the process; capture pw/code and QR contents, verify NFC works + def doit(tt_code, allow_reuse=True, reset_pubkey=False): + expect_in_title = 'Receive' if tt_code == 'R' else 'Teleport Password' + + title, story = cap_story() + + if 'Reuse' in title and tt_code == 'R': + assert allow_reuse + assert 'press (R)' in story + + if reset_pubkey: + # make a new key anyway + need_keypress('r') + else: + press_select() + + time.sleep(.1) + title, story = cap_story() + + assert 'Teleport' in title + assert expect_in_title in title + + assert 'QR' in story + + code, = re.findall(' (\w{8}) = ', story) + assert len(code) == 8 + + nfc_raw = None + if KEY_NFC in story: + # test NFC case -- when enabled + need_keypress(KEY_NFC) + + # expect NFC animation + nfc_block4rf() + + url = nfc_read_url().replace('%24', '$') + + assert url.startswith('https://keyteleport.com/#') + + nfc_data = url.rsplit('#')[1] + assert nfc_data.startswith(f'B$2{tt_code}0100') + + filetype, nfc_raw = join_qrs([nfc_data]) # update your bbqr install if fails + assert filetype == tt_code + + need_keypress(KEY_QR) + + # will be multi-frame BBQr in case of PSBT, other cases usually one frame + filetype, qr_raw = readback_bbqr() + # this is un-split BBQR which didn't really happen, but useful + qr_data = f'B$2{filetype}0100' + b32encode(qr_raw).decode('ascii').rstrip('=') + + assert filetype == tt_code + + if nfc_raw: assert nfc_raw == qr_raw + + press_cancel() + press_cancel() + + return code, qr_data, qr_raw + + return doit + +@pytest.fixture +def rx_complete(press_select, need_keypress, press_cancel, cap_story, scan_a_qr, enter_complex, + cap_screen, goto_home, split_scan_bbqr): + # finish the teleport by doing QR and getting data + def doit(data, pw, expect_fail=False, expect_xfp=None): + goto_home() + need_keypress(KEY_QR) + time.sleep(.250) # required + + if isinstance(data, tuple): + bbrq_type, raw = data + split_scan_bbqr(raw, bbrq_type, max_version=26) + else: + assert len(data) < 2000 # USB protocol limit + scan_a_qr(data) + + if expect_fail: + time.sleep(.200) + return + + for _ in range(10): + scr = cap_screen() + if 'Teleport Password' in scr: break + time.sleep(.2) + else: + raise RuntimeError("Teleport Password not in screen") + + if expect_xfp: + assert xfp2str(expect_xfp) in scr + + enter_complex(pw) + time.sleep(.150) # required + + + return doit + +@pytest.fixture +def tx_start(press_select, need_keypress, press_cancel, goto_home, pick_menu_item, cap_story, + scan_a_qr, enter_complex, cap_screen): + + # start the Tx process, capturing password and leaving you are picker menu + def doit(rx_qr, rx_code, expect_fail=None, expect_wrong_code=False): + goto_home() + need_keypress(KEY_QR) + time.sleep(.250) # required + scan_a_qr(rx_qr) + + for _ in range(10): + scr = cap_screen() + if expect_fail and expect_fail in scr: + return + elif 'Teleport Password (number)' in scr: + break + time.sleep(.2) + else: + assert False, "Teleport Password not in screen" + + enter_complex(rx_code) + time.sleep(.150) # required + + + title, story = cap_story() + if expect_wrong_code: + # not a sure thing + if 'Incorrect Teleport Pass' in story: + return True + + assert title == 'Key Teleport: Send' + + assert 'Choose what to share' in story + assert 'WARNING' in story + press_select() + + return doit + +def test_rx_reuse(rx_start): + # check rx pubkey re-use logic + code, enc_pubkey = rx_start(allow_reuse=True, reset_pubkey=True) + assert code.isdigit() + code2, enc_pubkey2 = rx_start(allow_reuse=True, reset_pubkey=False) + assert code2 == code + assert enc_pubkey2 == enc_pubkey + + code3, pk3 = rx_start(allow_reuse=True, reset_pubkey=True) + assert code3 != code + +def test_tx_quick_note(rx_start, tx_start, cap_menu, enter_complex, pick_menu_item, grab_payload, + rx_complete, cap_story, press_cancel, press_select): + # Send a quick-note + code, rx_pubkey = rx_start() + pw = tx_start(rx_pubkey, code) + + m = cap_menu() + assert 'Master Seed Words' in m + assert 'Quick Text Message' in m + # other contents require other features to be enabled + + msg = b32encode(prandom(10)).decode('ascii') + + pick_menu_item('Quick Text Message') + + enter_complex(msg) + + time.sleep(.150) # required + pw, data, _ = grab_payload('S') + assert len(pw) == 8 + + # now, send that back + rx_complete(data, pw) + + # should arrive in notes menu + m = cap_menu() + assert m[-1] == 'Import' + mi = [i for i in m if i.endswith(': Quick Note')] + assert mi + pick_menu_item(mi[-1]) # most recent test + + # view note + m = cap_menu() + assert m[0] == '"Quick Note"' + pick_menu_item(m[0]) + + _, body = cap_story() + assert body == msg + + # cleanup + press_cancel() + pick_menu_item('Delete') + press_select() + + +@pytest.mark.parametrize('testcase', [ 'weak', 'strong']) +def test_tx_master_send(testcase, rx_start, tx_start, cap_menu, enter_complex, pick_menu_item, + grab_payload, rx_complete, cap_story, press_cancel, press_select, main_do_over): + # Send master secret, but doesn't really work since same as what we have + code, rx_pubkey = rx_start() + pw = tx_start(rx_pubkey, code) + + # other contents require other features to be enabled + pick_menu_item('Master Seed Words') + + title, body = cap_story() + + assert 'Are you SURE' in title + assert 'MASTER secret' in body + assert '24 words' in body + + press_select() + + time.sleep(.150) # required? + pw, data, _ = grab_payload('S') + + if testcase == 'strong': + # virginized + main_do_over() + + # now, send that back + rx_complete(data, pw) + + title, body = cap_story() + + if testcase == 'weak': + + assert title == 'FAILED' + assert 'Cannot use master seed as temp' in body + assert 'successfully tested' in body + + elif testcase == 'strong': + # real product would reboot; simulator just quietly goes back to top menu? + assert title == '' + m = cap_menu() + assert m[0] == 'Ready To Sign' + + press_cancel() + +@pytest.mark.parametrize('qty', [1, 3]) +def test_tx_notes(qty, rx_start, tx_start, cap_menu, enter_complex, pick_menu_item, grab_payload, + rx_complete, cap_story, press_cancel, press_select, need_some_passwords, + need_some_notes, settings_set, settings_get): + # Send notes. + settings_set('notes', []) + need_some_notes() + notes = need_some_passwords() + + assert len(notes) >= qty + + code, rx_pubkey = rx_start() + pw = tx_start(rx_pubkey, code) + + # other contents require other features to be enabled + if qty == 1: + pick_menu_item('Single Note / Password') + pick_menu_item('1: ' + notes[0]["title"]) + else: + pick_menu_item('Export All Notes & Passwords') + + time.sleep(.150) # required? + pw, data, _ = grab_payload('S') + + # now, send that back + rx_complete(data, pw) + + # arrive in settings menu, on last item (last imported) + m = cap_menu() + assert m[-1] == 'Import' + + after = settings_get('notes', None) + + assert notes[0:qty] == after[-qty:] + + settings_set('notes', []) + press_cancel() + + +@pytest.mark.parametrize('data', SEEDVAULT_TEST_DATA[0:2]) +def test_tx_seedvault(data, rx_start, tx_start, cap_menu, enter_complex, pick_menu_item, + grab_payload, rx_complete, cap_story, press_cancel, press_select, settings_set, + settings_get, goto_home, need_keypress): + # Send seeds from vault + + xfp, entropy, mnemonic = data + + # build stashed encoded secrets + entropy_bytes = bytes.fromhex(entropy) + if mnemonic: + vlen = len(entropy_bytes) + assert vlen in [16, 24, 32] + marker = 0x80 | ((vlen // 8) - 2) + stored_secret = bytes([marker]) + entropy_bytes + else: + stored_secret = entropy_bytes + + pkg = [xfp, stored_secret.hex(), f"[{xfp}]", "from testing"] + + settings_set("seedvault", True) + settings_set("seeds", [pkg]) + + # get ready to send + code, rx_pubkey = rx_start(reset_pubkey=True) + pw = tx_start(rx_pubkey, code) + + pick_menu_item('From Seed Vault') + mi, = (i for i in cap_menu() if i.endswith(f"[{xfp}]")) + pick_menu_item(mi) + + time.sleep(.150) # required? + pw, data, _ = grab_payload('S') + + settings_set("seeds", []) + + rx_complete(data, pw) + + if settings_get("seedvault", False): + time.sleep(.1) + title, body = cap_story() + assert 'Press (1) to store temp' in body + assert 'to continue without saving' in body + need_keypress('1') + + time.sleep(.1) + title, body = cap_story() + assert xfp in body + assert 'Saved to Seed Vault' in body + + assert settings_get('seeds') == [pkg] + + goto_home() + pick_menu_item('Restore Master') + press_select() + + time.sleep(.1) + assert settings_get('xfp', -1) == simulator_fixed_xfp + +def test_rx_truncated(rx_start, tx_start): + # Truncate the RX Code + code, rx_pubkey = rx_start() + tx_start(rx_pubkey[:-3], code, expect_fail='Truncated KT RX') + + +def test_tx_wrong_pub(rx_start, tx_start, cap_menu, enter_complex, pick_menu_item, grab_payload, + rx_complete, cap_story, press_cancel, press_select): + # simulate wrong numeric code only -- sender doesn't know + right_code, rx_pubkey = rx_start() + + for attempt in range(20): + code = '%08d' % attempt + failed = tx_start(rx_pubkey, code, expect_wrong_code=True) + + if failed: + # 50% odds (apx, maybe?) of wrong code being detected. + print(f'{code} => wasnt accepted') + continue + break + else: + raise pytest.fail('huh') + + # other contents require other features to be enabled + pick_menu_item('Master Seed Words') + time.sleep(.150) # required? + press_select() + + time.sleep(.150) # required? + pw, data, _ = grab_payload('S') + + # now, send that back + rx_complete(data, pw, expect_fail=True) + + time.sleep(.1) + title, body = cap_story() + + assert title == 'Teleport Fail' + assert 'password was wrong' in body + assert 'start again' in body + + press_cancel() + +@pytest.mark.unfinalized +@pytest.mark.parametrize('num_ins', [ 15 ]) +@pytest.mark.parametrize('M', [4]) +@pytest.mark.parametrize('hobbled', [True, False]) +def test_teleport_ms_sign(M, use_regtest, make_myself_wallet, num_ins, dev, clear_miniscript, hobbled, + fake_ms_txn, try_sign, bitcoind, cap_story, need_keypress, + cap_menu, pick_menu_item, grab_payload, rx_complete, press_select, + ndef_parse_txn_psbt, press_nfc, nfc_read, settings_get, settings_set, + txid_from_export_prompt, sim_root_dir, set_hobble, readback_bbqr, + nfc_is_enabled, goto_home, restore_main_seed): + + # IMPORTANT: won't work if you start simulator with --ms flag. Use no args + num_outs = 4 + af = "p2wsh" + + clear_miniscript() + use_regtest() + + # create a wallet, with 3 bip39 pw's + keys, select_wallet = make_myself_wallet(M, do_import=True, addr_fmt=af) + N = len(keys) + assert M<=N + + if hobbled: + # we need to import before hobbled mode is enabled + for i in range(3): # 4th is simulator (ignore) + select_wallet(i) + + restore_main_seed(preserve_settings=True) + time.sleep(.1) + + set_hobble(True, {'okeys'}) + goto_home() + + psbt = fake_ms_txn(15, num_outs, M, keys, inp_addr_fmt=af, incl_xpubs=False, + outstyles=["p2sh-p2wsh", af, af, af], + change_outputs=list(range(1,num_outs))) + + with open(f'{sim_root_dir}/debug/myself-before.psbt', 'wb') as f: + f.write(psbt) + + cur_wallet = 0 + my_xfp = select_wallet(cur_wallet, no_import=hobbled) + + _, updated = try_sign(psbt, accept_ms_import=False, exit_export_loop=False) + with open(f'{sim_root_dir}/debug/myself-after-1.psbt', 'wb') as f: + f.write(updated) + assert updated != psbt + + title, body = cap_story() + assert title == "PSBT Signed" + assert '(T) to use Key Teleport to send PSBT to other co-signers' in body + + num_sigs_needed = M - 1 # we have already signed with first at this point + + while 1: + # expect: a menu of other signers to pick from + need_keypress('t') + time.sleep(.1) + + m = cap_menu() + assert len(m) == N + assert 'YOU' in [ln for ln in m if xfp2str(my_xfp) in ln][0] + + unsigned = [ln[1:9] for ln in m if (xfp2str(my_xfp) not in ln) and ('DONE' not in ln)] + assert unsigned + + # find another signer + for idx, (xfp, *_) in enumerate(keys): + if xfp2str(xfp) in unsigned: + break + else: + assert 0, 'missing unsigned' + + # check XFP changes + next_xfp = keys[idx][0] + assert next_xfp != my_xfp + last_xfp = my_xfp + + # pick other xfp to send to + nm, = [mi for mi in m if xfp2str(next_xfp) in mi] + pick_menu_item(nm) + + # grab the payload and pw + pw, data, qr_raw = grab_payload('E') + assert len(pw) == 8 + + nn = xfp2str(next_xfp) + with open(f'{sim_root_dir}/debug/next_qr_{nn}.txt', 'wt') as f: + f.write(f'{nn}\n\n{pw}\n\n{data}') + + time.sleep(.1) + title, story = cap_story() + assert title == 'Sent by Teleport' + # s, aux = ("", "is") if num_sigs_needed == 1 else ("s", "are") + # msg = "%d more signature%s %s still required." % (num_sigs_needed, s, aux) + # assert msg in story + + # switch personalities, and try to read that QR + new_xfp = select_wallet(idx, no_import=hobbled) + assert new_xfp == next_xfp + my_xfp = next_xfp + assert settings_get('xfp') == my_xfp + + # import and sign + rx_complete(('E', qr_raw), pw, expect_xfp=last_xfp) + + title, body = cap_story() + assert title == 'OK TO SEND?' + + press_select() + time.sleep(.25) + + title, body = cap_story() + if 'Finalized TX' in body: + break + + assert '(T) to use Key Teleport to send PSBT to other co-signers' in body + num_sigs_needed -= 1 + + txid = txid_from_export_prompt() + press_select() # exit QR + + if nfc_is_enabled(): + # share signed txn via low-level NFC + press_nfc() + time.sleep(.1) + contents = nfc_read() + + got_psbt, got_txn, _ = ndef_parse_txn_psbt(contents, txid, expect_finalized=True) + else: + # NFC disabled. use other means .. bbqr + need_keypress(KEY_QR) + tcode, contents = readback_bbqr() + got_txn = (tcode == 'T') + got_psbt = (tcode == 'P') + + assert not got_psbt + assert got_txn + + +def test_teleport_big_ms(make_myself_wallet, clear_miniscript, fake_ms_txn, try_sign, cap_story, + need_keypress, cap_menu, pick_menu_item, grab_payload, rx_complete, + press_select, ndef_parse_txn_psbt, set_master_key, goto_home, press_nfc, + nfc_read, open_microsd, import_ms_wallet, press_cancel): + + # define lots of wallets and do teleport from SD disk + + clear_miniscript() + M, N = 2, 15 + for i in range(5): + keys = import_ms_wallet(M, N, name=f'ms{i}-test', unique=(i*73), accept=True, bip67=True) + + # just use last wallet + psbt = fake_ms_txn(1, 1, M, keys) + + fname = 'ms-example.psbt' + open_microsd(fname, 'wb').write(psbt) + + goto_home() + pick_menu_item('Advanced/Tools') + pick_menu_item('File Management') + pick_menu_item('Teleport Miniscript PSBT') + + need_keypress('1') # top slot + + try: + pick_menu_item(fname) + except KeyError: + # maybe just one file that is suitable --> str8 to xfp picking + pass + + # on Co-signer list menu + m = cap_menu() + assert len(m) == N + + myself, = [i for i in m if 'YOU' in i] + pick_menu_item(myself) + + title, body = cap_story() + assert title == 'OK TO SEND?' + press_select() + + time.sleep(.25) + + # have 1 sigs now, need one more via teleport + title, body = cap_story() + assert '(T) to use Key Teleport to send PSBT to other co-signers' in body + need_keypress('t') + + # pick another one randomly + m = cap_menu() + assert len(m) == N + + target = m[-1] if 'YOU' not in m[0] else m[-2] + pick_menu_item(target) + target_xfp = str2xfp(target[1:9]) + + # capture QR+pw to go there + pw, data, qr_raw = grab_payload('E') + + # switch to that key, receive it + node, = [n for x,n,_ in keys if x == target_xfp] + set_master_key(node.hwif(as_private=True)) + + # copy over the one MS wallet this xfp was involved in + import_ms_wallet(M, N, name=f'www', keys=keys, accept=True, bip67=True) + + # import and sign + rx_complete(('E', qr_raw), pw, expect_xfp=simulator_fixed_xfp) + + title, body = cap_story() + assert title == 'OK TO SEND?' + + press_select() + time.sleep(.25) + + title, body = cap_story() + assert 'Finalized TX' in body + press_cancel() + + +@pytest.mark.manual +def test_teleport_real_ms(dev, fake_ms_txn, sim_root_dir): + # + # Do a 2-of-2 w/ USB-attached REAL Q and simulator + # - build ms wallet beforehand, both devices (QR); default air-gap settings + # - this makes fake txn, sents to (real) device via USB + # - do your signature, press (T) to teleport to next + # - observe BBQr, but press NFC and capture URL text via keyteleport.com + # - get that BBQr string into clipboard, and paste into simulator + # - observe working signature on sim side + # + # py.test test_teleport.py --dev --manual -k test_teleport_real_ms + # + M = N = 2 + + #p2wsh + deriv = "m/48h/1h/0h/2h" + + # simulator key + n = BIP32Node.from_hwif(simulator_fixed_xprv).subkey_for_path(deriv) + keys = [ (simulator_fixed_xfp, None, n) ] + + # add device + xfp = dev.master_fingerprint + xpk = dev.send_recv(CCProtocolPacker.get_xpub(deriv)) + node = BIP32Node.from_wallet_key(xpk) + keys.append((xfp, None, node)) + + def p2wsh_mapper(cosigner_idx): + # match the default paths created by CC in airgapped MS wallet creation. + return str_to_path(deriv) + + psbt = fake_ms_txn(3, 2, M, keys, fee=10000, outvals=None, inp_addr_fmt="p2wsh", + outstyles=['p2pkh'], change_outputs=[], + hack_change_out=False, input_amount=1E8, path_mapper=p2wsh_mapper) + + with open(f'{sim_root_dir}/debug/teleport_real_ms.psbt', 'wb') as f: + f.write(psbt) + + ll, sha = dev.upload_file(psbt) + dev.send_recv(CCProtocolPacker.sign_transaction(ll, sha)) + + print("Follow signing prompts on device, and then do teleport back " + "to Simulator via NFC => website => clipboard") + + +@pytest.mark.parametrize('testcase', [ 'weak', 'partial', 'strong']) +def test_send_backup(testcase, rx_start, tx_start, cap_menu, enter_complex, pick_menu_item, + grab_payload, rx_complete, cap_story, press_cancel, press_select, settings_get, + settings_set, restore_backup_unpacked, main_do_over, set_encoded_secret, + reset_seed_words, make_big_notes): + # Send complete backup file. + code, rx_pubkey = rx_start() + pw = tx_start(rx_pubkey, code) + + if testcase == 'strong': + notes = make_big_notes() + + # other contents require other features to be enabled + pick_menu_item('Full COLDCARD Backup') + + title, body = cap_story() + + assert 'Sending complete backup' in body + + press_select() + + time.sleep(.150) # required? + pw, data, qr_raw = grab_payload('S') + + if testcase == 'partial': + # be on a different master, so backup is restored into seed vault/tmp seed + kp = settings_get('ktrx') + set_encoded_secret(b'\x20' + prandom(32)) + settings_set('ktrx', kp) + + if testcase == 'strong': + # wipe everything; except we need the keypair + main_do_over() + + # now, send that back + rx_complete(('S', qr_raw), pw) + + title, body = cap_story() + + if testcase == 'weak': + assert title == 'FAILED' + assert 'Cannot use master seed as temp' in body + assert 'successfully tested' in body + press_cancel() + + elif testcase == 'partial': + # should be in a tmp seed now + assert title == '[0F056943]' + assert 'temporary master key is in effect' in body + + reset_seed_words() + + elif testcase == 'strong': + restore_backup_unpacked() + assert settings_get('notes') == notes + settings_set('notes', []) + + +@pytest.mark.bitcoind +@pytest.mark.parametrize("taproot", [True, False]) +@pytest.mark.parametrize("keys", [True, False, None]) +@pytest.mark.parametrize("policy", [ + "thresh(4,pk(@0),s:pk(@1),s:pk(@2),s:pk(@3),sln:older(12960))", +]) +def test_teleport_miniscript_sign(dev, taproot, policy, get_cc_key, bitcoind, use_regtest, + clear_miniscript, set_bip39_pw, press_select, pick_menu_item, + need_keypress, offer_minsc_import, load_export, reset_seed_words, + cap_story, cap_menu, grab_payload, sim_root_dir, rx_complete, + settings_set, try_sign, settings_get, press_cancel, keys, + cap_screen): + + reset_seed_words() + use_regtest() + clear_miniscript() + + # bitcoin core is PSBT provider + name = "msc_tele" + wo = bitcoind.create_wallet(name, disable_private_keys=True, blank=True) + + deriv = "86h/1h/%dh" if taproot else "48h/1h/%dh/2h" + if keys is True: + # actually just 2 signers - both with 2 keys with different subderivation (change based) + deriv = deriv % 0 + keys = [get_cc_key(deriv)] + keys.append(get_cc_key(deriv, subderiv="/<2;3>/*")) + + seed = Mnemonic.to_seed(simulator_fixed_words, passphrase="11") + master = BIP32Node.from_master_secret(seed, netcode="XTN") + master_xfp = master.fingerprint().hex() + account_key = master.subkey_for_path(deriv) + keys.append(f"[{master_xfp}/{deriv}]{account_key.hwif()}/<0;1>/*") + keys.append(f"[{master_xfp}/{deriv}]{account_key.hwif()}/<2;3>/*") + + signers = [keys[0], keys[2]] + elif keys is False: + # 3 signers, 1 signer has two keys with different account derivation index + keys = [get_cc_key(deriv % 0)] + for i in range(1, 3): + seed = Mnemonic.to_seed(simulator_fixed_words, passphrase=str(i)+str(i)) + master = BIP32Node.from_master_secret(seed, netcode="XTN") + master_xfp = master.fingerprint().hex() + dd = deriv % 0 + account_key = master.subkey_for_path(dd) + keys.append(f"[{master_xfp}/{dd}]{account_key.hwif()}/<0;1>/*") + if i == 1: + dd = deriv % 1 + account_key = master.subkey_for_path(dd) + keys.append(f"[{master_xfp}/{dd}]{account_key.hwif()}/<0;1>/*") + + signers = [keys[0], keys[1], keys[3]] + + else: + # all keys different + # default simulator key always on index 0 + deriv = deriv % 0 + keys = [get_cc_key(deriv)] + + # 4 more keys for other co-signers + for i in range(1, 4): + seed = Mnemonic.to_seed(simulator_fixed_words, passphrase=str(i)*2) + master = BIP32Node.from_master_secret(seed, netcode="XTN") + master_xfp = master.fingerprint().hex() + account_key = master.subkey_for_path(deriv) + keys.append(f"[{master_xfp}/{deriv}]{account_key.hwif()}/<0;1>/*") + + signers = keys + + for i, key in enumerate(keys): + policy = policy.replace(f"@{i}", key) + + if taproot: + from test_miniscript import ranged_unspendable_internal_key + desc = f"tr(%s,%s)" % (ranged_unspendable_internal_key(), policy) + else: + desc = f"wsh(%s)" % policy + + title, story = offer_minsc_import(json.dumps({"name": name, "desc": desc})) + assert "Create new miniscript wallet?" in story + press_select() + time.sleep(.2) + + pick_menu_item("Settings") + pick_menu_item("Miniscript") + pick_menu_item(name) + pick_menu_item("Descriptors") + pick_menu_item("Bitcoin Core") + text = load_export("sd", label="Bitcoin Core miniscript", is_json=False) + text = text.replace("importdescriptors ", "").strip() + # remove junk + r1 = text.find("[") + r2 = text.find("]", -1, 0) + text = text[r1: r2] + core_desc_object = json.loads(text) + res = wo.importdescriptors(core_desc_object) + for obj in res: + assert obj["success"] + + af = "bech32m" if taproot else "bech32" + addr = wo.getnewaddress("", af) + assert bitcoind.supply_wallet.sendtoaddress(addr, 20) + bitcoind.supply_wallet.generatetoaddress(1, bitcoind.supply_wallet.getnewaddress()) + psbt_resp = wo.walletcreatefundedpsbt( + [], + [{bitcoind.supply_wallet.getnewaddress(): 2.5}], + 0, + {"fee_rate": 2, "change_type": af}, + ) + psbt = psbt_resp.get("psbt") + + _, psbt = try_sign(base64.b64decode(psbt), accept=True, exit_export_loop=False) + title, body = cap_story() + assert title == "PSBT Signed" + assert '(T) to use Key Teleport to send PSBT to other co-signers' in body + + my_xfp = xfp2str(simulator_fixed_xfp) + for i in range(len(signers)): + # expect: a menu of other signers to pick from + if i == (len(signers) - 1): + done = dev.send_recv(CCProtocolPacker.get_signed_txn(), timeout=None) + resp_len, chk = done + psbt_out = dev.download_file(resp_len, chk) + res = wo.finalizepsbt(base64.b64encode(psbt_out).decode()) + assert res["complete"] + tx_hex = res["hex"] + res = wo.testmempoolaccept([tx_hex]) + assert res[0]["allowed"] + res = wo.sendrawtransaction(tx_hex) + assert len(res) == 64 # tx id + press_cancel() + # done + break + + need_keypress('t') + time.sleep(.1) + + m = cap_menu() + assert len(m) == len(signers) + assert 'YOU' in [ln for ln in m if my_xfp in ln][0] + + unsigned = [ln[1:9] for ln in m if (my_xfp not in ln) and ('DONE' not in ln)] + assert unsigned + + # make sure we have checkmark after YOU because self has signed + assert "YOU \x14\x00" in cap_screen() + + # find another signer + for idx, k in enumerate(signers): + if k[1:9].upper() in unsigned: + next_xfp = k[1:9].upper() + break + else: + assert 0, 'missing unsigned' + + # check XFP changes + assert next_xfp != my_xfp + last_xfp = my_xfp + + # pick other xfp to send to + nm, = [mi for mi in m if next_xfp in mi] + pick_menu_item(nm) + + # grab the payload and pw + pw, data, qr_raw = grab_payload('E') + assert len(pw) == 8 + + with open(f'{sim_root_dir}/debug/next_qr_{next_xfp}.txt', 'wt') as f: + f.write(f'{next_xfp}\n\n{pw}\n\n{data}') + + time.sleep(.1) + title, story = cap_story() + assert title == 'Sent by Teleport' + + # try to enter the menu again & make sure "No more signers?" is not shown + need_keypress('t') + time.sleep(.1) + m = cap_menu() + assert len(m) == len(signers) + assert 'YOU' in [ln for ln in m if my_xfp in ln][0] + press_cancel() + + # switch personalities, and try to read that QR + new_xfp = set_bip39_pw(str(idx) + str(idx)) + use_regtest() + clear_miniscript() + dev.start_encryption() # + assert xfp2str(new_xfp) == next_xfp + assert settings_get('xfp') == new_xfp + my_xfp = xfp2str(new_xfp) + + # need miniscript wallet + title, story = offer_minsc_import(json.dumps({"name": name, "desc": desc})) + assert "Create new miniscript wallet?" in story + press_select() + time.sleep(.2) + + # import and sign + rx_complete(('E', qr_raw), pw, expect_xfp=str2xfp(last_xfp)) + + title, body = cap_story() + assert title == 'OK TO SEND?' + + press_select() + time.sleep(.25) + + title, body = cap_story() + + assert '(T) to use Key Teleport to send PSBT to other co-signers' in body + + +def test_hobble_limited(set_hobble, scan_a_qr, cap_menu, cap_screen, pick_menu_item, grab_payload, + rx_complete, cap_story, press_cancel, press_select, settings_get, + settings_set, restore_backup_unpacked, main_do_over, set_encoded_secret, + reset_seed_words, make_big_notes): + # verify: in hobbled mode, KT is blocked for everything except multisig cases + + set_hobble(True) + + from bbqr import split_qrs + + _, parts = split_qrs(b's'*33, 'R') + rx_complete(parts[0], '12345678', expect_fail=True) + time.sleep(.1) + last = cap_screen().split('\n')[-1] + assert last == 'KT Blocked' + + _, parts = split_qrs(b's'*33, 'S') + rx_complete(parts[0], 'abcdefgh', expect_fail=True) + time.sleep(.1) + last = cap_screen().split('\n')[-1] + assert last == 'KT Blocked' + +# EOF diff --git a/testing/test_unit.py b/testing/test_unit.py index a47b7a75..44c84da4 100644 --- a/testing/test_unit.py +++ b/testing/test_unit.py @@ -5,6 +5,8 @@ import pytest, os, shutil from helpers import B2A, taptweak +from constants import AF_P2WSH, AF_P2SH, AF_P2WSH_P2SH, AF_CLASSIC, AF_P2WPKH, AF_P2WPKH_P2SH +from charcodes import * def test_remote_exec(sim_exec): @@ -135,10 +137,6 @@ def test_slip132(unit_test): # slip132 ?pub stuff unit_test('devtest/unit_slip132.py') -def test_multisig(unit_test): - # scripts/multisig unit tests - unit_test('devtest/unit_multisig.py') - def test_decoding(unit_test): # utils.py Hex/Base64 streaming decoders unit_test('devtest/unit_decoding.py') @@ -278,28 +276,55 @@ def test_is_dir(microsd_path, sim_exec): assert rv == "False" shutil.rmtree(microsd_path("my_dir")) -@pytest.mark.parametrize('txt, x_line2', [ - ('Disk, press \x0e to share via NFC, \x11 to share', '\x11 to share'), -]) -def test_word_wrap(txt, x_line2, sim_exec, only_q1, width=34): - # one tricky double-wide char word-wrapping case .. but add others - assert '\n' not in txt +DOUBLE_W = ['⋯', '✔', '✓', '→', '←', '↦', '◉', '◯', '◌', '※', '—', '\x0e', '\x11', '\t', '\x0f', '\x12', '\x13', '\x14', '\x16', '\x17'] +@pytest.mark.parametrize('txt, target', [ + ('Disk, press \x0e to share via NFC, \x11 to share', ['Disk, press \x0e to share via NFC,', '\x11 to share']), + ((KEY_NFC * 17)+".", [KEY_NFC * 16, KEY_NFC + '.']), + ((KEY_NFC * 17)+(17*KEY_QR), [KEY_NFC * 16, KEY_NFC +(KEY_QR * 15), 2 * KEY_QR]), + ((KEY_NFC * 17)+" "+(17*KEY_QR), [KEY_NFC * 16, KEY_NFC, KEY_QR * 16, KEY_QR]), + ((KEY_NFC * 16)+".", [(KEY_NFC * 16)+'.']), + (f"Use {KEY_NFC}, or {KEY_F1}, {KEY_F2}, {KEY_F3}, or or or {KEY_F4}", [f"Use {KEY_NFC}, or {KEY_F1}, {KEY_F2}, {KEY_F3}, or or or", f"{KEY_F4}"]), + ("".join(DOUBLE_W), ["".join(DOUBLE_W[:16]), "".join(DOUBLE_W[16:])]), + ("".join(6*DOUBLE_W), ["".join(6*DOUBLE_W)[i:i + 16] for i in range(0, len(6*DOUBLE_W), 16)]), +]) +def test_word_wrap_double_wide(only_q1, txt, target, sim_exec): + width = 33 # check shared/ux.py CHAR_PER_W cmd = f'from utils import word_wrap; RV.write("\\n".join(word_wrap({txt!r}, {width})))' got = sim_exec(cmd) assert 'Traceback' not in got lines = got.split('\n') - assert width*2//3 <= len(lines[0]) <= width - assert lines[1] == x_line2 + assert lines == target - want_words = [i.strip() for i in txt.split()] - got_words = [i.strip() for i in got.split()] +@pytest.mark.parametrize('txt, target, width', [ + ((17*'a')+". ccc", [(17*'a')+".", "ccc"], 17), + ((17*'a')+".", [(17*'a')+"."], 17), + ((17*'-')+". ccc", [(17*'-')+".", "ccc"], 17), + ((34 * 'A'), [33 * "A", "A"], 33), + ((33 * 'A')+". ccc", [(33 * "A")+".", "ccc"], 33), + ('Coldcard is ready to sign spending transactions!', ['Coldcard is ready to sign', 'spending transactions!'], 33), + ('Coldcard is ready to sign spending transactions!', ['Coldcard is ready', 'to sign spending', 'transactions!'], 17), + ((16*"B")+ " AAAA", [16*"B", "AAAA"], 17), + ((16*"B")+ " AAAA", [(16*"B")+" ", "AAAA"], 17), + ((17*"B")+ " AAAA", [17*"B", "AAAA"], 17), + ((17*"B")+ " AAAA", [17*"B", " AAAA"], 17), + ("(recommended), or by typing numbers.", ["(recommended), or", "by typing numbers."], 17), + ("difficult to recover your funds.", ["difficult to", "recover your", "funds."], 17), + ("USB Serial Number:", ["USB Serial Number:"], 17), + ("USB Serial Number;", ["USB Serial Number;"], 17), + ("USB Serial Number/", ["USB Serial", "Number/"], 17), +]) +def test_word_wrap(txt, target, width, sim_exec): + cmd = f'from utils import word_wrap; RV.write("\\n".join(word_wrap({txt!r}, {width})))' + got = sim_exec(cmd) + assert 'Traceback' not in got - assert want_words == got_words + lines = got.split('\n') + + assert lines == target -from constants import AF_P2WSH, AF_P2SH, AF_P2WSH_P2SH, AF_CLASSIC, AF_P2WPKH, AF_P2WPKH_P2SH @pytest.mark.parametrize('addr,net,fmt', [ ( 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4', 'BTC', AF_P2WPKH ), @@ -360,4 +385,17 @@ def test_aes_compatibility(sim_execfile): res = sim_execfile('devtest/unit_aes_compat.py') assert res == "" + +def test_script(sim_execfile): + res = sim_execfile('devtest/unit_script.py') + assert res == "" + +def test_bip388(sim_execfile): + res = sim_execfile('devtest/unit_bip388.py') + assert res == "" + +def test_bip32(sim_execfile): + res = sim_execfile('devtest/unit_bip32.py') + assert res == "" + # EOF diff --git a/testing/test_upgrades.py b/testing/test_upgrades.py index b52353f4..b89eac03 100644 --- a/testing/test_upgrades.py +++ b/testing/test_upgrades.py @@ -14,7 +14,7 @@ assert packed_len == FW_HEADER_SIZE def parse_hdr(hdr): return Header(**dict(zip(FWH_PY_VALUES.split(), struct.unpack(FWH_PY_FORMAT, hdr)))) -@pytest.fixture() +@pytest.fixture def upload_file(dev): def doit(data, pkt_len=2048): for pos in range(0, len(data), pkt_len): @@ -25,13 +25,13 @@ def upload_file(dev): return doit @pytest.fixture -def make_firmware(): - def doit(hw_compat, fname='../stm32/firmware-signed.bin', outname='tmp-firmware.bin'): +def make_firmware(src_root_dir): + def doit(hw_compat, fname=f'{src_root_dir}/stm32/firmware-signed.bin', outname='tmp-firmware.bin'): # os.system(f'signit sign 3.0.99 --keydir ../stm32/keys -r {fname} -o {outname} --hw-compat=0x{hw_compat:02x}') p = subprocess.run( [ 'signit', 'sign', '3.0.99', - '--keydir', '../stm32/keys', + '--keydir', f'{src_root_dir}/stm32/keys', '-r', f'{fname}', '-o', f'{outname}', f'--hw-compat={hw_compat}' @@ -50,7 +50,7 @@ def make_firmware(): return doit @pytest.fixture -def upgrade_by_sd(open_microsd, cap_story, pick_menu_item, goto_home, press_select, microsd_path, sim_exec): +def upgrade_by_sd(open_microsd, cap_story, pick_menu_item, goto_home, press_select, microsd_path, sim_exec, src_root_dir): # send a firmware file over the microSD card @@ -64,7 +64,7 @@ def upgrade_by_sd(open_microsd, cap_story, pick_menu_item, goto_home, press_sele # create DFU file (wrapper) open(f'{fname}.bin', 'wb').write(data) dfu = microsd_path('tmp-firmware.dfu') - cmd = f'../external/micropython/tools/dfu.py -b 0x08008000:{fname}.bin {dfu}' + cmd = f'{src_root_dir}/external/micropython/tools/dfu.py -b 0x08008000:{fname}.bin {dfu}' print(cmd) os.system(cmd) @@ -91,28 +91,19 @@ def upgrade_by_sd(open_microsd, cap_story, pick_menu_item, goto_home, press_sele @pytest.mark.parametrize('mode', ['compat', 'incompat']) @pytest.mark.parametrize('transport', ['sd', 'usb']) -def test_hacky_upgrade(mode, cap_story, transport, dev, sim_exec, make_firmware, upload_file, sim_eval, upgrade_by_sd): - - # manually: run this test on all Mark1 thru 3 simulators - hw_label = eval(sim_eval('version.hw_label')) - assert hw_label[0:2] in ['mk', 'q1'] - try: - mkn = int(hw_label[2]) - except IndexError: - mkn = "q1" # q1 - - print(f"Simulator is {hw_label}") +def test_hacky_upgrade(mode, cap_story, transport, dev, sim_exec, make_firmware, upload_file, + upgrade_by_sd, press_cancel, is_q1): if mode == 'compat': - data = make_firmware(mkn) + data = make_firmware("q1" if is_q1 else 4) elif mode == 'incompat': - with pytest.raises(RuntimeError) as err: - if mkn == "q1": - mkn = 4 - - make_firmware(mkn-1) - assert "too big for our USB upgrades" in str(err) - return + if is_q1: + data = make_firmware(4) + else: + with pytest.raises(RuntimeError) as err: + make_firmware(3) + assert "too big for our USB upgrades" in str(err) + return hdr = data[FW_HEADER_OFFSET:FW_HEADER_OFFSET+FW_HEADER_SIZE] @@ -139,6 +130,7 @@ def test_hacky_upgrade(mode, cap_story, transport, dev, sim_exec, make_firmware, _, story = cap_story() assert "Install this new firmware?" in story + press_cancel() # check data was uploaded verbatim (VERY SLOW) # for pos in range(0, cooked.firmware_length + 128, 128): # to_eval = f'from sflash import SF;SF.array[{pos}:{pos+128}]' @@ -148,6 +140,6 @@ def test_hacky_upgrade(mode, cap_story, transport, dev, sim_exec, make_firmware, # assert a == hdr, f"wrong @ {pos}" # else: # assert a == data[pos:pos+128], repr(pos) - + # EOF diff --git a/testing/test_ux.py b/testing/test_ux.py index 6f534c6b..dc85336a 100644 --- a/testing/test_ux.py +++ b/testing/test_ux.py @@ -2,7 +2,7 @@ # import pytest, time, os, re, hashlib, shutil from helpers import xfp2str, prandom -from charcodes import KEY_DOWN, KEY_QR, KEY_NFC, KEY_DELETE +from charcodes import KEY_DOWN, KEY_QR, KEY_NFC, KEY_DELETE, KEY_CANCEL from constants import AF_CLASSIC, simulator_fixed_words, simulator_fixed_xfp from mnemonic import Mnemonic from bip32 import BIP32Node @@ -10,7 +10,7 @@ from bip32 import BIP32Node @pytest.fixture def enable_hw_ux(pick_menu_item, cap_story, press_select, goto_home): - def doit(way): + def doit(way, disable=False): pick_menu_item("Settings") pick_menu_item("Hardware On/Off") if way == "vdisk": @@ -18,13 +18,19 @@ def enable_hw_ux(pick_menu_item, cap_story, press_select, goto_home): _, story = cap_story() if "emulate a virtual disk drive" in story: press_select() - pick_menu_item("Enable") + if disable: + pick_menu_item("Default Off") + else: + pick_menu_item("Enable") elif way == "nfc": pick_menu_item("NFC Sharing") _, story = cap_story() if "(Near Field Communications)" in story: press_select() - pick_menu_item("Enable NFC") + if disable: + pick_menu_item("Default Off") + else: + pick_menu_item("Enable NFC") else: raise RuntimeError("TODO") @@ -39,8 +45,9 @@ def test_get_secrets(get_secrets, master_xpub): assert v['xpub'] == master_xpub def test_home_menu(cap_menu, cap_story, cap_screen, need_keypress, reset_seed_words, - press_select, press_cancel, press_down, is_q1): + press_select, press_cancel, press_down, is_q1, microsd_wipe): reset_seed_words() + microsd_wipe() # get to top, force a redraw press_cancel() press_cancel() @@ -80,7 +87,7 @@ def test_home_menu(cap_menu, cap_story, cap_screen, need_keypress, reset_seed_wo need_keypress('0') press_select() - time.sleep(.01) # required + time.sleep(.1) # required title, body = cap_story() assert title == 'NO-TITLE' @@ -95,33 +102,34 @@ def word_menu_entry(cap_menu, pick_menu_item, is_q1, do_keypresses, cap_screen): # easier for us on Q, but have to anticipate the autocomplete for n, w in enumerate(words, start=1): do_keypresses(w[0:2]) - time.sleep(0.50) + time.sleep(0.05) if 'Next key' in cap_screen(): do_keypresses(w[2]) - time.sleep(.1) + time.sleep(.01) if 'Next key' in cap_screen(): if len(w) > 3: do_keypresses(w[3]) else: do_keypresses(KEY_DOWN) - time.sleep(.1) + time.sleep(.01) pat = rf'{n}:\s?{w}' for x in range(10): if re.search(pat, cap_screen()): break - time.sleep(0.20) + time.sleep(0.02) else: raise RuntimeError('timeout') if len(words) == 23: do_keypresses(KEY_DOWN) - time.sleep(.3) + time.sleep(.03) cap_scr = cap_screen() while 'Next key' in cap_scr: target = cap_scr.split("\n")[-1].replace("Next key: ", "") + # picks first choice!? do_keypresses(target[0]) - time.sleep(.3) + time.sleep(.03) cap_scr = cap_screen() else: cap_scr = cap_screen() @@ -338,12 +346,13 @@ def test_import_from_dice(count, nwords, goto_home, pick_menu_item, cap_story, n time.sleep(0.1) title, body = cap_story() - assert f'Record these {nwords}' in body - - assert f'{KEY_QR if is_q1 else "(1)"} to view as QR Code' in body + target = f'Record these {nwords}' if is_q1: + assert target in title words = [i[:4].upper() for i in seed_story_to_words(body)] else: + assert target in body + assert "(1) to view as QR Code" in body words = [i[4:4+4].upper() for i in re.findall(r'[ 0-9][0-9]: \w*', body)] if not is_headless: @@ -389,8 +398,12 @@ def test_new_wallet(nwords, goto_home, pick_menu_item, cap_story, expect_ftux, pick_menu_item(f'{nwords} Words') title, body = cap_story() - assert title == 'NO-TITLE' - assert f'Record these {nwords} secret words!' in body + target = f'Record these {nwords} secret words!' + if is_q1: + assert target in title + else: + assert title == 'NO-TITLE' + assert target in body if is_q1: words = seed_story_to_words(body) @@ -584,10 +597,11 @@ def test_show_seed(mode, b39_word, goto_home, pick_menu_item, cap_story, need_ke time.sleep(0.01) title, body = cap_story() - assert title == 'NO-TITLE' + if not is_q1: + assert title == 'NO-TITLE' if mode == 'words': - assert '24' in body + assert '24' in (title if is_q1 else body) lines = body.split('\n') if is_q1: @@ -597,10 +611,10 @@ def test_show_seed(mode, b39_word, goto_home, pick_menu_item, cap_story, need_ke if b39_word: if is_q1: - assert lines[11] == 'BIP-39 Passphrase:' - assert "*" in lines[12] - assert "Seed+Passphrase" in lines[14] - ek = lines[15] + assert lines[9] == 'BIP-39 Passphrase:' + assert "*" in lines[10] + assert "Seed+Passphrase" in lines[12] + ek = lines[13] else: assert lines[26] == 'BIP-39 Passphrase:' assert "*" in lines[27] @@ -702,11 +716,14 @@ def test_destroy_seed(goto_home, pick_menu_item, cap_story, press_select, def test_menu_wrapping(goto_home, pick_menu_item, cap_story, cap_menu, press_select, press_up, press_down, press_cancel, - is_q1): + is_q1, settings_remove): + settings_remove("wa") # disable goto_home() # first try that infinite scroll is turned off # home - for i in range(10): # settings on 5th in home (10 is way past that) + assert len(cap_menu()) < 10 + + for i in range(10): press_down() # sitting at Logout @@ -717,7 +734,7 @@ def test_menu_wrapping(goto_home, pick_menu_item, cap_story, cap_menu, press_select() pick_menu_item("Menu Wrapping") press_select() - pick_menu_item("Enable") + pick_menu_item("Always Wrap") time.sleep(1) press_cancel() # back to home menu press_cancel() # at Ready To Sign @@ -728,7 +745,7 @@ def test_menu_wrapping(goto_home, pick_menu_item, cap_story, cap_menu, press_select() pick_menu_item("Menu Wrapping") - pick_menu_item("Default Off") + pick_menu_item("Default") time.sleep(1) press_cancel() # back in home menu press_cancel() # at Ready To Sign @@ -802,7 +819,6 @@ def test_sign_file_from_list_files(f_len, goto_home, cap_story, pick_menu_item, verify_detached_signature_file([fname], signame, "sd", AF_CLASSIC) time.sleep(0.1) _, story = cap_story() - assert "(4) to sign file digest and export detached signature" not in story assert "(6) to delete" in story @@ -812,8 +828,71 @@ def test_sign_file_from_list_files(f_len, goto_home, cap_story, pick_menu_item, assert "List Files" in menu +def test_rename_from_list_files(goto_home, cap_story, pick_menu_item, need_keypress, is_q1, + microsd_path, press_select, cap_screen, enter_complex): + def clear(fname): + for i in range(len(fname)): + if not is_q1 and not i: + # Mk4 different menu entry UX + continue + need_keypress(KEY_DELETE if is_q1 else "x") + time.sleep(0.01) + + fname = "file_to_rename.pdf" + fpath = microsd_path(fname) + contents = os.urandom(64) + digest = hashlib.sha256(contents).digest().hex() + with open(fpath, "wb") as f: + f.write(contents) + + goto_home() + pick_menu_item("Advanced/Tools") + pick_menu_item('File Management') + pick_menu_item('List Files') + time.sleep(0.1) + pick_menu_item(fname) + time.sleep(0.1) + _, story = cap_story() + assert f"SHA256({fname})" in story + assert digest in story + assert "Press (1) to rename file" in story + need_keypress("1") + time.sleep(0.1) + if is_q1: + scr = cap_screen() + assert fname in scr + + clear(fname) + + bad_fnames = ["renamed file.txt", "/sd/renamed_file.txt", "renamed\\file.txt"] + for bad in bad_fnames: + enter_complex(bad, b39pass=False) + time.sleep(.1) + title, story = cap_story() + assert title == "Failure" + assert "Failed to rename the file" in story + assert "illegal char" in story + press_select() + time.sleep(.1) + need_keypress("1") # rename again + time.sleep(.1) + clear(fname) + if not is_q1: + need_keypress("1") # toggle case back to upper (enter complex expect to start in that state) + + new_fname = "renamed_file.txt" + enter_complex(new_fname, b39pass=False) + time.sleep(.1) + _, story = cap_story() + assert f"SHA256({new_fname})" in story + assert digest in story + assert not os.path.exists(fpath) + assert os.path.exists(microsd_path(new_fname)) + + def test_bip39_pw_signing_xfp_ux(pick_menu_item, press_select, cap_story, enter_complex, - reset_seed_words, cap_menu, go_to_passphrase): + reset_seed_words, cap_menu, go_to_passphrase, microsd_wipe): + microsd_wipe() # need to wipe all PSBT on SD card so we do not proceed to signing go_to_passphrase() enter_complex("21coinkite21", apply=True) time.sleep(0.3) @@ -821,6 +900,7 @@ def test_bip39_pw_signing_xfp_ux(pick_menu_item, press_select, cap_story, enter_ assert title == "[0C9DC99D]" assert 'Above is the master key fingerprint of the new wallet' in story press_select() # confirm passphrase + time.sleep(0.1) m = cap_menu() assert m[0] == "[0C9DC99D]" pick_menu_item("Ready To Sign") @@ -949,19 +1029,48 @@ def test_custom_pushtx_url(goto_home, pick_menu_item, press_select, enter_comple assert settings_get('ptxurl', None) is None -@pytest.mark.parametrize("fname,mode,ftype", [ - ("ccbk-start.json", "r", "J"), - ("ckcc-backup.txt", "r", "U"), - ("devils-txn.txn", "rb", "T"), - ("example-change.psbt", "rb", "P"), - ("sim_conso5.psbt", "rb", "P"), # binary psbt - ("payjoin.psbt", "r", "U"), # base64 string in file - ("worked-unsigned.psbt", "rb", "U"), # hex string psbt - ("coldcard-export.json", "rb", "J"), - ("coldcard-export.sig", "r", "U"), +@pytest.mark.parametrize("fname,ftype", [ + ("ccbk-start.json", "J"), + ("ckcc-backup.txt", "U"), + ("devils-txn.txn", "T"), + ("example-change.psbt", "P"), + ("sim_conso5.psbt", "P"), # binary psbt + ("payjoin.psbt", "U"), # base64 string in file + ("worked-unsigned.psbt", "U"), # hex string psbt + ("coldcard-export.json", "J"), + ("coldcard-export.sig", "U"), ]) -def test_qr_share_files(fname, mode, ftype, readback_bbqr, need_keypress, - goto_home, pick_menu_item, is_q1, cap_menu): +def test_bbqr_share_files(fname, ftype, readback_bbqr, need_keypress, src_root_dir, + goto_home, pick_menu_item, is_q1, cap_menu, sim_root_dir): + goto_home() + if not is_q1: + pick_menu_item("Advanced/Tools") + pick_menu_item("File Management") + assert "BBQr File Share" not in cap_menu() + return + + fpath = f"{src_root_dir}/testing/data/" + fname + shutil.copy2(fpath, f'{sim_root_dir}/MicroSD') + pick_menu_item("Advanced/Tools") + pick_menu_item("File Management") + pick_menu_item("BBQr File Share") + time.sleep(.1) + pick_menu_item(fname) + file_type, rb = readback_bbqr() + assert file_type == ftype + with open(fpath, "rb") as f: + res = f.read() + + assert res == rb + os.remove(f'{sim_root_dir}/MicroSD/' + fname) + +@pytest.mark.parametrize("fname", [ + "ccbk-start.json", + "devils-txn.txn", + "payjoin.psbt", # base64 string in file +]) +def test_qr_share_files(fname, pick_menu_item, goto_home, is_q1, cap_menu, cap_screen_qr, + src_root_dir, sim_root_dir): goto_home() if not is_q1: pick_menu_item("Advanced/Tools") @@ -969,23 +1078,123 @@ def test_qr_share_files(fname, mode, ftype, readback_bbqr, need_keypress, assert "QR File Share" not in cap_menu() return - fpath = "data/" + fname - shutil.copy2(fpath, '../unix/work/MicroSD') + fpath = f"{src_root_dir}/testing/data/" + fname + shutil.copy2(fpath, f'{sim_root_dir}/MicroSD') pick_menu_item("Advanced/Tools") pick_menu_item("File Management") pick_menu_item("QR File Share") time.sleep(.1) pick_menu_item(fname) - file_type, rb = readback_bbqr() - assert file_type == ftype - with open(fpath, mode) as f: + qr = cap_screen_qr() + with open(fpath, "r") as f: res = f.read() - if fname.endswith(".txn"): - res = bytes.fromhex(res.decode()) + assert res == qr.decode() + os.remove(f'{sim_root_dir}/MicroSD/' + fname) - assert res == rb - os.remove('../unix/work/MicroSD/' + fname) +@pytest.mark.parametrize("word,cs_word", [ + # few combos with all words with length 8 + their longest possible checksum word + ("acoustic", "decrease"), + ("electric", "witness"), + ("umbrella", "convince"), + ("universe", "hamster"), +]) +def test_q1_24_8char_words(set_seed_words, is_q1, goto_home, pick_menu_item, press_select, + cap_story, cap_screen, word, cs_word): + # /issues/965 + # vectors calculated with `coldcard-mpy`: + # + # w8 = [w for w in bip39.wordlist_en if len(w) >= 8] + # for w in w8: + # wl = ([w]*23) + # ds = list(bip39.a2b_words_guess(wl)) + # print(w, max(ds, key=len)) + if not is_q1: + raise pytest.skip("only Q") + + goto_home() + # longest words in wordlist_en have 8 chars + words = ([word] * 23) + [cs_word] + set_seed_words(" ".join(words)) + + pick_menu_item("Advanced/Tools") + pick_menu_item("Danger Zone") + pick_menu_item("Seed Functions") + pick_menu_item('View Seed Words') + time.sleep(.01) + press_select() # skip warning + time.sleep(0.01) + + title, body = cap_story() + assert '24' in title + scr = cap_screen().split("\n") + assert "Seed words (24)" in scr[0] + assert scr[1] == "" + # 8 rows + assert len(scr[2:]) == 8 + + x = 1 + y = 9 + z = 17 + for row in scr[2:]: + # each row contains 3 colons (aka 3 words) + srow = [r for r in row.split(" ") if r] # filter empty strings + assert len(srow) == 3 # three columns + + # 8 words for each column + (tx, w0), (ty, w1), (tz, w2) = [pr.split(":") for pr in srow] + assert x == int(tx) and y == int(ty) and z == int(tz) + x += 1 + y += 1 + z += 1 + + if int(tz) == 24: + # last line with checksum word + assert w2 == cs_word + assert w0 == w1 == word + else: + assert w0 == w1 == w2 == word + + +def test_file_picker_suffixes(pick_menu_item, goto_home, cap_story, microsd_wipe, press_select, + microsd_path): + # make sure no .txt, .7z & .pdf files are not on the SD card + microsd_wipe() + # create files that must not be recognized, because they're missing the dot + for fn in ["backup7z", "backuptxt", "template:pdf"]: + with open(microsd_path(fn), "w") as f: + f.write("dummy") + + goto_home() + pick_menu_item("Advanced/Tools") + pick_menu_item("Danger Zone") + pick_menu_item("I Am Developer.") + pick_menu_item("Restore Bkup") + time.sleep(.1) + _, story = cap_story() + assert "No suitable files found" in story + assert "The filename must end in: .7z OR .txt" in story + press_select() + + goto_home() + pick_menu_item("Advanced/Tools") + pick_menu_item("Paper Wallets") + press_select() + pick_menu_item("Don't make PDF") + time.sleep(.1) + _, story = cap_story() + assert "No suitable files found" in story + assert "The filename must end in: .pdf" in story + + goto_home() + pick_menu_item("Advanced/Tools") + pick_menu_item("File Management") + pick_menu_item("Sign Text File") + time.sleep(.1) + _, story = cap_story() + assert "No suitable files found" in story + assert "The filename must end in: .txt OR .json" in story + microsd_wipe() @pytest.mark.onetime @@ -994,7 +1203,7 @@ def test_dump_menutree(sim_execfile): sim_execfile('devtest/menu_dump.py') if 0: - # show what the final word can be (debug only) + # show what the final word can be (debug only) Mk4 only def test_23_words(goto_home, pick_menu_item, cap_story, need_keypress, unit_test, cap_menu, word_menu_entry, get_secrets, reset_seed_words, cap_screen_qr, qr_quality_check): unit_test('devtest/clear_seed.py') diff --git a/testing/test_vdisk.py b/testing/test_vdisk.py index 44ef9125..c33161c0 100644 --- a/testing/test_vdisk.py +++ b/testing/test_vdisk.py @@ -29,14 +29,16 @@ def test_vd_basics(dev, virtdisk_path, is_simulator): assert os.path.isfile(virtdisk_path(f'ident/ckcc-{sn}.txt')) @pytest.fixture -def try_sign_virtdisk(press_select, virtdisk_path, cap_story, virtdisk_wipe, press_cancel): +def try_sign_virtdisk(press_select, virtdisk_path, cap_story, virtdisk_wipe, press_cancel, + pick_menu_item, goto_home, sim_root_dir): # like "try_sign" but use Virtual Disk to send/receive PSBT/results # - on real dev, need user to manually say yes ... alot # - on simulator, start with "--eject" arg so no SDCard emulated - def doit(f_or_data, accept=True, expect_finalize=False, accept_ms_import=False, complete=False, encoding='binary'): + def doit(f_or_data, accept=True, expect_finalize=False, accept_ms_import=False, + encoding='binary'): assert not accept_ms_import, 'no support' assert accept, 'no support' @@ -48,7 +50,8 @@ def try_sign_virtdisk(press_select, virtdisk_path, cap_story, virtdisk_wipe, pre filename = 'memory' else: filename = f_or_data - ip = open(f_or_data, 'rb').read() + with open(f_or_data, 'rb') as f: + ip = f.read() if ip[0:10] == b'70736274ff': ip = a2b_hex(ip.strip()) assert ip[0:5] == b'psbt\xff' @@ -65,12 +68,16 @@ def try_sign_virtdisk(press_select, virtdisk_path, cap_story, virtdisk_wipe, pre virtdisk_wipe() xfn = virtdisk_path('testcase.psbt') - open(xfn, 'wb').write(ip) + with open(xfn, 'wb') as f: + f.write(ip) - press_select() # ready to sign (hopefully) + goto_home() + pick_menu_item("Ready To Sign") # CC scans drive, reads PSBT, verifies... time.sleep(1) + title, story = cap_story() + assert "OK TO SEND" in title # approve siging txn if accept: @@ -78,35 +85,35 @@ def try_sign_virtdisk(press_select, virtdisk_path, cap_story, virtdisk_wipe, pre else: press_cancel() - if accept == False: + if accept is False: time.sleep(0.050) # look for "Aborting..." ?? return ip, None, None # wait for it to finish signing + time.sleep(.1) title, story = cap_story() - if "OK TO SEND" in title or "PSBT Signed" in title: - press_select() - result_fn = xfn.replace('.psbt', '-*.psbt') - result_txn = xfn.replace('.psbt', '.txn') + split_story = story.split("\n\n") + result_fn = split_story[1] + result_txn = None + result_txid = None + if expect_finalize: + result_txn = split_story[3] + result_txid = split_story[4].split("\n")[-1] got_psbt = None got_txn = None txid, got_txid = None, None - for i in range(15): - try: - got_txn = open(result_txn, 'rb').read() - except FileNotFoundError as e: - print(e) - pass - lst = glob.glob(result_fn) - if lst: - assert len(lst) == 1, "multi files: " + ', '.join(lst) - result_fn = lst[0] - got_psbt = open(result_fn, 'rb').read() + for i in range(15): + if result_txn: + with open(virtdisk_path(result_txn), 'rb') as f: + got_txn = f.read() + + with open(virtdisk_path(result_fn), 'rb') as f: + got_psbt = f.read() # for delete-psbt mode for ff in glob.glob(virtdisk_path('*.txn')): @@ -115,7 +122,9 @@ def try_sign_virtdisk(press_select, virtdisk_path, cap_story, virtdisk_wipe, pre got_txid = re.findall(r'[0-9a-f]{64}', ff)[0] except IndexError: got_txid = None - got_txn = a2b_hex(open(ff, 'rt').read().strip()) + + with open(ff, 'rt') as f: + got_txn = a2b_hex(f.read().strip()) if got_txn or got_psbt: break @@ -130,11 +139,11 @@ def try_sign_virtdisk(press_select, virtdisk_path, cap_story, virtdisk_wipe, pre txid = got_txid if got_txid: - assert got_txn - assert got_txid == txid assert expect_finalize - open("debug/vd-result.txn", 'wb').write(got_txid) - + assert got_txn + assert got_txid == txid == result_txid + with open(f"{sim_root_dir}/debug/vd-result.txn", 'wb') as f: + f.write(got_txid) # check output encoding matches input (for PSBT only) if got_psbt: @@ -160,7 +169,8 @@ def try_sign_virtdisk(press_select, virtdisk_path, cap_story, virtdisk_wipe, pre if got_psbt: assert got_psbt[0:5] == b'psbt\xff' - open("debug/vd-result.psbt", 'wb').write(got_psbt) + with open(f"{sim_root_dir}/debug/vd-result.psbt", 'wb') as f: + f.write(got_psbt) from psbt import BasicPSBT was = BasicPSBT().parse(ip) @@ -168,16 +178,18 @@ def try_sign_virtdisk(press_select, virtdisk_path, cap_story, virtdisk_wipe, pre assert was.txn == now.txn assert was != now - return ip, (got_psbt or got_txn), txid + return ip, (got_txn or got_psbt), txid return doit @pytest.mark.unfinalized # iff partial=1 +@pytest.mark.reexport @pytest.mark.parametrize('encoding', ['binary', 'hex', 'base64']) @pytest.mark.parametrize('num_outs', [1,2]) @pytest.mark.parametrize('partial', [1, 0]) -def test_virtdisk_signing(encoding, num_outs, partial, try_sign_virtdisk, fake_txn, dev, sd_cards_eject): +def test_virtdisk_signing(encoding, num_outs, partial, try_sign_virtdisk, fake_txn, dev, + sd_cards_eject, signing_artifacts_reexport): xp = dev.master_xpub sd_cards_eject() @@ -188,10 +200,18 @@ def test_virtdisk_signing(encoding, num_outs, partial, try_sign_virtdisk, fake_t pp = psbt.inputs[0].bip32_paths[pk] psbt.inputs[0].bip32_paths[pk] = b'what' + pp[4:] - psbt = fake_txn(2, num_outs, xp, segwit_in=True, psbt_hacker=hack) + psbt = fake_txn(2, num_outs, xp, addr_fmt="p2wpkh", psbt_hacker=hack) _, txn, txid = try_sign_virtdisk(psbt, expect_finalize=not partial, encoding=encoding) + sd_cards_eject(slot_a=0) + _psbt, _txn = signing_artifacts_reexport("vdisk", tx_final=not partial, txid=txid, + encoding=encoding) + if partial: + assert _psbt == txn + else: + assert _txn == txn + if 0: @pytest.mark.parametrize('num_outs', [ 1, 20, 250]) def test_virtdisk_after(num_outs, fake_txn, try_sign, nfc_read, need_keypress, cap_story, only_mk4): @@ -237,11 +257,11 @@ def test_macos_detection(): # not a portable test... at all. import platform, subprocess, plistlib - if not platform.platform().startswith('macOS-11'): + if not platform.platform().startswith('macOS-'): raise pytest.xfail("requires MacOS") if not os.path.isdir('/Volumes/COLDCARD'): - raise pytest.xfail("needs COLDCARD mounted in usual spot") + raise pytest.xfail("needs COLDCARD connected & mounted") cmd = ['diskutil', 'info', '-plist', '/Volumes/COLDCARD'] pl = subprocess.check_output(cmd) @@ -260,7 +280,7 @@ def test_macos_detection(): def test_import_prv_virtdisk(testnet, pick_menu_item, cap_story, need_keypress, unit_test, cap_menu, get_secrets, multiple_runs, reset_seed_words, virtdisk_path, virtdisk_wipe, - settings_set, press_select): + settings_set, press_select, enable_hw_ux): # copied from test_ux as we need vdisk enabled and card ejected if testnet: netcode = "XTN" @@ -271,6 +291,8 @@ def test_import_prv_virtdisk(testnet, pick_menu_item, cap_story, need_keypress, unit_test('devtest/clear_seed.py') + enable_hw_ux("vdisk") + fname = 'test-%d.txt' % os.getpid() path = virtdisk_path(fname) diff --git a/testing/txn.py b/testing/txn.py index f16ddb15..dad6e4e3 100644 --- a/testing/txn.py +++ b/testing/txn.py @@ -2,32 +2,43 @@ # # Creating fake transactions. Not simple. # -import pytest, struct +import pytest, struct, os from ckcc_protocol.protocol import MAX_TXN_LEN from psbt import BasicPSBT, BasicPSBTInput, BasicPSBTOutput from io import BytesIO -from helpers import fake_dest_addr, make_change_addr, hash160, taptweak +from helpers import fake_dest_addr, make_change_addr, hash160, taptweak, str_to_path from base58 import decode_base58 from bip32 import BIP32Node -from constants import ADDR_STYLES, simulator_fixed_tprv +from constants import simulator_fixed_tprv from serialize import uint256_from_str from ctransaction import CTransaction, COutPoint, CTxIn, CTxOut -@pytest.fixture() +@pytest.fixture def fake_txn(dev, pytestconfig): # make various size txn's ... completely fake and pointless values # - but has UTXO's to match needs # - input total = num_inputs * 1BTC - def doit(num_ins, num_outs, master_xpub=None, subpath="0/%d", fee=10000, - invals=None, outvals=None, segwit_in=False, wrapped=False, - outstyles=['p2pkh'], psbt_hacker=None, change_outputs=[], - capture_scripts=None, add_xpub=None, op_return=None, - psbt_v2=None, input_amount=1E8, taproot_in=False): + def doit(inputs, outputs, master_xpub=None, psbt_hacker=None, add_xpub=None, psbt_v2=None, + fee=200, addr_fmt="p2wpkh", input_amount=100_000_000, capture_scripts=None, + force_full_tx_utxo=False, supply_num_ins=1, supply_num_outs=1): # input_amount in sats psbt = BasicPSBT() + # support old argument types + if isinstance(inputs, int): + num_ins = inputs + inputs = range(num_ins) + else: + num_ins = len(inputs) + + if isinstance(outputs, int): + num_outs = outputs + outputs = range(num_outs) + else: + num_outs = len(outputs) + if psbt_v2 is None: # anything passed directly to this function overrides # pytest flag --psbt2 - only care about pytest flag @@ -45,56 +56,75 @@ def fake_txn(dev, pytestconfig): master_xpub = master_xpub or dev.master_xpub or simulator_fixed_tprv # we have a key; use it to provide "plausible" value inputs - mk = BIP32Node.from_wallet_key(master_xpub) - xfp = mk.fingerprint() + my_mk = BIP32Node.from_wallet_key(master_xpub) + my_xfp = my_mk.fingerprint() + + foreign_mk = BIP32Node.from_master_secret(os.urandom(32)) + foreign_xfp = foreign_mk.fingerprint() psbt.inputs = [BasicPSBTInput(idx=i) for i in range(num_ins)] psbt.outputs = [BasicPSBTOutput(idx=i) for i in range(num_outs)] - for i in range(num_ins): + inp_total = 0 + added_mine = False + added_foreign = False + for i, inp in enumerate(inputs): + sp = f"0/{i}" + af = addr_fmt + ia = input_amount + is_mine = True + try: + if inp[0] is not None: + af = inp[0] + if inp[1] is not None: + sp = inp[1] + if inp[2] is not None: + ia = inp[2] + is_mine = inp[3] + except: pass + # make a fake txn to supply each of the inputs - # - each input is 1BTC + # - each input is 1BTC if not specified otherwise + inp_total += ia + + # will this be my input that I cna sign + if is_mine: + mk = my_mk + mfp = my_xfp + added_mine = True + else: + mk = foreign_mk + mfp = foreign_xfp + added_foreign = True # addr where the fake money will be stored. - subkey = mk.subkey_for_path(subpath % i) + int_path = str_to_path(sp) + subkey = mk.subkey_for_path(sp) sec = subkey.sec() assert len(sec) == 33, "expect compressed" - assert subpath[0:2] == '0/' - if taproot_in: + is_segwit = True + if af == "p2tr": tweaked_xonly = taptweak(sec[1:]) - - if segwit_in and taproot_in: - # if both specified: - # even is segwit v0 - # odd is segvit v1 (taproot) - if i % 2 == 0: - psbt.inputs[i].bip32_paths[sec] = xfp + struct.pack(' go to the Derive Entropy menu inside settings, also loads XPRV from BIP - `--secret 01abababab...` => directly set contents of SE secret, see SecretStash.encode() - `--eject` => pretend no (simulated) SD Card is inserted -- `--eff` => (mk4) wipe setttings at startup, use simulator defaults +- `--eff` => wipe setttings at startup, use simulator defaults, save nothing. - `--seq 1234yx34` => after start, enter those keypresses to get you to some submenu - `--seq 2ENTER` => (Q) press 2 then ENTER, does QR at startup - `--bootup-movie` => begin a movie on startup, to capture boot sequence - `--scan` => (Q) use attached serial port connected to a QR scanner module (not simulation) - `--battery` => (Q) assume the USB cable is NOT connected (ie. on battery power) - `--early-usb` => start simulated USB interface even before user is login (useful for login testing) +- `--segregate` => scroll down to `Running simulators in parallel` section +- `--bricked` => simulate a system w/ bricked SE1: no more pin tries, etc. +- `--fails N` => simulate N wrong PIN attempts before login, where (1 <= N <= 13) See `variant/sim_settings.py` for the details of settings-related options. @@ -78,7 +81,7 @@ See `variant/sim_settings.py` for the details of settings-related options. ## Requirements -- uses good olde `xterm` for console input and output +- uses good old `xterm` for console input and output - this directory has additional `requirements.txt` (a superset of other requirements of the project) - run "brew install sdl2" before/after doing python requirements - run "make setup" then "make" @@ -99,4 +102,39 @@ See `variant/sim_settings.py` for the details of settings-related options. - linux supported (only tested on debian based Ubuntu 20.04), please check main README.md - Windows can work under WSL but is not supported by our team. Follow instructions on +# Running simulators in parallel +Normally, when simulator is spwned with `./simulator.py --eff --q1` (or similar) +the default socket file is produced (`/tmp/ckcc-simulator.sock`) for simulator to be able to emulate various types of comms. +Each time new simulator is spwned (while som older still running) the socket file gets claimed by the most recently opened simulator. +You can continue to use older simulator manually, but it is no longer possible to communicate via the socket file. +Besides shared socket file, all simulators share some working directories (`work` & previously `testing/debug`, currently `work/debug`). + +To enable full parallel operation on multiple simulators use `--segregate` simulator flag that: +* creates unique simulator socket file `/tmp/ckcc-simulator-.sock` for every simulator spwned with the flag +* creates separate simulator work directory in `/tmp/cc-simulators/` (every simulator has its own debug dir in work dir) + +Spawn two simulators: + +```shell +./simulator.py --eff --segregate # Mk4 +./simulator.py --eff --segregate --q1 # Q +``` + +Two directories were created inside `/tmp/cc-simulators` and two socket files in `/tmp` with same PID in names as directory names created. +To operate above simulators new `--socket`/`-c` flag needs to be used with client: `ckcc -c /tmp/ckcc-simulator-35156.sock ...` + +```shell +ckcc -c /tmp/ckcc-simulator-35156.sock addr -s +ckcc -c /tmp/ckcc-simulator-35291.sock addr -s +``` + +Simulator socket path is dumped to STDOUT after simulator is started: +```shell +Coldcard Simulator: Commands (over simulated window): + - Control-Q to quit + - ^Z to snapshot screen. + - ^S/^E to start/end movie recording + - ^N to capture NFC data (tap it) + - socket: /tmp/ckcc-simulator-35291.sock +``` diff --git a/unix/linux_addr.patch b/unix/linux_addr.patch deleted file mode 100644 index c7174eb5..00000000 --- a/unix/linux_addr.patch +++ /dev/null @@ -1,18 +0,0 @@ -diff --git a/unix/variant/pyb.py b/unix/variant/pyb.py -index d22bb1b..fe8e7ca 100644 ---- a/unix/variant/pyb.py -+++ b/unix/variant/pyb.py -@@ -36,10 +36,10 @@ class USB_HID: - import usocket as socket - self.pipe = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) - # If on linux, try commenting the following line -- addr = bytes([len(self.fn)+2, socket.AF_UNIX] + list(self.fn)) -+ # addr = bytes([len(self.fn)+2, socket.AF_UNIX] + list(self.fn)) - # If on linux, try uncommenting the following two lines -- #import struct -- #addr = struct.pack('H108s', socket.AF_UNIX, self.fn) -+ import struct -+ addr = struct.pack('H108s', socket.AF_UNIX, self.fn) - while 1: - try: - self.pipe.bind(addr) diff --git a/unix/sim_boot.py b/unix/sim_boot.py index b39b6128..2a28e6c0 100644 --- a/unix/sim_boot.py +++ b/unix/sim_boot.py @@ -6,6 +6,11 @@ import machine, pyb, sys +socket_path = sys.argv.pop() # last arg must be a socket path - remove +assert ("ckcc-simulator" in socket_path) and (".sock" in socket_path) +pyb.SOCKET_FILE_PATH = socket_path +print("socket:", pyb.SOCKET_FILE_PATH) + if '--metal' in sys.argv: # next in argv will be two open file descriptors to use for serial I/O to a real Coldcard import bare_metal @@ -24,11 +29,16 @@ if '--sflash' not in sys.argv: if '--eff' in sys.argv: # ignore files ondisk from previous runs, and also dont write any - nvstore.SettingsObject.load = lambda *a:None - nvstore.SettingsObject.save = lambda *a:None - # limitation: pre-login values arent stored even during operation + # - but do track settings during this run + NVSTORE_FAKE = {bytes(32): dict(sim_defaults)} # prelogin values - #glob.settings.current = dict(sim_defaults) + def _monkey_load(self, *a): + self.current = dict(NVSTORE_FAKE.get(self.nvram_key, False) or sim_defaults) + def _monkey_save(self, *a): + NVSTORE_FAKE[self.nvram_key] = dict(self.current) + + nvstore.SettingsObject.load = _monkey_load + nvstore.SettingsObject.save = _monkey_save if '--early-usb' in sys.argv: from usb import enable_usb diff --git a/unix/simulator.py b/unix/simulator.py index 016bb307..af7e94fa 100755 --- a/unix/simulator.py +++ b/unix/simulator.py @@ -14,12 +14,10 @@ # Limitations: # - USB light not fully implemented, because happens at irq level on real product # -import os, sys, signal, time, pdb, tempfile, struct, zlib -import subprocess, asyncio +import os, sys, signal, time, pdb, tempfile, struct, zlib, subprocess, shutil from dataclasses import dataclass import sdl2.ext -import PIL -from PIL import Image, ImageSequence, ImageOps +from PIL import Image, ImageOps from select import select import fcntl from bare import BareMetal @@ -31,6 +29,7 @@ UNIX_SOCKET_PATH = '/tmp/ckcc-simulator.sock' current_led_state = 0x0 + def activate_file(filename): # see if sys.platform == "win32": @@ -745,6 +744,14 @@ def handle_q1_key_events(event, numpad_tx, data_tx): def start(): is_q1 = ('--q1' in sys.argv) + segregate = ("--segregate" in sys.argv) + pid = os.getpid() + # for compatibility with old clients + # UNIX_SOCKET_PATH is always used if not segregate + socket_path = UNIX_SOCKET_PATH + if segregate: + socket_path = '/tmp/ckcc-simulator-%d.sock' % pid + if "--headless" in sys.argv: sys.argv.remove("--headless") is_headless = True @@ -760,6 +767,7 @@ def start(): - ^S/^E to start/end movie recording - ^N to capture NFC data (tap it)''' ) + print(" - socket: %s" % socket_path) if is_q1: print('''\ Q1 specials: @@ -818,10 +826,10 @@ Q1 specials: # manage unix socket cleanup for client def sock_cleanup(): import os - fp = UNIX_SOCKET_PATH + fp = socket_path if os.path.exists(fp): os.remove(fp) - sock_cleanup() + import atexit atexit.register(sock_cleanup) @@ -849,11 +857,30 @@ Q1 specials: scan_args = [ '--scan', str(port.fileno()) ] sys.argv.remove('--scan') - os.chdir('./work') - cc_cmd = ['../coldcard-mpy', - '-X', 'heapsize=9m', - '-i', '../sim_boot.py'] + [str(i) for i in pass_fds] \ - + metal_args + scan_args + sys.argv[1:] + # unix + cwd = os.getcwd() + # abs paths + cc_mpy = os.path.join(cwd, "coldcard-mpy") + sim_boot = os.path.join(cwd, "sim_boot.py") + + if segregate: + os.makedirs("/tmp/cc-simulators", exist_ok=True) + os.chdir("/tmp/cc-simulators") + # our new work /tmp/cc-simulators/ + os.mkdir(str(pid)) + os.chdir(str(pid)) + os.mkdir("MicroSD") + os.mkdir("settings") + os.mkdir("VirtDisk") + os.mkdir("debug") + # needed for VirtDisk test + shutil.copy(os.path.join(cwd, "work", "VirtDisk", "README.md"), + os.path.join(os.getcwd(), "VirtDisk", "README.md")) + else: + os.chdir('./work') + + cc_cmd = [cc_mpy, '-X', 'heapsize=9m', '-i', sim_boot] + [str(i) for i in pass_fds] \ + + metal_args + scan_args + sys.argv[1:] + [socket_path] if is_headless: pass_fds.remove("-1") diff --git a/unix/variant/ckcc.py b/unix/variant/ckcc.py index e32cb0b4..d634a3c9 100644 --- a/unix/variant/ckcc.py +++ b/unix/variant/ckcc.py @@ -98,6 +98,9 @@ def gate(method, buf_io, arg2): if method == 5: # are we a brick? No. + if '--bricked' in sys.argv: + # if SE1 has pairing secret rotated; wont be able to do much + return 1 return 0 if method == 6: @@ -198,10 +201,9 @@ def is_simulator(): def is_debug_build(): return True - def get_sim_root_dirs(): # return a single path and list of files to pretend to find there - import ffilib, os + import ffilib libc = ffilib.libc() b = bytearray(500) diff --git a/unix/variant/pyb.py b/unix/variant/pyb.py index 4c06ad67..b0b6b286 100644 --- a/unix/variant/pyb.py +++ b/unix/variant/pyb.py @@ -2,9 +2,10 @@ # import utime as time import uerrno as errno -import sys +import usocket as socket +import sys, struct, os -from machine import Pin +SOCKET_FILE_PATH = None class USB_VCP: @staticmethod @@ -28,22 +29,16 @@ def usb_mode(nm=UNSET, **kws): return _umode class USB_HID: - fn = b'/tmp/ckcc-simulator.sock' - def __init__(self): self.pipe = None self.last_from = None self._open() def _open(self): - import sys - import usocket as socket + + assert SOCKET_FILE_PATH # has to be set in sim_boot.py by caller self.pipe = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) - # If on linux, try commenting the following line - addr = bytes([len(self.fn)+2, socket.AF_UNIX] + list(self.fn)) - # If on linux, try uncommenting the following two lines - #import struct - #addr = struct.pack('H108s', socket.AF_UNIX, self.fn) + addr = struct.pack('H108s', socket.AF_UNIX, SOCKET_FILE_PATH.encode()) while 1: try: self.pipe.bind(addr) @@ -51,8 +46,7 @@ class USB_HID: except OSError as exc: if exc.args[0] == errno.EADDRINUSE: # handle restart after first run - import os - os.remove(self.fn) + os.remove(SOCKET_FILE_PATH) continue def recv(self, buf, timeout=0): diff --git a/unix/variant/sim_quickstart.py b/unix/variant/sim_quickstart.py index 476d8ab9..41459839 100644 --- a/unix/variant/sim_quickstart.py +++ b/unix/variant/sim_quickstart.py @@ -155,6 +155,7 @@ if '--enter' in sys.argv: # keep at end of file: extra enter to confirm something from above numpad.inject('y') + # not best place for this import hsm hsm.POLICY_FNAME = hsm.POLICY_FNAME.replace('/flash/', '') diff --git a/unix/variant/sim_se2.py b/unix/variant/sim_se2.py index a03e2b04..450ba94b 100644 --- a/unix/variant/sim_se2.py +++ b/unix/variant/sim_se2.py @@ -15,30 +15,34 @@ class SecondSecureElement: self.wallet = None self.load() - if not self.state: - # reconstruct based on user-space understanding of SE2 content - # - can't work with duress wallet cases here (no data) - # - mostly here so sim_settings works w/ non-empty defaults - print("SIM SE2: found no state, trying to reconstruct") - from glob import settings - from trick_pins import TC_FAKE_OUT, TC_WORD_WALLET, TC_XPRV_WALLET - from trick_pins import TC_DELTA_MODE, make_slot, TRICK_SLOT_LAYOUT + def reconstruct(self, tp): + # reconstruct based on user-space understanding of SE2 content + # - can't work with duress wallet cases here (no data) + # - mostly here so sim_settings works w/ non-empty defaults + print("SIM SE2: found no state, trying to reconstruct") + from glob import settings + from trick_pins import TC_FAKE_OUT, TC_WORD_WALLET, TC_XPRV_WALLET + from trick_pins import TC_DELTA_MODE, make_slot, TRICK_SLOT_LAYOUT - for pin, (slot_num, tc_flags, tc_arg) in settings.get('tp', {}).items(): - if (tc_flags & (TC_DELTA_MODE | TC_WORD_WALLET | TC_XPRV_WALLET)): - print("cant do duress cases") - continue - #assert not (tc_flags & (TC_DELTA_MODE | TC_WORD_WALLET | TC_XPRV_WALLET)), \ - #'unhandled simulated case: 0x%x' % tc_flags + print(" .. tp = %r" % tp) + if not tp: return - b, s = make_slot() - s.pin_len = len(pin) - s.pin[:s.pin_len] = pin.encode() - s.tc_flags = tc_flags - s.tc_arg = tc_arg - s.slot_num = slot_num + for pin, (slot_num, tc_flags, tc_arg) in tp.items(): + if (tc_flags & (TC_DELTA_MODE | TC_WORD_WALLET | TC_XPRV_WALLET)): + print("cant do duress cases") + continue + #assert not (tc_flags & (TC_DELTA_MODE | TC_WORD_WALLET | TC_XPRV_WALLET)), \ + #'unhandled simulated case: 0x%x' % tc_flags - self.state[slot_num] = bytes(b) + b, s = make_slot() + s.pin_len = len(pin) + s.pin[:s.pin_len] = pin.encode() + s.tc_flags = tc_flags + s.tc_arg = tc_arg + s.slot_num = slot_num + + self.state[slot_num] = bytes(b) + print("slot[%d] <= flags=0x%x arg=0x%x" % (slot_num, tc_flags, tc_arg)) # Storage: base64 encoded binary for all the slot numbers in a dict @@ -64,16 +68,18 @@ class SecondSecureElement: # merging default values as they contain useful nfc,vidsk info dv = obj.default_values() obj.current.update(dv) - s = obj.get('_se2', None) - if not s: - print("no SE2 data") - return + s = obj.get('_se2', None) or [] for record in s: b = a2b_base64(record) slot = uctypes.struct(uctypes.addressof(b), TRICK_SLOT_LAYOUT) self.state[slot.slot_num] = b print("SE2 slot %d is populated" % slot.slot_num) + else: + print("no SE2 data") + + if not self.state: + self.reconstruct(obj.get('tp')) def callgate(self, buf_io, arg2): # ckcc.callgate(22, ...) @@ -149,11 +155,12 @@ class SecondSecureElement: # similar to stm32/mk4-bootloader/se2.c se2_test_trick_pin(safety_mode=False) xs = self.get_by_pin(pin.encode(), num_fails) if not xs: + self.wallet = None # bugfix: normal login after trick login (SP unlock case) return None - print("PIN %s is a TRICK!" % pin) tc_flags = xs.tc_flags tc_arg = xs.tc_arg + print("PIN %s is a TRICK! flags=0x%x arg=%d" % (pin, tc_flags, tc_arg)) from trick_pins import TC_WIPE, TC_BRICK, TC_REBOOT, TC_FAKE_OUT from trick_pins import TC_WORD_WALLET, TC_XPRV_WALLET, TC_DELTA_MODE diff --git a/unix/variant/sim_settings.py b/unix/variant/sim_settings.py index 2706fb4a..c3d1788d 100644 --- a/unix/variant/sim_settings.py +++ b/unix/variant/sim_settings.py @@ -65,13 +65,13 @@ if '--ms' in sys.argv: # Include useful multisig wallet, and shortcut to MS menu if '--p2wsh' in sys.argv: - sim_defaults['multisig'] = [["P2WSH--2-of-4", [2, 4], [[1130956047, "tpubDF2rnouQaaYrXF4noGTv6rQYmx87cQ4GrUdhpvXkhtChwQPbdGTi8GA88NUaSrwZBwNsTkC9bFkkC8vDyGBVVAQTZ2AS6gs68RQXtXcCvkP"], [3503269483, "tpubDFcrvj5n7gyaxWQkoX69k2Zij4vthiAwvN2uhYjDrE6wktKoQaE7gKVZRiTbYdrAYH1UFPGdzdtWJc6WfR2gFMq6XpxA12gCdQmoQNU9mgm"], [2389277556, "tpubDExj5FnaUnPAn7sHGUeBqD3buoNH5dqmjAT6884vbDpH1iDYWigb7kFo2cA97dc8EHb54u13TRcZxC4kgRS9gc3Ey2xc8c5urytEzTcp3ac"], [3190206587, "tpubDFiuHYSJhNbHcbLJoxWdbjtUcbKR6PvLq53qC1Xq6t93CrRx78W3wcng8vJyQnY3giMJZEgNCRVzTojLb8RqPFpW5Ms2dYpjcJYofN1joyu"]], {"pp": "48'/1'/0'/2'", "ch": "XTN", "ft": 14}]] + sim_defaults['miniscript'] = [['P2WSH--2-of-4', 'wsh(sortedmulti(2,@0/**,@1/**))', ['[0f056943/48h/1h/0h/2h]tpubDF2rnouQaaYrXF4noGTv6rQYmx87cQ4GrUdhpvXkhtChwQPbdGTi8GA88NUaSrwZBwNsTkC9bFkkC8vDyGBVVAQTZ2AS6gs68RQXtXcCvkP', '[6ba6cfd0/48h/1h/0h/2h]tpubDFcrvj5n7gyaxWQkoX69k2Zij4vthiAwvN2uhYjDrE6wktKoQaE7gKVZRiTbYdrAYH1UFPGdzdtWJc6WfR2gFMq6XpxA12gCdQmoQNU9mgm', '[747b698e/48h/1h/0h/2h]tpubDExj5FnaUnPAn7sHGUeBqD3buoNH5dqmjAT6884vbDpH1iDYWigb7kFo2cA97dc8EHb54u13TRcZxC4kgRS9gc3Ey2xc8c5urytEzTcp3ac', '[7bb026be/48h/1h/0h/2h]tpubDFiuHYSJhNbHcbLJoxWdbjtUcbKR6PvLq53qC1Xq6t93CrRx78W3wcng8vJyQnY3giMJZEgNCRVzTojLb8RqPFpW5Ms2dYpjcJYofN1joyu'], {'af': 14, 'm_n': (2, 4), 'b67': 1, 'ct': 'XTN'}]] elif '--wrap' in sys.argv: # p2wsh-p2sh case - sim_defaults['multisig'] = [["CC-2-of-4", [2, 4], [[1130956047, "tpubDF2rnouQaaYrUEy2JM1YD3RFzew4onawGM4X2Re67gguTf5CbHonBRiFGe3Xjz7DK88dxBFGf2i7K1hef3PM4cFKyUjcbJXddaY9F5tJBoP"], [3503269483, "tpubDFcrvj5n7gyatVbr8dHCUfHT4CGvL8hREBjtxc4ge7HZgqNuPhFimPRtVg6fRRwfXiQthV9EBjNbwbpgV2VoQeL1ZNXoAWXxP2L9vMtRjax"], [2389277556, "tpubDExj5FnaUnPAjjgzELoSiNRkuXJG8Cm1pbdiA4Hc5vkAZHphibeVcUp6mqH5LuNVKbtLVZxVSzyja5X26Cfmx6pzRH6gXBUJAH7MiqwNyuM"], [3190206587, "tpubDFiuHYSJhNbHaGtB5skiuDLg12tRboh2uVZ6KGXxr8WVr28pLcS7F3gv8SsHFa2tm1jtx3VAuw56YfgRkdo6DXyfp51oygTKY3nJFT5jBMt"]], {"pp": "48'/1'/0'/1'", "ch": "XTN", "ft": 26}]] + sim_defaults['miniscript'] = [['CC-2-of-4', 'sh(wsh(sortedmulti(2,@0/**,@1/**)))', ['[0f056943/48h/1h/0h/1h]tpubDF2rnouQaaYrUEy2JM1YD3RFzew4onawGM4X2Re67gguTf5CbHonBRiFGe3Xjz7DK88dxBFGf2i7K1hef3PM4cFKyUjcbJXddaY9F5tJBoP', '[6ba6cfd0/48h/1h/0h/1h]tpubDFcrvj5n7gyatVbr8dHCUfHT4CGvL8hREBjtxc4ge7HZgqNuPhFimPRtVg6fRRwfXiQthV9EBjNbwbpgV2VoQeL1ZNXoAWXxP2L9vMtRjax', '[747b698e/48h/1h/0h/1h]tpubDExj5FnaUnPAjjgzELoSiNRkuXJG8Cm1pbdiA4Hc5vkAZHphibeVcUp6mqH5LuNVKbtLVZxVSzyja5X26Cfmx6pzRH6gXBUJAH7MiqwNyuM', '[7bb026be/48h/1h/0h/1h]tpubDFiuHYSJhNbHaGtB5skiuDLg12tRboh2uVZ6KGXxr8WVr28pLcS7F3gv8SsHFa2tm1jtx3VAuw56YfgRkdo6DXyfp51oygTKY3nJFT5jBMt'], {'af': 26, 'm_n': (2, 4), 'b67': 1, 'ct': 'XTN'}]] else: # P2SH: 2of4 using BIP39 passwords: "Me", "Myself", "and I", and (empty string) on simulator - sim_defaults['multisig'] = [['MeMyself', [2, 4], [[3503269483, 'tpubD9429UXFGCTKJ9NdiNK4rC5ygqSUkginycYHccqSg5gkmyQ7PZRHNjk99M6a6Y3NY8ctEUUJvCu6iCCui8Ju3xrHRu3Ez1CKB4ZFoRZDdP9'], [2389277556, 'tpubD97nVL37v5tWyMf9ofh5rznwhh1593WMRg6FT4o6MRJkKWANtwAMHYLrcJFsFmPfYbY1TE1LLQ4KBb84LBPt1ubvFwoosvMkcWJtMwvXgSc'], [3190206587, 'tpubD9ArfXowvGHnuECKdGXVKDMfZVGdephVWg8fWGWStH3VKHzT4ph3A4ZcgXWqFu1F5xGTfxncmrnf3sLC86dup2a8Kx7z3xQ3AgeNTQeFxPa'], [1130956047, 'tpubD8NXmKsmWp3a3DXhbihAYbYLGaRNVdTnr6JoSxxfXYQcmwVtW2hv8QoDwng6JtEonmJoL3cNEwfd2cLXMpGezwZ2vL2dQ7259bueNKj9C8n']], {'ch': 'XTN', 'pp': "45'"}]] + sim_defaults['miniscript'] = [['MeMyself', 'sh(sortedmulti(2,@0/**,@1/**))', ['[6ba6cfd0/45h]tpubD9429UXFGCTKJ9NdiNK4rC5ygqSUkginycYHccqSg5gkmyQ7PZRHNjk99M6a6Y3NY8ctEUUJvCu6iCCui8Ju3xrHRu3Ez1CKB4ZFoRZDdP9', '[747b698e/45h]tpubD97nVL37v5tWyMf9ofh5rznwhh1593WMRg6FT4o6MRJkKWANtwAMHYLrcJFsFmPfYbY1TE1LLQ4KBb84LBPt1ubvFwoosvMkcWJtMwvXgSc', '[7bb026be/45h]tpubD9ArfXowvGHnuECKdGXVKDMfZVGdephVWg8fWGWStH3VKHzT4ph3A4ZcgXWqFu1F5xGTfxncmrnf3sLC86dup2a8Kx7z3xQ3AgeNTQeFxPa', '[0f056943/45h]tpubD8NXmKsmWp3a3DXhbihAYbYLGaRNVdTnr6JoSxxfXYQcmwVtW2hv8QoDwng6JtEonmJoL3cNEwfd2cLXMpGezwZ2vL2dQ7259bueNKj9C8n'], {'af': 8, 'm_n': (2, 4), 'b67': 1, 'ct': 'XTN'}]] sim_defaults['fee_limit'] = -1 if '--xfp' in sys.argv: @@ -141,7 +141,14 @@ if '--secret' in sys.argv: if '-g' in sys.argv: - # do login + # do login.. but does not work if _skip_pin got saved into settings already + sim_defaults.pop('_skip_pin', 0) + +if '--fails' in sys.argv: + # fast-forward as if N PIN failures have already happened. + count = int(sys.argv[sys.argv.index('--fails') + 1]) + import ckcc + ckcc.SE_STATE.force_fails(count) sim_defaults.pop('_skip_pin', 0) if '--nick' in sys.argv: diff --git a/unix/variant/sim_vdisk.py b/unix/variant/sim_vdisk.py index 321617f5..16097655 100644 --- a/unix/variant/sim_vdisk.py +++ b/unix/variant/sim_vdisk.py @@ -75,9 +75,12 @@ class SimulatedVirtDisk(vdisk.VirtDisk): def import_file(self, filename, sz): # copy file into another area of PSRAM where rest of system can use it print("sim-virtdisk: read %s" % filename) - contents = open(SIMDIR_PATH+filename, 'rb').read(sz) + with open(filename, 'rb') as f: + contents = f.read(sz) from glob import PSRAM - PSRAM.write_at(0, sz)[:] = contents + runt = (4 - sz % 4) + sz = sz + runt + PSRAM.write_at(0, sz)[:] = contents + bytes(runt) return sz vdisk.VirtDisk = SimulatedVirtDisk diff --git a/unix/variant/version.py b/unix/variant/version.py index 62875beb..81931fd2 100644 --- a/unix/variant/version.py +++ b/unix/variant/version.py @@ -44,7 +44,7 @@ has_qr = False num_sd_slots = 1 has_battery = False has_qwerty = False -is_edge = False +is_edge = True if '--mk1' in sys.argv: # doubt this works still diff --git a/unix/work/debug/.gitignore b/unix/work/debug/.gitignore new file mode 100644 index 00000000..5146bd3b --- /dev/null +++ b/unix/work/debug/.gitignore @@ -0,0 +1,11 @@ +*.7z +*.txt +*.json +*.psbt +*.csv +*.pdf +*.dfu +*.txn +*.sig +*.png +.tmp.tmp \ No newline at end of file diff --git a/testing/debug/README.md b/unix/work/debug/README.md similarity index 100% rename from testing/debug/README.md rename to unix/work/debug/README.md