1
+ use std:: { mem, str} ;
2
+ use std:: fs:: { create_dir_all, File } ;
3
+ use std:: io:: { Read , Seek , Write } ;
4
+ use std:: path:: Path ;
5
+ use std:: ffi:: CStr ;
6
+ use anyhow:: { anyhow, Result } ;
7
+
8
+ pub const RKAFP_MAGIC : & str = "RKAF" ;
9
+ pub const PARM_MAGIC : & str = "PARM" ;
10
+ pub const MAX_PARTS : usize = 16 ;
11
+ pub const MAX_NAME_LEN : usize = 32 ;
12
+ const MAX_FULL_PATH_LEN : usize = 60 ;
13
+ const MAX_MODEL_LEN : usize = 34 ;
14
+ const MAX_ID_LEN : usize = 30 ;
15
+ const MAX_MANUFACTURER_LEN : usize = 56 ;
16
+ pub const RKAF_SIGNATURE : & [ u8 ] = b"RKAF" ;
17
+ pub const RKFW_SIGNATURE : & [ u8 ] = b"RKFW" ;
18
+ pub const RKFP_SIGNATURE : & [ u8 ] = b"RKFP" ;
19
+
20
+ #[ derive( Copy , Clone , Debug ) ]
21
+ #[ repr( C , packed) ]
22
+ pub struct UpdatePart {
23
+ name : [ u8 ; MAX_NAME_LEN ] ,
24
+ pub full_path : [ u8 ; MAX_FULL_PATH_LEN ] ,
25
+ flash_size : u32 ,
26
+ pub part_offset : u32 ,
27
+ flash_offset : u32 ,
28
+ padded_size : u32 ,
29
+ pub part_byte_count : u32 ,
30
+ }
31
+
32
+ #[ derive( Copy , Clone , Debug ) ]
33
+ #[ repr( C , packed) ]
34
+ pub struct UpdateHeader {
35
+ pub magic : [ u8 ; 4 ] ,
36
+ pub length : u32 ,
37
+ pub model : [ u8 ; MAX_MODEL_LEN ] ,
38
+ id : [ u8 ; MAX_ID_LEN ] ,
39
+ pub manufacturer : [ u8 ; MAX_MANUFACTURER_LEN ] ,
40
+ unknown1 : u32 ,
41
+ version : u32 ,
42
+ pub num_parts : u32 ,
43
+ pub parts : [ UpdatePart ; MAX_PARTS ] ,
44
+ reserved : [ u8 ; 116 ] ,
45
+ }
46
+
47
+ #[ derive( Copy , Clone , Debug ) ]
48
+ #[ repr( C , packed) ]
49
+ pub struct ParamHeader {
50
+ magic : [ u8 ; 4 ] ,
51
+ length : u32 ,
52
+ }
53
+
54
+
55
+ impl UpdateHeader {
56
+ pub fn default ( ) -> Self {
57
+ Self {
58
+ magic : [ 0u8 ; 4 ] ,
59
+ length : 0 ,
60
+ model : [ 0u8 ; MAX_MODEL_LEN ] ,
61
+ id : [ 0u8 ; MAX_ID_LEN ] ,
62
+ manufacturer : [ 0u8 ; MAX_MANUFACTURER_LEN ] ,
63
+ unknown1 : 0 ,
64
+ version : 0 ,
65
+ num_parts : 0 ,
66
+ parts : [ UpdatePart :: default ( ) ; MAX_PARTS ] ,
67
+ reserved : [ 0u8 ; 116 ] ,
68
+
69
+ }
70
+ }
71
+ pub fn from_bytes ( bytes : & [ u8 ] ) -> & UpdateHeader {
72
+ unsafe { mem:: transmute ( bytes. as_ptr ( ) ) }
73
+ }
74
+
75
+ pub fn to_bytes ( & self ) -> & [ u8 ] {
76
+ unsafe { std:: slice:: from_raw_parts ( self as * const _ as * const u8 , mem:: size_of :: < UpdatePart > ( ) ) }
77
+ }
78
+ }
79
+
80
+ impl UpdatePart {
81
+ pub fn default ( ) -> Self {
82
+ Self {
83
+ name : [ 0u8 ; MAX_NAME_LEN ] ,
84
+ full_path : [ 0u8 ; MAX_FULL_PATH_LEN ] ,
85
+ flash_size : 0 ,
86
+ part_offset : 0 ,
87
+ flash_offset : 0 ,
88
+ padded_size : 0 ,
89
+ part_byte_count : 0 ,
90
+ }
91
+ }
92
+ }
93
+
94
+ pub fn unpack_file ( file_path : & str , dst_path : & str ) -> Result < ( ) > {
95
+ let mut file = File :: open ( file_path) ?;
96
+ let mut buffer = Vec :: new ( ) ;
97
+ file. read_to_end ( & mut buffer) ?;
98
+
99
+ let signature = & buffer[ 0 ..4 ] ;
100
+ match signature {
101
+ RKAF_SIGNATURE => unpack_rkafp ( file_path, dst_path) ?,
102
+ RKFW_SIGNATURE => unpack_rkfw ( & buffer, dst_path) ?,
103
+ _ => {
104
+ return Err ( anyhow ! ( "Unknown signature: {:?}" , signature) ) ;
105
+ }
106
+ }
107
+ Ok ( ( ) )
108
+ }
109
+
110
+ fn unpack_rkfw ( buf : & [ u8 ] , dst_path : & str ) -> Result < ( ) > {
111
+ let mut chip: Option < & str > = None ;
112
+
113
+ println ! ( "RKFW signature detected" ) ;
114
+ println ! (
115
+ "version: {}.{}.{}" ,
116
+ buf[ 9 ] ,
117
+ buf[ 8 ] ,
118
+ ( buf[ 7 ] as u16 ) << 8 + buf[ 6 ] as u16
119
+ ) ;
120
+ println ! (
121
+ "date: {}-{:02}-{:02} {:02}:{:02}:{:02}" ,
122
+ ( buf[ 0x0f ] as u16 ) << 8 + buf[ 0x0e ] as u16 ,
123
+ buf[ 0x10 ] ,
124
+ buf[ 0x11 ] ,
125
+ buf[ 0x12 ] ,
126
+ buf[ 0x13 ] ,
127
+ buf[ 0x14 ]
128
+ ) ;
129
+
130
+ match buf[ 0x15 ] {
131
+ 0x50 => chip = Some ( "rk29xx" ) ,
132
+ 0x60 => chip = Some ( "rk30xx" ) ,
133
+ 0x70 => chip = Some ( "rk31xx" ) ,
134
+ 0x80 => chip = Some ( "rk32xx" ) ,
135
+ 0x41 => chip = Some ( "rk3368" ) ,
136
+ 0x36 => chip = Some ( "RK3326" ) ,
137
+ 0x38 => chip = Some ( "RK3566" ) ,
138
+ 0x30 => chip = Some ( "PX30" ) ,
139
+ _ => println ! (
140
+ "You got a brand new chip ({:#x}), congratulations!!!" ,
141
+ buf[ 0x15 ]
142
+ ) ,
143
+ }
144
+
145
+ println ! ( "family: {}" , chip. unwrap_or( "unknown" ) ) ;
146
+
147
+ let ioff = get_u32_le ( & buf[ 0x19 ..] ) ;
148
+ let isize: u32 = get_u32_le ( & buf[ 0x1d ..] ) ;
149
+
150
+ if & buf[ ioff as usize ..ioff as usize + 4 ] != b"BOOT" {
151
+ panic ! ( "cannot find BOOT signature" ) ;
152
+ }
153
+
154
+ println ! (
155
+ "{:08x}-{:08x} {:26} (size: {})" ,
156
+ ioff,
157
+ ioff + isize - 1 ,
158
+ "BOOT" ,
159
+ isize
160
+ ) ;
161
+ create_dir_all ( dst_path) ?;
162
+ write_file (
163
+ & Path :: new ( format ! ( "{}/BOOT" , dst_path) . as_mut ( ) ) ,
164
+ & buf[ ioff as usize ..ioff as usize + ( isize as usize ) ] ,
165
+ ) ?;
166
+
167
+ let ioff = get_u32_le ( & buf[ 0x21 ..] ) ;
168
+ let isize = get_u32_le ( & buf[ 0x25 ..] ) ;
169
+
170
+ if & buf[ ioff as usize ..ioff as usize + 4 ] != b"RKAF" {
171
+ panic ! ( "cannot find embedded RKAF update.img" ) ;
172
+ }
173
+
174
+ println ! (
175
+ "{:08x}-{:08x} {:26} (size: {})" ,
176
+ ioff,
177
+ ioff + isize - 1 ,
178
+ "embedded-update.img" ,
179
+ isize
180
+ ) ;
181
+ write_file (
182
+ & Path :: new ( format ! ( "{}/embedded-update.img" , dst_path) . as_mut ( ) ) ,
183
+ & buf[ ioff as usize ..ioff as usize + isize as usize ] ,
184
+ ) ?;
185
+ Ok ( ( ) )
186
+ }
187
+
188
+ pub unsafe fn any_as_u8_slice < T : Sized > ( p : & T ) -> & [ u8 ] {
189
+ core:: slice:: from_raw_parts (
190
+ ( p as * const T ) as * const u8 ,
191
+ mem:: size_of :: < T > ( ) ,
192
+ )
193
+ }
194
+
195
+ pub fn info_and_fatal ( is_fatal : bool , message : String ) {
196
+ if is_fatal {
197
+ eprint ! ( "rkunpack: fatal: " ) ;
198
+ } else {
199
+ eprint ! ( "rkunpack: info: " ) ;
200
+ }
201
+ eprintln ! ( "{}" , message) ;
202
+ if is_fatal {
203
+ std:: process:: exit ( 1 ) ;
204
+ }
205
+ }
206
+ #[ macro_export]
207
+ macro_rules! info {
208
+ ( $message: expr) => {
209
+ info_and_fatal( false , $message) ;
210
+ } ;
211
+ }
212
+
213
+ #[ macro_export]
214
+ macro_rules! fatal {
215
+ ( $message: expr) => {
216
+ info_and_fatal( true , $message) ;
217
+ } ;
218
+ }
219
+ fn extract_file ( fp : & mut File , offset : u64 , len : u64 , full_path : & str ) -> Result < ( ) > {
220
+ println ! ( "{:08x}-{:08x} {}" , offset, len, full_path) ;
221
+ let mut buffer = vec ! [ 0u8 ; 16 * 1024 ] ;
222
+ let mut fp_out = File :: create ( full_path) ?;
223
+
224
+ fp. seek ( std:: io:: SeekFrom :: Start ( offset) ) ?;
225
+
226
+ let mut remaining = len;
227
+
228
+ while remaining > 0 {
229
+ let read_len = std:: cmp:: min ( remaining as usize , buffer. len ( ) ) ;
230
+ let read_bytes = fp. read ( & mut buffer[ ..read_len] ) ?;
231
+
232
+ if read_bytes != read_len {
233
+ return Err ( anyhow ! ( "Insufficient length in container image file" ) ) ;
234
+ }
235
+
236
+ fp_out. write_all ( & buffer[ ..read_len] ) ?;
237
+
238
+ remaining -= read_len as u64 ;
239
+ }
240
+
241
+ Ok ( ( ) )
242
+ }
243
+
244
+ fn unpack_rkafp ( file_path : & str , dst_path : & str ) -> Result < ( ) > {
245
+ let mut fp = File :: open ( file_path) ?;
246
+ let mut buf = vec ! [ 0u8 ; mem:: size_of:: <UpdateHeader >( ) ] ;
247
+ fp. read_exact ( & mut buf) ?;
248
+ let header = UpdateHeader :: from_bytes ( buf. as_mut ( ) ) ;
249
+ let magic_str = str:: from_utf8 ( & header. magic ) ?;
250
+ if magic_str != RKAFP_MAGIC {
251
+ return Err ( anyhow ! ( "Invalid header magic id" ) ) ;
252
+ }
253
+
254
+ let filesize = fp. metadata ( ) ?. len ( ) ;
255
+ println ! ( "Filesize: {}" , filesize) ;
256
+ if filesize - 4 != header. length as u64 {
257
+ eprintln ! ( "update_header.length cannot be correct, cannot check CRC" ) ;
258
+ }
259
+ create_dir_all ( format ! ( "{}/Image" , dst_path) ) ?;
260
+ unsafe {
261
+ println ! ( "manufacturer: {}" , CStr :: from_ptr( header. manufacturer. as_ptr( ) as * const i8 ) . to_str( ) ?) ;
262
+ println ! ( "model: {}" , CStr :: from_ptr( header. model. as_ptr( ) as * const i8 ) . to_str( ) ?) ;
263
+ }
264
+ for i in 0 ..header. num_parts {
265
+ let part = & header. parts [ i as usize ] ;
266
+ unsafe {
267
+ let cstr = CStr :: from_ptr ( part. full_path . as_ptr ( ) as * const i8 ) ;
268
+ let part_full_path = cstr. to_str ( ) ?;
269
+ if part_full_path == "SELF" || part_full_path == "RESERVED" {
270
+ continue ;
271
+ }
272
+ let part_full_path = format ! ( "{}/{}" , dst_path, part_full_path) ;
273
+ extract_file (
274
+ & mut fp,
275
+ part. part_offset as u64 ,
276
+ part. part_byte_count as u64 ,
277
+ & part_full_path,
278
+ ) ?;
279
+ }
280
+ }
281
+
282
+ Ok ( ( ) )
283
+ }
284
+
285
+
286
+ fn get_u32_le ( slice : & [ u8 ] ) -> u32 {
287
+ ( ( slice[ 3 ] as u32 ) << 24 )
288
+ + ( ( slice[ 2 ] as u32 ) << 16 )
289
+ + ( ( slice[ 1 ] as u32 ) << 8 )
290
+ + slice[ 0 ] as u32
291
+ }
292
+
293
+ fn write_file ( path : & Path , buffer : & [ u8 ] ) -> Result < ( ) > {
294
+ let mut file = File :: create ( path) ?;
295
+ file. write_all ( buffer) ?;
296
+ Ok ( ( ) )
297
+ }
0 commit comments