summaryrefslogtreecommitdiffstats
path: root/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/libprefix.S
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/libprefix.S')
-rw-r--r--contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/libprefix.S819
1 files changed, 819 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/libprefix.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/libprefix.S
new file mode 100644
index 0000000..9e6ba6f
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/prefix/libprefix.S
@@ -0,0 +1,819 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+ .arch i386
+
+/**
+ * High memory temporary load address
+ *
+ * Temporary buffer into which to copy (or decompress) our runtime
+ * image, prior to calling get_memmap() and relocate(). We don't
+ * actually leave anything here once install() has returned.
+ *
+ * We use the start of an even megabyte so that we don't have to worry
+ * about the current state of the A20 line.
+ *
+ * We use 4MB rather than 2MB because some PXE stack / PMM BIOS
+ * combinations are known to place data required by other UNDI ROMs
+ * loader around the 2MB mark.
+ */
+ .globl HIGHMEM_LOADPOINT
+ .equ HIGHMEM_LOADPOINT, ( 4 << 20 )
+
+/* Image compression enabled */
+#define COMPRESS 1
+
+#define CR0_PE 1
+
+/*****************************************************************************
+ * Utility function: print character (with LF -> LF,CR translation)
+ *
+ * Parameters:
+ * %al : character to print
+ * %ds:di : output buffer (or %di=0 to print to console)
+ * Returns:
+ * %ds:di : next character in output buffer (if applicable)
+ *****************************************************************************
+ */
+ .section ".prefix.lib", "awx", @progbits
+ .code16
+ .globl print_character
+print_character:
+ /* Preserve registers */
+ pushw %ax
+ pushw %bx
+ pushw %bp
+ /* If %di is non-zero, write character to buffer and exit */
+ testw %di, %di
+ jz 1f
+ movb %al, %ds:(%di)
+ incw %di
+ jmp 3f
+1: /* Print character */
+ movw $0x0007, %bx /* page 0, attribute 7 (normal) */
+ movb $0x0e, %ah /* write char, tty mode */
+ cmpb $0x0a, %al /* '\n'? */
+ jne 2f
+ int $0x10
+ movb $0x0d, %al
+2: int $0x10
+ /* Restore registers and return */
+3: popw %bp
+ popw %bx
+ popw %ax
+ ret
+ .size print_character, . - print_character
+
+/*****************************************************************************
+ * Utility function: print a NUL-terminated string
+ *
+ * Parameters:
+ * %ds:si : string to print
+ * %ds:di : output buffer (or %di=0 to print to console)
+ * Returns:
+ * %ds:si : character after terminating NUL
+ * %ds:di : next character in output buffer (if applicable)
+ *****************************************************************************
+ */
+ .section ".prefix.lib", "awx", @progbits
+ .code16
+ .globl print_message
+print_message:
+ /* Preserve registers */
+ pushw %ax
+ /* Print string */
+1: lodsb
+ testb %al, %al
+ je 2f
+ call print_character
+ jmp 1b
+2: /* Restore registers and return */
+ popw %ax
+ ret
+ .size print_message, . - print_message
+
+/*****************************************************************************
+ * Utility functions: print hex digit/byte/word/dword
+ *
+ * Parameters:
+ * %al (low nibble) : digit to print
+ * %al : byte to print
+ * %ax : word to print
+ * %eax : dword to print
+ * %ds:di : output buffer (or %di=0 to print to console)
+ * Returns:
+ * %ds:di : next character in output buffer (if applicable)
+ *****************************************************************************
+ */
+ .section ".prefix.lib", "awx", @progbits
+ .code16
+ .globl print_hex_dword
+print_hex_dword:
+ rorl $16, %eax
+ call print_hex_word
+ rorl $16, %eax
+ /* Fall through */
+ .size print_hex_dword, . - print_hex_dword
+ .globl print_hex_word
+print_hex_word:
+ xchgb %al, %ah
+ call print_hex_byte
+ xchgb %al, %ah
+ /* Fall through */
+ .size print_hex_word, . - print_hex_word
+ .globl print_hex_byte
+print_hex_byte:
+ rorb $4, %al
+ call print_hex_nibble
+ rorb $4, %al
+ /* Fall through */
+ .size print_hex_byte, . - print_hex_byte
+ .globl print_hex_nibble
+print_hex_nibble:
+ /* Preserve registers */
+ pushw %ax
+ /* Print digit (technique by Norbert Juffa <norbert.juffa@amd.com> */
+ andb $0x0f, %al
+ cmpb $10, %al
+ sbbb $0x69, %al
+ das
+ call print_character
+ /* Restore registers and return */
+ popw %ax
+ ret
+ .size print_hex_nibble, . - print_hex_nibble
+
+/*****************************************************************************
+ * Utility function: print PCI bus:dev.fn
+ *
+ * Parameters:
+ * %ax : PCI bus:dev.fn to print
+ * %ds:di : output buffer (or %di=0 to print to console)
+ * Returns:
+ * %ds:di : next character in output buffer (if applicable)
+ *****************************************************************************
+ */
+ .section ".prefix.lib", "awx", @progbits
+ .code16
+ .globl print_pci_busdevfn
+print_pci_busdevfn:
+ /* Preserve registers */
+ pushw %ax
+ /* Print bus */
+ xchgb %al, %ah
+ call print_hex_byte
+ /* Print ":" */
+ movb $( ':' ), %al
+ call print_character
+ /* Print device */
+ movb %ah, %al
+ shrb $3, %al
+ call print_hex_byte
+ /* Print "." */
+ movb $( '.' ), %al
+ call print_character
+ /* Print function */
+ movb %ah, %al
+ andb $0x07, %al
+ call print_hex_nibble
+ /* Restore registers and return */
+ popw %ax
+ ret
+ .size print_pci_busdevfn, . - print_pci_busdevfn
+
+/*****************************************************************************
+ * Utility function: clear current line
+ *
+ * Parameters:
+ * %ds:di : output buffer (or %di=0 to print to console)
+ * Returns:
+ * %ds:di : next character in output buffer (if applicable)
+ *****************************************************************************
+ */
+ .section ".prefix.lib", "awx", @progbits
+ .code16
+ .globl print_kill_line
+print_kill_line:
+ /* Preserve registers */
+ pushw %ax
+ pushw %cx
+ /* Print CR */
+ movb $( '\r' ), %al
+ call print_character
+ /* Print 79 spaces */
+ movb $( ' ' ), %al
+ movw $79, %cx
+1: call print_character
+ loop 1b
+ /* Print CR */
+ movb $( '\r' ), %al
+ call print_character
+ /* Restore registers and return */
+ popw %cx
+ popw %ax
+ ret
+ .size print_kill_line, . - print_kill_line
+
+/****************************************************************************
+ * pm_call (real-mode near call)
+ *
+ * Call routine in 16-bit protected mode for access to extended memory
+ *
+ * Parameters:
+ * %ax : address of routine to call in 16-bit protected mode
+ * Returns:
+ * none
+ * Corrupts:
+ * %ax
+ *
+ * The specified routine is called in 16-bit protected mode, with:
+ *
+ * %cs : 16-bit code segment with base matching real-mode %cs
+ * %ss : 16-bit data segment with base matching real-mode %ss
+ * %ds,%es,%fs,%gs : 32-bit data segment with zero base and 4GB limit
+ *
+ ****************************************************************************
+ */
+
+#ifndef KEEP_IT_REAL
+
+ /* GDT for protected-mode calls */
+ .section ".prefix.lib", "awx", @progbits
+ .align 16
+pm_call_vars:
+gdt:
+gdt_limit: .word gdt_length - 1
+gdt_base: .long 0
+ .word 0 /* padding */
+pm_cs: /* 16-bit protected-mode code segment */
+ .equ PM_CS, pm_cs - gdt
+ .word 0xffff, 0
+ .byte 0, 0x9b, 0x00, 0
+pm_ss: /* 16-bit protected-mode stack segment */
+ .equ PM_SS, pm_ss - gdt
+ .word 0xffff, 0
+ .byte 0, 0x93, 0x00, 0
+pm_ds: /* 32-bit protected-mode flat data segment */
+ .equ PM_DS, pm_ds - gdt
+ .word 0xffff, 0
+ .byte 0, 0x93, 0xcf, 0
+gdt_end:
+ .equ gdt_length, . - gdt
+ .size gdt, . - gdt
+
+ .section ".prefix.lib", "awx", @progbits
+ .align 16
+pm_saved_gdt:
+ .long 0, 0
+ .size pm_saved_gdt, . - pm_saved_gdt
+
+ .equ pm_call_vars_size, . - pm_call_vars
+#define PM_CALL_VAR(x) ( -pm_call_vars_size + ( (x) - pm_call_vars ) )
+
+ .section ".prefix.lib", "awx", @progbits
+ .code16
+pm_call:
+ /* Preserve registers, flags, and RM return point */
+ pushw %bp
+ movw %sp, %bp
+ subw $pm_call_vars_size, %sp
+ andw $0xfff0, %sp
+ pushfl
+ pushw %gs
+ pushw %fs
+ pushw %es
+ pushw %ds
+ pushw %ss
+ pushw %cs
+ pushw $99f
+
+ /* Set up local variable block, and preserve GDT */
+ pushw %cx
+ pushw %si
+ pushw %di
+ pushw %ss
+ popw %es
+ movw $pm_call_vars, %si
+ leaw PM_CALL_VAR(pm_call_vars)(%bp), %di
+ movw $pm_call_vars_size, %cx
+ cs rep movsb
+ popw %di
+ popw %si
+ popw %cx
+ sgdt PM_CALL_VAR(pm_saved_gdt)(%bp)
+
+ /* Set up GDT bases */
+ pushl %eax
+ pushl %edi
+ xorl %eax, %eax
+ movw %ss, %ax
+ shll $4, %eax
+ movzwl %bp, %edi
+ addr32 leal PM_CALL_VAR(gdt)(%eax, %edi), %eax
+ movl %eax, PM_CALL_VAR(gdt_base)(%bp)
+ movw %cs, %ax
+ movw $PM_CALL_VAR(pm_cs), %di
+ call set_seg_base
+ movw %ss, %ax
+ movw $PM_CALL_VAR(pm_ss), %di
+ call set_seg_base
+ popl %edi
+ popl %eax
+
+ /* Switch CPU to protected mode and load up segment registers */
+ pushl %eax
+ cli
+ data32 lgdt PM_CALL_VAR(gdt)(%bp)
+ movl %cr0, %eax
+ orb $CR0_PE, %al
+ movl %eax, %cr0
+ ljmp $PM_CS, $1f
+1: movw $PM_SS, %ax
+ movw %ax, %ss
+ movw $PM_DS, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+ popl %eax
+
+ /* Call PM routine */
+ call *%ax
+
+ /* Set real-mode segment limits on %ds, %es, %fs and %gs */
+ movw %ss, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+
+ /* Return CPU to real mode */
+ movl %cr0, %eax
+ andb $0!CR0_PE, %al
+ movl %eax, %cr0
+
+ /* Restore registers and flags */
+ lret /* will ljmp to 99f */
+99: popw %ss
+ popw %ds
+ popw %es
+ popw %fs
+ popw %gs
+ data32 lgdt PM_CALL_VAR(pm_saved_gdt)(%bp)
+ popfl
+ movw %bp, %sp
+ popw %bp
+ ret
+ .size pm_call, . - pm_call
+
+set_seg_base:
+ rolw $4, %ax
+ movw %ax, 2(%bp,%di)
+ andw $0xfff0, 2(%bp,%di)
+ movb %al, 4(%bp,%di)
+ andb $0x0f, 4(%bp,%di)
+ ret
+ .size set_seg_base, . - set_seg_base
+
+#endif /* KEEP_IT_REAL */
+
+/****************************************************************************
+ * copy_bytes (real-mode or 16-bit protected-mode near call)
+ *
+ * Copy bytes
+ *
+ * Parameters:
+ * %ds:esi : source address
+ * %es:edi : destination address
+ * %ecx : length
+ * Returns:
+ * %ds:esi : next source address
+ * %es:edi : next destination address
+ * Corrupts:
+ * None
+ ****************************************************************************
+ */
+ .section ".prefix.lib", "awx", @progbits
+ .code16
+copy_bytes:
+ pushl %ecx
+ rep addr32 movsb
+ popl %ecx
+ ret
+ .size copy_bytes, . - copy_bytes
+
+/****************************************************************************
+ * install_block (real-mode near call)
+ *
+ * Install block to specified address
+ *
+ * Parameters:
+ * %esi : source physical address (must be a multiple of 16)
+ * %edi : destination physical address (must be a multiple of 16)
+ * %ecx : length of (decompressed) data
+ * %edx : total length of block (including any uninitialised data portion)
+ * Returns:
+ * %esi : next source physical address (will be a multiple of 16)
+ * Corrupts:
+ * none
+ ****************************************************************************
+ */
+ .section ".prefix.lib", "awx", @progbits
+ .code16
+install_block:
+
+#ifdef KEEP_IT_REAL
+
+ /* Preserve registers */
+ pushw %ds
+ pushw %es
+ pushl %ecx
+ pushl %edi
+
+ /* Convert %esi and %edi to segment registers */
+ shrl $4, %esi
+ movw %si, %ds
+ xorw %si, %si
+ shrl $4, %edi
+ movw %di, %es
+ xorw %di, %di
+
+#else /* KEEP_IT_REAL */
+
+ /* Call self in protected mode */
+ pushw %ax
+ movw $1f, %ax
+ call pm_call
+ popw %ax
+ ret
+1:
+ /* Preserve registers */
+ pushl %ecx
+ pushl %edi
+
+#endif /* KEEP_IT_REAL */
+
+
+#if COMPRESS
+ /* Decompress source to destination */
+ call decompress16
+#else
+ /* Copy source to destination */
+ call copy_bytes
+#endif
+
+ /* Zero .bss portion */
+ negl %ecx
+ addl %edx, %ecx
+ pushw %ax
+ xorw %ax, %ax
+ rep addr32 stosb
+ popw %ax
+
+ /* Round up %esi to start of next source block */
+ addl $0xf, %esi
+ andl $~0xf, %esi
+
+
+#ifdef KEEP_IT_REAL
+
+ /* Convert %ds:esi back to a physical address */
+ movzwl %ds, %cx
+ shll $4, %ecx
+ addl %ecx, %esi
+
+ /* Restore registers */
+ popl %edi
+ popl %ecx
+ popw %es
+ popw %ds
+
+#else /* KEEP_IT_REAL */
+
+ /* Restore registers */
+ popl %edi
+ popl %ecx
+
+#endif
+
+ ret
+ .size install_block, . - install_block
+
+/****************************************************************************
+ * alloc_basemem (real-mode near call)
+ *
+ * Allocate space for .text16 and .data16 from top of base memory.
+ * Memory is allocated using the BIOS free base memory counter at
+ * 0x40:13.
+ *
+ * Parameters:
+ * none
+ * Returns:
+ * %ax : .text16 segment address
+ * %bx : .data16 segment address
+ * Corrupts:
+ * none
+ ****************************************************************************
+ */
+ .section ".prefix.lib", "awx", @progbits
+ .code16
+ .globl alloc_basemem
+alloc_basemem:
+ /* Preserve registers */
+ pushw %fs
+
+ /* FBMS => %ax as segment address */
+ pushw $0x40
+ popw %fs
+ movw %fs:0x13, %ax
+ shlw $6, %ax
+
+ /* Calculate .data16 segment address */
+ subw $_data16_memsz_pgh, %ax
+ pushw %ax
+
+ /* Calculate .text16 segment address */
+ subw $_text16_memsz_pgh, %ax
+ pushw %ax
+
+ /* Update FBMS */
+ shrw $6, %ax
+ movw %ax, %fs:0x13
+
+ /* Retrieve .text16 and .data16 segment addresses */
+ popw %ax
+ popw %bx
+
+ /* Restore registers and return */
+ popw %fs
+ ret
+ .size alloc_basemem, . - alloc_basemem
+
+/****************************************************************************
+ * free_basemem (real-mode near call)
+ *
+ * Free space allocated with alloc_basemem.
+ *
+ * Parameters:
+ * %ax : .text16 segment address
+ * %bx : .data16 segment address
+ * Returns:
+ * %ax : 0 if successfully freed
+ * Corrupts:
+ * none
+ ****************************************************************************
+ */
+ .section ".text16", "ax", @progbits
+ .code16
+ .globl free_basemem
+free_basemem:
+ /* Preserve registers */
+ pushw %fs
+
+ /* Check FBMS counter */
+ pushw %ax
+ shrw $6, %ax
+ pushw $0x40
+ popw %fs
+ cmpw %ax, %fs:0x13
+ popw %ax
+ jne 1f
+
+ /* Check hooked interrupt count */
+ cmpw $0, %cs:hooked_bios_interrupts
+ jne 1f
+
+ /* OK to free memory */
+ addw $_text16_memsz_pgh, %ax
+ addw $_data16_memsz_pgh, %ax
+ shrw $6, %ax
+ movw %ax, %fs:0x13
+ xorw %ax, %ax
+
+1: /* Restore registers and return */
+ popw %fs
+ ret
+ .size free_basemem, . - free_basemem
+
+ .section ".text16.data", "aw", @progbits
+ .globl hooked_bios_interrupts
+hooked_bios_interrupts:
+ .word 0
+ .size hooked_bios_interrupts, . - hooked_bios_interrupts
+
+/****************************************************************************
+ * install (real-mode near call)
+ *
+ * Install all text and data segments.
+ *
+ * Parameters:
+ * none
+ * Returns:
+ * %ax : .text16 segment address
+ * %bx : .data16 segment address
+ * Corrupts:
+ * none
+ ****************************************************************************
+ */
+ .section ".prefix.lib", "awx", @progbits
+ .code16
+ .globl install
+install:
+ /* Preserve registers */
+ pushl %esi
+ pushl %edi
+ /* Allocate space for .text16 and .data16 */
+ call alloc_basemem
+ /* Image source = %cs:0000 */
+ xorl %esi, %esi
+ /* Image destination = HIGHMEM_LOADPOINT */
+ movl $HIGHMEM_LOADPOINT, %edi
+ /* Install text and data segments */
+ call install_prealloc
+ /* Restore registers and return */
+ popl %edi
+ popl %esi
+ ret
+ .size install, . - install
+
+/****************************************************************************
+ * install_prealloc (real-mode near call)
+ *
+ * Install all text and data segments.
+ *
+ * Parameters:
+ * %ax : .text16 segment address
+ * %bx : .data16 segment address
+ * %esi : Image source physical address (or zero for %cs:0000)
+ * %edi : Decompression temporary area physical address
+ * Corrupts:
+ * none
+ ****************************************************************************
+ */
+ .section ".prefix.lib", "awx", @progbits
+ .code16
+ .globl install_prealloc
+install_prealloc:
+ /* Save registers */
+ pushal
+ pushw %ds
+ pushw %es
+
+ /* Sanity: clear the direction flag asap */
+ cld
+
+ /* Calculate physical address of payload (i.e. first source) */
+ testl %esi, %esi
+ jnz 1f
+ movw %cs, %si
+ shll $4, %esi
+1: addl $_payload_lma, %esi
+
+ /* Install .text16 and .data16 */
+ pushl %edi
+ movzwl %ax, %edi
+ shll $4, %edi
+ movl $_text16_memsz, %ecx
+ movl %ecx, %edx
+ call install_block /* .text16 */
+ movzwl %bx, %edi
+ shll $4, %edi
+ movl $_data16_filesz, %ecx
+ movl $_data16_memsz, %edx
+ call install_block /* .data16 */
+ popl %edi
+
+ /* Set up %ds for access to .data16 */
+ movw %bx, %ds
+
+#ifdef KEEP_IT_REAL
+ /* Initialise libkir */
+ movw %ax, (init_libkir_vector+2)
+ lcall *init_libkir_vector
+#else
+ /* Install .text and .data to temporary area in high memory,
+ * prior to reading the E820 memory map and relocating
+ * properly.
+ */
+ movl $_textdata_filesz, %ecx
+ movl $_textdata_memsz, %edx
+ call install_block
+
+ /* Initialise librm at current location */
+ movw %ax, (init_librm_vector+2)
+ lcall *init_librm_vector
+
+ /* Call relocate() to determine target address for relocation.
+ * relocate() will return with %esi, %edi and %ecx set up
+ * ready for the copy to the new location.
+ */
+ movw %ax, (prot_call_vector+2)
+ pushl $relocate
+ lcall *prot_call_vector
+ popl %edx /* discard */
+
+ /* Copy code to new location */
+ pushl %edi
+ pushw %ax
+ movw $copy_bytes, %ax
+ call pm_call
+ popw %ax
+ popl %edi
+
+ /* Initialise librm at new location */
+ lcall *init_librm_vector
+
+#endif
+ /* Restore registers */
+ popw %es
+ popw %ds
+ popal
+ ret
+ .size install_prealloc, . - install_prealloc
+
+ /* Vectors for far calls to .text16 functions */
+ .section ".data16", "aw", @progbits
+#ifdef KEEP_IT_REAL
+init_libkir_vector:
+ .word init_libkir
+ .word 0
+ .size init_libkir_vector, . - init_libkir_vector
+#else
+init_librm_vector:
+ .word init_librm
+ .word 0
+ .size init_librm_vector, . - init_librm_vector
+prot_call_vector:
+ .word prot_call
+ .word 0
+ .size prot_call_vector, . - prot_call_vector
+#endif
+
+/****************************************************************************
+ * uninstall (real-mode near call)
+ *
+ * Uninstall all text and data segments.
+ *
+ * Parameters:
+ * %ax : .text16 segment address
+ * %bx : .data16 segment address
+ * Returns:
+ * none
+ * Corrupts:
+ * none
+ ****************************************************************************
+ */
+ .section ".text16", "ax", @progbits
+ .code16
+ .globl uninstall
+uninstall:
+ call free_basemem
+ ret
+ .size uninstall, . - uninstall
+
+
+
+ /* File split information for the compressor */
+#if COMPRESS
+ .section ".zinfo", "a", @progbits
+ .ascii "COPY"
+ .long _prefix_lma
+ .long _prefix_filesz
+ .long _max_align
+ .ascii "PACK"
+ .long _text16_lma
+ .long _text16_filesz
+ .long _max_align
+ .ascii "PACK"
+ .long _data16_lma
+ .long _data16_filesz
+ .long _max_align
+ .ascii "PACK"
+ .long _textdata_lma
+ .long _textdata_filesz
+ .long _max_align
+#else /* COMPRESS */
+ .section ".zinfo", "a", @progbits
+ .ascii "COPY"
+ .long _prefix_lma
+ .long _filesz
+ .long _max_align
+#endif /* COMPRESS */