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., 675 Mass Ave, Cambridge, MA 02139, USA.
20 FILE_LICENCE ( GPL2_OR_LATER )
25 * High memory temporary load address
27 * Temporary buffer into which to copy (or decompress) our runtime
28 * image, prior to calling get_memmap() and relocate(). We don't
29 * actually leave anything here once install() has returned.
31 * We use the start of an even megabyte so that we don't have to worry
32 * about the current state of the A20 line.
34 * We use 4MB rather than 2MB because some PXE stack / PMM BIOS
35 * combinations are known to place data required by other UNDI ROMs
36 * loader around the 2MB mark.
38 .globl HIGHMEM_LOADPOINT
39 .equ HIGHMEM_LOADPOINT, ( 4 << 20 )
41 /* Image compression enabled */
44 /*****************************************************************************
45 * Utility function: print character (with LF -> LF,CR translation)
48 * %al : character to print
49 * %ds:di : output buffer (or %di=0 to print to console)
51 * %ds:di : next character in output buffer (if applicable)
52 *****************************************************************************
54 .section ".prefix.lib", "awx", @progbits
56 .globl print_character
58 /* Preserve registers */
62 /* If %di is non-zero, write character to buffer and exit */
68 1: /* Print character */
69 movw $0x0007, %bx /* page 0, attribute 7 (normal) */
70 movb $0x0e, %ah /* write char, tty mode */
71 cmpb $0x0a, %al /* '\n'? */
76 /* Restore registers and return */
81 .size print_character, . - print_character
83 /*****************************************************************************
84 * Utility function: print a NUL-terminated string
87 * %ds:si : string to print
88 * %ds:di : output buffer (or %di=0 to print to console)
90 * %ds:si : character after terminating NUL
91 * %ds:di : next character in output buffer (if applicable)
92 *****************************************************************************
94 .section ".prefix.lib", "awx", @progbits
98 /* Preserve registers */
106 2: /* Restore registers and return */
109 .size print_message, . - print_message
111 /*****************************************************************************
112 * Utility functions: print hex digit/byte/word/dword
115 * %al (low nibble) : digit to print
116 * %al : byte to print
117 * %ax : word to print
118 * %eax : dword to print
119 * %ds:di : output buffer (or %di=0 to print to console)
121 * %ds:di : next character in output buffer (if applicable)
122 *****************************************************************************
124 .section ".prefix.lib", "awx", @progbits
126 .globl print_hex_dword
132 .size print_hex_dword, . - print_hex_dword
133 .globl print_hex_word
139 .size print_hex_word, . - print_hex_word
140 .globl print_hex_byte
143 call print_hex_nibble
146 .size print_hex_byte, . - print_hex_byte
147 .globl print_hex_nibble
149 /* Preserve registers */
151 /* Print digit (technique by Norbert Juffa <norbert.juffa@amd.com> */
157 /* Restore registers and return */
160 .size print_hex_nibble, . - print_hex_nibble
162 /*****************************************************************************
163 * Utility function: print PCI bus:dev.fn
166 * %ax : PCI bus:dev.fn to print
167 * %ds:di : output buffer (or %di=0 to print to console)
169 * %ds:di : next character in output buffer (if applicable)
170 *****************************************************************************
172 .section ".prefix.lib", "awx", @progbits
174 .globl print_pci_busdevfn
176 /* Preserve registers */
194 call print_hex_nibble
195 /* Restore registers and return */
198 .size print_pci_busdevfn, . - print_pci_busdevfn
200 /*****************************************************************************
201 * Utility function: clear current line
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_kill_line
213 /* Preserve registers */
219 /* Print 79 spaces */
222 1: call print_character
227 /* Restore registers and return */
231 .size print_kill_line, . - print_kill_line
233 /****************************************************************************
239 * %ds:esi : source address
240 * %es:edi : destination address
243 * %ds:esi : next source address
244 * %es:edi : next destination address
247 ****************************************************************************
250 .section ".prefix.lib", "awx", @progbits
257 .size copy_bytes, . - copy_bytes
258 #endif /* COMPRESS */
260 /****************************************************************************
263 * Install block to specified address
266 * %esi : source physical address (must be a multiple of 16)
267 * %edi : destination physical address (must be a multiple of 16)
268 * %ecx : length of (decompressed) data
269 * %edx : total length of block (including any uninitialised data portion)
271 * %esi : next source physical address (will be a multiple of 16)
272 * %edi : next destination physical address (will be a multiple of 16)
275 ****************************************************************************
277 .section ".prefix.lib", "awx", @progbits
280 /* Preserve registers */
285 /* Convert %esi and %edi to %ds:esi and %es:edi */
296 /* Decompress source to destination */
299 /* Copy source to destination */
303 /* Zero .bss portion */
311 /* Round up %esi and %edi to start of next blocks */
317 /* Convert %ds:esi and %es:edi back to physical addresses */
327 /* Restore registers and return */
332 .size install_block, . - install_block
334 /****************************************************************************
337 * Allocate space for .text16 and .data16 from top of base memory.
338 * Memory is allocated using the BIOS free base memory counter at
344 * %ax : .text16 segment address
345 * %bx : .data16 segment address
348 ****************************************************************************
350 .section ".prefix.lib", "awx", @progbits
354 /* Preserve registers */
357 /* FBMS => %ax as segment address */
363 /* Calculate .data16 segment address */
364 subw $_data16_memsz_pgh, %ax
367 /* Calculate .text16 segment address */
368 subw $_text16_memsz_pgh, %ax
375 /* Retrieve .text16 and .data16 segment addresses */
379 /* Restore registers and return */
382 .size alloc_basemem, . - alloc_basemem
384 /****************************************************************************
387 * Free space allocated with alloc_basemem.
390 * %ax : .text16 segment address
391 * %bx : .data16 segment address
393 * %ax : 0 if successfully freed
396 ****************************************************************************
398 .section ".text16", "ax", @progbits
402 /* Preserve registers */
405 /* Check FBMS counter */
414 /* Check hooked interrupt count */
415 cmpw $0, %cs:hooked_bios_interrupts
418 /* OK to free memory */
419 addw $_text16_memsz_pgh, %ax
420 addw $_data16_memsz_pgh, %ax
425 1: /* Restore registers and return */
428 .size free_basemem, . - free_basemem
430 .section ".text16.data", "aw", @progbits
431 .globl hooked_bios_interrupts
432 hooked_bios_interrupts:
434 .size hooked_bios_interrupts, . - hooked_bios_interrupts
436 /****************************************************************************
439 * Install all text and data segments.
444 * %ax : .text16 segment address
445 * %bx : .data16 segment address
448 ****************************************************************************
450 .section ".prefix.lib", "awx", @progbits
454 /* Preserve registers */
457 /* Allocate space for .text16 and .data16 */
459 /* Image source = %cs:0000 */
461 /* Image destination = HIGHMEM_LOADPOINT */
462 movl $HIGHMEM_LOADPOINT, %edi
463 /* Install text and data segments */
464 call install_prealloc
465 /* Restore registers and return */
469 .size install, . - install
471 /****************************************************************************
474 * Install all text and data segments.
477 * %ax : .text16 segment address
478 * %bx : .data16 segment address
479 * %esi : Image source physical address (or zero for %cs:0000)
480 * %edi : Decompression temporary area physical address
483 ****************************************************************************
485 .section ".prefix.lib", "awx", @progbits
487 .globl install_prealloc
494 /* Sanity: clear the direction flag asap */
497 /* Copy decompression temporary area physical address to %ebp */
500 /* Install .text16.early */
505 addl $_text16_early_lma, %esi
508 movl $_text16_early_filesz, %ecx
509 movl $_text16_early_memsz, %edx
510 call install_block /* .text16.early */
513 /* Open up access to payload */
515 /* Flatten real mode */
519 pushw $flatten_real_mode
524 /* Calculate physical address of payload (i.e. first source) */
529 1: addl %cs:payload_lma, %esi
531 /* Install .text16.late and .data16 */
532 movl $_text16_late_filesz, %ecx
533 movl $_text16_late_memsz, %edx
534 call install_block /* .text16.late */
537 movl $_data16_filesz, %ecx
538 movl $_data16_memsz, %edx
539 call install_block /* .data16 */
541 /* Set up %ds for access to .data16 */
545 /* Initialise libkir */
546 movw %ax, (init_libkir_vector+2)
547 lcall *init_libkir_vector
549 /* Install .text and .data to temporary area in high memory,
550 * prior to reading the E820 memory map and relocating
554 movl $_textdata_filesz, %ecx
555 movl $_textdata_memsz, %edx
558 /* Initialise librm at current location */
559 movw %ax, (init_librm_vector+2)
561 lcall *init_librm_vector
563 /* Call relocate() to determine target address for relocation.
564 * relocate() will return with %esi, %edi and %ecx set up
565 * ready for the copy to the new location.
567 movw %ax, (prot_call_vector+2)
569 lcall *prot_call_vector
570 popl %edx /* discard */
572 /* Copy code to new location */
578 /* Initialise librm at new location */
580 lcall *init_librm_vector
583 /* Restore registers */
588 .size install_prealloc, . - install_prealloc
590 /* Vectors for far calls to .text16 functions. Must be in
591 * .data16, since .prefix may not be writable.
593 .section ".data16", "aw", @progbits
598 .size init_libkir_vector, . - init_libkir_vector
603 .size init_librm_vector, . - init_librm_vector
607 .size prot_call_vector, . - prot_call_vector
610 /* Payload address */
611 .section ".prefix.lib", "awx", @progbits
614 .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
621 /****************************************************************************
624 * Uninstall all text and data segments.
627 * %ax : .text16 segment address
628 * %bx : .data16 segment address
633 ****************************************************************************
635 .section ".text16", "ax", @progbits
641 .size uninstall, . - uninstall
645 /* File split information for the compressor */
647 #define PACK_OR_COPY "PACK"
649 #define PACK_OR_COPY "COPY"
651 .section ".zinfo", "a", @progbits
657 .long _text16_early_lma
658 .long _text16_early_filesz
665 .long _text16_late_lma
666 .long _text16_late_filesz
674 .long _textdata_filesz