Move .zinfo to libprefix.S; it doesn't belong with the decompression code.
[people/holger/gpxe.git] / src / arch / i386 / prefix / unnrv2b.S
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 /****************************************************************************
24  * This file provides the decompress() and decompress16() functions
25  * which can be called in order to decompress an image compressed with
26  * the nrv2b utility in src/util.
27  *
28  * These functions are designed to be called by the prefix.  They are
29  * position-independent code.
30  *
31  * The same basic assembly code is used to compile both
32  * decompress() and decompress16().
33  ****************************************************************************
34  */
35
36         .text
37         .arch i386
38         .section ".prefix.lib", "ax", @progbits
39
40 #ifdef CODE16
41 /****************************************************************************
42  * decompress16 (real-mode near call, position independent)
43  *
44  * Decompress data in 16-bit mode
45  *
46  * Parameters (passed via registers):
47  *   %ds:%esi - Start of compressed input data
48  *   %es:%edi - Start of output buffer
49  * Returns:
50  *   %ds:%esi - End of compressed input data
51  *   %es:%edi - End of decompressed output data
52  *   All other registers are preserved
53  *
54  * NOTE: It would be possible to build a smaller version of the
55  * decompression code for -DKEEP_IT_REAL by using
56  *    #define REG(x) x
57  *    #define MOVSB movsb
58  * to use 16-bit registers where possible.  This would impose limits
59  * that the compressed data size must be in the range [1,65533-%si]
60  * and the uncompressed data size must be in the range [1,65536-%di]
61  * (where %si and %di are the input values for those registers).  Note
62  * particularly that the lower limit is 1, not 0, and that the upper
63  * limit on the input (compressed) data really is 65533, since the
64  * algorithm may read up to three bytes beyond the end of the input
65  * data, since it reads dwords.
66  ****************************************************************************
67  */
68
69 #define REG(x) e ## x
70 #define MOVSB addr32 movsb
71
72         .code16
73         .globl  decompress16
74 decompress16:
75         
76 #else /* CODE16 */
77
78 /****************************************************************************
79  * decompress (32-bit protected-mode near call, position independent)
80  *
81  * Parameters (passed via registers):
82  *   %ds:%esi - Start of compressed input data
83  *   %es:%edi - Start of output buffer
84  * Returns:
85  *   %ds:%esi - End of compressed input data
86  *   %es:%edi - End of decompressed output data
87  *   All other registers are preserved
88  ****************************************************************************
89  */
90
91 #define REG(x) e ## x
92         
93         .code32
94         .globl  decompress
95 decompress:
96
97 #endif /* CODE16 */
98
99 #define xAX     REG(ax)
100 #define xCX     REG(cx)
101 #define xBP     REG(bp)
102 #define xSI     REG(si)
103 #define xDI     REG(di)
104
105         /* Save registers */
106         push    %xAX
107         pushl   %ebx
108         push    %xCX
109         push    %xBP
110         /* Do the decompression */
111         cld
112         xor     %xBP, %xBP
113         dec     %xBP            /* last_m_off = -1 */
114         jmp     dcl1_n2b
115         
116 decompr_literals_n2b:
117         MOVSB
118 decompr_loop_n2b:
119         addl    %ebx, %ebx
120         jnz     dcl2_n2b
121 dcl1_n2b:
122         call    getbit32
123 dcl2_n2b:
124         jc      decompr_literals_n2b
125         xor     %xAX, %xAX
126         inc     %xAX            /* m_off = 1 */
127 loop1_n2b:
128         call    getbit1
129         adc     %xAX, %xAX      /* m_off = m_off*2 + getbit() */
130         call    getbit1
131         jnc     loop1_n2b       /* while(!getbit()) */
132         sub     $3, %xAX
133         jb      decompr_ebpeax_n2b      /* if (m_off == 2) goto decompr_ebpeax_n2b ? */
134         shl     $8, %xAX        
135         movb    (%xSI), %al     /* m_off = (m_off - 3)*256 + src[ilen++] */
136         inc     %xSI
137         xor     $-1, %xAX
138         jz      decompr_end_n2b /* if (m_off == 0xffffffff) goto decomp_end_n2b */
139         mov     %xAX, %xBP      /* last_m_off = m_off ?*/
140 decompr_ebpeax_n2b:
141         xor     %xCX, %xCX
142         call    getbit1
143         adc     %xCX, %xCX      /* m_len = getbit() */
144         call    getbit1
145         adc     %xCX, %xCX      /* m_len = m_len*2 + getbit()) */
146         jnz     decompr_got_mlen_n2b    /* if (m_len == 0) goto decompr_got_mlen_n2b */
147         inc     %xCX            /* m_len++ */
148 loop2_n2b:
149         call    getbit1 
150         adc     %xCX, %xCX      /* m_len = m_len*2 + getbit() */
151         call    getbit1
152         jnc     loop2_n2b       /* while(!getbit()) */
153         inc     %xCX
154         inc     %xCX            /* m_len += 2 */
155 decompr_got_mlen_n2b:
156         cmp     $-0xd00, %xBP
157         adc     $1, %xCX        /* m_len = m_len + 1 + (last_m_off > 0xd00) */
158         push    %xSI
159         lea     (%xBP,%xDI), %xSI       /* m_pos = dst + olen + -m_off  */
160         rep
161         es MOVSB                /* dst[olen++] = *m_pos++ while(m_len > 0) */
162         pop     %xSI
163         jmp     decompr_loop_n2b
164
165
166 getbit1:
167         addl    %ebx, %ebx
168         jnz     1f
169 getbit32:
170         movl    (%xSI), %ebx
171         sub     $-4, %xSI       /* sets carry flag */
172         adcl    %ebx, %ebx
173 1:
174         ret
175
176 decompr_end_n2b:
177         /* Restore registers and return */
178         pop     %xBP
179         pop     %xCX
180         popl    %ebx
181         pop     %xAX
182         ret