Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / arch / i386 / prefix / unnrv2b.S
diff --git a/qemu/roms/ipxe/src/arch/i386/prefix/unnrv2b.S b/qemu/roms/ipxe/src/arch/i386/prefix/unnrv2b.S
new file mode 100644 (file)
index 0000000..f5724c1
--- /dev/null
@@ -0,0 +1,184 @@
+/* 
+ * Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * Originally this code was part of ucl the data compression library
+ * for upx the ``Ultimate Packer of eXecutables''.
+ *
+ * - Converted to gas assembly, and refitted to work with etherboot.
+ *   Eric Biederman 20 Aug 2002
+ *
+ * - Structure modified to be a subroutine call rather than an
+ *   executable prefix.
+ *   Michael Brown 30 Mar 2004
+ *
+ * - Modified to be compilable as either 16-bit or 32-bit code.
+ *   Michael Brown 9 Mar 2005
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+/****************************************************************************
+ * This file provides the decompress() and decompress16() functions
+ * which can be called in order to decompress an image compressed with
+ * the nrv2b utility in src/util.
+ *
+ * These functions are designed to be called by the prefix.  They are
+ * position-independent code.
+ *
+ * The same basic assembly code is used to compile both
+ * decompress() and decompress16().
+ ****************************************************************************
+ */
+
+       .text
+       .arch i386
+       .section ".prefix.lib", "ax", @progbits
+
+#ifdef CODE16
+/****************************************************************************
+ * decompress16 (real-mode near call, position independent)
+ *
+ * Decompress data in 16-bit mode
+ *
+ * Parameters (passed via registers):
+ *   %ds:%esi - Start of compressed input data
+ *   %es:%edi - Start of output buffer
+ * Returns:
+ *   %ds:%esi - End of compressed input data
+ *   %es:%edi - End of decompressed output data
+ *   All other registers are preserved
+ *
+ * NOTE: It would be possible to build a smaller version of the
+ * decompression code for -DKEEP_IT_REAL by using
+ *    #define REG(x) x
+ * to use 16-bit registers where possible.  This would impose limits
+ * that the compressed data size must be in the range [1,65533-%si]
+ * and the uncompressed data size must be in the range [1,65536-%di]
+ * (where %si and %di are the input values for those registers).  Note
+ * particularly that the lower limit is 1, not 0, and that the upper
+ * limit on the input (compressed) data really is 65533, since the
+ * algorithm may read up to three bytes beyond the end of the input
+ * data, since it reads dwords.
+ ****************************************************************************
+ */
+
+#define REG(x) e ## x
+#define ADDR32 addr32
+
+       .code16
+       .globl  decompress16
+decompress16:
+       
+#else /* CODE16 */
+
+/****************************************************************************
+ * decompress (32-bit protected-mode near call, position independent)
+ *
+ * Parameters (passed via registers):
+ *   %ds:%esi - Start of compressed input data
+ *   %es:%edi - Start of output buffer
+ * Returns:
+ *   %ds:%esi - End of compressed input data
+ *   %es:%edi - End of decompressed output data
+ *   All other registers are preserved
+ ****************************************************************************
+ */
+
+#define REG(x) e ## x
+#define ADDR32
+       
+       .code32
+       .globl  decompress
+decompress:
+
+#endif /* CODE16 */
+
+#define xAX    REG(ax)
+#define xCX    REG(cx)
+#define xBP    REG(bp)
+#define xSI    REG(si)
+#define xDI    REG(di)
+
+       /* Save registers */
+       push    %xAX
+       pushl   %ebx
+       push    %xCX
+       push    %xBP
+       /* Do the decompression */
+       cld
+       xor     %xBP, %xBP
+       dec     %xBP            /* last_m_off = -1 */
+       jmp     dcl1_n2b
+       
+decompr_literals_n2b:
+       ADDR32 movsb
+decompr_loop_n2b:
+       addl    %ebx, %ebx
+       jnz     dcl2_n2b
+dcl1_n2b:
+       call    getbit32
+dcl2_n2b:
+       jc      decompr_literals_n2b
+       xor     %xAX, %xAX
+       inc     %xAX            /* m_off = 1 */
+loop1_n2b:
+       call    getbit1
+       adc     %xAX, %xAX      /* m_off = m_off*2 + getbit() */
+       call    getbit1
+       jnc     loop1_n2b       /* while(!getbit()) */
+       sub     $3, %xAX
+       jb      decompr_ebpeax_n2b      /* if (m_off == 2) goto decompr_ebpeax_n2b ? */
+       shl     $8, %xAX        
+       ADDR32 movb (%xSI), %al /* m_off = (m_off - 3)*256 + src[ilen++] */
+       inc     %xSI
+       xor     $-1, %xAX
+       jz      decompr_end_n2b /* if (m_off == 0xffffffff) goto decomp_end_n2b */
+       mov     %xAX, %xBP      /* last_m_off = m_off ?*/
+decompr_ebpeax_n2b:
+       xor     %xCX, %xCX
+       call    getbit1
+       adc     %xCX, %xCX      /* m_len = getbit() */
+       call    getbit1
+       adc     %xCX, %xCX      /* m_len = m_len*2 + getbit()) */
+       jnz     decompr_got_mlen_n2b    /* if (m_len == 0) goto decompr_got_mlen_n2b */
+       inc     %xCX            /* m_len++ */
+loop2_n2b:
+       call    getbit1 
+       adc     %xCX, %xCX      /* m_len = m_len*2 + getbit() */
+       call    getbit1
+       jnc     loop2_n2b       /* while(!getbit()) */
+       inc     %xCX
+       inc     %xCX            /* m_len += 2 */
+decompr_got_mlen_n2b:
+       cmp     $-0xd00, %xBP
+       adc     $1, %xCX        /* m_len = m_len + 1 + (last_m_off > 0xd00) */
+       push    %xSI
+       ADDR32 lea (%xBP,%xDI), %xSI    /* m_pos = dst + olen + -m_off  */
+       rep
+       es ADDR32 movsb         /* dst[olen++] = *m_pos++ while(m_len > 0) */
+       pop     %xSI
+       jmp     decompr_loop_n2b
+
+
+getbit1:
+       addl    %ebx, %ebx
+       jnz     1f
+getbit32:
+       ADDR32 movl (%xSI), %ebx
+       sub     $-4, %xSI       /* sets carry flag */
+       adcl    %ebx, %ebx
+1:
+       ret
+
+decompr_end_n2b:
+       /* Restore registers and return */
+       pop     %xBP
+       pop     %xCX
+       popl    %ebx
+       pop     %xAX
+       ret