remove obsolete Mk2/Mk3 code paths from firmware

(cherry picked from commit 6655238409)
This commit is contained in:
scgbckbone 2023-09-20 12:51:15 +02:00 committed by doc-hex
parent 615c0a5064
commit 342af8f78e
31 changed files with 226 additions and 838 deletions

View File

@ -5,6 +5,7 @@
Only needed for Mk 2-3 where SPI flash was external chip,
easily observed, but now that's different. New simpler and less storage
wasteful plausible deniability.
- Enhancement: Remove obsolete Mk2/Mk3 code-paths from master branch
## 5.1.4 - 2023-09-08

View File

@ -116,9 +116,6 @@ Extended Master Key:
if bn:
msg += '\nShipping Bag:\n %s\n' % bn
if not version.has_fatram:
# can't support on mk2
xpub = None
if xpub:
msg += '\nPress (3) to show QR code of xpub.'
@ -228,6 +225,9 @@ async def microsd_upgrade(menu, label, item):
# - erase serial flash
# - copy it over (slow)
# - reboot into bootloader, which finishes install
from glob import dis, PSRAM
from files import dfu_parse
from utils import check_firmware_hdr
from sigheader import FW_HEADER_OFFSET, FW_HEADER_SIZE, FW_MAX_LENGTH_MK4
force_vdisk = item.arg
@ -238,18 +238,8 @@ async def microsd_upgrade(menu, label, item):
if not fn: return
failed = None
with CardSlot(force_vdisk=force_vdisk) as card:
with card.open(fn, 'rb') as fp:
from version import has_psram
if has_psram:
from glob import PSRAM as SF
else:
from sflash import SF
from glob import dis
from files import dfu_parse
from utils import check_firmware_hdr
offset, size = dfu_parse(fp)
# we also put a copy of special signed heaer at the end of the flash
@ -264,12 +254,12 @@ async def microsd_upgrade(menu, label, item):
failed = check_firmware_hdr(hdr, size)
if not failed:
# copy binary into serial flash / PSRAM
# copy binary into PSRAM
fp.seek(offset)
dis.fullscreen("Loading...")
buf = bytearray(256 if not has_psram else 0x20000)
buf = bytearray(0x20000)
pos = 0
while pos < size:
dis.progress_bar_show(pos/size)
@ -277,21 +267,7 @@ async def microsd_upgrade(menu, label, item):
here = fp.readinto(buf)
if not here: break
if has_psram:
SF.write(pos, buf)
else:
if pos % 4096 == 0:
# erase here
SF.sector_erase(pos)
while SF.is_busy():
await sleep_ms(10)
SF.write(pos, buf)
# full page write: 0.6 to 3ms
while SF.is_busy():
await sleep_ms(1)
PSRAM.write(pos, buf)
pos += here
if failed:
@ -300,7 +276,7 @@ async def microsd_upgrade(menu, label, item):
# continue process...
from auth import FirmwareUpgradeRequest
m = FirmwareUpgradeRequest(hdr, size, psram_offset=(0 if has_psram else None))
m = FirmwareUpgradeRequest(hdr, size, psram_offset=0)
the_ux.push(m)
async def start_dfu(*a):
@ -429,9 +405,6 @@ async def block_until_login():
from login import LoginUX
from ux import AbortInteraction
# mk4 does differently, as a "trick pin"
cd_pin = settings.get('cd_pin', None) if not version.has_se2 else None
# do they want a randomized (shuffled) keypad?
rnd_keypad = settings.get('rngk', 0)
@ -444,7 +417,7 @@ async def block_until_login():
lll = LoginUX(rnd_keypad, kill_btn)
try:
rv = await lll.try_login(bypass_pin=cd_pin)
rv = await lll.try_login(bypass_pin=None)
if rv: break
except AbortInteraction:
# not allowed!
@ -609,16 +582,20 @@ async def clear_seed(*a):
import seed
if pa.has_duress_pin():
await ux_show_story('''Please empty the duress wallet, and clear the duress PIN before clearing main seed.''')
await ux_show_story('Please empty the duress wallet, and clear '
'the duress PIN before clearing main seed.')
return
if version.has_se2:
from trick_pins import tp
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 associated Trick PINs before clearing main seed.''')
return
from trick_pins import tp
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 '
'associated Trick PINs before clearing main seed.')
return
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.'''):
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.'):
return await ux_aborted()
ch = await ux_show_story('''Are you REALLY sure though???\n\n\
@ -687,8 +664,7 @@ async def view_seed_words(*a):
dis.busy_bar(False)
msg, qr, qr_alnum = render_master_secrets(sv.mode, sv.raw, sv.node)
if version.has_fatram:
msg += '\n\nPress (1) to view as QR Code.'
msg += '\n\nPress (1) to view as QR Code.'
while 1:
ch = await ux_show_story(msg, sensitive=True, escape='1')
@ -761,10 +737,9 @@ async def version_migration():
async def version_migration_prelogin():
# same, but for setting before login
if version.has_se2:
# these have moved into SE2 for Mk4 and so can be removed
for n in [ 'cd_lgto', 'cd_mode', 'cd_pin' ]:
settings.remove_key(n)
# these have moved into SE2 for Mk4 and so can be removed
for n in [ 'cd_lgto', 'cd_mode', 'cd_pin' ]:
settings.remove_key(n)
async def start_login_sequence():
# Boot up login sequence here.
@ -786,12 +761,6 @@ async def start_login_sequence():
if pa.is_blank():
# Blank devices, with no PIN set all, can continue w/o login
# Do green-light set immediately after firmware upgrade [not after mk3]
if version.is_fresh_version() and version.mk_num <=3:
pa.greenlight_firmware()
dis.show()
goto_top_menu()
return
@ -826,16 +795,11 @@ async def start_login_sequence():
# Do we need to do countdown delay? (real or otherwise)
delay = 0
if wants_countdown:
# Mk3 and earlier
await damage_myself()
delay = settings.get('cd_lgto', 60)
elif version.has_se2:
# Mk4 approach:
# - wiping has already occured if that was picked
# - delay is variable, stored in tc_arg
from trick_pins import tp
delay = tp.was_countdown_pin()
# Mk4 approach:
# - wiping has already occured if that was picked
# - 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
if not delay:
@ -846,23 +810,10 @@ async def start_login_sequence():
pa.reset()
await login_countdown(delay * (60 if not version.is_devmode else 1))
if version.has_se2:
# keep it simple for Mk4+: just challenge again for any PIN
# - if it's the same countdown pin, it will be accepted and they
# get in (as most trick pins would do)
await block_until_login()
else:
# second PIN challenge; but only if first one was actually legit
wants_countdown = await block_until_login()
# whenever they use the countdown pin on second screen, kill ourselves
if wants_countdown:
await damage_myself()
if wants_countdown:
# crash
dis.fullscreen("ERROR")
callgate.show_logout(1)
# keep it simple for Mk4+: just challenge again for any PIN
# - if it's the same countdown pin, it will be accepted and they
# get in (as most trick pins would do)
await block_until_login()
except BaseException as exc:
# Robustness: any logic errors/bugs in above will brick the Coldcard
@ -901,13 +852,6 @@ async def start_login_sequence():
from imptask import IMPT
IMPT.start_task('idle', idle_logout())
# Do green-light set immediately after firmware upgrade
# - mk4 doesn't work this way, light will already be green
if version.mk_num <= 3:
if version.is_fresh_version() and not pa.is_secondary:
pa.greenlight_firmware()
dis.show()
# Populate xfp/xpub values, if missing.
# - can happen for first-time login of duress wallet
# - may indicate lost settings, which we can easily recover from
@ -934,18 +878,17 @@ async def start_login_sequence():
# If HSM policy file is available, offer to start that,
# **before** the USB is even enabled.
if version.has_fatram:
# do not offer HSM if wallet is blank -> HSM needs secret
if not pa.is_secret_blank():
try:
import hsm, hsm_ux
# do not offer HSM if wallet is blank -> HSM needs secret
if not pa.is_secret_blank():
try:
import hsm, hsm_ux
if hsm.hsm_policy_available():
settings.put("hsmcmd", True)
ar = await hsm_ux.start_hsm_approval(usb_mode=False, startup_mode=True)
if ar:
await ar.interact()
except: pass
if hsm.hsm_policy_available():
settings.put("hsmcmd", True)
ar = await hsm_ux.start_hsm_approval(usb_mode=False, startup_mode=True)
if ar:
await ar.interact()
except: pass
if version.mk_num >= 4:
if version.has_nfc and settings.get('nfc', 0):
@ -2073,14 +2016,7 @@ async def show_version(*a):
bl = callgate.get_bl_version()[0]
chk = str(b2a_hex(callgate.get_bl_checksum(0))[-8:], 'ascii')
if version.has_se2:
se = '\n '.join(callgate.get_se_parts())
else:
se = 'ATECC'
if version.has_608:
se += '608B' if callgate.has_608b() else '608A'
else:
se += '508A'
se = '\n '.join(callgate.get_se_parts())
# exposed over USB interface:
serial = version.serial_number()
@ -2110,12 +2046,12 @@ Serial:
Hardware:
{hw}
Secure Element{ses}:
Secure Elements:
{se}
'''
await ux_show_story(msg.format(rel=rel, built=built, bl=bl, chk=chk, se=se,
ser=serial, hw=hw, ses='s' if version.has_se2 else ''))
ser=serial, hw=hw))
async def ship_wo_bag(*a):
# Factory command: for dev and test units that have no bag number, and never will.

