| /* |
| * 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., 51 Franklin Street, Fifth Floor, Boston, MA |
| * 02110-1301, USA. |
| * |
| * You can also choose to distribute this program under the terms of |
| * the Unmodified Binary Distribution Licence (as given in the file |
| * COPYING.UBDL), provided that you have satisfied its requirements. |
| * |
| */ |
| |
| FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) |
| |
| #include <librm.h> |
| |
| .section ".note.GNU-stack", "", @progbits |
| .code16 |
| .arch i386 |
| |
| /* Image compression enabled */ |
| #define COMPRESS 1 |
| |
| /* Protected mode flag */ |
| #define CR0_PE 1 |
| |
| /* Allow for DBG()-style messages within libprefix */ |
| #ifdef NDEBUG |
| .macro progress message, regs:vararg |
| .endm |
| #else |
| .macro dumpreg reg, others:vararg |
| pushl %eax |
| movl \reg, %eax |
| pushw %di |
| xorw %di, %di |
| call print_space |
| call print_hex_dword |
| popw %di |
| popl %eax |
| .ifnb \others |
| dumpreg \others |
| .endif |
| .endm |
| |
| .macro progress message, regs:vararg |
| pushfl |
| pushw %ds |
| pushw %si |
| pushw %di |
| pushw %cs |
| popw %ds |
| xorw %di, %di |
| movw $progress_\@, %si |
| call print_message |
| popw %di |
| popw %si |
| .ifnb \regs |
| dumpreg \regs |
| .endif |
| pushw %di |
| pushw %ax |
| xorw %di, %di |
| movb $( '\n' ), %al |
| call print_character |
| popw %ax |
| popw %di |
| popw %ds |
| popfl |
| .section ".prefix.data", "aw", @progbits |
| progress_\@: |
| .asciz "\message" |
| .size progress_\@, . - progress_\@ |
| .previous |
| .endm |
| #endif |
| |
| /***************************************************************************** |
| * 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.print_character", "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 space |
| * |
| * Parameters: |
| * %ds:di : output buffer (or %di=0 to print to console) |
| * Returns: |
| * %ds:di : next character in output buffer (if applicable) |
| ***************************************************************************** |
| */ |
| .section ".prefix.print_space", "awx", @progbits |
| .code16 |
| .globl print_space |
| print_space: |
| /* Preserve registers */ |
| pushw %ax |
| /* Print space */ |
| movb $( ' ' ), %al |
| call print_character |
| /* Restore registers and return */ |
| popw %ax |
| ret |
| .size print_space, . - print_space |
| |
| /***************************************************************************** |
| * 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.print_message", "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.print_hex", "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.print_pci_busdevfn", "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.print_kill_line", "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 */ |
| movw $79, %cx |
| 1: call print_space |
| loop 1b |
| /* Print CR */ |
| call print_character |
| /* Restore registers and return */ |
| popw %cx |
| popw %ax |
| ret |
| .size print_kill_line, . - print_kill_line |
| |
| /**************************************************************************** |
| * copy_bytes |
| * |
| * 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.copy_bytes", "awx", @progbits |
| .code16 |
| copy_bytes: |
| pushl %ecx |
| rep addr32 movsb |
| popl %ecx |
| ret |
| .size copy_bytes, . - copy_bytes |
| |
| /**************************************************************************** |
| * zero_bytes |
| * |
| * Zero bytes |
| * |
| * Parameters: |
| * %es:edi : destination address |
| * %ecx : length |
| * Returns: |
| * %es:edi : next destination address |
| * Corrupts: |
| * None |
| **************************************************************************** |
| */ |
| .section ".prefix.zero_bytes", "awx", @progbits |
| .code16 |
| zero_bytes: |
| pushl %ecx |
| pushw %ax |
| xorw %ax, %ax |
| rep addr32 stosb |
| popw %ax |
| popl %ecx |
| ret |
| .size zero_bytes, . - zero_bytes |
| |
| /**************************************************************************** |
| * process_bytes |
| * |
| * Call memcpy()-like function |
| * |
| * Parameters: |
| * %esi : source physical address |
| * %edi : destination physical address |
| * %ecx : length |
| * %bx : memcpy()-like function to call, passing parameters: |
| * %ds:esi : source address |
| * %es:edi : destination address |
| * %ecx : length |
| * and returning: |
| * %ds:esi : next source address |
| * %es:edi : next destination address |
| * Returns: |
| * %esi : next source physical address |
| * %edi : next destination physical address |
| * CF : as returned by memcpy()-like function |
| * Corrupts: |
| * None |
| **************************************************************************** |
| */ |
| .section ".prefix.process_bytes", "awx", @progbits |
| .code16 |
| process_bytes: |
| |
| #ifndef KEEP_IT_REAL |
| |
| /* Preserve registers */ |
| pushl %eax |
| pushl %ebp |
| |
| /* Construct ljmp code on stack (since .prefix may not be writable) */ |
| .equ LJMP_LEN, 0x06 |
| pushw %cs /* "nop ; ljmp %cs, $2f" */ |
| pushw $2f |
| pushw $0xea90 |
| /* Construct GDT on stack (since .prefix may not be writable) */ |
| .equ GDT_LEN, 0x20 |
| .equ PM_DS, 0x18 /* Flat data segment */ |
| pushl $0x00cf9300 |
| pushl $0x0000ffff |
| .equ PM_SS, 0x10 /* Stack segment based at %ss:0000 */ |
| pushl $0x008f0930 |
| pushw %ss |
| pushw $0xffff |
| .equ PM_CS, 0x08 /* Code segment based at %cs:0000 */ |
| pushl $0x008f09b0 |
| pushw %cs |
| pushw $0xffff |
| pushl $0 /* Base and length */ |
| pushw %ss |
| pushw $( GDT_LEN - 1 ) |
| movzwl %sp, %ebp |
| shll $4, 0x02(%bp) |
| addl %ebp, 0x02(%bp) |
| shll $4, 0x0a(%bp) |
| shll $4, 0x12(%bp) |
| subw $8, %sp |
| sgdt -8(%bp) |
| |
| /* Switch to protected mode */ |
| pushw %gs |
| pushw %fs |
| pushw %es |
| pushw %ds |
| pushw %ss |
| pushw %ss /* Far pointer to ljmp code on stack */ |
| leaw (GDT_LEN + 1)(%bp), %ax |
| pushw %ax |
| cli |
| data32 lgdt (%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 |
| |
| #ifdef NDEBUG |
| /* Call memcpy()-like function */ |
| call *%bx |
| #endif |
| |
| /* Return to (flat) real mode */ |
| movl %cr0, %eax |
| pushfw |
| andb $0!CR0_PE, %al |
| popfw |
| movl %eax, %cr0 |
| lret |
| 2: /* lret will ljmp to here (via constructed ljmp on stack) */ |
| popw %ss |
| popw %ds |
| popw %es |
| popw %fs |
| popw %gs |
| |
| #ifndef NDEBUG |
| /* Call memcpy()-like function in flat real mode (to allow for |
| * debug output via INT 10). |
| */ |
| pushw %ds |
| pushw %es |
| xorw %ax, %ax |
| movw %ax, %ds |
| movw %ax, %es |
| call *%bx |
| popw %es |
| popw %ds |
| #endif |
| |
| /* Restore GDT */ |
| data32 lgdt -8(%bp) |
| leaw (GDT_LEN + LJMP_LEN)(%bp), %sp |
| |
| /* Restore registers and return */ |
| popl %ebp |
| popl %eax |
| ret |
| |
| #else /* KEEP_IT_REAL */ |
| |
| /* Preserve registers */ |
| pushl %eax |
| pushw %ds |
| pushw %es |
| |
| /* Convert %esi and %edi to %ds:esi and %es:edi */ |
| shrl $4, %esi |
| movw %si, %ds |
| xorw %si, %si |
| shll $4, %esi |
| shrl $4, %edi |
| movw %di, %es |
| xorw %di, %di |
| shll $4, %edi |
| |
| /* Call memcpy()-like function */ |
| call *%bx |
| |
| /* Convert %ds:esi and %es:edi back to physical addresses */ |
| pushfw |
| xorl %eax, %eax |
| movw %ds, %ax |
| shll $4, %eax |
| addl %eax, %esi |
| xorl %eax, %eax |
| movw %es, %ax |
| shll $4, %eax |
| addl %eax, %edi |
| popfw |
| |
| /* Restore registers and return */ |
| popw %es |
| popw %ds |
| popl %eax |
| ret |
| |
| #endif /* KEEP_IT_REAL */ |
| |
| .size process_bytes, . - process_bytes |
| |
| /**************************************************************************** |
| * install_block |
| * |
| * 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) |
| * %edi : next destination physical address (will be a multiple of 16) |
| * CF set on failure |
| * Corrupts: |
| * none |
| **************************************************************************** |
| */ |
| .section ".prefix.install_block", "awx", @progbits |
| .code16 |
| install_block: |
| /* Preserve registers */ |
| pushl %ecx |
| pushw %bx |
| |
| /* Decompress (or copy) source to destination */ |
| #if COMPRESS |
| movw $decompress16, %bx |
| #else |
| movw $copy_bytes, %bx |
| #endif |
| call process_bytes |
| jc 99f |
| |
| /* Zero .bss portion */ |
| negl %ecx |
| addl %edx, %ecx |
| movw $zero_bytes, %bx |
| call process_bytes |
| |
| /* Round up %esi and %edi to start of next blocks */ |
| addl $0xf, %esi |
| andl $~0xf, %esi |
| addl $0xf, %edi |
| andl $~0xf, %edi /* Will also clear CF */ |
| |
| 99: /* Restore registers and return */ |
| popw %bx |
| popl %ecx |
| ret |
| .size install_block, . - install_block |
| |
| /**************************************************************************** |
| * alloc_basemem |
| * |
| * 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.alloc_basemem", "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_ppgh, %ax |
| pushw %ax |
| |
| /* Calculate .text16 segment address */ |
| subw $_text16_memsz_ppgh, %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 |
| * |
| * Free space allocated with alloc_basemem. |
| * |
| * Parameters: |
| * none (.text16 segment address is implicit in %cs) |
| * Returns: |
| * %ax : 0 if successfully freed |
| * Corrupts: |
| * none |
| **************************************************************************** |
| */ |
| .section ".text16.free_basemem", "ax", @progbits |
| .code16 |
| .globl free_basemem |
| free_basemem: |
| /* Preserve registers */ |
| pushw %fs |
| pushw %ax |
| |
| /* Check FBMS counter */ |
| movw %cs, %ax |
| shrw $6, %ax |
| pushw $0x40 |
| popw %fs |
| cmpw %ax, %fs:0x13 |
| jne 1f |
| |
| /* Check hooked interrupt count */ |
| cmpw $0, %cs:hooked_bios_interrupts |
| jne 1f |
| |
| /* OK to free memory */ |
| movw %cs, %ax |
| addw $_text16_memsz_ppgh, %ax |
| addw $_data16_memsz_ppgh, %ax |
| shrw $6, %ax |
| movw %ax, %fs:0x13 |
| xorw %ax, %ax |
| |
| 1: /* Restore registers and return */ |
| popw %ax |
| popw %fs |
| ret |
| .size free_basemem, . - free_basemem |
| |
| .section ".text16.data.hooked_bios_interrupts", "aw", @progbits |
| .globl hooked_bios_interrupts |
| hooked_bios_interrupts: |
| .word 0 |
| .size hooked_bios_interrupts, . - hooked_bios_interrupts |
| |
| /**************************************************************************** |
| * install |
| * |
| * Install all text and data segments. |
| * |
| * Parameters: |
| * none |
| * Returns: |
| * %ax : .text16 segment address |
| * %bx : .data16 segment address |
| * Corrupts: |
| * none |
| **************************************************************************** |
| */ |
| .section ".prefix.install", "awx", @progbits |
| .code16 |
| .globl install |
| install: |
| progress "\ninstall:" |
| /* Preserve registers */ |
| pushl %esi |
| pushl %edi |
| pushl %ebp |
| /* Allocate space for .text16 and .data16 */ |
| call alloc_basemem |
| /* Image source = %cs:0000 */ |
| xorl %esi, %esi |
| /* Image destination = default */ |
| xorl %edi, %edi |
| /* Allow arbitrary relocation */ |
| orl $0xffffffff, %ebp |
| /* Install text and data segments */ |
| call install_prealloc |
| /* Restore registers and return */ |
| popl %ebp |
| popl %edi |
| popl %esi |
| ret |
| .size install, . - install |
| |
| /**************************************************************************** |
| * install_prealloc |
| * |
| * 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 (or zero for default) |
| * %ebp : Maximum end address for relocation |
| * - 0xffffffff for no maximum |
| * - 0x00000000 to inhibit use of INT 15,e820 and INT 15,e801 |
| * Corrupts: |
| * none |
| **************************************************************************** |
| */ |
| .section ".prefix.install_prealloc", "awx", @progbits |
| .code16 |
| .globl install_prealloc |
| install_prealloc: |
| progress "\ninstall_prealloc:", %eax, %ebx, %esi, %edi, %ebp |
| /* Save registers on external stack */ |
| pushal |
| pushw %ds |
| pushw %es |
| cld /* Sanity: clear the direction flag asap */ |
| |
| /* Switch to temporary stack in .bss16 */ |
| pushw %ss |
| popw %ds |
| movl %esp, %ecx |
| movw %bx, %ss |
| movl $_data16_memsz, %esp |
| pushw %ds |
| pushl %ecx |
| |
| /* Set up %ds for (read-only) access to .prefix */ |
| pushw %cs |
| popw %ds |
| |
| /* Save decompression temporary area physical address */ |
| pushl %edi |
| |
| /* Install .text16.early and calculate %ecx as offset to next block */ |
| pushl %esi |
| xorl %esi, %esi |
| movw %cs, %si |
| shll $4, %esi |
| pushl %esi /* Save original %cs:0000 */ |
| addl $_text16_early_lma, %esi |
| movzwl %ax, %edi |
| shll $4, %edi |
| movl $_text16_early_filesz, %ecx |
| movl $_text16_early_memsz, %edx |
| progress " .text16.early ", %esi, %edi, %ecx, %edx |
| call install_block /* .text16.early */ |
| jc install_block_death |
| popl %ecx /* Calculate offset to next block */ |
| subl %esi, %ecx |
| negl %ecx |
| popl %esi |
| |
| #ifndef KEEP_IT_REAL |
| |
| /* Access high memory by enabling the A20 gate. (We will |
| * already have 4GB segment limits as a result of calling |
| * install_block.) |
| */ |
| progress " access_highmem" |
| pushw %cs |
| pushw $1f |
| pushw %ax |
| pushw $access_highmem |
| lret |
| 1: /* Die if we could not access high memory */ |
| jc access_highmem_death |
| |
| #endif |
| |
| /* Open payload (which may not yet be in memory) */ |
| progress " open_payload ", %esi, %ecx |
| pushw %cs |
| pushw $1f |
| pushw %ax |
| pushw $open_payload |
| lret |
| 1: /* Die if we could not access the payload */ |
| jc open_payload_death |
| |
| /* Calculate physical address of payload (i.e. first source) */ |
| testl %esi, %esi |
| jnz 1f |
| movw %cs, %si |
| shll $4, %esi |
| 1: addl %ecx, %esi |
| |
| /* Install .text16.late and .data16 */ |
| movl $_text16_late_filesz, %ecx |
| movl $_text16_late_memsz, %edx |
| progress " .text16.late ", %esi, %edi, %ecx, %edx |
| call install_block /* .text16.late */ |
| jc install_block_death |
| movzwl %bx, %edi |
| shll $4, %edi |
| movl $_data16_filesz, %ecx |
| movl $_data16_filesz, %edx /* do not zero our temporary stack */ |
| progress " .data16 ", %esi, %edi, %ecx, %edx |
| call install_block /* .data16 */ |
| jc install_block_death |
| |
| /* Set up %ds for access to .data16 */ |
| movw %bx, %ds |
| |
| /* Restore decompression temporary area physical address */ |
| popl %edi |
| |
| #ifndef KEEP_IT_REAL |
| |
| /* Find a suitable decompression temporary area, if none specified */ |
| pushl %eax |
| testl %edi, %edi |
| jnz 1f |
| /* Use INT 15,88 to find the highest available address via INT |
| * 15,88. This limits us to around 64MB, which should avoid |
| * all of the POST-time memory map failure modes. |
| */ |
| movb $0x88, %ah |
| int $0x15 |
| movw %ax, %di |
| addl $0x400, %edi |
| subl $_textdata_memsz_kb, %edi |
| andw $~0x03, %di |
| shll $10, %edi |
| /* Sanity check: if we have ended up below 1MB, use 1MB */ |
| cmpl $0x100000, %edi |
| jae 1f |
| movl $0x100000, %edi |
| 1: popl %eax |
| |
| /* Install .text and .data to temporary area in high memory, |
| * prior to reading the E820 memory map and relocating |
| * properly. |
| */ |
| pushl %edi |
| movl $_textdata_filesz, %ecx |
| movl $_textdata_memsz, %edx |
| progress " .textdata ", %esi, %edi, %ecx, %edx |
| call install_block |
| jc install_block_death |
| popl %edi |
| |
| #endif /* KEEP_IT_REAL */ |
| |
| /* Switch back to original stack and zero .bss16 */ |
| addr32 lss %ss:(%esp), %esp |
| pushl %edi |
| pushw %es |
| movw %bx, %es |
| movl $_data16_filesz, %edi |
| movl $_data16_memsz, %ecx |
| subl %edi, %ecx |
| call zero_bytes |
| popw %es |
| popl %edi |
| |
| #ifndef KEEP_IT_REAL |
| |
| /* Initialise librm at current location */ |
| progress " init_librm ", %eax, %ebx, %edi |
| movw %ax, (init_librm_vector+2) |
| lcall *init_librm_vector |
| |
| /* Prepare for return to .prefix segment */ |
| pushw %cs |
| |
| /* Jump to .text16 segment */ |
| pushw %ax |
| pushw $1f |
| lret |
| .section ".text16.install_prealloc", "ax", @progbits |
| 1: |
| /* Inhibit INT 15,e820 and INT 15,e801 if applicable */ |
| testl %ebp, %ebp |
| jnz 1f |
| incb memmap_post |
| decl %ebp |
| 1: |
| /* 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. |
| */ |
| virtcall relocate |
| |
| /* Jump back to .prefix segment */ |
| pushw $1f |
| lret |
| .section ".prefix.install_prealloc", "awx", @progbits |
| 1: |
| /* Copy code to new location */ |
| progress " copy ", %esi, %edi, %ecx |
| pushl %edi |
| pushw %bx |
| movw $copy_bytes, %bx |
| call process_bytes |
| popw %bx |
| popl %edi |
| |
| /* Initialise librm at new location */ |
| progress " init_librm ", %eax, %ebx, %edi |
| lcall *init_librm_vector |
| |
| #else /* KEEP_IT_REAL */ |
| |
| /* Initialise libkir */ |
| movw %ax, (init_libkir_vector+2) |
| lcall *init_libkir_vector |
| |
| #endif /* KEEP_IT_REAL */ |
| |
| /* Close access to payload */ |
| progress " close_payload" |
| movw %ax, (close_payload_vector+2) |
| lcall *close_payload_vector |
| |
| /* Restore registers */ |
| popw %es |
| popw %ds |
| popal |
| ret |
| .size install_prealloc, . - install_prealloc |
| |
| /* Vectors for far calls to .text16 functions. Must be in |
| * .data16, since .prefix may not be writable. |
| */ |
| .section ".data16.install_prealloc", "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 |
| #endif |
| close_payload_vector: |
| .word close_payload |
| .word 0 |
| .size close_payload_vector, . - close_payload_vector |
| |
| /* Dummy routines to open and close payload */ |
| .section ".text16.early.data.open_payload", "aw", @progbits |
| .weak open_payload |
| .weak close_payload |
| open_payload: |
| close_payload: |
| clc |
| lret |
| .size open_payload, . - open_payload |
| .size close_payload, . - close_payload |
| |
| /* Report installation failure */ |
| .section ".prefix.install_death", "ax", @progbits |
| install_death: |
| pushw %cs |
| popw %ds |
| xorw %di, %di |
| call print_hex_dword |
| call print_space |
| movl %esi, %eax |
| call print_hex_dword |
| call print_space |
| movl %ecx, %eax |
| call print_hex_dword |
| movw $install_death_message, %si |
| call print_message |
| 2: /* Halt system */ |
| cli |
| hlt |
| jmp 2b |
| .size install_death, . - install_death |
| .section ".prefix.data.install_death_message", "aw", @progbits |
| install_death_message: |
| .asciz "\nInstallation failed - cannot continue\n" |
| .size install_death_message, . - install_death_message |
| |
| /* Report failure to access high memory */ |
| .section ".prefix.install_block_death", "ax", @progbits |
| install_block_death: |
| movl $0x1b101b10, %eax |
| jmp install_death |
| .size install_block_death, . - install_block_death |
| |
| /* Report failure to access high memory */ |
| .section ".prefix.access_highmem_death", "ax", @progbits |
| access_highmem_death: |
| movl $0x0a200a20, %eax |
| jmp install_death |
| .size access_highmem_death, . - access_highmem_death |
| |
| /* Report failure to open payload */ |
| .section ".prefix.open_payload_death", "ax", @progbits |
| open_payload_death: |
| xorl %eax, %eax |
| jmp install_death |
| .size open_payload_death, . - open_payload_death |
| |
| /**************************************************************************** |
| * uninstall |
| * |
| * Uninstall all text and data segments. |
| * |
| * Parameters: |
| * none (.text16 segment address is implicit in %cs) |
| * Returns: |
| * none |
| * Corrupts: |
| * none |
| **************************************************************************** |
| */ |
| .section ".text16.uninstall", "ax", @progbits |
| .code16 |
| .globl uninstall |
| uninstall: |
| call free_basemem |
| ret |
| .size uninstall, . - uninstall |
| |
| |
| |
| /* File split information for the compressor */ |
| #if COMPRESS |
| #define PACK_OR_COPY "PACK" |
| #else |
| #define PACK_OR_COPY "COPY" |
| #endif |
| .section ".zinfo", "a", @progbits |
| .ascii "COPY" |
| .long _prefix_lma |
| .long _prefix_filesz |
| .long _max_align |
| .ascii PACK_OR_COPY |
| .long _text16_early_lma |
| .long _text16_early_filesz |
| .long _max_align |
| .ascii "PAYL" |
| .long 0 |
| .long 0 |
| .long _payload_align |
| .ascii "COPY" |
| .long _pprefix_lma |
| .long _pprefix_filesz |
| .long _max_align |
| .ascii PACK_OR_COPY |
| .long _text16_late_lma |
| .long _text16_late_filesz |
| .long _max_align |
| .ascii PACK_OR_COPY |
| .long _data16_lma |
| .long _data16_filesz |
| .long _max_align |
| .ascii PACK_OR_COPY |
| .long _textdata_lma |
| .long _textdata_filesz |
| .long _max_align |
| |
| .weak _payload_align |
| .equ _payload_align, 1 |