2022-08-16 05:57:36 +00:00
#! /usr/bin/env python3
import argparse
import usb . core
import usb . util
import array
import sys
import hashlib
import csv
import urllib . request
2022-09-15 17:39:49 +00:00
import re
2022-08-16 05:57:36 +00:00
from progressbar . bar import ProgressBar
class PrecursorUsb :
def __init__ ( self , dev ) :
self . dev = dev
self . RDSR = 0x05
self . RDSCUR = 0x2B
self . RDID = 0x9F
self . WREN = 0x06
self . WRDI = 0x04
self . SE4B = 0x21
self . BE4B = 0xDC
self . PP4B = 0x12
self . registers = { }
self . regions = { }
self . gitrev = ' '
def register ( self , name ) :
return int ( self . registers [ name ] , 0 )
def peek ( self , addr , display = False ) :
_dummy_s = ' \x00 ' . encode ( ' utf-8 ' )
data = array . array ( ' B ' , _dummy_s * 4 )
numread = self . dev . ctrl_transfer ( bmRequestType = ( 0x80 | 0x43 ) , bRequest = 0 ,
wValue = ( addr & 0xffff ) , wIndex = ( ( addr >> 16 ) & 0xffff ) ,
data_or_wLength = data , timeout = 500 )
read_data = int . from_bytes ( data . tobytes ( ) , byteorder = ' little ' , signed = False )
if display == True :
print ( " 0x {:08x} " . format ( read_data ) )
return read_data
def poke ( self , addr , wdata , check = False , display = False ) :
if check == True :
_dummy_s = ' \x00 ' . encode ( ' utf-8 ' )
data = array . array ( ' B ' , _dummy_s * 4 )
numread = self . dev . ctrl_transfer ( bmRequestType = ( 0x80 | 0x43 ) , bRequest = 0 ,
wValue = ( addr & 0xffff ) , wIndex = ( ( addr >> 16 ) & 0xffff ) ,
data_or_wLength = data , timeout = 500 )
read_data = int . from_bytes ( data . tobytes ( ) , byteorder = ' little ' , signed = False )
print ( " before poke: 0x {:08x} " . format ( read_data ) )
data = array . array ( ' B ' , wdata . to_bytes ( 4 , ' little ' ) )
numwritten = self . dev . ctrl_transfer ( bmRequestType = ( 0x00 | 0x43 ) , bRequest = 0 ,
wValue = ( addr & 0xffff ) , wIndex = ( ( addr >> 16 ) & 0xffff ) ,
data_or_wLength = data , timeout = 500 )
if check == True :
_dummy_s = ' \x00 ' . encode ( ' utf-8 ' )
data = array . array ( ' B ' , _dummy_s * 4 )
numread = self . dev . ctrl_transfer ( bmRequestType = ( 0x80 | 0x43 ) , bRequest = 0 ,
wValue = ( addr & 0xffff ) , wIndex = ( ( addr >> 16 ) & 0xffff ) ,
data_or_wLength = data , timeout = 500 )
read_data = int . from_bytes ( data . tobytes ( ) , byteorder = ' little ' , signed = False )
print ( " after poke: 0x {:08x} " . format ( read_data ) )
if display == True :
print ( " wrote 0x {:08x} to 0x {:08x} " . format ( wdata , addr ) )
def burst_read ( self , addr , len ) :
_dummy_s = ' \x00 ' . encode ( ' utf-8 ' )
maxlen = 4096
ret = bytearray ( )
packet_count = len / / maxlen
if ( len % maxlen ) != 0 :
packet_count + = 1
for pkt_num in range ( packet_count ) :
cur_addr = addr + pkt_num * maxlen
if pkt_num == packet_count - 1 :
if len % maxlen != 0 :
bufsize = len % maxlen
else :
bufsize = maxlen
else :
bufsize = maxlen
data = array . array ( ' B ' , _dummy_s * bufsize )
numread = self . dev . ctrl_transfer ( bmRequestType = ( 0x80 | 0x43 ) , bRequest = 0 ,
wValue = ( cur_addr & 0xffff ) , wIndex = ( ( cur_addr >> 16 ) & 0xffff ) ,
data_or_wLength = data , timeout = 500 )
if numread != bufsize :
print ( " Burst read error: {} bytes requested, {} bytes read at 0x {:08x} " . format ( bufsize , numread , cur_addr ) )
exit ( 1 )
ret = ret + data
return ret
def burst_write ( self , addr , data ) :
if len ( data ) == 0 :
return
# the actual "addr" doesn't matter for a burst_write, because it's specified
# as an argument to the flash_pp4b command. We lock out access to the base of
# SPINOR because it's part of the gateware, so, we pick a "safe" address to
# write to instead. The page write responder will aggregate any write data
# to anywhere in the SPINOR address range.
writebuf_addr = 0x2098_0000 # the current start address of the kernel, for example
maxlen = 4096
packet_count = len ( data ) / / maxlen
if ( len ( data ) % maxlen ) != 0 :
packet_count + = 1
for pkt_num in range ( packet_count ) :
cur_addr = addr + pkt_num * maxlen
if pkt_num == packet_count - 1 :
if len ( data ) % maxlen != 0 :
bufsize = len ( data ) % maxlen
else :
bufsize = maxlen
else :
bufsize = maxlen
wdata = array . array ( ' B ' , data [ ( pkt_num * maxlen ) : ( pkt_num * maxlen ) + bufsize ] )
numwritten = self . dev . ctrl_transfer ( bmRequestType = ( 0x00 | 0x43 ) , bRequest = 0 ,
# note use of writebuf_addr instead of cur_addr -> see comment above about the quirk of write addressing
wValue = ( writebuf_addr & 0xffff ) , wIndex = ( ( writebuf_addr >> 16 ) & 0xffff ) ,
data_or_wLength = wdata , timeout = 500 )
if numwritten != bufsize :
print ( " Burst write error: {} bytes requested, {} bytes written at 0x {:08x} " . format ( bufsize , numwritten , cur_addr ) )
exit ( 1 )
def ping_wdt ( self ) :
self . poke ( self . register ( ' wdt_watchdog ' ) , 1 , display = False )
self . poke ( self . register ( ' wdt_watchdog ' ) , 1 , display = False )
def spinor_command_value ( self , exec = 0 , lock_reads = 0 , cmd_code = 0 , dummy_cycles = 0 , data_words = 0 , has_arg = 0 ) :
return ( ( exec & 1 ) << 1 |
( lock_reads & 1 ) << 24 |
( cmd_code & 0xff ) << 2 |
( dummy_cycles & 0x1f ) << 11 |
( data_words & 0xff ) << 16 |
( has_arg & 1 ) << 10
)
def flash_rdsr ( self , lock_reads ) :
self . poke ( self . register ( ' spinor_cmd_arg ' ) , 0 )
self . poke ( self . register ( ' spinor_command ' ) ,
self . spinor_command_value ( exec = 1 , lock_reads = lock_reads , cmd_code = self . RDSR , dummy_cycles = 4 , data_words = 1 , has_arg = 1 )
)
return self . peek ( self . register ( ' spinor_cmd_rbk_data ' ) , display = False )
def flash_rdscur ( self ) :
self . poke ( self . register ( ' spinor_cmd_arg ' ) , 0 )
self . poke ( self . register ( ' spinor_command ' ) ,
self . spinor_command_value ( exec = 1 , lock_reads = 1 , cmd_code = self . RDSCUR , dummy_cycles = 4 , data_words = 1 , has_arg = 1 )
)
return self . peek ( self . register ( ' spinor_cmd_rbk_data ' ) , display = False )
def flash_rdid ( self , offset ) :
self . poke ( self . register ( ' spinor_cmd_arg ' ) , 0 )
self . poke ( self . register ( ' spinor_command ' ) ,
self . spinor_command_value ( exec = 1 , cmd_code = self . RDID , dummy_cycles = 4 , data_words = offset , has_arg = 1 )
)
return self . peek ( self . register ( ' spinor_cmd_rbk_data ' ) , display = False )
def flash_wren ( self ) :
self . poke ( self . register ( ' spinor_cmd_arg ' ) , 0 )
self . poke ( self . register ( ' spinor_command ' ) ,
self . spinor_command_value ( exec = 1 , lock_reads = 1 , cmd_code = self . WREN )
)
def flash_wrdi ( self ) :
self . poke ( self . register ( ' spinor_cmd_arg ' ) , 0 )
self . poke ( self . register ( ' spinor_command ' ) ,
self . spinor_command_value ( exec = 1 , lock_reads = 1 , cmd_code = self . WRDI )
)
def flash_se4b ( self , sector_address ) :
self . poke ( self . register ( ' spinor_cmd_arg ' ) , sector_address )
self . poke ( self . register ( ' spinor_command ' ) ,
self . spinor_command_value ( exec = 1 , lock_reads = 1 , cmd_code = self . SE4B , has_arg = 1 )
)
def flash_be4b ( self , block_address ) :
self . poke ( self . register ( ' spinor_cmd_arg ' ) , block_address )
self . poke ( self . register ( ' spinor_command ' ) ,
self . spinor_command_value ( exec = 1 , lock_reads = 1 , cmd_code = self . BE4B , has_arg = 1 )
)
def flash_pp4b ( self , address , data_bytes ) :
self . poke ( self . register ( ' spinor_cmd_arg ' ) , address )
self . poke ( self . register ( ' spinor_command ' ) ,
self . spinor_command_value ( exec = 1 , lock_reads = 1 , cmd_code = self . PP4B , has_arg = 1 , data_words = ( data_bytes / / 2 ) )
)
def load_csrs ( self , fname = None ) :
LOC_CSRCSV = 0x20277000 # this address shouldn't change because it's how we figure out our version number
# CSR extraction:
# dd if=soc_csr.bin of=csr_data_0.9.6.bin skip=2524 count=32 bs=1024
if fname == None :
csr_data = self . burst_read ( LOC_CSRCSV , 0x8000 )
else :
with open ( fname , " rb " ) as f :
csr_data = f . read ( 0x8000 )
hasher = hashlib . sha512 ( )
hasher . update ( csr_data [ : 0x7FC0 ] )
digest = hasher . digest ( )
if digest != csr_data [ 0x7fc0 : ] :
print ( " Could not find a valid csr.csv descriptor on the device, aborting! " )
exit ( 1 )
csr_len = int . from_bytes ( csr_data [ : 4 ] , ' little ' )
csr_extracted = csr_data [ 4 : 4 + csr_len ]
decoded = csr_extracted . decode ( ' utf-8 ' )
# strip comments
stripped = [ ]
for line in decoded . split ( ' \n ' ) :
if line . startswith ( ' # ' ) == False :
stripped . append ( line )
# create database
csr_db = csv . reader ( stripped )
for row in csr_db :
if len ( row ) > 1 :
if ' csr_register ' in row [ 0 ] :
self . registers [ row [ 1 ] ] = row [ 2 ]
if ' memory_region ' in row [ 0 ] :
self . regions [ row [ 1 ] ] = [ row [ 2 ] , row [ 3 ] ]
if ' git_rev ' in row [ 0 ] :
self . gitrev = row [ 1 ]
print ( " Using SoC {} registers " . format ( self . gitrev ) )
def erase_region ( self , addr , length ) :
# ID code check
code = self . flash_rdid ( 1 )
print ( " ID code bytes 1-2: 0x {:08x} " . format ( code ) )
if code != 0x8080c2c2 :
print ( " ID code mismatch " )
exit ( 1 )
code = self . flash_rdid ( 2 )
print ( " ID code bytes 2-3: 0x {:08x} " . format ( code ) )
if code != 0x3b3b8080 :
print ( " ID code mismatch " )
exit ( 1 )
# block erase
progress = ProgressBar ( min_value = 0 , max_value = length , prefix = ' Erasing ' ) . start ( )
erased = 0
while erased < length :
self . ping_wdt ( )
if ( length - erased > = 65536 ) and ( ( addr & 0xFFFF ) == 0 ) :
blocksize = 65536
else :
blocksize = 4096
while True :
self . flash_wren ( )
status = self . flash_rdsr ( 1 )
if status & 0x02 != 0 :
break
if blocksize == 4096 :
self . flash_se4b ( addr + erased )
else :
self . flash_be4b ( addr + erased )
erased + = blocksize
while ( self . flash_rdsr ( 1 ) & 0x01 ) != 0 :
pass
result = self . flash_rdscur ( )
if result & 0x60 != 0 :
print ( " E_FAIL/P_FAIL set on erase, programming may fail, but trying anyways... " )
if self . flash_rdsr ( 1 ) & 0x02 != 0 :
self . flash_wrdi ( )
while ( self . flash_rdsr ( 1 ) & 0x02 ) != 0 :
pass
if erased < length :
progress . update ( erased )
progress . finish ( )
print ( " Erase finished " )
# addr is relative to the base of FLASH (not absolute)
def flash_program ( self , addr , data , verify = True ) :
flash_region = int ( self . regions [ ' spiflash ' ] [ 0 ] , 0 )
flash_len = int ( self . regions [ ' spiflash ' ] [ 1 ] , 0 )
if ( addr + len ( data ) > flash_len ) :
print ( " Write data out of bounds! Aborting. " )
exit ( 1 )
# ID code check
code = self . flash_rdid ( 1 )
print ( " ID code bytes 1-2: 0x {:08x} " . format ( code ) )
if code != 0x8080c2c2 :
print ( " ID code mismatch " )
exit ( 1 )
code = self . flash_rdid ( 2 )
print ( " ID code bytes 2-3: 0x {:08x} " . format ( code ) )
if code != 0x3b3b8080 :
print ( " ID code mismatch " )
exit ( 1 )
# block erase
progress = ProgressBar ( min_value = 0 , max_value = len ( data ) , prefix = ' Erasing ' ) . start ( )
erased = 0
while erased < len ( data ) :
self . ping_wdt ( )
if ( len ( data ) - erased > = 65536 ) and ( ( addr & 0xFFFF ) == 0 ) :
blocksize = 65536
else :
blocksize = 4096
while True :
self . flash_wren ( )
status = self . flash_rdsr ( 1 )
if status & 0x02 != 0 :
break
if blocksize == 4096 :
self . flash_se4b ( addr + erased )
else :
self . flash_be4b ( addr + erased )
erased + = blocksize
while ( self . flash_rdsr ( 1 ) & 0x01 ) != 0 :
pass
result = self . flash_rdscur ( )
if result & 0x60 != 0 :
print ( " E_FAIL/P_FAIL set on erase, programming may fail, but trying anyways... " )
if self . flash_rdsr ( 1 ) & 0x02 != 0 :
self . flash_wrdi ( )
while ( self . flash_rdsr ( 1 ) & 0x02 ) != 0 :
pass
if erased < len ( data ) :
progress . update ( erased )
progress . finish ( )
print ( " Erase finished " )
# program
# pad out to the nearest word length
if len ( data ) % 4 != 0 :
data + = bytearray ( [ 0xff ] * ( 4 - ( len ( data ) % 4 ) ) )
written = 0
progress = ProgressBar ( min_value = 0 , max_value = len ( data ) , prefix = ' Writing ' ) . start ( )
while written < len ( data ) :
self . ping_wdt ( )
if len ( data ) - written > 256 :
chunklen = 256
else :
chunklen = len ( data ) - written
while True :
self . flash_wren ( )
status = self . flash_rdsr ( 1 )
if status & 0x02 != 0 :
break
self . burst_write ( self . register ( ' spinor_wdata ' ) , data [ written : ( written + chunklen ) ] )
self . flash_pp4b ( addr + written , chunklen )
written + = chunklen
if written < len ( data ) :
progress . update ( written )
progress . finish ( )
print ( " Write finished " )
if self . flash_rdsr ( 1 ) & 0x02 != 0 :
self . flash_wrdi ( )
while ( self . flash_rdsr ( 1 ) & 0x02 ) != 0 :
pass
# dummy reads to clear the "read lock" bit
self . flash_rdsr ( 0 )
# verify
self . ping_wdt ( )
if verify :
print ( " Performing readback for verification... " )
self . ping_wdt ( )
rbk_data = self . burst_read ( addr + flash_region , len ( data ) )
if rbk_data != data :
errs = 0
err_thresh = 64
for i in range ( 0 , len ( rbk_data ) ) :
if rbk_data [ i ] != data [ i ] :
if errs < err_thresh :
print ( " Error at 0x {:x} : {:x} -> {:x} " . format ( i , data [ i ] , rbk_data [ i ] ) )
errs + = 1
if errs == err_thresh :
print ( " Too many errors, stopping print... " )
print ( " Errors were found in verification, programming failed " )
print ( " Total byte errors: {} " . format ( errs ) )
exit ( 1 )
else :
print ( " Verification passed. " )
else :
print ( " Skipped verification at user request " )
self . ping_wdt ( )
def auto_int ( x ) :
return int ( x , 0 )
def main ( ) :
parser = argparse . ArgumentParser ( description = " Developer tool for loading local images to a Precursor. Use `precursorupdater` to fetch from a pre-built image. " )
parser . add_argument (
" --soc " , required = False , help = " ' Factory Reset ' the SoC gateware. Note: this will overwrite any secret keys stored in your device! " , type = str , nargs = ' ? ' , metavar = ( ' SoC gateware file ' ) , const = ' ../precursors/soc_csr.bin '
)
parser . add_argument (
" -s " , " --staging " , required = False , help = " Stage an update to apply " , type = str , nargs = ' ? ' , metavar = ( ' SoC gateware file ' ) , const = ' ../precursors/soc_csr.bin '
)
parser . add_argument (
" -l " , " --loader " , required = False , help = " Loader " , type = str , nargs = ' ? ' , metavar = ( ' loader file ' ) , const = ' ../target/riscv32imac-unknown-xous-elf/release/loader.bin '
)
parser . add_argument (
" --disable-boot " , required = False , action = ' store_true ' , help = " Disable system boot (for use in multi-stage updates) "
)
parser . add_argument (
" --enable-boot-wipe " , required = False , action = ' store_true ' , help = " Re-enable system boot for factory reset. Requires both a loader (-l) and a soc (--soc) spec. Overwrites root keys. "
)
parser . add_argument (
" --enable-boot-update " , required = False , action = ' store_true ' , help = " Re-enable system boot for updates. Requires both a loader (-l) and a staging (-s) spec. Stages SOC without overwriting root keys. "
)
parser . add_argument (
" -k " , " --kernel " , required = False , help = " Kernel " , type = str , nargs = ' ? ' , metavar = ( ' kernel file ' ) , const = ' ../target/riscv32imac-unknown-xous-elf/release/xous.img '
)
parser . add_argument (
" -e " , " --ec " , required = False , help = " EC gateware " , type = str , nargs = ' ? ' , metavar = ( ' EC gateware package ' ) , const = ' ec_fw.bin '
)
parser . add_argument (
" -w " , " --wf200 " , required = False , help = " WF200 firmware " , type = str , nargs = ' ? ' , metavar = ( ' WF200 firmware package ' ) , const = ' wf200_fw.bin '
)
parser . add_argument (
" --erase-pddb " , help = " Erase the PDDB area " , action = " store_true "
)
parser . add_argument (
" --audiotest " , required = False , help = " Test audio clip (must be 8kHz WAV) " , type = str , nargs = ' ? ' , metavar = ( ' Test audio clip ' ) , const = " testaudio.wav "
)
parser . add_argument (
" --peek " , required = False , help = " Inspect an address " , type = auto_int , metavar = ( ' ADDR ' )
)
parser . add_argument (
" --poke " , required = False , help = " Write to an address " , type = auto_int , nargs = 2 , metavar = ( ' ADDR ' , ' DATA ' )
)
parser . add_argument (
" --check-poke " , required = False , action = ' store_true ' , help = " Read data before and after the poke "
)
parser . add_argument (
" --config " , required = False , help = " Print the descriptor " , action = ' store_true '
)
parser . add_argument (
" -i " , " --image " , required = False , help = " Manually specify an image and address. Offset is relative to bottom of flash. " , type = str , nargs = 2 , metavar = ( ' IMAGEFILE ' , ' ADDR ' )
)
parser . add_argument (
" --verify " , help = " Readback verification. May fail for large files due to WDT timeout. " , default = False , action = ' store_true '
)
parser . add_argument (
" --force " , help = " Ignore gitrev version on SoC and try to burn an image anyways " , action = " store_true "
)
parser . add_argument (
" --bounce " , help = " cycle the device through a reset " , action = " store_true "
)
parser . add_argument (
" --factory-new " , help = " reset the entire image to mimic exactly what comes out of the factory, including temp files for testing. Warning: this will take a long time. " , action = " store_true "
)
parser . add_argument (
" --override-csr " , required = False , help = " CSR file to use instead of CSR values stored with the image. Used to recover in case of partial update of soc_csr.bin " , type = str ,
)
2022-09-15 17:39:49 +00:00
parser . add_argument (
" --dump " , required = False , help = " Dump a region of memory. Takes a virtual memory map file as an argument. Looks for lines of format `V|P vaddr paddr` " , type = str ,
)
parser . add_argument (
" --dump-file " , required = False , help = " Name out output file for dump. Required if --dump is specified. " , type = str ,
)
2022-08-16 05:57:36 +00:00
args = parser . parse_args ( )
if not len ( sys . argv ) > 1 :
print ( " No arguments specified, doing nothing. Use --help for more information. " )
print ( " If you are looking to fetch pre-built images and burn them, this is the wrong tool: " )
print ( " Use `precursorupdater` instead (via `pip3 install precursorupdater`) " )
exit ( 1 )
dev = usb . core . find ( idProduct = 0x5bf0 , idVendor = 0x1209 )
if dev is None :
raise ValueError ( ' Precursor device not found ' )
dev . set_configuration ( )
if args . config :
cfg = dev . get_active_configuration ( )
print ( cfg )
pc_usb = PrecursorUsb ( dev )
if args . verify :
verify = True
else :
verify = False
if args . peek :
pc_usb . peek ( args . peek , display = True )
# print(burst_read(dev, args.peek, 256).hex())
exit ( 0 )
if args . poke :
addr , data = args . poke
pc_usb . poke ( addr , data , check = args . check_poke , display = True )
# import os
# d = bytearray(os.urandom(8000))
# burst_write(dev, addr, d)
# r = burst_read(dev, addr, 8000)
# print(r.hex())
# if d != r:
# print("mismatch")
# else:
# print("match")
exit ( 0 )
pc_usb . load_csrs ( args . override_csr ) # prime the CSR values
if " v0.8 " in pc_usb . gitrev :
locs = {
" LOC_SOC " : [ 0x0000_0000 , " soc_csr.bin " ] ,
" LOC_STAGING " : [ 0x0028_0000 , " pass " ] ,
" LOC_LOADER " : [ 0x0050_0000 , " loader.bin " ] ,
" LOC_KERNEL " : [ 0x0098_0000 , " xous.img " ] ,
" LOC_WF200 " : [ 0x07F8_0000 , " pass " ] ,
" LOC_EC " : [ 0x07FC_E000 , " pass " ] ,
" LOC_AUDIO " : [ 0x0634_0000 , " short_8khz.wav " ] ,
" LEN_AUDIO " : [ 0x01C4_0000 , " pass " ] ,
" LOC_PDDB " : [ 0x0100_0000 , " pass " ] ,
}
elif " v0.9 " in pc_usb . gitrev :
locs = {
" LOC_SOC " : [ 0x0000_0000 , " soc_csr.bin " ] ,
" LOC_STAGING " : [ 0x0028_0000 , " pass " ] ,
" LOC_LOADER " : [ 0x0050_0000 , " loader.bin " ] ,
" LOC_KERNEL " : [ 0x0098_0000 , " xous.img " ] ,
" LOC_WF200 " : [ 0x07F8_0000 , " pass " ] ,
" LOC_EC " : [ 0x07FC_E000 , " pass " ] ,
" LOC_AUDIO " : [ 0x0634_0000 , " short_8khz.wav " ] ,
" LEN_AUDIO " : [ 0x01C4_0000 , " pass " ] ,
" LOC_PDDB " : [ 0x01D8_0000 , " pass " ] ,
}
elif args . force == True :
# try the v0.9 offsets
locs = {
" LOC_SOC " : [ 0x00000000 , " soc_csr.bin " ] ,
" LOC_STAGING " : [ 0x00280000 , " pass " ] ,
" LOC_LOADER " : [ 0x00500000 , " loader.bin " ] ,
" LOC_KERNEL " : [ 0x00980000 , " xous.img " ] ,
" LOC_WF200 " : [ 0x07F80000 , " pass " ] ,
" LOC_EC " : [ 0x07FCE000 , " pass " ] ,
" LOC_AUDIO " : [ 0x06340000 , " short_8khz.wav " ] ,
" LEN_AUDIO " : [ 0x01C40000 , " pass " ] ,
" LOC_PDDB " : [ 0x01D80000 , " pass " ] ,
}
else :
print ( " SoC is from an unknow rev ' {} ' , use --force to continue anyways with v0.9 firmware offsets " . format ( pc_usb . load_csrs ( ) ) )
exit ( 1 )
vexdbg_addr = int ( pc_usb . regions [ ' vexriscv_debug ' ] [ 0 ] , 0 )
pc_usb . ping_wdt ( )
2022-09-15 17:39:49 +00:00
if args . dump :
table = [ ]
with open ( args . dump , ' r ' ) as map :
for line in map . readlines ( ) :
rgx = re . search ( ' .*V \ |P \ s([0-9a-fA-F]*) \ s([0-9a-fA-F]*).* ' , line )
if rgx is not None :
map = rgx . groups ( )
table + = [ int ( map [ 1 ] , 16 ) ]
if args . dump_file is None :
print ( " Must specify --dump-file when using --dump " )
exit ( 0 )
with open ( args . dump_file , ' wb ' ) as f :
for page in table :
pc_usb . poke ( vexdbg_addr , 0x00020000 )
data = pc_usb . burst_read ( page , 4096 )
pc_usb . poke ( vexdbg_addr , 0x02000000 )
f . write ( data )
exit ( 0 )
2022-08-16 05:57:36 +00:00
print ( " Halting CPU. " )
pc_usb . poke ( vexdbg_addr , 0x00020000 )
if args . erase_pddb :
print ( " Erasing PDDB region " )
pc_usb . erase_region ( locs [ ' LOC_PDDB ' ] [ 0 ] , locs [ ' LOC_EC ' ] [ 0 ] - locs [ ' LOC_PDDB ' ] [ 0 ] )
if args . disable_boot :
print ( " Disabling boot " )
pc_usb . erase_region ( locs [ ' LOC_LOADER ' ] [ 0 ] , 1024 * 256 )
if args . enable_boot_wipe :
if args . loader == None :
print ( " Must provide both a loader and soc image " )
if args . soc == None :
print ( " Must provide both a soc and loader image " )
print ( " Enabling boot with {} and {} " . format ( args . loader , args . soc ) )
print ( " Programming loader image {} " . format ( args . loader ) )
with open ( args . loader , " rb " ) as f :
image = f . read ( )
pc_usb . flash_program ( locs [ ' LOC_LOADER ' ] [ 0 ] , image , verify = verify )
print ( " Programming SoC gateware " . format ( args . soc ) )
with open ( args . soc , " rb " ) as f :
image = f . read ( )
if verify == True :
print ( " Note: SoC verification is not possible as readback is locked for security purposes " )
pc_usb . flash_program ( locs [ ' LOC_SOC ' ] [ 0 ] , image , verify = False )
print ( " Erasing PDDB root structures " )
pc_usb . erase_region ( locs [ ' LOC_PDDB ' ] [ 0 ] , 1024 * 1024 )
print ( " Resuming CPU. " )
pc_usb . poke ( vexdbg_addr , 0x02000000 )
print ( " Resetting SOC... " )
try :
pc_usb . poke ( pc_usb . register ( ' reboot_soc_reset ' ) , 0xac , display = False )
except usb . core . USBError :
pass # we expect an error because we reset the SOC and that includes the USB core
exit ( 0 )
if args . enable_boot_update :
if args . loader == None :
print ( " Must provide both a loader and soc image " )
if args . staging == None :
print ( " Must provide both a soc and loader image " )
print ( " Enabling boot with {} and {} " . format ( args . loader , args . staging ) )
print ( " Programming loader image {} " . format ( args . loader ) )
with open ( args . loader , " rb " ) as f :
image = f . read ( )
pc_usb . flash_program ( locs [ ' LOC_LOADER ' ] [ 0 ] , image , verify = verify )
print ( " Staging SoC gateware " . format ( args . staging ) )
with open ( args . staging , " rb " ) as f :
image = f . read ( )
if verify == True :
print ( " Note: staging area verification is not possible as readback is locked for security purposes " )
pc_usb . flash_program ( locs [ ' LOC_STAGING ' ] [ 0 ] , image , verify = verify )
print ( " Resuming CPU. " )
pc_usb . poke ( vexdbg_addr , 0x02000000 )
print ( " Resetting SOC... " )
try :
pc_usb . poke ( pc_usb . register ( ' reboot_soc_reset ' ) , 0xac , display = False )
except usb . core . USBError :
pass # we expect an error because we reset the SOC and that includes the USB core
exit ( 0 )
if args . image :
image_file , addr_str = args . image
addr = int ( addr_str , 0 )
print ( " Burning manually specified image ' {} ' to address 0x {:08x} relative to bottom of FLASH " . format ( image_file , addr ) )
with open ( image_file , " rb " ) as f :
image_data = f . read ( )
pc_usb . flash_program ( addr , image_data , verify = verify )
if args . ec != None :
print ( " Staging EC firmware package ' {} ' in SOC memory space... " . format ( args . ec ) )
with open ( args . ec , " rb " ) as f :
image = f . read ( )
pc_usb . flash_program ( locs [ ' LOC_EC ' ] [ 0 ] , image , verify = verify )
if args . wf200 != None :
print ( " Staging WF200 firmware package ' {} ' in SOC memory space... " . format ( args . wf200 ) )
with open ( args . wf200 , " rb " ) as f :
image = f . read ( )
pc_usb . flash_program ( locs [ ' LOC_WF200 ' ] [ 0 ] , image , verify = verify )
if args . staging != None :
print ( " Staging SoC gateware {} " . format ( args . soc ) )
with open ( args . staging , " rb " ) as f :
image = f . read ( )
if verify == True :
print ( " Note: staging area verification is not possible as readback is locked for security purposes " )
pc_usb . flash_program ( locs [ ' LOC_STAGING ' ] [ 0 ] , image , verify = verify )
if args . kernel != None :
print ( " Programming kernel image {} " . format ( args . kernel ) )
with open ( args . kernel , " rb " ) as f :
image = f . read ( )
pc_usb . flash_program ( locs [ ' LOC_KERNEL ' ] [ 0 ] , image , verify = verify )
if args . loader != None :
print ( " Programming loader image {} " . format ( args . loader ) )
with open ( args . loader , " rb " ) as f :
image = f . read ( )
pc_usb . flash_program ( locs [ ' LOC_LOADER ' ] [ 0 ] , image , verify = verify )
if args . soc != None :
if args . force == True :
print ( " Programming SoC gateware {} " . format ( args . soc ) )
with open ( args . soc , " rb " ) as f :
image = f . read ( )
if verify == True :
print ( " Note: SoC verification is not possible as readback is locked for security purposes " )
pc_usb . flash_program ( locs [ ' LOC_SOC ' ] [ 0 ] , image , verify = False )
print ( " Erasing PDDB root structures " )
pc_usb . erase_region ( locs [ ' LOC_PDDB ' ] [ 0 ] , 1024 * 1024 )
else :
print ( " This will overwrite any secret keys in your device and erase PDDB keys. Continue? (y/n) " )
confirm = input ( )
if len ( confirm ) > 0 and confirm . lower ( ) [ : 1 ] == ' y ' :
print ( " Programming SoC gateware {} " . format ( args . soc ) )
with open ( args . soc , " rb " ) as f :
image = f . read ( )
if verify == True :
print ( " Note: SoC verification is not possible as readback is locked for security purposes " )
pc_usb . flash_program ( locs [ ' LOC_SOC ' ] [ 0 ] , image , verify = False )
print ( " Erasing PDDB root structures " )
pc_usb . erase_region ( locs [ ' LOC_PDDB ' ] [ 0 ] , 1024 * 1024 )
if args . audiotest != None :
print ( " Loading audio test clip {} " . format ( args . audiotest ) )
with open ( args . audiotest , " rb " ) as f :
image = f . read ( )
if len ( image ) > = locs [ ' LEN_AUDIO ' ] [ 0 ] :
print ( " audio file is too long, aborting audio burn! " )
else :
pc_usb . flash_program ( locs [ ' LOC_AUDIO ' ] [ 0 ] , image , verify = verify )
if args . factory_new :
base_url = " https://ci.betrusted.io/releases/v0.9.5/ "
# erase the entire flash
pc_usb . erase_region ( 0 , 0x800_0000 )
# burn the gateware
for sections in locs . values ( ) :
if sections [ 1 ] != ' pass ' :
print ( ' retrieving {} ' . format ( base_url + sections [ 1 ] ) )
with urllib . request . urlopen ( base_url + sections [ 1 ] ) as f :
print ( ' burning at {:x} ' . format ( sections [ 0 ] ) )
image = f . read ( )
pc_usb . flash_program ( sections [ 0 ] , image , verify = False )
print ( " Resuming CPU. " )
pc_usb . poke ( vexdbg_addr , 0x02000000 )
print ( " Resetting SOC... " )
try :
pc_usb . poke ( pc_usb . register ( ' reboot_soc_reset ' ) , 0xac , display = False )
except usb . core . USBError :
pass # we expect an error because we reset the SOC and that includes the USB core
# print("If you need to run more commands, please unplug and re-plug your device in, as the Precursor USB core was just reset")
if __name__ == " __main__ " :
main ( )
exit ( 0 )