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
21 FILE_LICENCE ( GPL2_OR_LATER )
25 /* Image compression enabled */
28 /* Protected mode flag */
31 /* Allow for DBG()-style messages within libprefix */
33 .macro progress message
36 .macro progress message
44 movw $progress_\@, %si
50 .section ".prefix.data", "aw", @progbits
53 .size progress_\@, . - progress_\@
58 /*****************************************************************************
59 * Utility function: print character (with LF -> LF,CR translation)
62 * %al : character to print
63 * %ds:di : output buffer (or %di=0 to print to console)
65 * %ds:di : next character in output buffer (if applicable)
66 *****************************************************************************
68 .section ".prefix.lib", "awx", @progbits
70 .globl print_character
72 /* Preserve registers */
76 /* If %di is non-zero, write character to buffer and exit */
82 1: /* Print character */
83 movw $0x0007, %bx /* page 0, attribute 7 (normal) */
84 movb $0x0e, %ah /* write char, tty mode */
85 cmpb $0x0a, %al /* '\n'? */
90 /* Restore registers and return */
95 .size print_character, . - print_character
97 /*****************************************************************************
98 * Utility function: print space
101 * %ds:di : output buffer (or %di=0 to print to console)
103 * %ds:di : next character in output buffer (if applicable)
104 *****************************************************************************
106 .section ".prefix.lib", "awx", @progbits
110 /* Preserve registers */
115 /* Restore registers and return */
118 .size print_space, . - print_space
120 /*****************************************************************************
121 * Utility function: print a NUL-terminated string
124 * %ds:si : string to print
125 * %ds:di : output buffer (or %di=0 to print to console)
127 * %ds:si : character after terminating NUL
128 * %ds:di : next character in output buffer (if applicable)
129 *****************************************************************************
131 .section ".prefix.lib", "awx", @progbits
135 /* Preserve registers */
143 2: /* Restore registers and return */
146 .size print_message, . - print_message
148 /*****************************************************************************
149 * Utility functions: print hex digit/byte/word/dword
152 * %al (low nibble) : digit to print
153 * %al : byte to print
154 * %ax : word to print
155 * %eax : dword to print
156 * %ds:di : output buffer (or %di=0 to print to console)
158 * %ds:di : next character in output buffer (if applicable)
159 *****************************************************************************
161 .section ".prefix.lib", "awx", @progbits
163 .globl print_hex_dword
169 .size print_hex_dword, . - print_hex_dword
170 .globl print_hex_word
176 .size print_hex_word, . - print_hex_word
177 .globl print_hex_byte
180 call print_hex_nibble
183 .size print_hex_byte, . - print_hex_byte
184 .globl print_hex_nibble
186 /* Preserve registers */
188 /* Print digit (technique by Norbert Juffa <norbert.juffa@amd.com> */
194 /* Restore registers and return */
197 .size print_hex_nibble, . - print_hex_nibble
199 /*****************************************************************************
200 * Utility function: print PCI bus:dev.fn
203 * %ax : PCI bus:dev.fn to print
204 * %ds:di : output buffer (or %di=0 to print to console)
206 * %ds:di : next character in output buffer (if applicable)
207 *****************************************************************************
209 .section ".prefix.lib", "awx", @progbits
211 .globl print_pci_busdevfn
213 /* Preserve registers */
231 call print_hex_nibble
232 /* Restore registers and return */
235 .size print_pci_busdevfn, . - print_pci_busdevfn
237 /*****************************************************************************
238 * Utility function: clear current line
241 * %ds:di : output buffer (or %di=0 to print to console)
243 * %ds:di : next character in output buffer (if applicable)
244 *****************************************************************************
246 .section ".prefix.lib", "awx", @progbits
248 .globl print_kill_line
250 /* Preserve registers */
256 /* Print 79 spaces */
262 /* Restore registers and return */
266 .size print_kill_line, . - print_kill_line
268 /****************************************************************************
274 * %ds:esi : source address
275 * %es:edi : destination address
278 * %ds:esi : next source address
279 * %es:edi : next destination address
282 ****************************************************************************
284 .section ".prefix.lib", "awx", @progbits
291 .size copy_bytes, . - copy_bytes
293 /****************************************************************************
299 * %ds:esi : source address
300 * %es:edi : destination address
303 * %ds:esi : next source address
304 * %es:edi : next destination address
307 ****************************************************************************
309 .section ".prefix.lib", "awx", @progbits
319 .size zero_bytes, . - zero_bytes
321 /****************************************************************************
324 * Call memcpy()-like function
327 * %esi : source physical address
328 * %edi : destination physical address
330 * %bx : memcpy()-like function to call, passing parameters:
331 * %ds:esi : source address
332 * %es:edi : destination address
335 * %ds:esi : next source address
336 * %es:edi : next destination address
338 * %esi : next source physical address
339 * %edi : next destination physical address
342 ****************************************************************************
344 .section ".prefix.lib", "awx", @progbits
350 /* Preserve registers */
354 /* Construct GDT on stack (since .prefix may not be writable) */
355 .equ PM_DS, 0x18 /* Flat data segment */
358 .equ PM_SS, 0x10 /* Stack segment based at %ss:0000 */
362 .equ PM_CS, 0x08 /* Code segment based at %cs:0000 */
366 pushl $0 /* Base and length */
377 /* Switch to protected mode */
399 /* Call memcpy()-like function */
402 /* Return to (flat) real mode */
407 2: /* lret will ljmp to here */
416 addw $( 8 /* saved GDT */ + ( PM_DS + 8 ) /* GDT on stack */ ), %sp
418 /* Restore registers and return */
423 #else /* KEEP_IT_REAL */
425 /* Preserve registers */
430 /* Convert %esi and %edi to %ds:esi and %es:edi */
440 /* Call memcpy()-like function */
443 /* Convert %ds:esi and %es:edi back to physical addresses */
453 /* Restore registers and return */
459 #endif /* KEEP_IT_REAL */
461 .size process_bytes, . - process_bytes
463 /****************************************************************************
466 * Install block to specified address
469 * %esi : source physical address (must be a multiple of 16)
470 * %edi : destination physical address (must be a multiple of 16)
471 * %ecx : length of (decompressed) data
472 * %edx : total length of block (including any uninitialised data portion)
474 * %esi : next source physical address (will be a multiple of 16)
475 * %edi : next destination physical address (will be a multiple of 16)
478 ****************************************************************************
480 .section ".prefix.lib", "awx", @progbits
483 /* Preserve registers */
487 /* Decompress (or copy) source to destination */
489 movw $decompress16, %bx
491 movw $copy_bytes, %bx
495 /* Zero .bss portion */
498 movw $zero_bytes, %bx
501 /* Round up %esi and %edi to start of next blocks */
507 /* Restore registers and return */
511 .size install_block, . - install_block
513 /****************************************************************************
516 * Allocate space for .text16 and .data16 from top of base memory.
517 * Memory is allocated using the BIOS free base memory counter at
523 * %ax : .text16 segment address
524 * %bx : .data16 segment address
527 ****************************************************************************
529 .section ".prefix.lib", "awx", @progbits
533 /* Preserve registers */
536 /* FBMS => %ax as segment address */
542 /* Calculate .data16 segment address */
543 subw $_data16_memsz_pgh, %ax
546 /* Calculate .text16 segment address. Round down to ensure
547 * low bits are zero, to speed up mode transitions under KVM.
549 subw $_text16_memsz_pgh, %ax
557 /* Retrieve .text16 and .data16 segment addresses */
561 /* Restore registers and return */
564 .size alloc_basemem, . - alloc_basemem
566 /****************************************************************************
569 * Free space allocated with alloc_basemem.
572 * none (.text16 segment address is implicit in %cs)
574 * %ax : 0 if successfully freed
577 ****************************************************************************
579 .section ".text16", "ax", @progbits
583 /* Preserve registers */
587 /* Check FBMS counter */
595 /* Check hooked interrupt count */
596 cmpw $0, %cs:hooked_bios_interrupts
599 /* OK to free memory */
601 addw $_text16_memsz_pgh, %ax
602 addw $_data16_memsz_pgh, %ax
607 1: /* Restore registers and return */
611 .size free_basemem, . - free_basemem
613 .section ".text16.data", "aw", @progbits
614 .globl hooked_bios_interrupts
615 hooked_bios_interrupts:
617 .size hooked_bios_interrupts, . - hooked_bios_interrupts
619 /****************************************************************************
622 * Install all text and data segments.
627 * %ax : .text16 segment address
628 * %bx : .data16 segment address
631 ****************************************************************************
633 .section ".prefix.lib", "awx", @progbits
637 progress "install:\n"
638 /* Preserve registers */
642 /* Allocate space for .text16 and .data16 */
644 /* Image source = %cs:0000 */
646 /* Image destination = default */
648 /* Allow arbitrary relocation */
649 orl $0xffffffff, %ebp
650 /* Install text and data segments */
651 call install_prealloc
652 /* Restore registers and return */
657 .size install, . - install
659 /****************************************************************************
662 * Install all text and data segments.
665 * %ax : .text16 segment address
666 * %bx : .data16 segment address
667 * %esi : Image source physical address (or zero for %cs:0000)
668 * %edi : Decompression temporary area physical address (or zero for default)
669 * %ebp : Maximum end address for relocation
670 * - 0xffffffff for no maximum
671 * - 0x00000000 to inhibit use of INT 15,e820 and INT 15,e801
674 ****************************************************************************
676 .section ".prefix.lib", "awx", @progbits
678 .globl install_prealloc
680 progress "install_prealloc:\n"
685 cld /* Sanity: clear the direction flag asap */
687 /* Set up %ds for (read-only) access to .prefix */
691 /* Save decompression temporary area physical address */
694 /* Install .text16.early and calculate %ecx as offset to next block */
695 progress " .text16.early\n"
700 pushl %esi /* Save original %cs:0000 */
701 addl $_text16_early_lma, %esi
704 movl $_text16_early_filesz, %ecx
705 movl $_text16_early_memsz, %edx
706 call install_block /* .text16.early */
707 popl %ecx /* Calculate offset to next block */
713 /* Access high memory by enabling the A20 gate. (We will
714 * already have 4GB segment limits as a result of calling
717 progress " access_highmem\n"
721 pushw $access_highmem
723 1: /* Die if we could not access high memory */
725 movw $a20_death_message, %si
729 .section ".prefix.data", "aw", @progbits
731 .asciz "\nHigh memory inaccessible - cannot continue\n"
732 .size a20_death_message, . - a20_death_message
737 /* Open payload (which may not yet be in memory) */
738 progress " open_payload\n"
744 1: /* Die if we could not access the payload */
752 movw $payload_death_message, %si
758 .section ".prefix.data", "aw", @progbits
759 payload_death_message:
760 .asciz "\nPayload inaccessible - cannot continue\n"
761 .size payload_death_message, . - payload_death_message
765 /* Calculate physical address of payload (i.e. first source) */
772 /* Install .text16.late and .data16 */
773 progress " .text16.late\n"
774 movl $_text16_late_filesz, %ecx
775 movl $_text16_late_memsz, %edx
776 call install_block /* .text16.late */
777 progress " .data16\n"
780 movl $_data16_filesz, %ecx
781 movl $_data16_memsz, %edx
782 call install_block /* .data16 */
784 /* Set up %ds for access to .data16 */
787 /* Restore decompression temporary area physical address */
791 /* Initialise libkir */
792 movw %ax, (init_libkir_vector+2)
793 lcall *init_libkir_vector
795 /* Find a suitable decompression temporary area, if none specified */
799 /* Use INT 15,88 to find the highest available address via INT
800 * 15,88. This limits us to around 64MB, which should avoid
801 * all of the POST-time memory map failure modes.
807 subl $_textdata_memsz_kb, %edi
809 /* Sanity check: if we have ended up below 1MB, use 1MB */
815 /* Install .text and .data to temporary area in high memory,
816 * prior to reading the E820 memory map and relocating
819 progress " .textdata\n"
821 movl $_textdata_filesz, %ecx
822 movl $_textdata_memsz, %edx
826 /* Initialise librm at current location */
827 progress " init_librm\n"
828 movw %ax, (init_librm_vector+2)
829 lcall *init_librm_vector
831 /* Inhibit INT 15,e820 and INT 15,e801 if applicable */
838 /* Call relocate() to determine target address for relocation.
839 * relocate() will return with %esi, %edi and %ecx set up
840 * ready for the copy to the new location.
842 progress " relocate\n"
843 movw %ax, (prot_call_vector+2)
845 lcall *prot_call_vector
846 popl %edx /* discard */
848 /* Copy code to new location */
852 movw $copy_bytes, %bx
857 /* Initialise librm at new location */
858 progress " init_librm\n"
859 lcall *init_librm_vector
862 /* Close access to payload */
863 progress " close_payload\n"
864 movw %ax, (close_payload_vector+2)
865 lcall *close_payload_vector
867 /* Restore registers */
872 .size install_prealloc, . - install_prealloc
874 /* Vectors for far calls to .text16 functions. Must be in
875 * .data16, since .prefix may not be writable.
877 .section ".data16", "aw", @progbits
882 .size init_libkir_vector, . - init_libkir_vector
887 .size init_librm_vector, . - init_librm_vector
891 .size prot_call_vector, . - prot_call_vector
893 close_payload_vector:
896 .size close_payload_vector, . - close_payload_vector
898 /* Dummy routines to open and close payload */
899 .section ".text16.early.data", "aw", @progbits
906 .size open_payload, . - open_payload
907 .size close_payload, . - close_payload
909 /****************************************************************************
912 * Uninstall all text and data segments.
915 * none (.text16 segment address is implicit in %cs)
920 ****************************************************************************
922 .section ".text16", "ax", @progbits
928 .size uninstall, . - uninstall
932 /* File split information for the compressor */
934 #define PACK_OR_COPY "PACK"
936 #define PACK_OR_COPY "COPY"
938 .section ".zinfo", "a", @progbits
944 .long _text16_early_lma
945 .long _text16_early_filesz
953 .long _pprefix_filesz
956 .long _text16_late_lma
957 .long _text16_late_filesz
965 .long _textdata_filesz
969 .equ _payload_align, 1