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