View File

@ -265,7 +265,7 @@ Press (3) if you really understand and accept these risks.
return _cache[(change, start, n)]
export_msg = "Press (1) to save Address summary file to SD Card."
if version.has_fatram and not ms_wallet:
if not ms_wallet:
export_msg += " Press (2) to view QR Codes."
if NFC:
export_msg += " Press (3) to share via NFC."
@ -346,8 +346,7 @@ Press (3) if you really understand and accept these risks.
elif ch == '2':
# switch into a mode that shows them as QR codes
if not version.has_fatram or ms_wallet:
# requires mk3 and not multisig
if ms_wallet:
continue
from ux import show_qr_codes

View File

@ -18,7 +18,7 @@ from utils import HexWriter, xfp2str, problem_file_line, cleanup_deriv_path
from utils import B2A, parse_addr_fmt_str
from psbt import psbtObject, FatalPSBTIssue, FraudulentChangeOutput
from exceptions import HSMDenied
from version import has_psram, has_fatram, MAX_TXN_LEN
from version import MAX_TXN_LEN
# Where in SPI flash/PSRAM the two PSBT files are (in and out)
TXN_INPUT_OFFSET = 0
@ -634,7 +634,7 @@ class ApproveTransaction(UserAuthorizedAction):
# Prompt user w/ details and get approval
from glob import dis, hsm_active
# step 1: parse PSBT from sflash into in-memory objects.
# step 1: parse PSBT from PSRAM into in-memory objects.
try:
with SFFile(TXN_INPUT_OFFSET, length=self.psbt_len, message='Reading...') as fd:
@ -801,16 +801,14 @@ class ApproveTransaction(UserAuthorizedAction):
while 1:
# Show txid when we can; advisory
# - maybe even as QR, hex-encoded in alnum mode
tmsg = txid + '\n\n'
tmsg = txid + '\n\nPress (1) for QR Code of TXID. '
if has_fatram:
tmsg += 'Press (1) for QR Code of TXID. '
if NFC:
tmsg += 'Press (3) to share signed txn via NFC.'
ch = await ux_show_story(tmsg, "Final TXID", escape='13')
if ch=='1' and has_fatram:
if ch == '1':
await show_qr_code(txid, True)
continue
@ -955,7 +953,7 @@ class ApproveTransaction(UserAuthorizedAction):
def sign_transaction(psbt_len, flags=0x0, psbt_sha=None):
# transaction (binary) loaded into sflash/PSRAM already, checksum checked
# transaction (binary) loaded into PSRAM already, checksum checked
UserAuthorizedAction.check_busy(ApproveTransaction)
UserAuthorizedAction.active_request = ApproveTransaction(psbt_len, flags, psbt_sha=psbt_sha)
@ -989,9 +987,10 @@ async def sign_psbt_file(filename, force_vdisk=False):
from files import CardSlot, CardMissingError
from glob import dis
from ux import the_ux
from sram2 import tmp_buf
# copy file into our spiflash
tmp_buf = bytearray(1024)
# 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
with CardSlot(force_vdisk, readonly=True) as card:
@ -1270,13 +1269,13 @@ class ShowAddressBase(UserAuthorizedAction):
msg += '\n\nCompare this payment address to the one shown on your other, less-trusted, software.'
if NFC:
msg += ' Press (3) to share via NFC.'
if has_fatram:
msg += ' Press (4) to view QR Code.'
msg += ' Press (4) to view QR Code.'
while 1:
ch = await ux_show_story(msg, title=self.title, escape='34')
if ch == '4' and has_fatram:
if ch == '4':
await show_qr_code(self.address, (self.addr_fmt & AFC_BECH32))
continue
if ch == '3' and NFC:
@ -1517,26 +1516,15 @@ Binary checksum and signature will be further verified before any changes are ma
# - reboot to start process
from glob import dis
dis.fullscreen('Upgrading...', percent=1)
if not has_psram:
from sflash import SF
import callgate
SF.write(self.length, self.hdr)
callgate.show_logout(2)
else:
# Mk4 copies from PSRAM to flash inside bootrom, we have
# nothing to do here except start that process.
from pincodes import pa
pa.firmware_upgrade(self.psram_offset, self.length)
# not reached, unless issue?
raise RuntimeError("bootrom fail")
# Mk4 copies from PSRAM to flash inside bootrom, we have
# nothing to do here except start that process.
from pincodes import pa
pa.firmware_upgrade(self.psram_offset, self.length)
# not reached, unless issue?
raise RuntimeError("bootrom fail")
else:
# they don't want to!
self.refused = True
if not has_psram:
from sflash import SF
SF.block_erase(0) # just in case, but not required
await ux_dramatic_pause("Refused.", 2)
except BaseException as exc:

