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}  )
133+         offset  =  getattr (header , f'code{ code :x}  )
134+         size  =  getattr (header , f'code{ code :x}  )
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