Modified calling convention: we now update %esi and %edi just like a
[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", "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         jmp     dcl1_n2b
113         
114 decompr_literals_n2b:
115         movsb
116 decompr_loop_n2b:
117         addl    %ebx, %ebx
118         jnz     dcl2_n2b
119 dcl1_n2b:
120         call    getbit32
121 dcl2_n2b:
122         jc      decompr_literals_n2b
123         xor     %xAX, %xAX
124         inc     %xAX            /* m_off = 1 */
125 loop1_n2b:
126         call    getbit1
127         adc     %xAX, %xAX      /* m_off = m_off*2 + getbit() */
128         call    getbit1
129         jnc     loop1_n2b       /* while(!getbit()) */
130         sub     $3, %xAX
131         jb      decompr_ebpeax_n2b      /* if (m_off == 2) goto decompr_ebpeax_n2b ? */
132         shl     $8, %xAX        
133         movb    (%xSI), %al     /* m_off = (m_off - 3)*256 + src[ilen++] */
134         inc     %xSI
135         xor     $-1, %xAX
136         jz      decompr_end_n2b /* if (m_off == 0xffffffff) goto decomp_end_n2b */
137         mov     %xAX, %xBP      /* last_m_off = m_off ?*/
138 decompr_ebpeax_n2b:
139         xor     %xCX, %xCX
140         call    getbit1
141         adc     %xCX, %xCX      /* m_len = getbit() */
142         call    getbit1
143         adc     %xCX, %xCX      /* m_len = m_len*2 + getbit()) */
144         jnz     decompr_got_mlen_n2b    /* if (m_len == 0) goto decompr_got_mlen_n2b */
145         inc     %xCX            /* m_len++ */
146 loop2_n2b:
147         call    getbit1 
148         adc     %xCX, %xCX      /* m_len = m_len*2 + getbit() */
149         call    getbit1
150         jnc     loop2_n2b       /* while(!getbit()) */
151         inc     %xCX
152         inc     %xCX            /* m_len += 2 */
153 decompr_got_mlen_n2b:
154         cmp     $-0xd00, %xBP
155         adc     $1, %xCX        /* m_len = m_len + 1 + (last_m_off > 0xd00) */
156         push    %xSI
157         lea     (%xBP,%xDI), %xSI       /* m_pos = dst + olen + -m_off  */
158         rep
159         es movsb                /* dst[olen++] = *m_pos++ while(m_len > 0) */
160         pop     %xSI
161         jmp     decompr_loop_n2b
162
163
164 getbit1:
165         addl    %ebx, %ebx
166         jnz     1f
167 getbit32:
168         movl    (%xSI), %ebx
169         sub     $-4, %xSI       /* sets carry flag */
170         adcl    %ebx, %ebx
171 1:
172         ret
173
174 decompr_end_n2b:
175         /* Restore registers and return */
176         pop     %xBP
177         pop     %xCX
178         popl    %ebx
179         pop     %xAX
180         ret