d62441a950b48138742024b73252dcb1ecd0fdc3
[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_block() and decompress_block16()
25  * functions which can be called in order to decompress an image
26  * compressed with 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_block() and decompress_block16().
33  ****************************************************************************
34  */
35
36         .text
37         .arch i386
38         .section ".prefix", "ax", @progbits
39
40 #ifdef CODE16
41 /****************************************************************************
42  * decompress_block16 (real-mode near call, position independent)
43  *
44  * Parameters (passed via registers):
45  *   %ds:%si - Pointer to compressed input data
46  *   %es:%di - Pointer to output buffer
47  * Returns:
48  *   All registers are preserved
49  *
50  * NOTE: The compressed data size must be in the range [1,65533-%si]
51  * and the uncompressed data size must be in the range [1,65536-%di]
52  * (where %si and %di are the input values for those registers).  Note
53  * particularly that the lower limit is 1, not 0, and that the upper
54  * limit on the input (compressed) data really is 65533, since the
55  * algorithm may read up to three bytes beyond the end of the input
56  * data, since it reads dwords.
57  *
58  * Although splitting up the data into (almost) 64kB chunks for
59  * compression is awkward and worsens the compression ratio, it has
60  * little to no practical effect since our image size is currently
61  * <64kB for all single drivers.  Having a decompression routine that
62  * can run in real-mode avoids the need to duplicate RM-to-PM
63  * transition code from librm (or have part of librm kept
64  * uncompressed, which is itself awkward) and means that we don't need
65  * to set up the PM stack until we hit the setup routine itself.
66  ****************************************************************************
67  */
68
69 #define REG(x) x
70
71         .code16
72         .globl  decompress_block16
73 decompress_block16:
74         
75 #else /* CODE16 */
76
77 /****************************************************************************
78  * decompress_block (32-bit protected-mode near call, position independent)
79  *
80  * Parameters (passed via registers):
81  *   %ds:%esi - Pointer to compressed input data
82  *   %es:%edi - Pointer to output buffer
83  * Returns:
84  *   All registers are preserved
85  ****************************************************************************
86  */
87
88 #define REG(x) e ## x
89         
90         .code32
91         .globl  decompress_block
92 decompress_block:
93
94 #endif /* CODE16 */
95
96 #define xAX     REG(ax)
97 #define xCX     REG(cx)
98 #define xBP     REG(bp)
99 #define xSI     REG(si)
100 #define xDI     REG(di)
101
102         /* Save registers */
103         pushal
104         /* Do the decompression */
105         cld
106         xor     %xBP, %xBP
107         dec     %xBP            /* last_m_off = -1 */
108         jmp     dcl1_n2b
109         
110 decompr_literals_n2b:
111         movsb
112 decompr_loop_n2b:
113         addl    %ebx, %ebx
114         jnz     dcl2_n2b
115 dcl1_n2b:
116         call    getbit32
117 dcl2_n2b:
118         jc      decompr_literals_n2b
119         xor     %xAX, %xAX
120         inc     %xAX            /* m_off = 1 */
121 loop1_n2b:
122         call    getbit1
123         adc     %xAX, %xAX      /* m_off = m_off*2 + getbit() */
124         call    getbit1
125         jnc     loop1_n2b       /* while(!getbit()) */
126         sub     $3, %xAX
127         jb      decompr_ebpeax_n2b      /* if (m_off == 2) goto decompr_ebpeax_n2b ? */
128         shl     $8, %xAX        
129         movb    (%xSI), %al     /* m_off = (m_off - 3)*256 + src[ilen++] */
130         inc     %xSI
131         xor     $-1, %xAX
132         jz      decompr_end_n2b /* if (m_off == 0xffffffff) goto decomp_end_n2b */
133         mov     %xAX, %xBP      /* last_m_off = m_off ?*/
134 decompr_ebpeax_n2b:
135         xor     %xCX, %xCX
136         call    getbit1
137         adc     %xCX, %xCX      /* m_len = getbit() */
138         call    getbit1
139         adc     %xCX, %xCX      /* m_len = m_len*2 + getbit()) */
140         jnz     decompr_got_mlen_n2b    /* if (m_len == 0) goto decompr_got_mlen_n2b */
141         inc     %xCX            /* m_len++ */
142 loop2_n2b:
143         call    getbit1 
144         adc     %xCX, %xCX      /* m_len = m_len*2 + getbit() */
145         call    getbit1
146         jnc     loop2_n2b       /* while(!getbit()) */
147         inc     %xCX
148         inc     %xCX            /* m_len += 2 */
149 decompr_got_mlen_n2b:
150         cmp     $-0xd00, %xBP
151         adc     $1, %xCX        /* m_len = m_len + 1 + (last_m_off > 0xd00) */
152         push    %xSI
153         lea     (%xBP,%xDI), %xSI       /* m_pos = dst + olen + -m_off  */
154         rep
155         es movsb                /* dst[olen++] = *m_pos++ while(m_len > 0) */
156         pop     %xSI
157         jmp     decompr_loop_n2b
158
159
160 getbit1:
161         addl    %ebx, %ebx
162         jnz     1f
163 getbit32:
164         movl    (%xSI), %ebx
165         sub     $-4, %xSI       /* sets carry flag */
166         adcl    %ebx, %ebx
167 1:
168         ret
169
170 decompr_end_n2b:
171         /* Restore registers and return */
172         popal
173         ret