View File

@ -65,21 +65,13 @@ def render_backup_contents():
ADD('long_secret', b2a_hex(pa.ls_fetch()))
# Duress wallets (somewhat optional, since derived)
if version.mk_num <= 3:
if pa.has_duress_pin():
COMMENT('Duress Wallet (informational)')
dpk, p = sv.duress_root()
COMMENT('path = %s' % p)
ADD('duress_xprv', chain.serialize_private(dpk))
ADD('duress_xpub', chain.serialize_public(dpk))
else:
from trick_pins import tp
for label, path, pairs in tp.backup_duress_wallets(sv):
COMMENT()
COMMENT(label + ' (informational)')
COMMENT(path)
for k,v in pairs:
ADD(k, v)
from trick_pins import tp
for label, path, pairs in tp.backup_duress_wallets(sv):
COMMENT()
COMMENT(label + ' (informational)')
COMMENT(path)
for k,v in pairs:
ADD(k, v)
COMMENT('Firmware version (informational)')
date, vers, timestamp = version.get_mpy_version()[0:3]
@ -100,10 +92,9 @@ def render_backup_contents():
if k == 'words': continue # words length is recalculated from secret
ADD('setting.' + k, v)
if version.has_fatram:
import hsm
if hsm.hsm_policy_available():
ADD('hsm_policy', hsm.capture_backup())
import hsm
if hsm.hsm_policy_available():
ADD('hsm_policy', hsm.capture_backup())
rv.write('\n# EOF\n')
@ -205,7 +196,7 @@ def restore_from_dict_ll(vals):
# write out
settings.save()
if version.has_fatram and ('hsm_policy' in vals):
if 'hsm_policy' in vals:
import hsm
hsm.restore_backup(vals['hsm_policy'])

View File

@ -7,11 +7,12 @@ from ssd1306 import SSD1306_SPI
from version import is_devmode, is_edge
import framebuf
from graphics import Graphics
from sram2 import display2_buf
# we support 4 fonts
from zevvpeep import FontSmall, FontLarge, FontTiny
FontFixed = object() # ugly 8x8 PET font
display2_buf = bytearray(1024)
class Display:

View File

@ -188,7 +188,7 @@ async def drv_entro_step2(_1, picked, _2):
prompt += ', (2) to switch to derived secret'
elif s_mode == 'pw':
prompt += ', (2) to type password over USB'
if (qr is not None) and version.has_fatram:
if qr is not None:
prompt += ', (3) to view as QR code'
if glob.NFC:
prompt += ', (4) to share via NFC'
@ -226,7 +226,7 @@ async def drv_entro_step2(_1, picked, _2):
story = "Filename is:\n\n%s" % out_fn
story += "\n\nSignature filename is:\n\n%s" % sig_nice
await ux_show_story(story, title='Saved')
elif ch == '3' and version.has_fatram:
elif ch == '3':
from ux import show_qr_code
await show_qr_code(qr, qr_alnum)
continue

View File

@ -56,8 +56,7 @@ def wipe_flash_filesystem():
# erase and re-format the flash filesystem (/flash/**)
import ckcc, pyb
from glob import dis
from version import mk_num
dis.fullscreen('Erasing...')
os.umount('/flash')
@ -81,16 +80,10 @@ def wipe_flash_filesystem():
# rebuild and mount /flash
dis.fullscreen('Rebuilding...')
if mk_num == 4:
# no need to erase, we just put new FS on top
import mk4
mk4.make_flash_fs()
else:
ckcc.wipe_fs()
# remount it
os.mount(fl, '/flash')
# no need to erase, we just put new FS on top
import mk4
mk4.make_flash_fs()
# re-store current settings
from glob import settings

View File

@ -29,7 +29,7 @@ transfer data easily via NFC.''' + COMMON
# Disabled for now, because limited audience and
# extra barrier to "just getting started"
if 0: # version.has_psram and not settings.get('vidsk', 0):
if 0: # if not settings.get('vidsk', 0):
msg = '''Enable USB Drive?\n\n\
Connect your COLDCARD directly as a USB flash drive \
to your phone or desktop. You will be able to drag-n-drop or \

View File

@ -682,12 +682,6 @@ class HSMPolicy:
with open(POLICY_FNAME, 'w+t') as f:
ujson.dump(self.save(), f)
if version.mk_num <= 3:
# that changes the flash, so need to update
# the hash stored in SE (Mk3 and earlier)
pa.greenlight_firmware()
dis.show()
if self.set_sl:
self.save_storage_locker()

View File

@ -39,21 +39,17 @@ glob.dis = dis
# slowish imports, some with side-effects
import ckcc, uasyncio
if version.mk_num >= 4:
# early setup code needed on Mk4
try:
import mk4
mk4.init0()
# early setup code needed on Mk4
try:
import mk4
mk4.init0()
from psram import PSRAMWrapper
glob.PSRAM = PSRAMWrapper()
from psram import PSRAMWrapper
glob.PSRAM = PSRAMWrapper()
except BaseException as exc:
sys.print_exception(exc)
# continue tho
else:
# Serial Flash memory
from sflash import SF
except BaseException as exc:
sys.print_exception(exc)
# continue tho
# Setup membrane numpad (mark 2+)
from mempad import MembraneNumpad

View File

