123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819 |
- /*
- * 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 */
|