mirror of
https://github.com/ipxe/ipxe
synced 2025-12-30 13:11:11 +03:00
Merged mcb30-realmode-redesign back to HEAD
This commit is contained in:
@@ -15,115 +15,159 @@
|
||||
* - 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
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
* This file provides the decompress_block() and decompress_block16()
|
||||
* 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_block() and decompress_block16().
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
.text
|
||||
.arch i386
|
||||
.section ".prefix", "ax", @progbits
|
||||
.code32
|
||||
|
||||
#ifdef CODE16
|
||||
/****************************************************************************
|
||||
* decompress_block16 (real-mode near call, position independent)
|
||||
*
|
||||
* Parameters (passed via registers):
|
||||
* %ds:%si - Pointer to compressed input data
|
||||
* %es:%di - Pointer to output buffer
|
||||
* Returns:
|
||||
* All registers are preserved
|
||||
*
|
||||
* NOTE: 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.
|
||||
*
|
||||
* Although splitting up the data into (almost) 64kB chunks for
|
||||
* compression is awkward and worsens the compression ratio, it has
|
||||
* little to no practical effect since our image size is currently
|
||||
* <64kB for all single drivers. Having a decompression routine that
|
||||
* can run in real-mode avoids the need to duplicate RM-to-PM
|
||||
* transition code from librm (or have part of librm kept
|
||||
* uncompressed, which is itself awkward) and means that we don't need
|
||||
* to set up the PM stack until we hit the setup routine itself.
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#define REG(x) x
|
||||
|
||||
.code16
|
||||
.globl decompress_block16
|
||||
decompress_block16:
|
||||
|
||||
.globl decompress
|
||||
decompress:
|
||||
/* Save the initial register values */
|
||||
#else /* CODE16 */
|
||||
|
||||
/****************************************************************************
|
||||
* decompress_block (32-bit protected-mode near call, position independent)
|
||||
*
|
||||
* Parameters (passed via registers):
|
||||
* %ds:%esi - Pointer to compressed input data
|
||||
* %es:%edi - Pointer to output buffer
|
||||
* Returns:
|
||||
* All registers are preserved
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#define REG(x) e ## x
|
||||
|
||||
.code32
|
||||
.globl decompress_block
|
||||
decompress_block:
|
||||
|
||||
#endif /* CODE16 */
|
||||
|
||||
#define xAX REG(ax)
|
||||
#define xCX REG(cx)
|
||||
#define xBP REG(bp)
|
||||
#define xSI REG(si)
|
||||
#define xDI REG(di)
|
||||
|
||||
/* Save registers */
|
||||
pushal
|
||||
|
||||
/*
|
||||
* See where I am running, and compute %ebp
|
||||
* %ebp holds delta between physical and virtual addresses.
|
||||
*/
|
||||
call 1f
|
||||
1: popl %ebp
|
||||
subl $1b, %ebp
|
||||
|
||||
/* "compressed" and "decompress_to" defined by linker script */
|
||||
/* move compressed image up to temporary area before decompressing */
|
||||
std
|
||||
movl $_compressed_size, %ecx
|
||||
leal _compressed+4-1(%ebp, %ecx), %esi
|
||||
leal _compressed_copy-1(%ebp, %ecx), %edi
|
||||
rep movsb
|
||||
/* Setup to run the decompressor */
|
||||
/* Do the decompression */
|
||||
cld
|
||||
leal _compressed_copy(%ebp), %esi
|
||||
leal decompress_to(%ebp), %edi
|
||||
movl $-1, %ebp /* last_m_off = -1 */
|
||||
xor %xBP, %xBP
|
||||
dec %xBP /* last_m_off = -1 */
|
||||
jmp dcl1_n2b
|
||||
|
||||
/* ------------- DECOMPRESSION -------------
|
||||
|
||||
Input:
|
||||
%esi - source
|
||||
%edi - dest
|
||||
%ebp - -1
|
||||
cld
|
||||
|
||||
Output:
|
||||
%eax - 0
|
||||
%ecx - 0
|
||||
*/
|
||||
|
||||
.macro getbit bits
|
||||
.if \bits == 1
|
||||
addl %ebx, %ebx
|
||||
jnz 1f
|
||||
.endif
|
||||
movl (%esi), %ebx
|
||||
subl $-4, %esi /* sets carry flag */
|
||||
adcl %ebx, %ebx
|
||||
1:
|
||||
.endm
|
||||
|
||||
|
||||
decompr_literals_n2b:
|
||||
movsb
|
||||
|
||||
decompr_loop_n2b:
|
||||
addl %ebx, %ebx
|
||||
jnz dcl2_n2b
|
||||
dcl1_n2b:
|
||||
getbit 32
|
||||
call getbit32
|
||||
dcl2_n2b:
|
||||
jc decompr_literals_n2b
|
||||
xorl %eax, %eax
|
||||
incl %eax /* m_off = 1 */
|
||||
xor %xAX, %xAX
|
||||
inc %xAX /* m_off = 1 */
|
||||
loop1_n2b:
|
||||
getbit 1
|
||||
adcl %eax, %eax /* m_off = m_off*2 + getbit() */
|
||||
getbit 1
|
||||
call getbit1
|
||||
adc %xAX, %xAX /* m_off = m_off*2 + getbit() */
|
||||
call getbit1
|
||||
jnc loop1_n2b /* while(!getbit()) */
|
||||
xorl %ecx, %ecx
|
||||
subl $3, %eax
|
||||
sub $3, %xAX
|
||||
jb decompr_ebpeax_n2b /* if (m_off == 2) goto decompr_ebpeax_n2b ? */
|
||||
shll $8, %eax
|
||||
movb (%esi), %al /* m_off = (m_off - 3)*256 + src[ilen++] */
|
||||
incl %esi
|
||||
xorl $-1, %eax
|
||||
shl $8, %xAX
|
||||
movb (%xSI), %al /* m_off = (m_off - 3)*256 + src[ilen++] */
|
||||
inc %xSI
|
||||
not %xAX
|
||||
jz decompr_end_n2b /* if (m_off == 0xffffffff) goto decomp_end_n2b */
|
||||
movl %eax, %ebp /* last_m_off = m_off ?*/
|
||||
mov %xAX, %xBP /* last_m_off = m_off ?*/
|
||||
decompr_ebpeax_n2b:
|
||||
getbit 1
|
||||
adcl %ecx, %ecx /* m_len = getbit() */
|
||||
getbit 1
|
||||
adcl %ecx, %ecx /* m_len = m_len*2 + getbit()) */
|
||||
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 */
|
||||
incl %ecx /* m_len++ */
|
||||
inc %xCX /* m_len++ */
|
||||
loop2_n2b:
|
||||
getbit 1
|
||||
adcl %ecx, %ecx /* m_len = m_len*2 + getbit() */
|
||||
getbit 1
|
||||
call getbit1
|
||||
adc %xCX, %xCX /* m_len = m_len*2 + getbit() */
|
||||
call getbit1
|
||||
jnc loop2_n2b /* while(!getbit()) */
|
||||
incl %ecx
|
||||
incl %ecx /* m_len += 2 */
|
||||
inc %xCX
|
||||
inc %xCX /* m_len += 2 */
|
||||
decompr_got_mlen_n2b:
|
||||
cmpl $-0xd00, %ebp
|
||||
adcl $1, %ecx /* m_len = m_len + 1 + (last_m_off > 0xd00) */
|
||||
pushl %esi
|
||||
leal (%edi,%ebp), %esi /* m_pos = dst + olen + -m_off */
|
||||
cmp $-0xd00, %xBP
|
||||
adc $1, %xCX /* m_len = m_len + 1 + (last_m_off > 0xd00) */
|
||||
push %xSI
|
||||
lea (%xBP,%xDI), %xSI /* m_pos = dst + olen + -m_off */
|
||||
rep
|
||||
movsb /* dst[olen++] = *m_pos++ while(m_len > 0) */
|
||||
popl %esi
|
||||
es movsb /* dst[olen++] = *m_pos++ while(m_len > 0) */
|
||||
pop %xSI
|
||||
jmp decompr_loop_n2b
|
||||
|
||||
|
||||
getbit1:
|
||||
addl %ebx, %ebx
|
||||
jnz 1f
|
||||
getbit32:
|
||||
movl (%xSI), %ebx
|
||||
sub $-4, %xSI /* sets carry flag */
|
||||
adcl %ebx, %ebx
|
||||
1:
|
||||
ret
|
||||
|
||||
decompr_end_n2b:
|
||||
/* Restore the initial register values */
|
||||
/* Restore registers and return */
|
||||
popal
|
||||
ret
|
||||
|
||||
Reference in New Issue
Block a user