Esempio n. 1
0
async def test_sflash():
    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.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)
Esempio n. 2
0
    async def erase(self):
        # must be used by caller before writing any bytes
        assert not self.readonly
        assert self.length == 0  # 'already wrote?'

        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)
Esempio n. 3
0
    async def handle_upload(self, offset, total_size, data):
        from sflash import SF
        from glob import dis, hsm_active
        from utils import check_firmware_hdr
        from sigheader import FW_HEADER_OFFSET, FW_HEADER_SIZE, FW_HEADER_MAGIC

        # maintain a running SHA256 over what's received
        if offset == 0:
            self.file_checksum = sha256()
            self.is_fw_upgrade = False

        assert offset % 256 == 0, 'alignment'
        assert offset + len(data) <= total_size <= MAX_UPLOAD_LEN, 'long'

        if hsm_active:
            # additional restrictions in HSM mode
            assert offset + len(data) <= total_size <= MAX_TXN_LEN, 'psbt'
            if offset == 0:
                assert data[0:5] == b'psbt\xff', 'psbt'

        for pos in range(offset, offset + len(data), 256):
            if pos % 4096 == 0:
                # erase here
                dis.fullscreen("Receiving...", offset / total_size)

                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)

            # Very special case for firmware upgrades: intercept and modify
            # header contents on the fly, and also fail faster if wouldn't work
            # on this specific hardware.
            # - workaround: ckcc-protocol upgrade process understates the file
            #   length and appends hdr, but that's kinda a bug, so support both
            is_trailer = (pos == (total_size - FW_HEADER_SIZE)
                          or pos == total_size)

            if pos == (FW_HEADER_OFFSET & ~255):
                hdr = memoryview(here)[-128:]
                magic, = unpack_from('<I', hdr[0:4])
                if magic == FW_HEADER_MAGIC:
                    self.is_fw_upgrade = bytes(hdr)

                    prob = check_firmware_hdr(hdr, total_size)
                    if prob:
                        raise ValueError(prob)

            if is_trailer and self.is_fw_upgrade:
                # expect the trailer to exactly match the original one
                assert len(here) == 128  # == FW_HEADER_SIZE
                hdr = memoryview(here)[-128:]
                assert hdr == self.is_fw_upgrade  # indicates hacking

                # but don't write it, instead offer user a chance to abort
                from auth import authorize_upgrade
                authorize_upgrade(self.is_fw_upgrade, pos)

                # pretend we wrote it, so ckcc-protocol or whatever gives normal feedback
                return offset

            SF.write(pos, here)

            # full page write: 0.6 to 3ms
            while SF.is_busy():
                await sleep_ms(1)

        if offset + len(data) >= total_size and not hsm_active:
            # probably done
            dis.progress_bar_show(1.0)
            ux.restore_menu()

        return offset
Esempio n. 4
0
 def wait_writable(self):
     # TODO: timeouts here
     while SF.is_busy():
         pass
Esempio n. 5
0
    async def handle_upload(self, offset, total_size, data):
        from sflash import SF
        from glob import dis, hsm_active
        from utils import check_firmware_hdr
        from sigheader import FW_HEADER_OFFSET, FW_HEADER_SIZE

        # maintain a running SHA256 over what's received
        if offset == 0:
            self.file_checksum = sha256()

        assert offset % 256 == 0, 'alignment'
        assert offset + len(data) <= total_size <= MAX_UPLOAD_LEN, 'long'

        if hsm_active:
            # additional restrictions in HSM mode
            assert offset + len(data) <= total_size <= MAX_TXN_LEN, 'psbt'
            if offset == 0:
                assert data[0:5] == b'psbt\xff', 'psbt'

        for pos in range(offset, offset + len(data), 256):
            if pos % 4096 == 0:
                # erase here
                dis.fullscreen("Receiving...", offset / total_size)

                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)

            # Very special case for firmware upgrades: intercept and modify
            # header contents on the fly, and also fail faster if wouldn't work
            # on this specific hardware.
            # - workaround: ckcc-protocol upgrade process understates the file
            #   length and appends hdr, but that's kinda a bug, so support both
            if (pos == (FW_HEADER_OFFSET & ~255)
                    or pos == (total_size - FW_HEADER_SIZE)
                    or pos == total_size):

                prob = check_firmware_hdr(memoryview(here)[-128:],
                                          None,
                                          bad_magic_ok=True)
                if prob:
                    raise ValueError(prob)

            SF.write(pos, here)

            # full page write: 0.6 to 3ms
            while SF.is_busy():
                await sleep_ms(1)

        if offset + len(data) >= total_size and not hsm_active:
            # probably done
            dis.progress_bar_show(1.0)
            ux.restore_menu()

        return offset