From 0ff80b477dcff0726ebdbed95e8a93971e59e82b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 8 Apr 2005 15:01:17 +0000 Subject: Merged mcb30-realmode-redesign back to HEAD --- src/arch/i386/prefix/dskprefix.S | 385 ++++++++++++++++++++++++++++++++++++ src/arch/i386/prefix/floppyprefix.S | 359 --------------------------------- src/arch/i386/prefix/int19exit.c | 13 ++ src/arch/i386/prefix/unnrv2b.S | 198 +++++++++++-------- 4 files changed, 519 insertions(+), 436 deletions(-) create mode 100644 src/arch/i386/prefix/dskprefix.S delete mode 100644 src/arch/i386/prefix/floppyprefix.S create mode 100644 src/arch/i386/prefix/int19exit.c (limited to 'src/arch/i386/prefix') diff --git a/src/arch/i386/prefix/dskprefix.S b/src/arch/i386/prefix/dskprefix.S new file mode 100644 index 000000000..d1f64e7ae --- /dev/null +++ b/src/arch/i386/prefix/dskprefix.S @@ -0,0 +1,385 @@ +#include "compiler.h" + +/* NOTE: this boot sector contains instructions that need at least an 80186. + * Yes, as86 has a bug somewhere in the valid instruction set checks. + * + * SYS_SIZE is the number of clicks (16 bytes) to be loaded. + */ +.equ SYSSIZE, 8192 # 8192 * 16 bytes = 128kB maximum size of .ROM file + +/* floppyload.S Copyright (C) 1991, 1992 Linus Torvalds + * modified by Drew Eckhardt + * modified by Bruce Evans (bde) + * + * floppyprefix.S is loaded at 0x0000:0x7c00 by the bios-startup routines. + * + * It then loads the system at SYSSEG<<4, using BIOS interrupts. + * + * The loader has been made as simple as possible, and continuous read errors + * will result in a unbreakable loop. Reboot by hand. It loads pretty fast by + * getting whole tracks at a time whenever possible. + */ + +.equ BOOTSEG, 0x07C0 /* original address of boot-sector */ + +.equ SYSSEG, 0x1000 /* system loaded at SYSSEG<<4 */ + + .org 0 + .arch i386 + .text + .section ".prefix", "ax", @progbits + .code16 + + jmp $BOOTSEG, $go /* reload cs:ip to match relocation addr */ +go: + movw $0x2000-12, %di /* 0x2000 is arbitrary value >= length */ + /* of bootsect + room for stack + 12 for */ + /* saved disk parm block */ + + movw $BOOTSEG, %ax + movw %ax,%ds + movw %ax,%es + movw %ax,%ss /* put stack at BOOTSEG:0x4000-12. */ + movw %di,%sp + +/* Many BIOS's default disk parameter tables will not recognize multi-sector + * reads beyond the maximum sector number specified in the default diskette + * parameter tables - this may mean 7 sectors in some cases. + * + * Since single sector reads are slow and out of the question, we must take care + * of this by creating new parameter tables (for the first disk) in RAM. We + * will set the maximum sector count to 36 - the most we will encounter on an + * ED 2.88. High doesn't hurt. Low does. + * + * Segments are as follows: ds=es=ss=cs - BOOTSEG + */ + + xorw %cx,%cx + movw %cx,%es /* access segment 0 */ + movw $0x78, %bx /* 0:bx is parameter table address */ + pushw %ds /* save ds */ +/* 0:bx is parameter table address */ + ldsw %es:(%bx),%si /* loads ds and si */ + + movw %ax,%es /* ax is BOOTSECT (loaded above) */ + movb $6, %cl /* copy 12 bytes */ + cld + pushw %di /* keep a copy for later */ + rep + movsw /* ds:si is source, es:di is dest */ + popw %di + + movb $36,%es:4(%di) + + movw %cx,%ds /* access segment 0 */ + xchgw %di,(%bx) + movw %es,%si + xchgw %si,2(%bx) + popw %ds /* restore ds */ + movw %di, dpoff /* save old parameters */ + movw %si, dpseg /* to restore just before finishing */ + pushw %ds + popw %es /* reload es */ + +/* Note that es is already set up. Also cx is 0 from rep movsw above. */ + + xorb %ah,%ah /* reset FDC */ + xorb %dl,%dl + int $0x13 + +/* Get disk drive parameters, specifically number of sectors/track. + * + * It seems that there is no BIOS call to get the number of sectors. Guess + * 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read, + * 15 if sector 15 can be read. Otherwise guess 9. + */ + + movw $disksizes, %si /* table of sizes to try */ + +probe_loop: + lodsb + cbtw /* extend to word */ + movw %ax, sectors + cmpw $disksizes+4, %si + jae got_sectors /* if all else fails, try 9 */ + xchgw %cx,%ax /* cx = track and sector */ + xorw %dx,%dx /* drive 0, head 0 */ + movw $0x0200, %bx /* address after boot sector */ + /* (512 bytes from origin, es = cs) */ + movw $0x0201, %ax /* service 2, 1 sector */ + int $0x13 + jc probe_loop /* try next value */ + +got_sectors: + movw $msg1end-msg1, %cx + movw $msg1, %si + call print_str + +/* ok, we've written the Loading... message, now we want to load the system */ + + movw $SYSSEG, %ax + movw %ax,%es /* segment of SYSSEG<<4 */ + pushw %es + call read_it + +/* This turns off the floppy drive motor, so that we enter the kernel in a + * known state, and don't have to worry about it later. + */ + movw $0x3f2, %dx + xorb %al,%al + outb %al,%dx + + call print_nl + pop %es /* = SYSSEG */ + +/* Restore original disk parameters */ + movw $0x78, %bx + movw dpoff, %di + movw dpseg, %si + xorw %ax,%ax + movw %ax,%ds + movw %di,(%bx) + movw %si,2(%bx) + + /* Everything now loaded. %es = SYSSEG, so %es:0000 points to + * start of loaded image. + */ + +start_runtime: + +#ifdef COMPRESS + /* Decompress runtime image. %es:0000 points to decompressed + * image on exit. + */ + lcall $SYSSEG, $decompress16 +#endif + + /* Set up internal environment. Address of entry-point + * function is returned in %es:di. + */ + pushw %es /* setup16 says %ds:0000 must point to image */ + popw %ds + movw $setup16, %di + pushw %cs + call ljmp_to_es_di + + /* Call initialisation routine. Relocation may be done. New + * address of entry-point function is returned in %es:di. + */ + pushl $arch_rm_initialise + pushw %cs /* == lcall %es:di */ + call ljmp_to_es_di + + /* Call to arch_rm_main. Register INT19 as an exit path. This + * call will never return. + */ + movl $exit_via_int19, %eax + pushl $arch_rm_main + pushl %eax /* Dummy return address */ + + /* Do the equivalent of ljmp *%es:di */ +ljmp_to_es_di: + pushw %es + pushw %di + lret + +/* This routine loads the system at address SYSSEG<<4, making sure no 64kB + * boundaries are crossed. We try to load it as fast as possible, loading whole + * tracks whenever we can. + * + * in: es - starting address segment (normally SYSSEG) + */ +read_it: + movw $1,sread /* don't reload the prefix */ + movw %es,%ax + testw $0x0fff, %ax +die: jne die /* es must be at 64kB boundary */ + xorw %bx,%bx /* bx is starting address within segment */ +rp_read: + movw %es,%ax + movw %bx,%dx + movb $4, %cl + shrw %cl,%dx /* bx is always divisible by 16 */ + addw %dx,%ax + cmpw $SYSSEG+SYSSIZE, %ax /* have we loaded all yet? */ + jb ok1_read + ret +ok1_read: + movw sectors, %ax + subw sread, %ax + movw %ax,%cx + shlw $9, %cx + addw %bx,%cx + jnc ok2_read + je ok2_read + xorw %ax,%ax + subw %bx,%ax + shrw $9, %ax +ok2_read: + call read_track + movw %ax,%cx + addw sread, %ax + cmpw sectors, %ax + jne ok3_read + movw $1, %ax + subw head, %ax + jne ok4_read + incw track +ok4_read: + movw %ax, head + xorw %ax,%ax +ok3_read: + movw %ax, sread + shlw $9, %cx + addw %cx,%bx + jnc rp_read + movw %es,%ax + addb $0x10, %ah + movw %ax,%es + xorw %bx,%bx + jmp rp_read + +read_track: + pusha + pushw %ax + pushw %bx + pushw %bp /* just in case the BIOS is buggy */ + movw $0x0e2e, %ax /* 0x2e = . */ + movw $0x0007, %bx + int $0x10 + popw %bp + popw %bx + popw %ax + + movw track, %dx + movw sread, %cx + incw %cx + movb %dl,%ch + movw head, %dx + movb %dl,%dh + andw $0x0100, %dx + movb $2, %ah + + pushw %dx /* save for error dump */ + pushw %cx + pushw %bx + pushw %ax + + int $0x13 + jc bad_rt + addw $8, %sp + popa + ret + +bad_rt: pushw %ax /* save error code */ + call print_all /* ah = error, al = read */ + + xorb %ah,%ah + xorb %dl,%dl + int $0x13 + + addw $10, %sp + popa + jmp read_track + +/* print_all is for debugging purposes. It will print out all of the registers. + * The assumption is that this is called from a routine, with a stack frame like + * dx + * cx + * bx + * ax + * error + * ret <- sp + */ + +print_all: + call print_nl /* nl for readability */ + movw $5, %cx /* error code + 4 registers */ + movw %sp,%bp + +print_loop: + pushw %cx /* save count left */ + + cmpb $5, %cl + jae no_reg /* see if register name is needed */ + + movw $0x0007, %bx /* page 0, attribute 7 (normal) */ + movw $0xe05+0x41-1, %ax + subb %cl,%al + int $0x10 + + movb $0x58, %al /* 'X' */ + int $0x10 + + movb $0x3A, %al /* ':' */ + int $0x10 + +no_reg: + addw $2, %bp /* next register */ + call print_hex /* print it */ + movb $0x20, %al /* print a space */ + int $0x10 + popw %cx + loop print_loop + call print_nl /* nl for readability */ + ret + +print_str: + movw $0x0007, %bx /* page 0, attribute 7 (normal) */ + movb $0x0e, %ah /* write char, tty mode */ +prloop: + lodsb + int $0x10 + loop prloop + ret + +print_nl: + movw $0x0007, %bx /* page 0, attribute 7 (normal) */ + movw $0xe0d, %ax /* CR */ + int $0x10 + movb $0xa, %al /* LF */ + int $0x10 + ret + +/* print_hex prints the word pointed to by ss:bp in hexadecimal. */ + +print_hex: + movw (%bp),%dx /* load word into dx */ + movb $4, %cl + movb $0x0e, %ah /* write char, tty mode */ + movw $0x0007, %bx /* page 0, attribute 7 (normal) */ + call print_digit + call print_digit + call print_digit +/* fall through */ +print_digit: + rol %cl,%dx /* rotate so that lowest 4 bits are used */ + movb $0x0f, %al /* mask for nybble */ + andb %dl,%al + addb $0x90, %al /* convert al to ascii hex (four instructions) */ + daa + adcb $0x40, %al + daa + int $0x10 + ret + +sread: .word 0 /* sectors read of current track */ +head: .word 0 /* current head */ +track: .word 0 /* current track */ + +sectors: + .word 0 + +dpseg: .word 0 +dpoff: .word 0 + +disksizes: + .byte 36,18,15,9 + +msg1: + .ascii "Loading ROM image" +msg1end: + + .org 510, 0 + .word 0xAA55 + diff --git a/src/arch/i386/prefix/floppyprefix.S b/src/arch/i386/prefix/floppyprefix.S deleted file mode 100644 index 18bed4c8f..000000000 --- a/src/arch/i386/prefix/floppyprefix.S +++ /dev/null @@ -1,359 +0,0 @@ -/* NOTE: this boot sector contains instructions that need at least an 80186. - * Yes, as86 has a bug somewhere in the valid instruction set checks. - * - * SYS_SIZE is the number of clicks (16 bytes) to be loaded. - */ -.equ SYSSIZE, 8192 # 8192 * 16 bytes = 128kB maximum size of .ROM file - -/* floppyload.S Copyright (C) 1991, 1992 Linus Torvalds - * modified by Drew Eckhardt - * modified by Bruce Evans (bde) - * - * floppyprefix.S is loaded at 0x0000:0x7c00 by the bios-startup routines. - * - * It then loads the system at SYSSEG<<4, using BIOS interrupts. - * - * The loader has been made as simple as possible, and continuous read errors - * will result in a unbreakable loop. Reboot by hand. It loads pretty fast by - * getting whole tracks at a time whenever possible. - */ - -.equ BOOTSEG, 0x07C0 /* original address of boot-sector */ - -.equ SYSSEG, 0x1000 /* system loaded at SYSSEG<<4 */ - - .org 0 - .arch i386 - .text - .section ".prefix", "ax", @progbits - .code16 - - jmp $BOOTSEG, $go /* reload cs:ip to match relocation addr */ -go: - movw $0x2000-12, %di /* 0x2000 is arbitrary value >= length */ - /* of bootsect + room for stack + 12 for */ - /* saved disk parm block */ - - movw $BOOTSEG, %ax - movw %ax,%ds - movw %ax,%es - movw %ax,%ss /* put stack at BOOTSEG:0x4000-12. */ - movw %di,%sp - -/* Many BIOS's default disk parameter tables will not recognize multi-sector - * reads beyond the maximum sector number specified in the default diskette - * parameter tables - this may mean 7 sectors in some cases. - * - * Since single sector reads are slow and out of the question, we must take care - * of this by creating new parameter tables (for the first disk) in RAM. We - * will set the maximum sector count to 36 - the most we will encounter on an - * ED 2.88. High doesn't hurt. Low does. - * - * Segments are as follows: ds=es=ss=cs - BOOTSEG - */ - - xorw %cx,%cx - movw %cx,%es /* access segment 0 */ - movw $0x78, %bx /* 0:bx is parameter table address */ - pushw %ds /* save ds */ -/* 0:bx is parameter table address */ - ldsw %es:(%bx),%si /* loads ds and si */ - - movw %ax,%es /* ax is BOOTSECT (loaded above) */ - movb $6, %cl /* copy 12 bytes */ - cld - pushw %di /* keep a copy for later */ - rep - movsw /* ds:si is source, es:di is dest */ - popw %di - - movb $36,%es:4(%di) - - movw %cx,%ds /* access segment 0 */ - xchgw %di,(%bx) - movw %es,%si - xchgw %si,2(%bx) - popw %ds /* restore ds */ - movw %di, dpoff /* save old parameters */ - movw %si, dpseg /* to restore just before finishing */ - pushw %ds - popw %es /* reload es */ - -/* Note that es is already set up. Also cx is 0 from rep movsw above. */ - - xorb %ah,%ah /* reset FDC */ - xorb %dl,%dl - int $0x13 - -/* Get disk drive parameters, specifically number of sectors/track. - * - * It seems that there is no BIOS call to get the number of sectors. Guess - * 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read, - * 15 if sector 15 can be read. Otherwise guess 9. - */ - - movw $disksizes, %si /* table of sizes to try */ - -probe_loop: - lodsb - cbtw /* extend to word */ - movw %ax, sectors - cmpw $disksizes+4, %si - jae got_sectors /* if all else fails, try 9 */ - xchgw %cx,%ax /* cx = track and sector */ - xorw %dx,%dx /* drive 0, head 0 */ - movw $0x0200, %bx /* address after boot sector */ - /* (512 bytes from origin, es = cs) */ - movw $0x0201, %ax /* service 2, 1 sector */ - int $0x13 - jc probe_loop /* try next value */ - -got_sectors: - movw $msg1end-msg1, %cx - movw $msg1, %si - call print_str - -/* ok, we've written the Loading... message, now we want to load the system */ - - pushw %es /* = ds */ - movw $SYSSEG, %ax - movw %ax,%es /* segment of SYSSEG<<4 */ - pushw %es - call read_it - -/* This turns off the floppy drive motor, so that we enter the kernel in a - * known state, and don't have to worry about it later. - */ - movw $0x3f2, %dx - xorb %al,%al - outb %al,%dx - - call print_nl - pop %es /* = SYSSEG */ - pop %es /* balance push/pop es */ -sigok: - -/* Restore original disk parameters */ - movw $0x78, %bx - movw dpoff, %di - movw dpseg, %si - xorw %ax,%ax - movw %ax,%ds - movw %di,(%bx) - movw %si,2(%bx) - -/* after that (everything loaded), we call to the .ROM file loaded. */ - - pushl $0 /* No parameters to preserve for exit path */ - pushw $0 /* Use prefix exit path mechanism */ - ljmp $SYSSEG, $_start - - .section ".text16", "ax", @progbits - .globl prefix_exit -prefix_exit: - xchgw %bx, %bx - int $0x19 /* should try to boot machine */ - .globl prefix_exit_end -prefix_exit_end: - .previous - -/* This routine loads the system at address SYSSEG<<4, making sure no 64kB - * boundaries are crossed. We try to load it as fast as possible, loading whole - * tracks whenever we can. - * - * in: es - starting address segment (normally SYSSEG) - */ -read_it: - movw $0,sread /* read whole image incl boot sector */ - movw %es,%ax - testw $0x0fff, %ax -die: jne die /* es must be at 64kB boundary */ - xorw %bx,%bx /* bx is starting address within segment */ -rp_read: - movw %es,%ax - movw %bx,%dx - movb $4, %cl - shrw %cl,%dx /* bx is always divisible by 16 */ - addw %dx,%ax - cmpw $SYSSEG+SYSSIZE, %ax /* have we loaded all yet? */ - jb ok1_read - ret -ok1_read: - movw sectors, %ax - subw sread, %ax - movw %ax,%cx - shlw $9, %cx - addw %bx,%cx - jnc ok2_read - je ok2_read - xorw %ax,%ax - subw %bx,%ax - shrw $9, %ax -ok2_read: - call read_track - movw %ax,%cx - addw sread, %ax - cmpw sectors, %ax - jne ok3_read - movw $1, %ax - subw head, %ax - jne ok4_read - incw track -ok4_read: - movw %ax, head - xorw %ax,%ax -ok3_read: - movw %ax, sread - shlw $9, %cx - addw %cx,%bx - jnc rp_read - movw %es,%ax - addb $0x10, %ah - movw %ax,%es - xorw %bx,%bx - jmp rp_read - -read_track: - pusha - pushw %ax - pushw %bx - pushw %bp /* just in case the BIOS is buggy */ - movw $0x0e2e, %ax /* 0x2e = . */ - movw $0x0007, %bx - int $0x10 - popw %bp - popw %bx - popw %ax - - movw track, %dx - movw sread, %cx - incw %cx - movb %dl,%ch - movw head, %dx - movb %dl,%dh - andw $0x0100, %dx - movb $2, %ah - - pushw %dx /* save for error dump */ - pushw %cx - pushw %bx - pushw %ax - - int $0x13 - jc bad_rt - addw $8, %sp - popa - ret - -bad_rt: pushw %ax /* save error code */ - call print_all /* ah = error, al = read */ - - xorb %ah,%ah - xorb %dl,%dl - int $0x13 - - addw $10, %sp - popa - jmp read_track - -/* print_all is for debugging purposes. It will print out all of the registers. - * The assumption is that this is called from a routine, with a stack frame like - * dx - * cx - * bx - * ax - * error - * ret <- sp - */ - -print_all: - call print_nl /* nl for readability */ - movw $5, %cx /* error code + 4 registers */ - movw %sp,%bp - -print_loop: - pushw %cx /* save count left */ - - cmpb $5, %cl - jae no_reg /* see if register name is needed */ - - movw $0x0007, %bx /* page 0, attribute 7 (normal) */ - movw $0xe05+0x41-1, %ax - subb %cl,%al - int $0x10 - - movb $0x58, %al /* 'X' */ - int $0x10 - - movb $0x3A, %al /* ':' */ - int $0x10 - -no_reg: - addw $2, %bp /* next register */ - call print_hex /* print it */ - movb $0x20, %al /* print a space */ - int $0x10 - popw %cx - loop print_loop - call print_nl /* nl for readability */ - ret - -print_str: - movw $0x0007, %bx /* page 0, attribute 7 (normal) */ - movb $0x0e, %ah /* write char, tty mode */ -prloop: - lodsb - int $0x10 - loop prloop - ret - -print_nl: - movw $0x0007, %bx /* page 0, attribute 7 (normal) */ - movw $0xe0d, %ax /* CR */ - int $0x10 - movb $0xa, %al /* LF */ - int $0x10 - ret - -/* print_hex prints the word pointed to by ss:bp in hexadecimal. */ - -print_hex: - movw (%bp),%dx /* load word into dx */ - movb $4, %cl - movb $0x0e, %ah /* write char, tty mode */ - movw $0x0007, %bx /* page 0, attribute 7 (normal) */ - call print_digit - call print_digit - call print_digit -/* fall through */ -print_digit: - rol %cl,%dx /* rotate so that lowest 4 bits are used */ - movb $0x0f, %al /* mask for nybble */ - andb %dl,%al - addb $0x90, %al /* convert al to ascii hex (four instructions) */ - daa - adcb $0x40, %al - daa - int $0x10 - ret - -sread: .word 0 /* sectors read of current track */ -head: .word 0 /* current head */ -track: .word 0 /* current track */ - -sectors: - .word 0 - -dpseg: .word 0 -dpoff: .word 0 - -disksizes: - .byte 36,18,15,9 - -msg1: - .ascii "Loading ROM image" -msg1end: - - .org 510, 0 - .word 0xAA55 - diff --git a/src/arch/i386/prefix/int19exit.c b/src/arch/i386/prefix/int19exit.c new file mode 100644 index 000000000..e7be06244 --- /dev/null +++ b/src/arch/i386/prefix/int19exit.c @@ -0,0 +1,13 @@ +#include "bochs.h" +#include "realmode.h" + +/* + * The "exit via INT 19" exit path. INT 19 is the old (pre-BBS) "boot + * system" interrupt. + * + */ + +void exit_via_int19 ( struct real_mode_regs *rm_regs ) { + bochsbp(); + /* Placeholder */ +} diff --git a/src/arch/i386/prefix/unnrv2b.S b/src/arch/i386/prefix/unnrv2b.S index 1836fa715..50776dc93 100644 --- a/src/arch/i386/prefix/unnrv2b.S +++ b/src/arch/i386/prefix/unnrv2b.S @@ -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 - - .globl decompress -decompress: - /* Save the initial register values */ - 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 +#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 - /* "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 */ - cld - leal _compressed_copy(%ebp), %esi - leal decompress_to(%ebp), %edi - movl $-1, %ebp /* last_m_off = -1 */ - jmp dcl1_n2b + .code16 + .globl decompress_block16 +decompress_block16: + +#else /* CODE16 */ -/* ------------- DECOMPRESSION ------------- +/**************************************************************************** + * 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 + **************************************************************************** + */ - Input: - %esi - source - %edi - dest - %ebp - -1 - cld +#define REG(x) e ## x + + .code32 + .globl decompress_block +decompress_block: - Output: - %eax - 0 - %ecx - 0 -*/ +#endif /* CODE16 */ -.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 +#define xAX REG(ax) +#define xCX REG(cx) +#define xBP REG(bp) +#define xSI REG(si) +#define xDI REG(di) + /* Save registers */ + pushal + /* Do the decompression */ + cld + xor %xBP, %xBP + dec %xBP /* last_m_off = -1 */ + jmp dcl1_n2b + 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 -- cgit v1.2.3-55-g7522