2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
25 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
29 /* Image compression enabled */
32 /* Protected mode flag */
35 /* Allow for DBG()-style messages within libprefix */
37 .macro progress message
40 .macro progress message
48 movw $progress_\@, %si
54 .section ".prefix.data", "aw", @progbits
57 .size progress_\@, . - progress_\@
62 /*****************************************************************************
63 * Utility function: print character (with LF -> LF,CR translation)
66 * %al : character to print
67 * %ds:di : output buffer (or %di=0 to print to console)
69 * %ds:di : next character in output buffer (if applicable)
70 *****************************************************************************
72 .section ".prefix.lib", "awx", @progbits
74 .globl print_character
76 /* Preserve registers */
80 /* If %di is non-zero, write character to buffer and exit */
86 1: /* Print character */
87 movw $0x0007, %bx /* page 0, attribute 7 (normal) */
88 movb $0x0e, %ah /* write char, tty mode */
89 cmpb $0x0a, %al /* '\n'? */
94 /* Restore registers and return */
99 .size print_character, . - print_character
101 /*****************************************************************************
102 * Utility function: print space
105 * %ds:di : output buffer (or %di=0 to print to console)
107 * %ds:di : next character in output buffer (if applicable)
108 *****************************************************************************
110 .section ".prefix.lib", "awx", @progbits
114 /* Preserve registers */
119 /* Restore registers and return */
122 .size print_space, . - print_space
124 /*****************************************************************************
125 * Utility function: print a NUL-terminated string
128 * %ds:si : string to print
129 * %ds:di : output buffer (or %di=0 to print to console)
131 * %ds:si : character after terminating NUL
132 * %ds:di : next character in output buffer (if applicable)
133 *****************************************************************************
135 .section ".prefix.lib", "awx", @progbits
139 /* Preserve registers */
147 2: /* Restore registers and return */
150 .size print_message, . - print_message
152 /*****************************************************************************
153 * Utility functions: print hex digit/byte/word/dword
156 * %al (low nibble) : digit to print
157 * %al : byte to print
158 * %ax : word to print
159 * %eax : dword to print
160 * %ds:di : output buffer (or %di=0 to print to console)
162 * %ds:di : next character in output buffer (if applicable)
163 *****************************************************************************
165 .section ".prefix.lib", "awx", @progbits
167 .globl print_hex_dword
173 .size print_hex_dword, . - print_hex_dword
174 .globl print_hex_word
180 .size print_hex_word, . - print_hex_word
181 .globl print_hex_byte
184 call print_hex_nibble
187 .size print_hex_byte, . - print_hex_byte
188 .globl print_hex_nibble
190 /* Preserve registers */
192 /* Print digit (technique by Norbert Juffa <norbert.juffa@amd.com> */
198 /* Restore registers and return */
201 .size print_hex_nibble, . - print_hex_nibble
203 /*****************************************************************************
204 * Utility function: print PCI bus:dev.fn
207 * %ax : PCI bus:dev.fn to print
208 * %ds:di : output buffer (or %di=0 to print to console)
210 * %ds:di : next character in output buffer (if applicable)
211 *****************************************************************************
213 .section ".prefix.lib", "awx", @progbits
215 .globl print_pci_busdevfn
217 /* Preserve registers */
235 call print_hex_nibble
236 /* Restore registers and return */
239 .size print_pci_busdevfn, . - print_pci_busdevfn
241 /*****************************************************************************
242 * Utility function: clear current line
245 * %ds:di : output buffer (or %di=0 to print to console)
247 * %ds:di : next character in output buffer (if applicable)
248 *****************************************************************************
250 .section ".prefix.lib", "awx", @progbits
252 .globl print_kill_line
254 /* Preserve registers */
260 /* Print 79 spaces */
266 /* Restore registers and return */
270 .size print_kill_line, . - print_kill_line
272 /****************************************************************************
278 * %ds:esi : source address
279 * %es:edi : destination address
282 * %ds:esi : next source address
283 * %es:edi : next destination address
286 ****************************************************************************
288 .section ".prefix.lib", "awx", @progbits
295 .size copy_bytes, . - copy_bytes
297 /****************************************************************************
303 * %es:edi : destination address
306 * %es:edi : next destination address
309 ****************************************************************************
311 .section ".prefix.lib", "awx", @progbits
321 .size zero_bytes, . - zero_bytes
323 /****************************************************************************
326 * Call memcpy()-like function
329 * %esi : source physical address
330 * %edi : destination physical address
332 * %bx : memcpy()-like function to call, passing parameters:
333 * %ds:esi : source address
334 * %es:edi : destination address
337 * %ds:esi : next source address
338 * %es:edi : next destination address
340 * %esi : next source physical address
341 * %edi : next destination physical address
344 ****************************************************************************
346 .section ".prefix.lib", "awx", @progbits
352 /* Preserve registers */
356 /* Construct GDT on stack (since .prefix may not be writable) */
357 .equ PM_DS, 0x18 /* Flat data segment */
360 .equ PM_SS, 0x10 /* Stack segment based at %ss:0000 */
364 .equ PM_CS, 0x08 /* Code segment based at %cs:0000 */
368 pushl $0 /* Base and length */
379 /* Switch to protected mode */
402 /* Call memcpy()-like function */
406 /* Return to (flat) real mode */
411 2: /* lret will ljmp to here */
419 /* Call memcpy()-like function in flat real mode (to allow for
420 * debug output via INT 10).
434 addw $( 8 /* saved GDT */ + ( PM_DS + 8 ) /* GDT on stack */ ), %sp
436 /* Restore registers and return */
441 #else /* KEEP_IT_REAL */
443 /* Preserve registers */
448 /* Convert %esi and %edi to %ds:esi and %es:edi */
458 /* Call memcpy()-like function */
461 /* Convert %ds:esi and %es:edi back to physical addresses */
471 /* Restore registers and return */
477 #endif /* KEEP_IT_REAL */
479 .size process_bytes, . - process_bytes
481 /****************************************************************************
484 * Install block to specified address
487 * %esi : source physical address (must be a multiple of 16)
488 * %edi : destination physical address (must be a multiple of 16)
489 * %ecx : length of (decompressed) data
490 * %edx : total length of block (including any uninitialised data portion)
492 * %esi : next source physical address (will be a multiple of 16)
493 * %edi : next destination physical address (will be a multiple of 16)
496 ****************************************************************************
498 .section ".prefix.lib", "awx", @progbits
501 /* Preserve registers */
505 /* Decompress (or copy) source to destination */
507 movw $decompress16, %bx
509 movw $copy_bytes, %bx
513 /* Zero .bss portion */
516 movw $zero_bytes, %bx
519 /* Round up %esi and %edi to start of next blocks */
525 /* Restore registers and return */
529 .size install_block, . - install_block
531 /****************************************************************************
534 * Allocate space for .text16 and .data16 from top of base memory.
535 * Memory is allocated using the BIOS free base memory counter at
541 * %ax : .text16 segment address
542 * %bx : .data16 segment address
545 ****************************************************************************
547 .section ".prefix.lib", "awx", @progbits
551 /* Preserve registers */
554 /* FBMS => %ax as segment address */
560 /* Calculate .data16 segment address */
561 subw $_data16_memsz_pgh, %ax
564 /* Calculate .text16 segment address. Round down to ensure
565 * low bits are zero, to speed up mode transitions under KVM.
567 subw $_text16_memsz_pgh, %ax
575 /* Retrieve .text16 and .data16 segment addresses */
579 /* Restore registers and return */
582 .size alloc_basemem, . - alloc_basemem
584 /****************************************************************************
587 * Free space allocated with alloc_basemem.
590 * none (.text16 segment address is implicit in %cs)
592 * %ax : 0 if successfully freed
595 ****************************************************************************
597 .section ".text16", "ax", @progbits
601 /* Preserve registers */
605 /* Check FBMS counter */
613 /* Check hooked interrupt count */
614 cmpw $0, %cs:hooked_bios_interrupts
617 /* OK to free memory */
619 addw $_text16_memsz_pgh, %ax
620 addw $_data16_memsz_pgh, %ax
625 1: /* Restore registers and return */
629 .size free_basemem, . - free_basemem
631 .section ".text16.data", "aw", @progbits
632 .globl hooked_bios_interrupts
633 hooked_bios_interrupts:
635 .size hooked_bios_interrupts, . - hooked_bios_interrupts
637 /****************************************************************************
640 * Install all text and data segments.
645 * %ax : .text16 segment address
646 * %bx : .data16 segment address
649 ****************************************************************************
651 .section ".prefix.lib", "awx", @progbits
655 progress "install:\n"
656 /* Preserve registers */
660 /* Allocate space for .text16 and .data16 */
662 /* Image source = %cs:0000 */
664 /* Image destination = default */
666 /* Allow arbitrary relocation */
667 orl $0xffffffff, %ebp
668 /* Install text and data segments */
669 call install_prealloc
670 /* Restore registers and return */
675 .size install, . - install
677 /****************************************************************************
680 * Install all text and data segments.
683 * %ax : .text16 segment address
684 * %bx : .data16 segment address
685 * %esi : Image source physical address (or zero for %cs:0000)
686 * %edi : Decompression temporary area physical address (or zero for default)
687 * %ebp : Maximum end address for relocation
688 * - 0xffffffff for no maximum
689 * - 0x00000000 to inhibit use of INT 15,e820 and INT 15,e801
692 ****************************************************************************
694 .section ".prefix.lib", "awx", @progbits
696 .globl install_prealloc
698 progress "install_prealloc:\n"
699 /* Save registers on external stack */
703 cld /* Sanity: clear the direction flag asap */
705 /* Switch to temporary stack in .bss16 */
710 movl $_data16_memsz, %esp
714 /* Set up %ds for (read-only) access to .prefix */
718 /* Save decompression temporary area physical address */
721 /* Install .text16.early and calculate %ecx as offset to next block */
722 progress " .text16.early\n"
727 pushl %esi /* Save original %cs:0000 */
728 addl $_text16_early_lma, %esi
731 movl $_text16_early_filesz, %ecx
732 movl $_text16_early_memsz, %edx
733 call install_block /* .text16.early */
734 popl %ecx /* Calculate offset to next block */
741 /* Access high memory by enabling the A20 gate. (We will
742 * already have 4GB segment limits as a result of calling
745 progress " access_highmem\n"
749 pushw $access_highmem
751 1: /* Die if we could not access high memory */
753 movw $a20_death_message, %si
757 .section ".prefix.data", "aw", @progbits
759 .asciz "\nHigh memory inaccessible - cannot continue\n"
760 .size a20_death_message, . - a20_death_message
765 /* Open payload (which may not yet be in memory) */
766 progress " open_payload\n"
772 1: /* Die if we could not access the payload */
780 movw $payload_death_message, %si
786 .section ".prefix.data", "aw", @progbits
787 payload_death_message:
788 .asciz "\nPayload inaccessible - cannot continue\n"
789 .size payload_death_message, . - payload_death_message
793 /* Calculate physical address of payload (i.e. first source) */
800 /* Install .text16.late and .data16 */
801 progress " .text16.late\n"
802 movl $_text16_late_filesz, %ecx
803 movl $_text16_late_memsz, %edx
804 call install_block /* .text16.late */
805 progress " .data16\n"
808 movl $_data16_filesz, %ecx
809 movl $_data16_filesz, %edx /* do not zero our temporary stack */
810 call install_block /* .data16 */
812 /* Set up %ds for access to .data16 */
815 /* Restore decompression temporary area physical address */
820 /* Find a suitable decompression temporary area, if none specified */
824 /* Use INT 15,88 to find the highest available address via INT
825 * 15,88. This limits us to around 64MB, which should avoid
826 * all of the POST-time memory map failure modes.
832 subl $_textdata_memsz_kb, %edi
834 /* Sanity check: if we have ended up below 1MB, use 1MB */
840 /* Install .text and .data to temporary area in high memory,
841 * prior to reading the E820 memory map and relocating
844 progress " .textdata\n"
846 movl $_textdata_filesz, %ecx
847 movl $_textdata_memsz, %edx
851 #endif /* KEEP_IT_REAL */
853 /* Switch back to original stack and zero .bss16 */
854 addr32 lss %ss:(%esp), %esp
858 movl $_data16_filesz, %edi
859 movl $_data16_memsz, %ecx
867 /* Initialise librm at current location */
868 progress " init_librm\n"
869 movw %ax, (init_librm_vector+2)
870 lcall *init_librm_vector
872 /* Inhibit INT 15,e820 and INT 15,e801 if applicable */
878 /* Call relocate() to determine target address for relocation.
879 * relocate() will return with %esi, %edi and %ecx set up
880 * ready for the copy to the new location.
882 progress " relocate\n"
883 movw %ax, (prot_call_vector+2)
885 lcall *prot_call_vector
886 popl %edx /* discard */
888 /* Copy code to new location */
892 movw $copy_bytes, %bx
897 /* Initialise librm at new location */
898 progress " init_librm\n"
899 lcall *init_librm_vector
901 #else /* KEEP_IT_REAL */
903 /* Initialise libkir */
904 movw %ax, (init_libkir_vector+2)
905 lcall *init_libkir_vector
907 #endif /* KEEP_IT_REAL */
909 /* Close access to payload */
910 progress " close_payload\n"
911 movw %ax, (close_payload_vector+2)
912 lcall *close_payload_vector
914 /* Restore registers */
919 .size install_prealloc, . - install_prealloc
921 /* Vectors for far calls to .text16 functions. Must be in
922 * .data16, since .prefix may not be writable.
924 .section ".data16", "aw", @progbits
929 .size init_libkir_vector, . - init_libkir_vector
934 .size init_librm_vector, . - init_librm_vector
938 .size prot_call_vector, . - prot_call_vector
940 close_payload_vector:
943 .size close_payload_vector, . - close_payload_vector
945 /* Dummy routines to open and close payload */
946 .section ".text16.early.data", "aw", @progbits
953 .size open_payload, . - open_payload
954 .size close_payload, . - close_payload
956 /****************************************************************************
959 * Uninstall all text and data segments.
962 * none (.text16 segment address is implicit in %cs)
967 ****************************************************************************
969 .section ".text16", "ax", @progbits
975 .size uninstall, . - uninstall
979 /* File split information for the compressor */
981 #define PACK_OR_COPY "PACK"
983 #define PACK_OR_COPY "COPY"
985 .section ".zinfo", "a", @progbits
991 .long _text16_early_lma
992 .long _text16_early_filesz
1000 .long _pprefix_filesz
1003 .long _text16_late_lma
1004 .long _text16_late_filesz
1008 .long _data16_filesz
1012 .long _textdata_filesz
1015 .weak _payload_align
1016 .equ _payload_align, 1