33that typically initializes DRAM, followed by optionally loading a secondary
44image to start of DRAM, when a Rockchip device is in MASKROM mode.
55"""
6+ from collections import namedtuple
7+ from struct import unpack
68from time import sleep
79
810import usb .core
5254]
5355
5456
57+ # polynomial: 0x04c10db7
58+ CRC32_TABLE = [
59+ 0x00000000 , 0x04c10db7 , 0x09821b6e , 0x0d4316d9 , 0x130436dc , 0x17c53b6b , 0x1a862db2 , 0x1e472005 ,
60+ 0x26086db8 , 0x22c9600f , 0x2f8a76d6 , 0x2b4b7b61 , 0x350c5b64 , 0x31cd56d3 , 0x3c8e400a , 0x384f4dbd ,
61+ 0x4c10db70 , 0x48d1d6c7 , 0x4592c01e , 0x4153cda9 , 0x5f14edac , 0x5bd5e01b , 0x5696f6c2 , 0x5257fb75 ,
62+ 0x6a18b6c8 , 0x6ed9bb7f , 0x639aada6 , 0x675ba011 , 0x791c8014 , 0x7ddd8da3 , 0x709e9b7a , 0x745f96cd ,
63+ 0x9821b6e0 , 0x9ce0bb57 , 0x91a3ad8e , 0x9562a039 , 0x8b25803c , 0x8fe48d8b , 0x82a79b52 , 0x866696e5 ,
64+ 0xbe29db58 , 0xbae8d6ef , 0xb7abc036 , 0xb36acd81 , 0xad2ded84 , 0xa9ece033 , 0xa4aff6ea , 0xa06efb5d ,
65+ 0xd4316d90 , 0xd0f06027 , 0xddb376fe , 0xd9727b49 , 0xc7355b4c , 0xc3f456fb , 0xceb74022 , 0xca764d95 ,
66+ 0xf2390028 , 0xf6f80d9f , 0xfbbb1b46 , 0xff7a16f1 , 0xe13d36f4 , 0xe5fc3b43 , 0xe8bf2d9a , 0xec7e202d ,
67+ 0x34826077 , 0x30436dc0 , 0x3d007b19 , 0x39c176ae , 0x278656ab , 0x23475b1c , 0x2e044dc5 , 0x2ac54072 ,
68+ 0x128a0dcf , 0x164b0078 , 0x1b0816a1 , 0x1fc91b16 , 0x018e3b13 , 0x054f36a4 , 0x080c207d , 0x0ccd2dca ,
69+ 0x7892bb07 , 0x7c53b6b0 , 0x7110a069 , 0x75d1adde , 0x6b968ddb , 0x6f57806c , 0x621496b5 , 0x66d59b02 ,
70+ 0x5e9ad6bf , 0x5a5bdb08 , 0x5718cdd1 , 0x53d9c066 , 0x4d9ee063 , 0x495fedd4 , 0x441cfb0d , 0x40ddf6ba ,
71+ 0xaca3d697 , 0xa862db20 , 0xa521cdf9 , 0xa1e0c04e , 0xbfa7e04b , 0xbb66edfc , 0xb625fb25 , 0xb2e4f692 ,
72+ 0x8aabbb2f , 0x8e6ab698 , 0x8329a041 , 0x87e8adf6 , 0x99af8df3 , 0x9d6e8044 , 0x902d969d , 0x94ec9b2a ,
73+ 0xe0b30de7 , 0xe4720050 , 0xe9311689 , 0xedf01b3e , 0xf3b73b3b , 0xf776368c , 0xfa352055 , 0xfef42de2 ,
74+ 0xc6bb605f , 0xc27a6de8 , 0xcf397b31 , 0xcbf87686 , 0xd5bf5683 , 0xd17e5b34 , 0xdc3d4ded , 0xd8fc405a ,
75+ 0x6904c0ee , 0x6dc5cd59 , 0x6086db80 , 0x6447d637 , 0x7a00f632 , 0x7ec1fb85 , 0x7382ed5c , 0x7743e0eb ,
76+ 0x4f0cad56 , 0x4bcda0e1 , 0x468eb638 , 0x424fbb8f , 0x5c089b8a , 0x58c9963d , 0x558a80e4 , 0x514b8d53 ,
77+ 0x25141b9e , 0x21d51629 , 0x2c9600f0 , 0x28570d47 , 0x36102d42 , 0x32d120f5 , 0x3f92362c , 0x3b533b9b ,
78+ 0x031c7626 , 0x07dd7b91 , 0x0a9e6d48 , 0x0e5f60ff , 0x101840fa , 0x14d94d4d , 0x199a5b94 , 0x1d5b5623 ,
79+ 0xf125760e , 0xf5e47bb9 , 0xf8a76d60 , 0xfc6660d7 , 0xe22140d2 , 0xe6e04d65 , 0xeba35bbc , 0xef62560b ,
80+ 0xd72d1bb6 , 0xd3ec1601 , 0xdeaf00d8 , 0xda6e0d6f , 0xc4292d6a , 0xc0e820dd , 0xcdab3604 , 0xc96a3bb3 ,
81+ 0xbd35ad7e , 0xb9f4a0c9 , 0xb4b7b610 , 0xb076bba7 , 0xae319ba2 , 0xaaf09615 , 0xa7b380cc , 0xa3728d7b ,
82+ 0x9b3dc0c6 , 0x9ffccd71 , 0x92bfdba8 , 0x967ed61f , 0x8839f61a , 0x8cf8fbad , 0x81bbed74 , 0x857ae0c3 ,
83+ 0x5d86a099 , 0x5947ad2e , 0x5404bbf7 , 0x50c5b640 , 0x4e829645 , 0x4a439bf2 , 0x47008d2b , 0x43c1809c ,
84+ 0x7b8ecd21 , 0x7f4fc096 , 0x720cd64f , 0x76cddbf8 , 0x688afbfd , 0x6c4bf64a , 0x6108e093 , 0x65c9ed24 ,
85+ 0x11967be9 , 0x1557765e , 0x18146087 , 0x1cd56d30 , 0x02924d35 , 0x06534082 , 0x0b10565b , 0x0fd15bec ,
86+ 0x379e1651 , 0x335f1be6 , 0x3e1c0d3f , 0x3add0088 , 0x249a208d , 0x205b2d3a , 0x2d183be3 , 0x29d93654 ,
87+ 0xc5a71679 , 0xc1661bce , 0xcc250d17 , 0xc8e400a0 , 0xd6a320a5 , 0xd2622d12 , 0xdf213bcb , 0xdbe0367c ,
88+ 0xe3af7bc1 , 0xe76e7676 , 0xea2d60af , 0xeeec6d18 , 0xf0ab4d1d , 0xf46a40aa , 0xf9295673 , 0xfde85bc4 ,
89+ 0x89b7cd09 , 0x8d76c0be , 0x8035d667 , 0x84f4dbd0 , 0x9ab3fbd5 , 0x9e72f662 , 0x9331e0bb , 0x97f0ed0c ,
90+ 0xafbfa0b1 , 0xab7ead06 , 0xa63dbbdf , 0xa2fcb668 , 0xbcbb966d , 0xb87a9bda , 0xb5398d03 , 0xb1f880b4 ,
91+ ]
92+
93+
5594def crc16_ccitt_false (data , crc = 0xffff ):
5695 for byte in data :
5796 crc = ((crc << 8 ) & 0xff00 ) ^ CRC16_TABLE [((crc >> 8 ) & 0xff ) ^ byte ]
5897 return crc & 0xffff
5998
6099
100+ def crc32_rkboot (data , crc = 0x0 ):
101+ for byte in data :
102+ crc = ((crc << 8 ) & 0xffffff00 ) ^ CRC32_TABLE [((crc >> 24 ) & 0xff ) ^ byte ]
103+ return crc & 0xffffffff
104+
105+
61106def rc4_ksa (key ):
62107 keylength = len (key )
63108 S = list (range (256 ))
@@ -79,6 +124,36 @@ def rc4_prga(S):
79124 yield K
80125
81126
127+ def get_rkboot_entries (data , header ):
128+ RKBootEntry = namedtuple ('RKBootEntry' , [
129+ 'size' , 'type' , 'dataOffset' , 'dataSize' , 'dataDelay' ,
130+ ])
131+ for code in (0x471 , 0x472 ):
132+ entries = getattr (header , f'code{ code :x} Num' )
133+ offset = getattr (header , f'code{ code :x} Offset' )
134+ size = getattr (header , f'code{ code :x} Size' )
135+ for _ in range (entries ):
136+ entry = RKBootEntry ._make (unpack ('<BL40xLLL' , data [offset :offset + size ]))
137+ entry_data = data [entry .dataOffset :entry .dataOffset + entry .dataSize ]
138+ yield code , entry_data , entry .dataDelay / 1000
139+ offset += size
140+
141+
142+ def parse_rkboot_header (data ):
143+ tag = int .from_bytes (data [:4 ], 'little' )
144+ RKBootHeader = namedtuple ('RKBootHeader' , [
145+ 'tag' , 'size' , 'version' , 'mergerVersion' ,
146+ 'code471Num' , 'code471Offset' , 'code471Size' ,
147+ 'code472Num' , 'code472Offset' , 'code472Size' ,
148+ ])
149+ if tag in (0x544f4f42 , 0x2052444c ) and \
150+ crc32_rkboot (data [:- 4 ]) == int .from_bytes (data [- 4 :], 'little' ):
151+ header = RKBootHeader ._make (unpack ('<LHLL11xBLBBLB65x' , data [:102 ]))
152+ if header .size == 102 and header .code471Num + header .code472Num > 0 :
153+ return header
154+ return None
155+
156+
82157class RKUSBMaskrom :
83158 def __init__ (self , ** args ):
84159 self ._dev = usb .core .find (** args )
@@ -99,15 +174,18 @@ def __exit__(self, exc_type, exc_value, traceback):
99174 usb .util .release_interface (self ._dev , 0 )
100175 usb .util .dispose_resources (self ._dev )
101176
102- def load (self , code , path ):
103- with open (path , 'rb' ) as f :
104- data = bytearray (f .read ())
177+ def load (self , code , bytesOrPath ):
178+ if isinstance (bytesOrPath , bytes ):
179+ data = bytearray (bytesOrPath )
180+ else :
181+ with open (bytesOrPath , 'rb' ) as f :
182+ data = bytearray (f .read ())
105183
106- # encrypt data using the known rockchip key for older devices
107- if self ._dev .idProduct < 0x3500 and \
108- self ._dev .idProduct not in (0x110c , 0x110e , 0x110f ):
109- keystream = rc4_prga (rc4_ksa (RK_RC4_KEY ))
110- data = bytearray ([byte ^ next (keystream ) for byte in data ])
184+ # encrypt data using the known rockchip key for older devices
185+ if self ._dev .idProduct < 0x3500 and \
186+ self ._dev .idProduct not in (0x110c , 0x110e , 0x110f ):
187+ keystream = rc4_prga (rc4_ksa (RK_RC4_KEY ))
188+ data = bytearray ([byte ^ next (keystream ) for byte in data ])
111189
112190 # ensure crc16 fit in the last chunk
113191 if len (data ) % 4096 == 4095 :
@@ -129,12 +207,25 @@ def load(self, code, path):
129207
130208
131209def handle_load (busnum , devnum , initial , secondary = None , delay = None ):
210+ with open (initial , 'rb' ) as f :
211+ data = f .read ()
212+ header = parse_rkboot_header (data )
213+ if header is None and secondary is not None :
214+ with open (secondary , 'rb' ) as f :
215+ data = f .read ()
216+ header = parse_rkboot_header (data )
132217 with RKUSBMaskrom (bus = busnum , address = devnum ) as maskrom :
133- maskrom .load (0x471 , initial )
134- if secondary is not None :
135- if delay :
136- sleep (delay )
137- maskrom .load (0x472 , secondary )
218+ if header is not None :
219+ for code , entry_data , entry_delay in get_rkboot_entries (data , header ):
220+ maskrom .load (code , entry_data )
221+ if entry_delay :
222+ sleep (entry_delay )
223+ else :
224+ maskrom .load (0x471 , initial )
225+ if secondary is not None :
226+ if delay :
227+ sleep (delay )
228+ maskrom .load (0x472 , secondary )
138229
139230
140231methods = {
0 commit comments