[contrib] Allow Network Protocol header to display in rom-o-matic
[gpxe.git] / src / arch / i386 / prefix / unnrv2b.S
blobf5724c134b065a7c2a973b3d3aa15e4e5e3a568f
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  */
23 FILE_LICENCE ( GPL2_OR_LATER )
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  */
38         .text
39         .arch i386
40         .section ".prefix.lib", "ax", @progbits
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  */
70 #define REG(x) e ## x
71 #define ADDR32 addr32
73         .code16
74         .globl  decompress16
75 decompress16:
76         
77 #else /* CODE16 */
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  */
92 #define REG(x) e ## x
93 #define ADDR32
94         
95         .code32
96         .globl  decompress
97 decompress:
99 #endif /* CODE16 */
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)
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
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
176         ret
178 decompr_end_n2b:
179         /* Restore registers and return */
180         pop     %xBP
181         pop     %xCX
182         popl    %ebx
183         pop     %xAX
184         ret