@ -21,6 +21,7 @@ freeze_as_mpy('', [
'export.py',
'files.py',
'flow.py',
'ftux.py',
'glob.py',
'history.py',
'hsm.py',
@ -56,7 +57,6 @@ freeze_as_mpy('', [
'ux.py',
'version.py',
'xor_seed.py',
'ftux.py',
], opt=0)
# Optimize data-like files, since no need to debug them.

View File

@ -1,5 +1,4 @@
# Mk3 and earlier only files; would not be needed on Mk4 or later
freeze_as_mpy('', [
'sflash.py',
], opt=0)
'sflash.py',
], opt=0)

View File

@ -10,4 +10,4 @@ freeze_as_mpy('', [
freeze_as_mpy('', [
'graphics_mk4.py',
], opt=3)
], opt=3)

View File

@ -73,16 +73,11 @@ class PaperWalletMaker:
self.update_menu()
return self.atype()[0], ['Classic P2PKH', 'Segwit P2WPKH', 'Taproot P2TR'], set
@staticmethod
def can_do_qr():
import version
return version.has_fatram
def update_menu(self):
# Reconstruct the menu contents based on our state.
self.my_menu.replace_items([
MenuItem("Don't make PDF" if not self.template_fn else 'Making PDF',
f=self.pick_template, predicate=self.can_do_qr),
f=self.pick_template),
MenuItem(self.atype()[1], chooser=self.addr_format_chooser),
MenuItem('Use Dice', f=self.use_dice),
MenuItem('GENERATE WALLET', f=self.doit),
@ -122,18 +117,14 @@ class PaperWalletMaker:
wif = ngu.codecs.b58_encode(ch.b58_privkey + privkey + b'\x01')
if self.can_do_qr():
with imported('uqr') as uqr:
# make the QR's now, since it's slow
is_alnum = self.is_segwit
qr_addr = uqr.make(addr if not is_alnum else addr.upper(),
min_version=4, max_version=4,
encoding=(uqr.Mode_ALPHANUMERIC if is_alnum else 0))
with imported('uqr') as uqr:
# make the QR's now, since it's slow
is_alnum = self.is_segwit
qr_addr = uqr.make(addr if not is_alnum else addr.upper(),
min_version=4, max_version=4,
encoding=(uqr.Mode_ALPHANUMERIC if is_alnum else 0))
qr_wif = uqr.make(wif, min_version=4, max_version=4, encoding=uqr.Mode_BYTE)
else:
qr_addr = None
qr_wif = None
qr_wif = uqr.make(wif, min_version=4, max_version=4, encoding=uqr.Mode_BYTE)
# Use address as filename. clearly will be unique, but perhaps a bit
# awkward to work with.
@ -308,7 +299,8 @@ class PaperWalletMaker:
async def make_paper_wallet(*a):
msg = background_msg.format(can_qr=('\nIf you have a special PDF template file, it can also make a pretty version of the same data.' if PaperWalletMaker.can_do_qr() else ''))
msg = background_msg.format(can_qr='\nIf you have a special PDF template file, '
'it can also make a pretty version of the same data.')
if await ux_show_story(msg) != 'y':
return

View File

@ -472,9 +472,6 @@ class PinAttempt:
def is_deltamode(self):
# (mk4 only) are we operating w/ a slightly wrong PIN code?
if version.mk_num < 4:
return False
from trick_pins import TC_DELTA_MODE
return bool(self.delay_required & TC_DELTA_MODE)

View File

@ -11,8 +11,8 @@ from uio import BytesIO
from chains import taptweak, tapleaf_hash
from sffile import SizerFile
from sram2 import psbt_tmp256
from multisig import MultisigWallet, disassemble_multisig_mn
from miniscript import MiniScriptWallet
from multisig import MultisigWallet, disassemble_multisig, disassemble_multisig_mn
from exceptions import FatalPSBTIssue, FraudulentChangeOutput
from serializations import ser_compact_size, deser_compact_size, hash160
from serializations import CTxIn, CTxInWitness, CTxOut, ser_string
@ -32,6 +32,8 @@ from public_constants import (
TAPROOT_LEAF_TAPSCRIPT, TAPROOT_LEAF_MASK
)
psbt_tmp256 = bytearray(256)
# PSBT proprietary keytype
PSBT_PROPRIETARY = const(0xFC)

View File

@ -2,11 +2,10 @@
#
# qrs.py - QR Display related UX
#
import framebuf, math, uqr
import framebuf, uqr
from ux import UserInteraction, ux_wait_keyup, the_ux
from utils import word_wrap
from version import has_fatram
from ubinascii import hexlify as b2a_hex
class QRDisplaySingle(UserInteraction):
# Show a single QR code for (typically) a list of addresses, or a single value.

View File

@ -275,10 +275,8 @@ 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!"
if version.has_fatram:
escape = (escape or '') + '1'
extra += 'Press (1) to view as QR Code. '
escape = (escape or '') + '1'
extra += 'Press (1) to view as QR Code. '
if extra:
msg += '\n\n'
@ -637,21 +635,9 @@ def clear_seed():
# clear settings associated with this key, since it will be no more
settings.blank()
if version.mk_num >= 4:
callgate.fast_wipe(True)
# NOT REACHED
else:
# save a blank secret (all zeros is a special case, detected by bootloader)
nv = bytes(AE_SECRET_LEN)
pa.change(new_secret=nv)
callgate.fast_wipe(True)
# NOT REACHED
if version.has_608:
# wipe the long secret too
nv = bytes(AE_LONG_SECRET_LEN)
pa.ls_change(nv)
dis.busy_bar(False)
dis.fullscreen('Reboot...')
utime.sleep(1)
# security: need to reboot to really be sure to clear the secrets from main memory.

View File

@ -56,11 +56,7 @@ async def test_secure_element():
assert not get_is_bricked() # bricked already
# test right chips installed
if version.has_fatram:
assert version.has_608 # expect 608
else:
assert not version.has_608 # expect 508a
assert version.hw_label == 'mk2'
assert version.has_608 # expect 608
if ckcc.is_simulator(): return
@ -115,9 +111,6 @@ async def test_sd_active():
async def test_usb_light():
# Mk4's new USB activity light (right by connector)
if version.mk_num < 4: return
from machine import Pin
p = Pin('USB_ACTIVE', Pin.OUT)
@ -139,8 +132,6 @@ async def test_nfc():
await NFCHandler.selftest()
async def test_psram():
if not version.has_psram: return
from glob import PSRAM
from ustruct import pack
import ngu
@ -168,54 +159,6 @@ async def test_psram():
assert chk == rnd, "RB bad @ 0x%x" % pos
dis.progress_bar_show((PSRAM.length + pos) / test_len)
async def test_sflash():
if version.has_psram: return
dis.clear()
dis.text(None, 18, 'Serial Flash')
dis.show()
from sflash import SF
from ustruct import pack
import ngu
msize = 1024*1024
SF.chip_erase()
for phase in [0, 1]:
steps = 7*4
for i in range(steps):
dis.progress_bar(i/steps)
dis.show()
await sleep_ms(250)
if not SF.is_busy(): break
assert not SF.is_busy() # "didn't finish"
# leave chip blank
if phase == 1: break
buf = bytearray(32)
for addr in range(0, msize, 1024):
SF.read(addr, buf)
assert set(buf) == {255} # "not blank"
rnd = ngu.hash.sha256s(pack('I', addr))
SF.write(addr, rnd)
SF.wait_done()
SF.read(addr, buf)
assert buf == rnd # "write failed"
dis.progress_bar_show(addr/msize)
# check no aliasing, also right size part
for addr in range(0, msize, 1024):
expect = ngu.hash.sha256s(pack('I', addr))
SF.read(addr, buf)
assert buf == expect # "readback failed"
dis.progress_bar_show(addr/msize)
async def test_oled():
# all on/off tests
@ -306,7 +249,6 @@ async def start_selftest():
await test_oled()
await test_psram()
await test_nfc()
await test_sflash()
await test_microsd()
await test_numpad()
await test_secure_element()

View File

@ -9,29 +9,16 @@
# - the offset is the file name
# - (<Mk3) last 64k of memory reserved for settings
#
from uasyncio import sleep_ms
from uio import BytesIO
from uhashlib import sha256
from version import has_psram
if not has_psram:
# Use SPI flash chip
from sflash import SF
# this code works on large "blocks" defined by the chip as 64k
blksize = 65536
# Use PSRAM chip
from glob import PSRAM
blksize = 4
PADOUT = lambda n: n
def PADOUT(n):
# rounds up
return (n + blksize - 1) & ~(blksize-1)
else:
# Use PSRAM chip
from glob import PSRAM
blksize = 4
PADOUT = lambda n: n
def ALIGN4(n):
return n & ~0x3
def ALIGN4(n):
return n & ~0x3
class SFFile:
def __init__(self, start, length=0, max_size=None, message=None, pre_erased=False):
@ -49,10 +36,9 @@ class SFFile:
self.readonly = False
self.checksum = sha256()
if has_psram:
# up to 3 bytes that haven't been written-out yet
self.runt = bytearray()
self._pos = 0
# up to 3 bytes that haven't been written-out yet
self.runt = bytearray()
self._pos = 0
else:
# Read
self.readonly = True
@ -89,19 +75,7 @@ class SFFile:
# must be used by caller before writing any bytes
assert not self.readonly
assert self.length == 0 # 'already wrote?'
if has_psram: return
for i in range(0, self.max_size, blksize):
SF.block_erase(self.start + i)
if i and self.message:
from glob import dis
dis.progress_bar_show(i/self.max_size)
# expect block erase to take up to 2 seconds
while SF.is_busy():
await sleep_ms(50)
return
def __enter__(self):
if self.message:
@ -118,12 +92,6 @@ class SFFile:
return False
def wait_writable(self):
if has_psram: return
while SF.is_busy():
pass
def close(self):
# PSRAM might leave a little behind
if self.runt:
@ -144,58 +112,24 @@ class SFFile:
left = len(b)
if has_psram:
# Mk4: memory-mapped, but can only do word-aligned writes
self.checksum.update(b)
# Mk4: memory-mapped, but can only do word-aligned writes
self.checksum.update(b)
self.runt.extend(b)
here = ALIGN4(len(self.runt))
if here:
PSRAM.write(self.start + self._pos, self.runt[0:here])
self._pos += here
self.runt = self.runt[here:]
self.runt.extend(b)
here = ALIGN4(len(self.runt))
if here:
PSRAM.write(self.start + self._pos, self.runt[0:here])
self._pos += here
self.runt = self.runt[here:]
self.pos += left
self.length = self.pos
self.pos += left
self.length = self.pos
if self.message:
from glob import dis
dis.progress_sofar(self.pos, self.length)
if self.message:
from glob import dis
dis.progress_sofar(self.pos, self.length)
return left
else:
# must perform page-aligned (256) writes, but can start
# anywhere in the page, and can write just one byte
sofar = 0
while left:
if (self.pos + sofar) % 256 != 0:
# start is unaligned, do a partial write to align
assert sofar == 0 #, (sofar, (self.pos+sofar)) # can only happen on first page
runt = min(left, 256 - (self.pos % 256))
here = memoryview(b)[0:runt]
assert len(here) == runt
else:
# write full pages, or final runt
here = memoryview(b)[sofar:sofar+256]
assert 1 <= len(here) <= 256
self.wait_writable()
SF.write(self.start + self.pos + sofar, here)
left -= len(here)
sofar += len(here)
self.checksum.update(here)
assert left >= 0
assert sofar == len(b)
self.pos += sofar
self.length = self.pos
return sofar
return left
def read(self, ll=None):
if ll == 0:
@ -210,10 +144,7 @@ class SFFile:
return b''
rv = bytearray(ll)
if has_psram:
PSRAM.read(self.start + self.pos, rv)
else:
SF.read(self.start + self.pos, rv)
PSRAM.read(self.start + self.pos, rv)
self.pos += ll
@ -227,10 +158,7 @@ class SFFile:
if actual <= 0:
return 0
if has_psram:
PSRAM.read(self.start + self.pos, b)
else:
SF.read(self.start + self.pos, b)
PSRAM.read(self.start + self.pos, b)
self.pos += actual
@ -252,9 +180,6 @@ class SizerFile(SFFile):
def __exit__(self, exc_type, exc_val, exc_tb):
return False
def wait_writable(self):
return
def write(self, b):
# immediate write, no buffering
assert self.pos == self.length # "can only append"

View File

@ -1,137 +0,0 @@
# (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC.
#
# sflash.py - SPI Flash on rev D and up boards. Simple serial SPI flash on SPI2 port.
#
# see also ../external/micropython/drivers/memory/spiflash.c
# but not using that, because:
# - not exposed as python objects
# - it wants to waste 4k on a buffer
#
# Layout for project:
# - 384k PSBT incoming (MAX_TXN_LEN)
# - 384k PSBT outgoing (MAX_TXN_LEN)
# - 128k nvram settings (32 slots of 4k each)
#
# During firmware updates, entire flash, starting at zero may be used.
#
import machine
from version import mk_num
CMD_WRSR = const(0x01)
CMD_WRITE = const(0x02)
CMD_READ = const(0x03)
CMD_FAST_READ = const(0x0b)
CMD_RDSR = const(0x05)
CMD_WREN = const(0x06)
CMD_RDCR = const(0x35)
CMD_RD_DEVID = const(0x9f)
CMD_SEC_ERASE = const(0x20) # 4k unit, 40-200ms
CMD_BLK_ERASE = const(0xd8) # 64k, 0.4 - 2s
CMD_CHIP_ERASE = const(0xc7) # 1MB, 3.5 - 6s
CMD_C4READ = const(0xeb)
class SPIFlash:
# must write with this page size granulatity
PAGE_SIZE = 256
# must erase with one of these size granulatity!
SECTOR_SIZE = 4096
BLOCK_SIZE = 65536
def __init__(self):
from machine import Pin
# chip can do 80Mhz, but very limited prescaler-only baudrate generation, so
# sysclk/2 or /4 will happen depending on Mk3 vs. 4
# - Mk4: 120Mhz => 60Mhz result (div 2)
# - Mk3: 80Mhz => 40Mhz result (div 2)
self.spi = machine.SPI(2, baudrate=80_000_000)
self.cs = Pin('SF_CS', Pin.OUT)
def cmd(self, cmd, addr=None, complete=True, pad=False):
if addr is not None:
buf = bytes([cmd, (addr>>16) & 0xff, (addr >> 8) & 0xff, addr & 0xff])
else:
buf = bytes([cmd])
if pad:
buf = buf + b'\0'
self.cs.low()
self.spi.write(buf)
if complete:
self.cs.high()
def read(self, address, buf, cmd=CMD_FAST_READ):
# random read (fast mode, because why wouldn't we?!)
self.cmd(cmd, address, complete=False, pad=True)
self.spi.readinto(buf)
self.cs.high()
def write(self, address, buf):
# 'page program', must already be erased
assert 1 <= len(buf) <= 256 # "max 256"
assert address & ~0xff == (address+len(buf)-1) & ~0xff # "page boundary"
self.cmd(CMD_WREN)
self.cmd(CMD_WRITE, address, complete=False)
self.spi.write(buf)
self.cs.high()
def read_reg(self, cmd, length=3):
# read register
rv = bytearray(length)
self.cmd(cmd, 0, complete=False)
self.spi.readinto(rv)
self.cs.high()
return rv
def is_busy(self):
# return status of WIP = Write In Progress bit
r = self.read_reg(CMD_RDSR, 1)
return bool(r[0] & 0x01)
def wait_done(self):
# wait until write done; could be fancier
while 1:
if not self.is_busy():
return
def chip_erase(self):
# can take up to 6 seconds, so poll is_busy()
self.cmd(CMD_WREN)
self.cmd(CMD_CHIP_ERASE)
def sector_erase(self, address):
# erase 4k. 40-200ms delay; poll is_busy()
assert address % 4096 == 0 # "not sector start"
self.cmd(CMD_WREN)
self.cmd(CMD_SEC_ERASE, address)
def block_erase(self, address):
# erase 64k at once
assert address % 65536 == 0 # "not block start"
self.cmd(CMD_WREN)
self.cmd(CMD_BLK_ERASE, address)
def wipe_most(self):
# erase everything except settings: takes 5 seconds at least
from glob import dis
assert mk_num <= 3 # obsolete in mk4
from nvstore import SLOTS
end = SLOTS[0]
for addr in range(0, end, self.BLOCK_SIZE):
self.block_erase(addr)
dis.progress_bar_show(addr/end)
while self.is_busy():
pass
# singleton
SF = SPIFlash()
# EOF

View File

@ -1,46 +0,0 @@
# (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC.
#
# sram2.py - Jam some larger, long-lived objects into the SRAM2 area, which isn't used enough.
#
# Cautions/Notes:
# - mpy heap does not include SRAM2, so doing manual memory alloc here.
# - top 8k reserved for bootloader, which will wipe it on each entry
# - top page of that is specially marked to cause reset if any attempt to change
# - 2k at bottom reserved for code in `flashbdev.c` to use as cache data for flash writing
# - keep this file in sync with simulated version
# - none of the above is true anymore on mk4
#
import uctypes, ckcc
from version import mk_num
if mk_num < 4:
# see stm32/COLDCARD/layout.ld where this is effectively defined
SRAM2_START = const(0x10000800)
SRAM2_LENGTH = const(0x5800)
_start = SRAM2_START
def _alloc(ln):
global _start
rv = uctypes.bytearray_at(_start, ln)
_start += ln
return rv
else:
# Mk4 has tons of memory, so just use it
def _alloc(ln):
return bytearray(ln)
nvstore_buf = _alloc(4096-32)
display_buf = _alloc(1024)
display2_buf = _alloc(1024)
usb_buf = _alloc(2048+12) # 2060 @ 0x10001be0
tmp_buf = _alloc(1024)
psbt_tmp256 = _alloc(256)
if mk_num < 4:
assert _start <= 0x10006000
# observed: about 22k on Mk2
ckcc.stack_limit(SRAM2_LENGTH - (_start - SRAM2_START))
# EOF

View File

@ -37,8 +37,7 @@ class SSD1306(framebuf.FrameBuffer):
#self.buffer = bytearray(self.pages * self.width)
from sram2 import display_buf
self.buffer = display_buf
self.buffer = bytearray(1024)
assert len(self.buffer) == self.pages * self.width
super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB)

