1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - MI
3 File: mi_secureuncompression.c
4
5 Copyright 2008 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Date:: 2008-08-29#$
14 $Rev: 8159 $
15 $Author: yasuda_kei $
16 *---------------------------------------------------------------------------*/
17
18 #include <nitro.h>
19 #include <nitro/mi/secureUncompress.h>
20
21 #include <nitro/code32.h>
22
23 void MIi_UncompressBLZ(void *bottom);
24
25 //======================================================================
26 // Expanding compressed data
27 //======================================================================
28
29 /*---------------------------------------------------------------------------*
30 Name: MI_SecureUncompressAny
31
32 Description: Determines the compression type from the data header and performs the appropriate decompression process.
33
34 Since decompression processes for all types of compression are linked, it may be better to execute separate functions for each for each compression type when not using formats other than the specific compression formats.
35
36
37
38 Arguments: srcp Source address
39 srcSize Source size
40 destp Destination address
41 dstSize Destination size
42
43 Returns: Returns 0 when conversion succeeds
44 Returns a negative error code if failed
45 *---------------------------------------------------------------------------*/
MI_SecureUncompressAny(const void * srcp,u32 srcSize,void * destp,u32 dstSize)46 s32 MI_SecureUncompressAny( const void* srcp, u32 srcSize, void* destp, u32 dstSize )
47 {
48 switch ( MI_GetCompressionType( srcp ) )
49 {
50 // Run-length compressed data
51 case MI_COMPRESSION_RL:
52 return MI_SecureUncompressRL( srcp, srcSize, destp, dstSize );
53 // LZ77-compressed data
54 case MI_COMPRESSION_LZ:
55 return MI_SecureUncompressLZ( srcp, srcSize, destp, dstSize );
56 // Huffman-compressed data
57 case MI_COMPRESSION_HUFFMAN:
58 return MI_SecureUncompressHuffman( srcp, srcSize, destp, dstSize );
59 // Difference filter
60 case MI_COMPRESSION_DIFF:
61 return MI_SecureUnfilterDiff( srcp, srcSize, destp, dstSize );
62 default:
63 return MI_ERR_UNSUPPORTED;
64 }
65 }
66
67
68 /*---------------------------------------------------------------------------*
69 Name: MI_SecureUncompressRL
70
71 Description: 8-bit decompression of run-length compressed data
72
73 - Decompresses run-length compressed data, writing in 8 bit units.
74 - Use 4 byte alignment for the source address.
75
76 - Data header
77 u32 :4 : Reserved
78 compType:4 Compression type( = 3)
79 destSize:24 Data size after decompression
80
81 - Flag data format
82 u8 length:7 Decompressed data length - 1 (When not compressed)
83 Decompressed data length - 3 (only compress when the contiguous length is 3 bytes or greater)
84 flag:1 (0, 1) = (not compressed, compressed)
85
86 Arguments: *srcp Source address
87 srcSize Source size
88 *destp Destination address
89 dstSize Destination size
90
91 Returns: Returns 0 when conversion succeeds
92 Returns a negative error code if failed
93 *---------------------------------------------------------------------------*/
MI_SecureUncompressRL(const void * srcp,u32 srcSize,void * destp,u32 dstSize)94 s32 MI_SecureUncompressRL( const void *srcp, u32 srcSize, void *destp, u32 dstSize )
95 {
96 const u8 *pSrc = srcp;
97 u8 *pDst = destp;
98 u8 compType = (u8)( MI_HToLE32( *(u32*)pSrc ) & 0xFF );
99 u32 destCount = MI_HToLE32( *(u32*)pSrc ) >> 8;
100 s32 srcCount = (s32)srcSize;
101
102 if ( (compType & MI_COMPRESSION_TYPE_MASK) != MI_COMPRESSION_RL )
103 {
104 return MI_ERR_UNSUPPORTED;
105 }
106 if ( (compType & 0xF) != 0 )
107 {
108 return MI_ERR_UNSUPPORTED;
109 }
110 if ( srcSize <= 4 )
111 {
112 return MI_ERR_SRC_SHORTAGE;
113 }
114
115 pSrc += 4;
116 srcCount -= 4;
117
118 if ( destCount == 0 )
119 {
120 if ( srcCount < 4 )
121 {
122 return MI_ERR_SRC_SHORTAGE;
123 }
124 destCount = MI_HToLE32( *(u32*)pSrc );
125 pSrc += 4;
126 srcCount -= 4;
127 }
128
129 if ( dstSize < destCount )
130 {
131 return MI_ERR_DEST_OVERRUN;
132 }
133
134 while ( destCount > 0 )
135 {
136 u8 flags = *pSrc++;
137 s32 length = flags & 0x7f;
138 if ( --srcCount < 0 )
139 {
140 return MI_ERR_SRC_SHORTAGE;
141 }
142
143 if ( !(flags & 0x80) )
144 {
145 length++;
146 if ( length > destCount )
147 // Measures for buffer overrun when invalid data is decompressed.
148 {
149 return MI_ERR_DEST_OVERRUN;
150 }
151 srcCount -= length;
152 if ( srcCount < 0 )
153 {
154 return MI_ERR_SRC_SHORTAGE;
155 }
156
157 destCount -= length;
158 do
159 {
160 *pDst++ = *pSrc++;
161 } while ( --length > 0 );
162 }
163 else
164 {
165 u8 srcTmp;
166
167 length += 3;
168 if ( length > destCount )
169 // Measures for buffer overrun when invalid data is decompressed.
170 {
171 return MI_ERR_DEST_OVERRUN;
172 }
173
174 destCount -= length;
175 srcTmp = *pSrc++;
176 if ( --srcCount < 0 )
177 {
178 return MI_ERR_SRC_SHORTAGE;
179 }
180 do
181 {
182 *pDst++ = srcTmp;
183 } while ( --length > 0 );
184 }
185 }
186
187 if ( srcCount > 32 )
188 {
189 return MI_ERR_SRC_REMAINDER;
190 }
191
192 return MI_ERR_SUCCESS;
193 }
194
195
196 /*---------------------------------------------------------------------------*
197 Name: MI_SecureUncompressLZ
198
199 Description: 8-bit decompression of LZ77 compressed data
200
201 * Expands LZ77-compressed data and writes it in 8-bit units.
202 - Use 4 byte alignment for the source address.
203
204 - Data header
205 u32 :4 : Reserved
206 compType:4 Compression type( = 1)
207 destSize:24 Data size after decompression
208
209 - Flag data format
210 u8 flags Compression/no compression flag
211 (0, 1) = (not compressed, compressed)
212 - Code data format (Big Endian)
213 u16 length:4 Decompressed data length - 3 (only compress when the match length is 3 bytes or greater)
214 offset:12 Match data offset - 1
215
216 Arguments: *srcp Source address
217 srcSize Source size
218 *destp Destination address
219 dstSize Destination size
220
221 Returns: Returns 0 when conversion succeeds
222 Returns a negative error code if failed
223 *---------------------------------------------------------------------------*/
224 #define SRC_COUNT_CHECK
MI_SecureUncompressLZ(const void * srcp,u32 srcSize,void * destp,u32 dstSize)225 s32 MI_SecureUncompressLZ( const void *srcp, u32 srcSize, void *destp, u32 dstSize )
226 {
227 const u8* pSrc = srcp;
228 u8* pDst = destp;
229 u8 compType = (u8)( MI_HToLE32( *(u32*)pSrc ) & 0xFF );
230 u32 destCount = MI_HToLE32( *(u32*)pSrc ) >> 8;
231 s32 srcCount = (s32)srcSize;
232 BOOL exFormat = (*pSrc & 0x0F)? TRUE : FALSE;
233
234 if ( (compType & MI_COMPRESSION_TYPE_MASK) != MI_COMPRESSION_LZ )
235 {
236 return MI_ERR_UNSUPPORTED;
237 }
238 if ( ((compType & 0xF) != 0x0) && ((compType & 0xF) != 0x1) )
239 {
240 return MI_ERR_UNSUPPORTED;
241 }
242 if ( srcSize <= 4 )
243 {
244 return MI_ERR_SRC_SHORTAGE;
245 }
246
247 pSrc += 4;
248 srcCount -= 4;
249
250 if ( destCount == 0 )
251 {
252 if ( srcCount < 4 )
253 {
254 return MI_ERR_SRC_SHORTAGE;
255 }
256
257 destCount = MI_HToLE32( *(u32*)pSrc );
258 pSrc += 4;
259 srcCount -= 4;
260 }
261
262 if ( dstSize < destCount )
263 {
264 return MI_ERR_DEST_OVERRUN;
265 }
266
267 while ( destCount > 0 )
268 {
269 u32 i;
270 #if !defined(SRC_COUNT_CHECK)
271 u32 flags = *pSrc++;
272 #else
273 u32 flags;
274 #endif
275 if ( --srcCount < 0 )
276 {
277 return MI_ERR_SRC_SHORTAGE;
278 }
279 #if defined(SRC_COUNT_CHECK)
280 flags = *pSrc++;
281 #endif
282
283 for ( i = 0; i < 8; ++i )
284 {
285 if ( !(flags & 0x80) )
286 {
287 #if defined(SRC_COUNT_CHECK)
288 if ( --srcCount < 0 )
289 {
290 return MI_ERR_SRC_SHORTAGE;
291 }
292 destCount--; // Should this also be checked?
293 #endif
294 *pDst++ = *pSrc++;
295 #if !defined(SRC_COUNT_CHECK)
296 if ( --srcCount < 0 )
297 {
298 return MI_ERR_SRC_SHORTAGE;
299 }
300 destCount--;
301 #endif
302 }
303 else
304 {
305 s32 length = (*pSrc >> 4);
306 s32 offset;
307
308 if ( ! exFormat )
309 {
310 length += 3;
311 }
312 else
313 {
314 // LZ77 extended format
315 if ( length == 1 )
316 {
317 #if defined(SRC_COUNT_CHECK)
318 srcCount -= 2;
319 if ( srcCount < 0 )
320 {
321 return MI_ERR_SRC_SHORTAGE;
322 }
323 #endif
324 length = (*pSrc++ & 0x0F) << 12;
325 length |= (*pSrc++) << 4;
326 length |= (*pSrc >> 4);
327 length += 0xFF + 0xF + 3;
328 #if !defined(SRC_COUNT_CHECK)
329 srcCount -= 2;
330 #endif
331 }
332 else if ( length == 0 )
333 {
334 #if defined(SRC_COUNT_CHECK)
335 if ( --srcCount < 0 )
336 {
337 return MI_ERR_SRC_SHORTAGE;
338 }
339 #endif
340 length = (*pSrc++ & 0x0F) << 4;
341 length |= (*pSrc >> 4);
342 length += 0xF + 2;
343 #if !defined(SRC_COUNT_CHECK)
344 srcCount -= 1;
345 #endif
346 }
347 else
348 {
349 length += 1;
350 }
351 }
352
353 #if defined(SRC_COUNT_CHECK)
354 srcCount -= 2;
355 if ( srcCount < 0 )
356 {
357 return MI_ERR_SRC_SHORTAGE;
358 }
359 #endif
360 offset = (*pSrc++ & 0x0f) << 8;
361 offset = (offset | *pSrc++) + 1;
362
363 #if !defined(SRC_COUNT_CHECK)
364 srcCount -= 2;
365 if ( srcCount < 0 )
366 {
367 return MI_ERR_SRC_SHORTAGE;
368 }
369 #endif
370
371 // Measures for buffer overrun when invalid data is decompressed.
372 if ( length > destCount )
373 {
374 return MI_ERR_DEST_OVERRUN;
375 }
376 if ( &pDst[ -offset ] < destp )
377 {
378 return MI_ERR_DEST_OVERRUN;
379 }
380
381 destCount -= length;
382 do
383 {
384 *pDst = pDst[ -offset ];
385 pDst++;
386 } while ( --length > 0 );
387 }
388 if ( destCount <= 0 )
389 {
390 break;
391 }
392 flags <<= 1;
393 }
394 }
395
396 if ( srcCount > 32 )
397 {
398 return MI_ERR_SRC_REMAINDER;
399 }
400
401 return MI_ERR_SUCCESS;
402 }
403
404
405 extern BOOL MIi_VerifyHuffmanTable_( const void* pTable, u8 bit );
406 /*---------------------------------------------------------------------------*
407 Name: MIi_VerifyHuffmanTable_
408
409 Description: Huffman table integrity check
410
411 Arguments: Pointer to the Huffman table
412
413 Returns: TRUE when the table is valid
414 FALSE when the table is invalid
415 *---------------------------------------------------------------------------*/
416 BOOL
MIi_VerifyHuffmanTable_(const void * pTable,u8 bit)417 MIi_VerifyHuffmanTable_( const void* pTable, u8 bit )
418 {
419 const u32 FLAGS_ARRAY_NUM = 512 / 8; /* 64Byte */
420 u8* treep = (u8*)pTable;
421 u8* treeStartp = treep + 1;
422 u32 treeSize = *treep;
423 u8* treeEndp = (u8*)pTable + (treeSize + 1) * 2;
424 u32 i;
425 u8 end_flags[ FLAGS_ARRAY_NUM ];
426 u32 idx;
427
428 for ( i = 0; i < FLAGS_ARRAY_NUM; i++ )
429 {
430 end_flags[ i ] = 0;
431 }
432
433 if ( bit == 4 )
434 {
435 if ( treeSize >= 0x10 )
436 {
437 return FALSE;
438 }
439 }
440
441 idx = 1;
442 treep = treeStartp;
443 while ( treep < treeEndp )
444 {
445 if ( (end_flags[ idx / 8 ] & (1 << (idx % 8) )) == 0 )
446 {
447 u32 offset = (u32)( ( (*treep & 0x3F) + 1 ) << 1);
448 u8* nodep = (u8*)( (((u32)treep >> 1) << 1) + offset );
449
450 // Skip data added at the end for alignment.
451 if ( *treep == 0 && idx >= (treeSize * 2) )
452 {
453 goto next;
454 }
455
456 if ( nodep >= treeEndp )
457 {
458 return FALSE;
459 }
460 if ( *treep & 0x80 )
461 {
462 u32 left = (idx & ~0x1) + offset;
463 end_flags[ left / 8 ] |= (u8)( 1 << (left % 8) );
464 }
465 if ( *treep & 0x40 )
466 {
467 u32 right = (idx & ~0x1) + offset + 1;
468 end_flags[ right / 8 ] |= (u8)( 1 << (right % 8) );
469 }
470 }
471 next:
472 ++idx;
473 ++treep;
474 }
475 return TRUE;
476 }
477
478
479 /*---------------------------------------------------------------------------*
480 Name: MI_SecureUncompressHuffman
481
482 Description: Decompression of Huffman compressed data
483
484 - Decompresses Huffman compressed data, writing in 32 bit units.
485 - Use 4 byte alignment for the source address.
486 - Use 4-byte alignment for the destination address.
487 - The target decompression buffer size must be prepared in 4-byte multiples.
488
489 - Data header
490 u32 bitSize:4 1 data bit size (Normally 4|8)
491 compType:4 Compression type( = 2)
492 destSize:24 Data size after decompression
493
494 - Tree table
495 u8 treeSize Tree table size/2 - 1
496 TreeNodeData nodeRoot Root node
497
498 TreeNodeData nodeLeft Root left node
499 TreeNodeData nodeRight Root right node
500
501 TreeNodeData nodeLeftLeft Left left node
502 TreeNodeData nodeLeftRight Left right node
503
504 TreeNodeData nodeRightLeft Right left node
505 TreeNodeData nodeRightRight Right right node
506
507 �E
508 �E
509
510 The compressed data itself follows
511
512 - TreeNodeData structure
513 u8 nodeNextOffset:6 : Offset to the next node data - 1 (2 byte units)
514 rightEndFlag:1 Right node end flag
515 leftEndzflag:1 Left node end flag
516 When the end flag is set
517 There is data in next node
518
519 Arguments: *srcp Source address
520 srcSize Source size
521 *destp Destination address
522 dstSize Destination size
523
524 Returns: Returns 0 when conversion succeeds
525 Returns a negative error code if failed
526 *---------------------------------------------------------------------------*/
MI_SecureUncompressHuffman(const void * srcp,u32 srcSize,void * destp,u32 dstSize)527 s32 MI_SecureUncompressHuffman( const void *srcp, u32 srcSize, void *destp, u32 dstSize )
528 {
529 #define TREE_END 0x80
530 const u32 *pSrc = srcp;
531 u32 *pDst = destp;
532 u8 compType = (u8)( MI_HToLE32( *(u32*)pSrc ) & 0xFF );
533 s32 destCount = (s32)( MI_HToLE32( *pSrc ) >> 8 );
534 u8 *treep = (destCount != 0)? ((u8*)pSrc + 4) : ((u8*)pSrc + 8);
535 u8 *treeStartp = treep + 1;
536 u32 dataBit = *(u8*)pSrc & 0x0FU;
537 u32 destTmp = 0;
538 u32 destTmpCount = 0;
539 u32 destTmpDataNum = 4 + ( dataBit & 0x7 );
540 s32 srcCount = (s32)srcSize;
541 u32 treeSize = (u32)( (*treep + 1) << 1 );
542
543 if ( (compType & MI_COMPRESSION_TYPE_MASK) != MI_COMPRESSION_HUFFMAN )
544 {
545 return MI_ERR_UNSUPPORTED;
546 }
547 if ( (dataBit != 4) && (dataBit != 8) )
548 {
549 return MI_ERR_UNSUPPORTED;
550 }
551
552 if ( destCount == 0 )
553 {
554 if ( srcSize < 8 + treeSize )
555 {
556 return MI_ERR_SRC_SHORTAGE;
557 }
558 destCount = (s32)( MI_HToLE32( *(pSrc + 1) ) );
559 }
560 else if ( srcSize < 4 + treeSize )
561 {
562 return MI_ERR_SRC_SHORTAGE;
563 }
564
565 if ( ! MIi_VerifyHuffmanTable_(treep, (u8)dataBit) )
566 {
567 return MI_ERR_ILLEGAL_TABLE;
568 }
569
570 pSrc = (u32*)( treep + treeSize );
571 srcCount -= ( (u32)pSrc - (u32)srcp );
572
573 if ( srcCount < 0 )
574 {
575 return MI_ERR_SRC_SHORTAGE;
576 }
577
578 if ( dstSize < destCount )
579 {
580 return MI_ERR_DEST_OVERRUN;
581 }
582
583 treep = treeStartp;
584
585 while ( destCount > 0 )
586 {
587 s32 srcTmpCount = 32;
588 u32 srcTmp = MI_HToLE32( *pSrc++ ); // Endian strategy
589 srcCount -= 4;
590 if ( srcCount < 0 )
591 {
592 return MI_ERR_SRC_SHORTAGE;
593 }
594
595 while ( --srcTmpCount >= 0 )
596 {
597 u32 treeShift = (srcTmp >> 31) & 0x1;
598 u32 treeCheck = *treep;
599 treeCheck <<= treeShift;
600 treep = (u8*)( (((u32)treep >> 1) << 1) + (((*treep & 0x3f) + 1) << 1) + treeShift );
601 if ( treeCheck & TREE_END )
602 {
603 destTmp >>= dataBit;
604 destTmp |= *treep << (32 - dataBit);
605 treep = treeStartp;
606 ++destTmpCount;
607
608 if ( destCount <= (destTmpCount * dataBit) / 8 )
609 {
610 destTmp >>= (destTmpDataNum - destTmpCount) * dataBit;
611 destTmpCount = destTmpDataNum;
612 }
613
614 if ( destTmpCount == destTmpDataNum )
615 {
616 // Over-access until the last 4-byte alignment of the decompression buffer
617 *pDst++ = MI_HToLE32(destTmp); // Endian strategy
618 destCount -= 4;
619 destTmpCount = 0;
620 }
621 }
622 if ( destCount <= 0 )
623 {
624 break;
625 }
626 srcTmp <<= 1;
627 }
628 }
629 if ( srcCount > 32 )
630 {
631 return MI_ERR_SRC_REMAINDER;
632 }
633
634 return MI_ERR_SUCCESS;
635 }
636
637
638 /*---------------------------------------------------------------------------*
639 Name: MIi_HuffImportTree
640
641 Description: Decompresses a resource's Huffman table into the work buffer.
642
643 Arguments: pTable: Pointer to a buffer for decompressing the Huffman table
644 srcp: Pointer to the resource data
645 bitSize: Size (in bits) of the Huffman table elements
646 srcRemainSize: Valid remaining data size contained in srcp
647
648 Returns: Returns the actual data size loaded from the resource.
649 *---------------------------------------------------------------------------*/
650 static u32
MIi_HuffImportTree(u16 * pTable,const u8 * srcp,u8 bitSize,u32 srcRemainSize)651 MIi_HuffImportTree( u16* pTable, const u8* srcp, u8 bitSize, u32 srcRemainSize )
652 {
653 u32 tableSize;
654 u32 idx = 1;
655 u32 data = 0;
656 u32 bitNum = 0;
657 u32 bitMask = (1 << bitSize) - 1U;
658 u32 srcCnt = 0;
659 const u32 MAX_IDX = (u32)( (1 << bitSize) * 2 );
660
661 if ( bitSize > 8 )
662 {
663 tableSize = MI_HToLE16( *(u16*)srcp );
664 srcp += 2;
665 srcCnt += 2;
666 }
667 else
668 {
669 tableSize = *srcp;
670 srcp += 1;
671 srcCnt += 1;
672 }
673 tableSize = (tableSize + 1) * 4;
674 if ( srcRemainSize < tableSize )
675 {
676 return tableSize;
677 }
678
679 while ( srcCnt < tableSize )
680 {
681 while ( bitNum < bitSize )
682 {
683 data <<= 8;
684 data |= *srcp++;
685 ++srcCnt;
686 bitNum += 8;
687 }
688 if ( idx < MAX_IDX )
689 {
690 pTable[ idx++ ] = (u16)( ( data >> (bitNum - bitSize) ) & bitMask );
691 }
692 bitNum -= bitSize;
693 }
694 return tableSize;
695 }
696
697 /*---------------------------------------------------------------------------*
698 Name: MI_SecureUnfilterDiff
699
700 Description: 8-bit decompression to restore differential filter conversion.
701
702 - Restores a differential filter, writing in 8 bit units.
703 - Use 4 byte alignment for the source address.
704
705 Arguments: *srcp Source address
706 *destp Destination address
707
708 Returns: Returns 0 when conversion succeeds
709 Returns a negative error code if failed
710 *---------------------------------------------------------------------------*/
MI_SecureUnfilterDiff(register const void * srcp,u32 srcSize,register void * destp,u32 dstSize)711 s32 MI_SecureUnfilterDiff( register const void *srcp, u32 srcSize, register void *destp, u32 dstSize )
712 {
713 const u8* pSrc = srcp;
714 u8* pDst = destp;
715 u32 bitSize = *pSrc & 0xFU;
716 u8 compType = (u8)( MI_HToLE32( *(u32*)pSrc ) & 0xFF );
717 s32 destCount = (s32)( MI_HToLE32( *(u32*)pSrc ) >> 8 );
718 u32 sum = 0;
719 s32 srcCount = (s32)srcSize;
720
721 if ( (compType & MI_COMPRESSION_TYPE_MASK) != MI_COMPRESSION_DIFF )
722 {
723 return MI_ERR_UNSUPPORTED;
724 }
725 if ( (bitSize != 0) && (bitSize != 1) )
726 {
727 return MI_ERR_UNSUPPORTED;
728 }
729 if ( srcSize <= 4 )
730 {
731 return MI_ERR_SRC_SHORTAGE;
732 }
733 if ( dstSize < destCount )
734 {
735 return MI_ERR_DEST_OVERRUN;
736 }
737
738 pSrc += 4;
739 srcCount -= 4;
740
741 if ( bitSize != 1 )
742 {
743 // Difference calculation in units of 8 bits
744 do
745 {
746 u8 tmp = *(pSrc++);
747 if ( --srcCount < 0 )
748 {
749 return MI_ERR_SRC_SHORTAGE;
750 }
751 destCount--;
752 sum += tmp;
753 *(pDst++) = (u8)sum;
754 } while ( destCount > 0 );
755 }
756 else
757 {
758 // Difference calculation in units of 16 bits
759 do
760 {
761 u16 tmp = MI_HToLE16( *(u16*)pSrc );
762 pSrc += 2;
763 srcCount -= 2;
764 if ( srcCount < 0 )
765 {
766 return MI_ERR_SRC_SHORTAGE;
767 }
768 destCount -= 2;
769 sum += tmp;
770 *(u16*)pDst = MI_HToLE16( (u16)sum );
771 pDst += 2;
772 } while ( destCount > 0 );
773 }
774 if ( srcCount > 32 )
775 {
776 return MI_ERR_SRC_REMAINDER;
777 }
778
779 return MI_ERR_SUCCESS;
780 }
781
782 /*---------------------------------------------------------------------------*
783 Name: MI_SecureUncompressBLZ
784
785 Description: Uncompress BLZ ( backword LZ )
786
787 Arguments:
788 void *srcp source address ( data buffer compressed by compBLZ.exe )
789 u32 srcSize source data size ( data size of compressed data )
790 u32 dstSize data size after uncompressing
791
792 Returns: None.
793 *---------------------------------------------------------------------------*/
MI_SecureUncompressBLZ(const void * srcp,u32 srcSize,u32 dstSize)794 s32 MI_SecureUncompressBLZ(const void *srcp, u32 srcSize, u32 dstSize)
795 {
796 // Check whether the compressed data specified by srcp is BLZ
797 // If there is a footer, treat as BLZ.
798 // Check bufferTop
799 if ((*(u32 *)((u32)srcp + srcSize - 8) & 0xFFFFFF) > srcSize)
800 {
801 return MI_ERR_UNSUPPORTED;
802 }
803
804 // Check compressBottom
805 if (*(u8 *)((u32)srcp + srcSize - 5) < 0x08 && *(u8 *)((u32)srcp + srcSize - 5) > 0x0B)
806 {
807 return MI_ERR_UNSUPPORTED;
808 }
809
810 // Size check
811 if (*(u32 *)((u32)srcp + srcSize - 4) + srcSize > dstSize)
812 {
813 return MI_ERR_DEST_OVERRUN;
814 }
815 MIi_UncompressBLZ((void*)((u32)srcp + srcSize));
816 return 0;
817 }
818
819 /*---------------------------------------------------------------------------*
820 Name: MIi_UncompressBackward
821
822 Description: Uncompress special archive for module compression
823
824 Arguments: bottom = Bottom adrs of packed archive + 1
825 bottom[-8..-6] = offset for top of compressed data
826 inp_top = bottom - bottom[-8..-6]
827 bottom[ -5] = offset for bottom of compressed data
828 inp = bottom - bottom[-5]
829 bottom[-4..-1] = offset for bottom of original data
830 outp = bottom + bottom[-4..-1]
831
832 typedef struct
833 {
834 u32 bufferTop:24;
835 u32 compressBottom:8;
836 u32 originalBottom;
837 } CompFooter;
838
839 Returns: None.
840 *---------------------------------------------------------------------------*/
MIi_UncompressBLZ(register void * bottom)841 asm void MIi_UncompressBLZ( register void* bottom )
842 {
843 #define data r0
844 #define inp_top r1
845 #define outp r2
846 #define inp r3
847 #define outp_save r4
848 #define flag r5
849 #define count8 r6
850 #define index r7
851 #define dummy r8
852 #define len r12
853 cmp bottom, #0
854 beq @exit
855 stmfd sp!, {r4-r8}
856 ldmdb bottom, {r1-r2}
857 add outp, bottom, outp
858 sub inp, bottom, inp_top, LSR #24
859 bic inp_top, inp_top, #0xff000000
860 sub inp_top, bottom, inp_top
861 mov outp_save, outp
862
863 @loop:
864 cmp inp, inp_top // exit if inp==inp_top
865 ble @end_loop
866 ldrb flag, [inp, #-1]! // r4 = compress_flag = *--inp
867 mov count8, #8
868 @loop8:
869 subs count8, count8, #1
870 blt @loop
871 tst flag, #0x80
872 bne @blockcopy
873 @bytecopy:
874 ldrb data, [inp, #-1]!
875 ldrb dummy, [outp, #-1] // dummy read to use D-Cache efficiently
876 strb data, [outp, #-1]! // Copy 1 byte
877 b @joinhere
878 @blockcopy:
879 ldrb len, [inp, #-1]!
880 ldrb index, [inp, #-1]!
881 orr index, index, len, LSL #8
882 bic index, index, #0xf000
883 add index, index, #0x0002
884 add len, len, #0x0020
885 @patterncopy:
886 ldrb data, [outp, index]
887 ldrb dummy, [outp, #-1] // dummy read to use D-Cache efficiently
888 strb data, [outp, #-1]!
889 subs len, len, #0x0010
890 bge @patterncopy
891
892 @joinhere:
893 cmp inp, inp_top
894 mov flag, flag, LSL #1
895 bgt @loop8
896 @end_loop:
897
898 // DC_FlushRange & IC_InvalidateRange
899 mov r0, #0
900 bic inp, inp_top, #HW_CACHE_LINE_SIZE - 1
901 @cacheflush:
902 mcr p15, 0, r0, c7, c10, 4 // wait writebuffer empty
903 mcr p15, 0, inp, c7, c5, 1 // ICache
904 mcr p15, 0, inp, c7, c14, 1 // DCache
905 add inp, inp, #HW_CACHE_LINE_SIZE
906 cmp inp, outp_save
907 blt @cacheflush
908
909 ldmfd sp!, {r4-r8}
910 @exit bx lr
911 }
912