3
3
that typically initializes DRAM, followed by optionally loading a secondary
4
4
image to start of DRAM, when a Rockchip device is in MASKROM mode.
5
5
"""
6
+ from collections import namedtuple
7
+ from struct import unpack
6
8
from time import sleep
7
9
8
10
import usb .core
52
54
]
53
55
54
56
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
+
55
94
def crc16_ccitt_false (data , crc = 0xffff ):
56
95
for byte in data :
57
96
crc = ((crc << 8 ) & 0xff00 ) ^ CRC16_TABLE [((crc >> 8 ) & 0xff ) ^ byte ]
58
97
return crc & 0xffff
59
98
60
99
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
+
61
106
def rc4_ksa (key ):
62
107
keylength = len (key )
63
108
S = list (range (256 ))
@@ -79,6 +124,37 @@ def rc4_prga(S):
79
124
yield K
80
125
81
126
127
+ def prase_rkboot_header (data ):
128
+ RKBootHeader = namedtuple ('RKBootHeader' , [
129
+ 'tag' , 'size' , 'version' , 'mergerVersion' ,
130
+ 'code471Num' , 'code471Offset' , 'code471Size' ,
131
+ 'code472Num' , 'code472Offset' , 'code472Size' ,
132
+ ])
133
+ tag = int .from_bytes (data [0 :4 ], 'little' )
134
+ if tag in (0x544f4f42 , 0x2052444c ) and \
135
+ crc32_rkboot (data [0 :- 4 ]) == int .from_bytes (data [- 4 :], 'little' ):
136
+ header = RKBootHeader ._make (unpack ('<LHLL11xBLBBLB65x' , data [0 :102 ]))
137
+ if header .code471Num + header .code472Num > 0 :
138
+ return header
139
+ return None
140
+
141
+
142
+ def get_rkboot_entries (data , header ):
143
+ RKBootEntry = namedtuple ('RKBootEntry' , [
144
+ 'size' , 'type' , 'dataOffset' , 'dataSize' , 'dataDelay' ,
145
+ ])
146
+ for code in (0x471 , 0x472 ):
147
+ entries = getattr (header , f'code{ code :x} Num' )
148
+ offset = getattr (header , f'code{ code :x} Offset' )
149
+ size = getattr (header , f'code{ code :x} Size' )
150
+ for _ in range (entries ):
151
+ header_data = data [offset :offset + size ]
152
+ entry = RKBootEntry ._make (unpack ('<BL40xLLL' , header_data ))
153
+ entry_data = data [entry .dataOffset :entry .dataOffset + entry .dataSize ]
154
+ yield code , entry_data , entry .dataDelay / 1000
155
+ offset += size
156
+
157
+
82
158
class RKUSBMaskrom :
83
159
def __init__ (self , ** args ):
84
160
self ._dev = usb .core .find (** args )
@@ -99,14 +175,17 @@ def __exit__(self, exc_type, exc_value, traceback):
99
175
usb .util .release_interface (self ._dev , 0 )
100
176
usb .util .dispose_resources (self ._dev )
101
177
102
- def load (self , code , path ):
103
- with open (path , 'rb' ) as fh :
104
- data = bytearray (fh .read ())
178
+ def load (self , code , bytesOrPath ):
179
+ if isinstance (bytesOrPath , bytes ):
180
+ data = bytearray (bytesOrPath )
181
+ else :
182
+ with open (bytesOrPath , 'rb' ) as fh :
183
+ data = bytearray (fh .read ())
105
184
106
- # encrypt data using the known rockchip key for older devices
107
- if self ._dev .idProduct < 0x3500 :
108
- keystream = rc4_prga (rc4_ksa (RK_RC4_KEY ))
109
- data = bytearray ([byte ^ next (keystream ) for byte in data ])
185
+ # encrypt data using the known rockchip key for older devices
186
+ if self ._dev .idProduct < 0x3500 :
187
+ keystream = rc4_prga (rc4_ksa (RK_RC4_KEY ))
188
+ data = bytearray ([byte ^ next (keystream ) for byte in data ])
110
189
111
190
# ensure crc16 fit in the last chunk
112
191
if len (data ) % 4096 == 4095 :
@@ -128,12 +207,25 @@ def load(self, code, path):
128
207
129
208
130
209
def handle_load (busnum , devnum , initial , secondary = None , delay = None ):
210
+ with open (initial , 'rb' ) as fh :
211
+ data = fh .read ()
212
+ header = prase_rkboot_header (data )
213
+ if header is None and secondary is not None :
214
+ with open (secondary , 'rb' ) as fh :
215
+ data = fh .read ()
216
+ header = prase_rkboot_header (data )
131
217
with RKUSBMaskrom (bus = busnum , address = devnum ) as maskrom :
132
- maskrom .load (0x471 , initial )
133
- if secondary is not None :
134
- if delay :
135
- sleep (delay )
136
- 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 )
137
229
138
230
139
231
methods = {
0 commit comments