View File

@ -10,7 +10,7 @@ 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 has_fatram, is_devmode, has_psram, MAX_TXN_LEN, MAX_UPLOAD_LEN
from version import is_devmode, MAX_TXN_LEN, MAX_UPLOAD_LEN
from exceptions import FramingError, CCBusyError, HSMDenied, HSMCMDDisabled
# Unofficial, unpermissioned... numbers
@ -90,7 +90,7 @@ def enable_usb():
else:
# subclass, protocol, max packet length, polling interval, report descriptor
hid_info = (0x0, 0x0, 64, 5, hid_descp)
classes = 'VCP+HID' if not has_psram else 'VCP+MSC+HID'
classes = 'VCP+MSC+HID'
pyb.usb_mode(classes, vid=COINKITE_VID, pid=CKCC_PID, hid=hid_info)
global handler
@ -129,8 +129,7 @@ class USBHandler:
# handle simulator
self.blockable = getattr(self.dev, 'pipe', self.dev)
from sram2 import usb_buf
self.msg = usb_buf
self.msg = bytearray(2048+12)
assert len(self.msg) == MAX_MSG_LEN
self.encrypted_req = False
@ -586,66 +585,64 @@ class USBHandler:
if cmd == 'bagi':
return self.handle_bag_number(args)
if has_fatram:
# HSM and user-related features only supported on larger-memory Mk3
# HSM and user-related features only supported on larger-memory Mk3
if cmd == 'hsms':
# HSM mode "start" -- requires user approval
if args:
file_len, file_sha = unpack_from('<I32s', args)
if file_sha != self.file_checksum.digest():
return b'err_Checksum'
assert 2 <= file_len <= (200*1000), "badlen"
else:
file_len = 0
if cmd == 'hsms':
# HSM mode "start" -- requires user approval
if args:
file_len, file_sha = unpack_from('<I32s', args)
if file_sha != self.file_checksum.digest():
return b'err_Checksum'
assert 2 <= file_len <= (200*1000), "badlen"
else:
file_len = 0
# Start an UX interaction but return (mostly) immediately here
from hsm_ux import start_hsm_approval
await start_hsm_approval(sf_len=file_len, usb_mode=True)
# Start an UX interaction but return (mostly) immediately here
from hsm_ux import start_hsm_approval
await start_hsm_approval(sf_len=file_len, usb_mode=True)
return None
if cmd == 'hsts':
# can always query HSM mode
from hsm import hsm_status_report
import ujson
return b'asci' + ujson.dumps(hsm_status_report())
if cmd == 'gslr':
# get the value held in the Storage Locker
assert hsm_active, 'need hsm'
return b'biny' + hsm_active.fetch_storage_locker()
# User Mgmt
if cmd == 'nwur': # new user
from users import Users
auth_mode, ul, sl = unpack_from('<BBB', args)
username = bytes(args[3:3+ul]).decode('ascii')
secret = bytes(args[3+ul:3+ul+sl])
return b'asci' + Users.create(username, auth_mode, secret).encode('ascii')
if cmd == 'rmur': # delete user
from users import Users
ul, = unpack_from('<B', args)
username = bytes(args[1:1+ul]).decode('ascii')
return Users.delete(username)
if cmd == 'user': # auth user (HSM mode)
from users import Users
totp_time, ul, tl = unpack_from('<IBB', args)
username = bytes(args[6:6+ul]).decode('ascii')
token = bytes(args[6+ul:6+ul+tl])
if hsm_active:
# just queues these details, can't be checked until PSBT on-hand
hsm_active.usb_auth_user(username, token, totp_time)
return None
if cmd == 'hsts':
# can always query HSM mode
from hsm import hsm_status_report
import ujson
return b'asci' + ujson.dumps(hsm_status_report())
if cmd == 'gslr':
# get the value held in the Storage Locker
assert hsm_active, 'need hsm'
return b'biny' + hsm_active.fetch_storage_locker()
# User Mgmt
if cmd == 'nwur': # new user
from users import Users
auth_mode, ul, sl = unpack_from('<BBB', args)
username = bytes(args[3:3+ul]).decode('ascii')
secret = bytes(args[3+ul:3+ul+sl])
return b'asci' + Users.create(username, auth_mode, secret).encode('ascii')
if cmd == 'rmur': # delete user
from users import Users
ul, = unpack_from('<B', args)
username = bytes(args[1:1+ul]).decode('ascii')
return Users.delete(username)
if cmd == 'user': # auth user (HSM mode)
from users import Users
totp_time, ul, tl = unpack_from('<IBB', args)
username = bytes(args[6:6+ul]).decode('ascii')
token = bytes(args[6+ul:6+ul+tl])
if hsm_active:
# just queues these details, can't be checked until PSBT on-hand
hsm_active.usb_auth_user(username, token, totp_time)
return None
else:
# dryrun/testing purposes: validate only, doesn't unlock nothing
return b'asci' + Users.auth_okay(username, token, totp_time).encode('ascii')
else:
# dryrun/testing purposes: validate only, doesn't unlock nothing
return b'asci' + Users.auth_okay(username, token, totp_time).encode('ascii')
#print("USB garbage: %s +[%d]" % (cmd, len(args)))
@ -736,23 +733,16 @@ class USBHandler:
buf = memoryview(resp)[4:]
pos = (MAX_TXN_LEN * file_number) + offset
if has_psram:
from glob import PSRAM
PSRAM.read(pos, buf)
else:
from sflash import SF
SF.read(pos, buf)
from glob import PSRAM
PSRAM.read(pos, buf)
self.file_checksum.update(buf)
return resp
async def handle_upload(self, offset, total_size, data):
if has_psram:
from glob import PSRAM
else:
from sflash import SF
from glob import PSRAM
from glob import dis, hsm_active
from utils import check_firmware_hdr
from sigheader import FW_HEADER_OFFSET, FW_HEADER_SIZE, FW_HEADER_MAGIC
@ -775,15 +765,6 @@ class USBHandler:
if pos % 4096 == 0:
dis.fullscreen("Receiving...", offset/total_size)
if not has_psram:
# erase here
SF.sector_erase(pos)
# expect 10-22 ms delay here
await sleep_ms(12)
while SF.is_busy():
await sleep_ms(2)
# write up to 256 bytes
here = data[pos-offset:pos-offset+256]
self.file_checksum.update(here)
@ -817,15 +798,8 @@ class USBHandler:
# pretend we wrote it, so ckcc-protocol or whatever gives normal feedback
return offset
# write to SPI Flash / PSRAM
if has_psram:
PSRAM.write(pos, here)
else:
SF.write(pos, here)
# full page write: 0.6 to 3ms
while SF.is_busy():
await sleep_ms(1)
# write to PSRAM
PSRAM.write(pos, here)
if offset+len(data) >= total_size and not hsm_active:
# probably done

