Home | History | Annotate | Download | only in prefix
      1 /*
      2  * Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer
      3  *
      4  * This file is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU General Public License as
      6  * published by the Free Software Foundation; either version 2 of
      7  * the License, or (at your option) any later version.
      8  *
      9  * Originally this code was part of ucl the data compression library
     10  * for upx the ``Ultimate Packer of eXecutables''.
     11  *
     12  * - Converted to gas assembly, and refitted to work with etherboot.
     13  *   Eric Biederman 20 Aug 2002
     14  *
     15  * - Structure modified to be a subroutine call rather than an
     16  *   executable prefix.
     17  *   Michael Brown 30 Mar 2004
     18  *
     19  * - Modified to be compilable as either 16-bit or 32-bit code.
     20  *   Michael Brown 9 Mar 2005
     21  */
     22 
     23 FILE_LICENCE ( GPL2_OR_LATER )
     24 
     25 /****************************************************************************
     26  * This file provides the decompress() and decompress16() functions
     27  * which can be called in order to decompress an image compressed with
     28  * the nrv2b utility in src/util.
     29  *
     30  * These functions are designed to be called by the prefix.  They are
     31  * position-independent code.
     32  *
     33  * The same basic assembly code is used to compile both
     34  * decompress() and decompress16().
     35  ****************************************************************************
     36  */
     37 
     38 	.text
     39 	.arch i386
     40 	.section ".prefix.lib", "ax", @progbits
     41 
     42 #ifdef CODE16
     43 /****************************************************************************
     44  * decompress16 (real-mode near call, position independent)
     45  *
     46  * Decompress data in 16-bit mode
     47  *
     48  * Parameters (passed via registers):
     49  *   %ds:%esi - Start of compressed input data
     50  *   %es:%edi - Start of output buffer
     51  * Returns:
     52  *   %ds:%esi - End of compressed input data
     53  *   %es:%edi - End of decompressed output data
     54  *   All other registers are preserved
     55  *
     56  * NOTE: It would be possible to build a smaller version of the
     57  * decompression code for -DKEEP_IT_REAL by using
     58  *    #define REG(x) x
     59  * to use 16-bit registers where possible.  This would impose limits
     60  * that the compressed data size must be in the range [1,65533-%si]
     61  * and the uncompressed data size must be in the range [1,65536-%di]
     62  * (where %si and %di are the input values for those registers).  Note
     63  * particularly that the lower limit is 1, not 0, and that the upper
     64  * limit on the input (compressed) data really is 65533, since the
     65  * algorithm may read up to three bytes beyond the end of the input
     66  * data, since it reads dwords.
     67  ****************************************************************************
     68  */
     69 
     70 #define REG(x) e ## x
     71 #define ADDR32 addr32
     72 
     73 	.code16
     74 	.globl	decompress16
     75 decompress16:
     76 
     77 #else /* CODE16 */
     78 
     79 /****************************************************************************
     80  * decompress (32-bit protected-mode near call, position independent)
     81  *
     82  * Parameters (passed via registers):
     83  *   %ds:%esi - Start of compressed input data
     84  *   %es:%edi - Start of output buffer
     85  * Returns:
     86  *   %ds:%esi - End of compressed input data
     87  *   %es:%edi - End of decompressed output data
     88  *   All other registers are preserved
     89  ****************************************************************************
     90  */
     91 
     92 #define REG(x) e ## x
     93 #define ADDR32
     94 
     95 	.code32
     96 	.globl	decompress
     97 decompress:
     98 
     99 #endif /* CODE16 */
    100 
    101 #define xAX	REG(ax)
    102 #define xCX	REG(cx)
    103 #define xBP	REG(bp)
    104 #define xSI	REG(si)
    105 #define xDI	REG(di)
    106 
    107 	/* Save registers */
    108 	push	%xAX
    109 	pushl	%ebx
    110 	push	%xCX
    111 	push	%xBP
    112 	/* Do the decompression */
    113 	cld
    114 	xor	%xBP, %xBP
    115 	dec	%xBP		/* last_m_off = -1 */
    116 	jmp	dcl1_n2b
    117 
    118 decompr_literals_n2b:
    119 	ADDR32 movsb
    120 decompr_loop_n2b:
    121 	addl	%ebx, %ebx
    122 	jnz	dcl2_n2b
    123 dcl1_n2b:
    124 	call	getbit32
    125 dcl2_n2b:
    126 	jc	decompr_literals_n2b
    127 	xor	%xAX, %xAX
    128 	inc	%xAX		/* m_off = 1 */
    129 loop1_n2b:
    130 	call	getbit1
    131 	adc	%xAX, %xAX	/* m_off = m_off*2 + getbit() */
    132 	call	getbit1
    133 	jnc	loop1_n2b	/* while(!getbit()) */
    134 	sub	$3, %xAX
    135 	jb	decompr_ebpeax_n2b	/* if (m_off == 2) goto decompr_ebpeax_n2b ? */
    136 	shl	$8, %xAX
    137 	ADDR32 movb (%xSI), %al	/* m_off = (m_off - 3)*256 + src[ilen++] */
    138 	inc	%xSI
    139 	xor	$-1, %xAX
    140 	jz	decompr_end_n2b	/* if (m_off == 0xffffffff) goto decomp_end_n2b */
    141 	mov	%xAX, %xBP	/* last_m_off = m_off ?*/
    142 decompr_ebpeax_n2b:
    143 	xor	%xCX, %xCX
    144 	call	getbit1
    145 	adc	%xCX, %xCX	/* m_len = getbit() */
    146 	call	getbit1
    147 	adc	%xCX, %xCX	/* m_len = m_len*2 + getbit()) */
    148 	jnz	decompr_got_mlen_n2b	/* if (m_len == 0) goto decompr_got_mlen_n2b */
    149 	inc	%xCX		/* m_len++ */
    150 loop2_n2b:
    151 	call	getbit1
    152 	adc	%xCX, %xCX	/* m_len = m_len*2 + getbit() */
    153 	call	getbit1
    154 	jnc	loop2_n2b	/* while(!getbit()) */
    155 	inc	%xCX
    156 	inc	%xCX		/* m_len += 2 */
    157 decompr_got_mlen_n2b:
    158 	cmp	$-0xd00, %xBP
    159 	adc	$1, %xCX	/* m_len = m_len + 1 + (last_m_off > 0xd00) */
    160 	push	%xSI
    161 	ADDR32 lea (%xBP,%xDI), %xSI	/* m_pos = dst + olen + -m_off  */
    162 	rep
    163 	es ADDR32 movsb		/* dst[olen++] = *m_pos++ while(m_len > 0) */
    164 	pop	%xSI
    165 	jmp	decompr_loop_n2b
    166 
    167 
    168 getbit1:
    169 	addl	%ebx, %ebx
    170 	jnz	1f
    171 getbit32:
    172 	ADDR32 movl (%xSI), %ebx
    173 	sub	$-4, %xSI	/* sets carry flag */
    174 	adcl	%ebx, %ebx
    175 1:
    176 	ret
    177 
    178 decompr_end_n2b:
    179 	/* Restore registers and return */
    180 	pop	%xBP
    181 	pop	%xCX
    182 	popl	%ebx
    183 	pop	%xAX
    184 	ret
    185