|
|
@ -1,3 +1,4 @@ |
|
|
|
#!/usr/bin/env python3 |
|
|
|
# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. <hello@foundationdevices.com> |
|
|
|
# SPDX-License-Identifier: GPL-3.0-or-later |
|
|
|
# |
|
|
@ -33,10 +34,6 @@ TELNET_CMD_LINE = ['telnet', 'localhost', '4444'] |
|
|
|
telnet_proc = None |
|
|
|
|
|
|
|
|
|
|
|
# FACTORY SETTINGS |
|
|
|
DIAGNOSTIC_MODE = False # Set to True to get more menu options |
|
|
|
|
|
|
|
|
|
|
|
def connect_to_telnet(): |
|
|
|
# Connect |
|
|
|
global tn |
|
|
@ -45,6 +42,27 @@ def connect_to_telnet(): |
|
|
|
# We still see the commands we send echoed from the remote side, but they are not also echoed locally now. |
|
|
|
tn.write(b'' + telnetlib.IAC + telnetlib.DONT + telnetlib.ECHO) |
|
|
|
|
|
|
|
def banner(s): |
|
|
|
divider = '=' * len(s) |
|
|
|
print(divider) |
|
|
|
print(s) |
|
|
|
print(divider) |
|
|
|
|
|
|
|
# def poll_for_device(): |
|
|
|
# attempts_remaining = 10 |
|
|
|
# print('Waiting for device to be ready...') |
|
|
|
# while attempts_remaining > 0: |
|
|
|
# print(' {}...'.format(attempts_remaining)) |
|
|
|
# result = init_device() |
|
|
|
# if result: |
|
|
|
# print('Device Ready!') |
|
|
|
# return True |
|
|
|
# |
|
|
|
# time.sleep(1) |
|
|
|
# attempts_remaining -= 1 |
|
|
|
# |
|
|
|
# print('Timeout! Device did not respond.') |
|
|
|
# return False |
|
|
|
|
|
|
|
# Numato 32 channel GPIO board over USB serial: |
|
|
|
# |
|
|
@ -103,19 +121,42 @@ def wait_for_prompt(timeout=None): |
|
|
|
else: |
|
|
|
return True |
|
|
|
|
|
|
|
|
|
|
|
MAX_ATTEMPTS = 10 |
|
|
|
|
|
|
|
# Put device into halt state, and discard all unread data to get ready for a new command |
|
|
|
def init_device(timeout=None): |
|
|
|
r = tn.read_very_eager() |
|
|
|
# print('Halting device...') |
|
|
|
tn.write(b'reset halt\r') |
|
|
|
return wait_for_prompt(timeout) |
|
|
|
attempts_remaining = MAX_ATTEMPTS |
|
|
|
if not tn: |
|
|
|
print('Connecting to OpenOCD...') |
|
|
|
|
|
|
|
while attempts_remaining > 0: |
|
|
|
if not tn: |
|
|
|
connect_to_telnet() |
|
|
|
|
|
|
|
if tn: |
|
|
|
r = tn.read_very_eager() |
|
|
|
# print('Halting device...') |
|
|
|
tn.write(b'reset halt\r') |
|
|
|
result = wait_for_prompt(timeout) |
|
|
|
if result: |
|
|
|
if attempts_remaining < MAX_ATTEMPTS: |
|
|
|
banner('Connected to device!') |
|
|
|
return True |
|
|
|
|
|
|
|
print(' {}...'.format(attempts_remaining)) |
|
|
|
time.sleep(1) |
|
|
|
attempts_remaining -= 1 |
|
|
|
|
|
|
|
banner('Timeout! Device did not respond.') |
|
|
|
return False |
|
|
|
|
|
|
|
def random_fn_ext(l): |
|
|
|
import os, binascii |
|
|
|
return binascii.b2a_hex(os.urandom(l)).decode('utf-8') |
|
|
|
|
|
|
|
def provision_device(flash_bootloader=False, flash_firmware=False, with_secrets=False): |
|
|
|
init_device() |
|
|
|
if not init_device(): return |
|
|
|
|
|
|
|
# Check to see if the device was already provisioned - it will have data in its secrets |
|
|
|
if flash_bootloader and not with_secrets: |
|
|
@ -183,7 +224,7 @@ def provision_device(flash_bootloader=False, flash_firmware=False, with_secrets= |
|
|
|
print('Complete!') |
|
|
|
|
|
|
|
def write_supply_chain_secret(): |
|
|
|
init_device() |
|
|
|
if not init_device(): return |
|
|
|
|
|
|
|
# Write the supply chain secret |
|
|
|
print('Setting Supply Chain Validation Secret...') |
|
|
@ -196,19 +237,15 @@ def write_supply_chain_secret(): |
|
|
|
tn.write(bytes(cmd, 'utf-8')) |
|
|
|
wait_for_prompt() |
|
|
|
|
|
|
|
def test_device_connection(): |
|
|
|
tn.read_very_eager() |
|
|
|
device_found = init_device(timeout=5) |
|
|
|
if device_found: |
|
|
|
print('Passport is connected and responding to commands.') |
|
|
|
else: |
|
|
|
print('===================================================================') |
|
|
|
print('Unable to connect to device (Error or timeout connecting to device)') |
|
|
|
print('===================================================================') |
|
|
|
# def test_device_connection(): |
|
|
|
# # tn.read_very_eager() |
|
|
|
# device_found = init_device(timeout=5) |
|
|
|
# if device_found: |
|
|
|
# print('Passport is connected and responding to commands.') |
|
|
|
|
|
|
|
def read_supply_chain_secret(do_init=True): |
|
|
|
if do_init: |
|
|
|
init_device() |
|
|
|
if not init_device(): return |
|
|
|
|
|
|
|
# Read the supply chain secret to make sure the device is ready for provisioning |
|
|
|
tn.write(bytes('mdb {} 32\r'.format(hex(SUPPLY_CHAIN_SECRET_ADDRESS)), 'utf-8')) |
|
|
@ -235,7 +272,7 @@ def is_already_provisioned(secrets): |
|
|
|
return any(map(lambda b: b != 0xFF, secrets)) |
|
|
|
|
|
|
|
def get_secrets(): |
|
|
|
init_device() |
|
|
|
if not init_device(): return [] |
|
|
|
|
|
|
|
cmd = bytes('mdb {} 256\r'.format(hex(BL_NVROM_BASE)), 'utf-8') |
|
|
|
tn.write(cmd) |
|
|
@ -266,7 +303,7 @@ def save_secrets(): |
|
|
|
print('\nUnable to read secrets from device!') |
|
|
|
|
|
|
|
def reset_device(): |
|
|
|
init_device() |
|
|
|
if not init_device(): return |
|
|
|
|
|
|
|
print('Resetting Device...') |
|
|
|
tn.write(b'reset\r') |
|
|
@ -274,7 +311,7 @@ def reset_device(): |
|
|
|
print('Done.') |
|
|
|
|
|
|
|
def erase_all_flash(): |
|
|
|
init_device() |
|
|
|
if not init_device(): return |
|
|
|
|
|
|
|
print('Erasing all internal flash (bootloader, secrets, firmware, user settings)...') |
|
|
|
tn.write(b'flash erase_address 0x8000000 0x200000\r') |
|
|
@ -298,9 +335,14 @@ def erase_all_flash(): |
|
|
|
# |
|
|
|
|
|
|
|
def main(): |
|
|
|
DIAGNOSTIC_MODE = False |
|
|
|
if len(sys.argv) > 1: |
|
|
|
if sys.argv[1] == '--diag': |
|
|
|
DIAGNOSTIC_MODE = True |
|
|
|
|
|
|
|
if DIAGNOSTIC_MODE: |
|
|
|
options = [ |
|
|
|
'[1] Test Device Connection', |
|
|
|
'[1] Connect to Test Device', |
|
|
|
'[2] Provision Device', |
|
|
|
'[3] Update Bootloader Only (with secrets.bin)', |
|
|
|
'[4] Update Firmware Only', |
|
|
@ -314,7 +356,7 @@ def main(): |
|
|
|
] |
|
|
|
else: |
|
|
|
options = [ |
|
|
|
'[1] Test Device Connection', |
|
|
|
'[1] Connect to Test Device', |
|
|
|
'[2] Provision Device', |
|
|
|
'[3] Print Secrets', |
|
|
|
'[4] Reset Device', |
|
|
@ -331,8 +373,7 @@ def main(): |
|
|
|
|
|
|
|
if DIAGNOSTIC_MODE: |
|
|
|
if selection == 0: |
|
|
|
connect_to_telnet() |
|
|
|
test_device_connection() |
|
|
|
init_device() |
|
|
|
elif selection == 1: |
|
|
|
provision_device(flash_bootloader=True, flash_firmware=True) |
|
|
|
elif selection == 2: |
|
|
@ -355,8 +396,7 @@ def main(): |
|
|
|
exit = True |
|
|
|
else: |
|
|
|
if selection == 0: |
|
|
|
connect_to_telnet() |
|
|
|
test_device_connection() |
|
|
|
init_device() |
|
|
|
elif selection == 1: |
|
|
|
provision_device(flash_bootloader=True, flash_firmware=True) |
|
|
|
elif selection == 2: |
|
|
|