4e3090e2954199ff4648c75535d1c0331394bb16
[people/xl0/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", "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  * to use 16-bit registers where possible.  This would impose limits
58  * that the compressed data size must be in the range [1,65533-%si]
59  * and the uncompressed data size must be in the range [1,65536-%di]
60  * (where %si and %di are the input values for those registers).  Note
61  * particularly that the lower limit is 1, not 0, and that the upper
62  * limit on the input (compressed) data really is 65533, since the
63  * algorithm may read up to three bytes beyond the end of the input
64  * data, since it reads dwords.
65  ****************************************************************************
66  */
67
68 #define REG(x) e ## x
69
70         .code16
71         .globl  decompress16
72 decompress16:
73         
74 #else /* CODE16 */
75
76 /****************************************************************************
77  * decompress (32-bit protected-mode near call, position independent)
78  *
79  * Parameters (passed via registers):
80  *   %ds:%esi - Start of compressed input data
81  *   %es:%edi - Start of output buffer
82  * Returns:
83  *   %ds:%esi - End of compressed input data
84  *   %es:%edi - End of decompressed output data
85  *   All other registers are preserved
86  ****************************************************************************
87  */
88
89 #define REG(x) e ## x
90         
91         .code32
92         .globl  decompress
93 decompress:
94
95 #endif /* CODE16 */
96
97 #define xAX     REG(ax)
98 #define xCX     REG(cx)
99 #define xBP     REG(bp)
100 #define xSI     REG(si)
101 #define xDI     REG(di)
102
103         /* Save registers */
104         push    %xAX
105         pushl   %ebx
106         push    %xCX
107         push    %xBP
108         /* Do the decompression */
109         cld
110         xor     %xBP, %xBP
111         dec     %xBP            /* last_m_off = -1 */
112         add     $4, %xSI        /* Skip "file length" field */
113         jmp     dcl1_n2b
114         
115 decompr_literals_n2b:
116         movsb
117 decompr_loop_n2b:
118         addl    %ebx, %ebx
119         jnz     dcl2_n2b
120 dcl1_n2b:
121         call    getbit32
122 dcl2_n2b:
123         jc      decompr_literals_n2b
124         xor     %xAX, %xAX
125         inc     %xAX            /* m_off = 1 */
126 loop1_n2b:
127         call    getbit1
128         adc     %xAX, %xAX      /* m_off = m_off*2 + getbit() */
129         call    getbit1
130         jnc     loop1_n2b       /* while(!getbit()) */
131         sub     $3, %xAX
132         jb      decompr_ebpeax_n2b      /* if (m_off == 2) goto decompr_ebpeax_n2b ? */
133         shl     $8, %xAX        
134         movb    (%xSI), %al     /* m_off = (m_off - 3)*256 + src[ilen++] */
135         inc     %xSI
136         xor     $-1, %xAX
137         jz      decompr_end_n2b /* if (m_off == 0xffffffff) goto decomp_end_n2b */
138         mov     %xAX, %xBP      /* last_m_off = m_off ?*/
139 decompr_ebpeax_n2b:
140         xor     %xCX, %xCX
141         call    getbit1
142         adc     %xCX, %xCX      /* m_len = getbit() */
143         call    getbit1
144         adc     %xCX, %xCX      /* m_len = m_len*2 + getbit()) */
145         jnz     decompr_got_mlen_n2b    /* if (m_len == 0) goto decompr_got_mlen_n2b */
146         inc     %xCX            /* m_len++ */
147 loop2_n2b:
148         call    getbit1 
149         adc     %xCX, %xCX      /* m_len = m_len*2 + getbit() */
150         call    getbit1
151         jnc     loop2_n2b       /* while(!getbit()) */
152         inc     %xCX
153         inc     %xCX            /* m_len += 2 */
154 decompr_got_mlen_n2b:
155         cmp     $-0xd00, %xBP
156         adc     $1, %xCX        /* m_len = m_len + 1 + (last_m_off > 0xd00) */
157         push    %xSI
158         lea     (%xBP,%xDI), %xSI       /* m_pos = dst + olen + -m_off  */
159         rep
160         es movsb                /* dst[olen++] = *m_pos++ while(m_len > 0) */
161         pop     %xSI
162         jmp     decompr_loop_n2b
163
164
165 getbit1:
166         addl    %ebx, %ebx
167         jnz     1f
168 getbit32:
169         movl    (%xSI), %ebx
170         sub     $-4, %xSI       /* sets carry flag */
171         adcl    %ebx, %ebx
172 1:
173         ret
174
175 decompr_end_n2b:
176         /* Restore registers and return */
177         pop     %xBP
178         pop     %xCX
179         popl    %ebx
180         pop     %xAX
181         ret