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.
21 .section ".prefix.lib", "awx", @progbits
22 .section ".data16", "aw", @progbits
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 */
46 /*****************************************************************************
47 * Utility function: print character (with LF -> LF,CR translation)
50 * %al : character to print
55 *****************************************************************************
57 .section ".prefix.lib"
59 .globl print_character
61 /* Preserve registers */
65 movw $0x0007, %bx /* page 0, attribute 7 (normal) */
66 movb $0x0e, %ah /* write char, tty mode */
67 cmpb $0x0a, %al /* '\n'? */
72 /* Restore registers and return */
76 .size print_character, . - print_character
78 /*****************************************************************************
79 * Utility function: print a NUL-terminated string
82 * %ds:si : string to print
84 * %ds:si : character after terminating NUL
85 *****************************************************************************
87 .section ".prefix.lib"
91 /* Preserve registers */
99 2: /* Restore registers and return */
102 .size print_message, . - print_message
104 /*****************************************************************************
105 * Utility functions: print hex digit/byte/word/dword
108 * %al (low nibble) : digit to print
109 * %al : byte to print
110 * %ax : word to print
111 * %eax : dword to print
114 *****************************************************************************
116 .section ".prefix.lib"
118 .globl print_hex_dword
124 .size print_hex_dword, . - print_hex_dword
125 .globl print_hex_word
131 .size print_hex_word, . - print_hex_word
132 .globl print_hex_byte
135 call print_hex_nibble
138 .size print_hex_byte, . - print_hex_byte
139 .globl print_hex_nibble
141 /* Preserve registers */
143 /* Print digit (technique by Norbert Juffa <norbert.juffa@amd.com> */
149 /* Restore registers and return */
152 .size print_hex_nibble, . - print_hex_nibble
154 /****************************************************************************
155 * pm_call (real-mode near call)
157 * Call routine in 16-bit protected mode for access to extended memory
160 * %ax : address of routine to call in 16-bit protected mode
166 * The specified routine is called in 16-bit protected mode, with:
168 * %cs : 16-bit code segment with base matching real-mode %cs
169 * %ss : 16-bit data segment with base matching real-mode %ss
170 * %ds,%es,%fs,%gs : 32-bit data segment with zero base and 4GB limit
172 ****************************************************************************
177 /* GDT for protected-mode calls */
181 gdt_limit: .word gdt_length - 1
183 .word 0 /* padding */
184 pm_cs: /* 16-bit protected-mode code segment */
185 .equ PM_CS, pm_cs - gdt
187 .byte 0, 0x9b, 0x00, 0
188 pm_ss: /* 16-bit protected-mode stack segment */
189 .equ PM_SS, pm_ss - gdt
191 .byte 0, 0x93, 0x00, 0
192 pm_ds: /* 32-bit protected-mode flat data segment */
193 .equ PM_DS, pm_ds - gdt
195 .byte 0, 0x93, 0xcf, 0
197 .equ gdt_length, . - gdt
204 .size pm_saved_gdt, . - pm_saved_gdt
206 .section ".prefix.lib"
209 /* Preserve registers, flags, GDT, and RM return point */
220 /* Set up GDT bases */
237 /* Switch CPU to protected mode and load up segment registers */
254 /* Call PM routine */
257 /* Set real-mode segment limits on %ds, %es, %fs and %gs */
264 /* Return CPU to real mode */
269 /* Restore registers and flags */
270 lret /* will ljmp to 99f */
280 .size pm_call, . - pm_call
289 .size set_seg_base, . - set_seg_base
291 #endif /* KEEP_IT_REAL */
293 /****************************************************************************
294 * copy_bytes (real-mode or 16-bit protected-mode near call)
299 * %ds:esi : source address
300 * %es:edi : destination address
303 * %ds:esi : next source address
304 * %ds:esi : next destination address
307 ****************************************************************************
309 .section ".prefix.lib"
316 .size copy_bytes, . - copy_bytes
318 /****************************************************************************
319 * install_block (real-mode or 16-bit protected-mode near call)
321 * Install block to specified address
324 * %ds:esi : source address (must be a multiple of 16)
325 * %es:edi : destination address
326 * %ecx : length of (decompressed) data
327 * %edx : total length of block (including any uninitialised data portion)
329 * %ds:esi : next source address (will be a multiple of 16)
332 ****************************************************************************
334 .section ".prefix.lib"
337 /* Preserve registers */
341 /* Decompress source to destination */
344 /* Copy source to destination */
348 /* Zero .bss portion */
356 /* Round up %esi to start of next source block */
360 /* Restore registers and return */
363 .size install_block, . - install_block
365 /****************************************************************************
366 * alloc_basemem (real-mode near call)
368 * Allocate space for .text16 and .data16 from top of base memory.
369 * Memory is allocated using the BIOS free base memory counter at
375 * %ax : .text16 segment address
376 * %bx : .data16 segment address
379 ****************************************************************************
381 .section ".prefix.lib"
385 /* FBMS => %ax as segment address */
391 /* .data16 segment address */
392 subw $_data16_size_pgh, %ax
395 /* .text16 segment address */
396 subw $_text16_size_pgh, %ax
407 .size alloc_basemem, . - alloc_basemem
409 /****************************************************************************
410 * install_basemem (real-mode near call)
412 * Install source block into base memory
415 * %esi : source physical address (must be a multiple of 16)
416 * %es : destination segment address
417 * %cx : length of (decompressed) data
418 * %dx : total length of block (including any uninitialised data portion)
420 * %esi : next source physical address (will be a multiple of 16)
423 ****************************************************************************
425 .section ".prefix.lib"
428 /* Preserve registers */
432 /* Preserve original %esi */
435 /* Install to specified address */
444 /* Fix up %esi for return */
448 /* Restore registers */
452 .size install_basemem, . - install_basemem
454 /****************************************************************************
455 * install_highmem (real-mode near call)
457 * Install source block into high memory
460 * %esi : source physical address (must be a multiple of 16)
461 * %edi : destination physical address
462 * %ecx : length of (decompressed) data
463 * %edx : total length of block (including any uninitialised data portion)
465 * %esi : next source physical address (will be a multiple of 16)
468 ****************************************************************************
473 .section ".prefix.lib"
476 /* Preserve registers */
479 /* Install to specified address */
480 movw $install_block, %ax
483 /* Restore registers */
486 .size install_highmem, . - install_highmem
488 #endif /* KEEP_IT_REAL */
490 /****************************************************************************
491 * install (real-mode near call)
493 * Install all text and data segments.
498 * %ax : .text16 segment address
499 * %bx : .data16 segment address
502 ****************************************************************************
504 .section ".prefix.lib"
508 /* Preserve registers */
511 /* Allocate space for .text16 and .data16 */
513 /* Image source = %cs:0000 */
515 /* Image destination = HIGHMEM_LOADPOINT */
516 movl $HIGHMEM_LOADPOINT, %edi
517 /* Install text and data segments */
518 call install_prealloc
519 /* Restore registers and return */
523 .size install, . - install
525 /****************************************************************************
526 * install_prealloc (real-mode near call)
528 * Install all text and data segments.
531 * %ax : .text16 segment address
532 * %bx : .data16 segment address
533 * %esi : Image source physical address (or zero for %cs:0000)
534 * %edi : Decompression temporary area physical address
537 ****************************************************************************
539 .section ".prefix.lib"
541 .globl install_prealloc
548 /* Sanity: clear the direction flag asap */
551 /* Calculate physical address of payload (i.e. first source) */
556 1: addl $_payload_offset, %esi
558 /* Install .text16 */
560 movw $_text16_size, %cx
564 /* Install .data16 */
566 movw $_data16_progbits_size, %cx
567 movw $_data16_size, %dx
570 /* Set up %ds for access to .data16 */
574 /* Initialise libkir */
575 movw %ax, (init_libkir_vector+2)
576 lcall *init_libkir_vector
578 /* Install .text and .data to temporary area in high memory,
579 * prior to reading the E820 memory map and relocating
582 movl $_textdata_progbits_size, %ecx
583 movl $_textdata_size, %edx
588 /* Initialise librm at current location */
589 movw %ax, (init_librm_vector+2)
590 lcall *init_librm_vector
592 /* Call relocate() to determine target address for relocation.
593 * relocate() will return with %esi, %edi and %ecx set up
594 * ready for the copy to the new location.
596 movw %ax, (prot_call_vector+2)
598 lcall *prot_call_vector
599 popl %edx /* discard */
601 /* Copy code to new location */
604 movw $copy_bytes, %ax
609 /* Initialise librm at new location */
610 lcall *init_librm_vector
613 /* Restore registers */
618 .size install_prealloc, . - install_prealloc
620 /* Vectors for far calls to .text16 functions */
626 .size init_libkir_vector, . - init_libkir_vector
631 .size init_librm_vector, . - init_librm_vector
635 .size prot_call_vector, . - prot_call_vector
639 /* File split information for the compressor */
641 .section ".zinfo", "a"
643 .long _prefix_load_offset
644 .long _prefix_progbits_size
647 .long _text16_load_offset
648 .long _text16_progbits_size
651 .long _data16_load_offset
652 .long _data16_progbits_size
655 .long _textdata_load_offset
656 .long _textdata_progbits_size
659 .section ".zinfo", "a"
661 .long _prefix_load_offset
664 #endif /* COMPRESS */