View File

@ -1,8 +1,5 @@
# items imported here may be useful to EVAL and EXEC commands, which test cases depend on.
import uio, sys, version, nvstore, glob, callgate
try:
from sflash import SF
except: pass
try:
import sim_display
except: pass

View File

@ -392,17 +392,11 @@ def clean_shutdown(style=0):
settings.save_if_dirty()
try:
from glob import dis
from glob import dis, NFC
dis.fullscreen("Cleanup...")
if not version.has_psram:
from sflash import SF
SF.wipe_most()
else:
from glob import NFC
if NFC:
uasyncio.run(NFC.wipe(True))
if NFC:
uasyncio.run(NFC.wipe(True))
except: pass

View File

@ -21,12 +21,12 @@ def decode_firmware_header(hdr):
def get_fw_header():
# located in our own flash
from sigheader import FLASH_HEADER_BASE, FLASH_HEADER_BASE_MK4, FW_HEADER_SIZE
from sigheader import FLASH_HEADER_BASE_MK4, FW_HEADER_SIZE
import uctypes
global mk_num
return uctypes.bytes_at(FLASH_HEADER_BASE_MK4 if mk_num == 4 else FLASH_HEADER_BASE,
return uctypes.bytes_at(FLASH_HEADER_BASE_MK4,
FW_HEADER_SIZE)
def get_mpy_version():
@ -58,37 +58,8 @@ def nfc_presence_check():
def get_is_devmode():
# what firmware signing key did we boot with? are we in dev mode?
if mk_num == 4:
# mk4: are we built differently?
import ckcc
return ckcc.is_debug_build()
from sigheader import RAM_HEADER_BASE, FWH_PK_NUM_OFFSET
import stm
# Important? Use the RAM version of this, not flash version!
kn = stm.mem32[RAM_HEADER_BASE + FWH_PK_NUM_OFFSET]
# For now, all keys are "production" except number zero, which will be made public
# - some other keys may be de-authorized and so on in the future
is_devmode = (kn == 0)
return is_devmode
def is_fresh_version():
# Did we just boot into a new firmware for the first time?
# - mk4+ does not use this approach, light will be solid green during upgrade
if mk_num >= 4: return False
from sigheader import RAM_BOOT_FLAGS, RBF_FRESH_VERSION
import stm
flags = stm.mem32[RAM_BOOT_FLAGS]
return bool(flags & RBF_FRESH_VERSION)
import ckcc
return ckcc.is_debug_build()
def serial_number():
@ -103,49 +74,25 @@ def serial_number():
def probe_system():
# run-once code to determine what hardware we are running on
global hw_label, has_608, has_fatram, is_factory_mode, is_devmode, has_psram
global has_se2, mk_num, has_nfc, is_edge
global hw_label, has_608, is_factory_mode
global mk_num, has_nfc, is_devmode, is_edge
global MAX_UPLOAD_LEN, MAX_TXN_LEN
from sigheader import RAM_BOOT_FLAGS, RBF_FACTORY_MODE
import ckcc, callgate, stm
from machine import Pin
import ckcc, callgate
# NOTE: mk1 not supported anymore.
# PA10 is pulled-down in Mark2, open in previous revs
#mark2 = (Pin('MARK2', Pin.IN, pull=Pin.PULL_UP).value() == 0)
hw_label = 'mk2'
has_fatram = False
has_psram = False
hw_label = 'mk4'
has_608 = True
has_se2 = False
has_nfc = False # hardware present; they might not be using it
mk_num = 2
has_nfc = nfc_presence_check() # hardware present; they might not be using it
mk_num = 4
cpuid = ckcc.get_cpu_id()
if cpuid == 0x461: # STM32L496RG6
hw_label = 'mk3'
has_fatram = True
mk_num = 3
elif cpuid == 0x470: # STM32L4S5VI
hw_label = 'mk4'
has_fatram = True
has_psram = True
has_se2 = True
mk_num = 4
has_nfc = nfc_presence_check()
else:
# mark 2
has_608 = callgate.has_608()
assert cpuid == 0x470 # STM32L4S5VI
# Boot loader needs to tell us stuff about how we were booted, sometimes:
# - did we just install a new version, for example (obsolete in mk4)
# - are we running in "factory mode" with flash un-secured?
if mk_num < 4:
is_factory_mode = bool(stm.mem32[RAM_BOOT_FLAGS] & RBF_FACTORY_MODE)
else:
is_factory_mode = callgate.get_factory_mode()
is_factory_mode = callgate.get_factory_mode()
bn = callgate.get_bag_number()
if bn:
@ -159,10 +106,9 @@ def probe_system():
is_edge = (get_mpy_version()[1][-1] == 'X')
# increase size limits for mk4
if has_psram:
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
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()

View File

@ -7,7 +7,6 @@ freeze_as_mpy('', [
'mock.py',
'os.py',
'pyb.py',
'sflash.py',
'sim_mk4.py',
'sim_nfc.py',
'sim_psram.py',
@ -16,7 +15,6 @@ freeze_as_mpy('', [
'sim_se2.py',
'sim_settings.py',
'sim_vdisk.py',
'sram2.py',
'ssd1306.py',
'stm.py',
'struct.py',

View File

@ -1,70 +0,0 @@
# replacement for serial flash stuff, just enough to pass selftest
#
# see real deal at ../shared/sflash.py
from version import mk_num
if mk_num < 4:
_SIZE = 1024*1024
class SPIFlash:
PAGE_SIZE = 256
SECTOR_SIZE = 4096
BLOCK_SIZE = 65536
array = bytearray(_SIZE)
def read(self, address, buf, **kw):
# random read
buf[0:len(buf)] = self.array[address:address+len(buf)]
def write(self, address, buf):
# 'page program', must already be erased
assert 1 <= len(buf) <= 256, "max 256"
assert address & ~0xff == (address+len(buf)-1) & ~0xff, \
"page aligned only: addr=0x%x len=0x%x" % (address, len(buf))
#self.array[address:address+len(buf)] = buf
# emulate flash memory: can only go from 1=>0
for i in range(len(buf)):
self.array[address+i] &= buf[i]
def is_busy(self):
# always instant
return False
def wait_done(self):
return
def chip_erase(self):
for i in range(_SIZE):
self.array[i] = 0xff
def sector_erase(self, address):
for i in range(self.SECTOR_SIZE):
self.array[address+i] = 0xff
def block_erase(self, address):
# erase 64k at once
assert address % 65536 == 0, "not block start"
for i in range(self.BLOCK_SIZE):
self.array[address+i] = 0xff
def wipe_most(self):
# XXX ux here is bad
# erase everything except settings: takes 5 seconds at least
from nvstore import SLOTS
end = SLOTS[0]
from main import dis
dis.fullscreen("Cleanup...")
for addr in range(0, end, self.BLOCK_SIZE):
self.block_erase(addr)
dis.progress_bar_show(addr/end)
while self.is_busy():
pass
SF = SPIFlash()
# EOF

View File

@ -1,8 +0,0 @@
# see shared/sram2.py
nvstore_buf = bytearray(4096-32)
display_buf = bytearray(1024)
display2_buf = bytearray(1024)
usb_buf = bytearray(2048+12)
tmp_buf = bytearray(1024)
psbt_tmp256 = bytearray(256)