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 */
178 .section ".prefix.lib"
182 gdt_limit: .word gdt_length - 1
184 .word 0 /* padding */
185 pm_cs: /* 16-bit protected-mode code segment */
186 .equ PM_CS, pm_cs - gdt
188 .byte 0, 0x9b, 0x00, 0
189 pm_ss: /* 16-bit protected-mode stack segment */
190 .equ PM_SS, pm_ss - gdt
192 .byte 0, 0x93, 0x00, 0
193 pm_ds: /* 32-bit protected-mode flat data segment */
194 .equ PM_DS, pm_ds - gdt
196 .byte 0, 0x93, 0xcf, 0
198 .equ gdt_length, . - gdt
201 .section ".prefix.lib"
205 .size pm_saved_gdt, . - pm_saved_gdt
207 .equ pm_call_vars_size, . - pm_call_vars
208 #define PM_CALL_VAR(x) ( -pm_call_vars_size + ( (x) - pm_call_vars ) )
210 .section ".prefix.lib"
213 /* Preserve registers, flags, and RM return point */
216 subw $pm_call_vars_size, %sp
227 /* Set up local variable block, and preserve GDT */
233 movw $pm_call_vars, %si
234 leaw PM_CALL_VAR(pm_call_vars)(%bp), %di
235 movw $pm_call_vars_size, %cx
240 sgdt PM_CALL_VAR(pm_saved_gdt)(%bp)
242 /* Set up GDT bases */
249 leal PM_CALL_VAR(gdt)(%eax, %edi), %eax
250 movl %eax, PM_CALL_VAR(gdt_base)(%bp)
252 movw $PM_CALL_VAR(pm_cs), %di
255 movw $PM_CALL_VAR(pm_ss), %di
260 /* Switch CPU to protected mode and load up segment registers */
263 lgdt PM_CALL_VAR(gdt)(%bp)
277 /* Call PM routine */
280 /* Set real-mode segment limits on %ds, %es, %fs and %gs */
287 /* Return CPU to real mode */
292 /* Restore registers and flags */
293 lret /* will ljmp to 99f */
299 lgdt PM_CALL_VAR(pm_saved_gdt)(%bp)
304 .size pm_call, . - pm_call
309 andw $0xfff0, 2(%bp,%di)
311 andb $0x0f, 4(%bp,%di)
313 .size set_seg_base, . - set_seg_base
315 #endif /* KEEP_IT_REAL */
317 /****************************************************************************
318 * copy_bytes (real-mode or 16-bit protected-mode near call)
323 * %ds:esi : source address
324 * %es:edi : destination address
327 * %ds:esi : next source address
328 * %es:edi : next destination address
331 ****************************************************************************
333 .section ".prefix.lib"
340 .size copy_bytes, . - copy_bytes
342 /****************************************************************************
343 * install_block (real-mode near call)
345 * Install block to specified address
348 * %esi : source physical address (must be a multiple of 16)
349 * %edi : destination physical address (must be a multiple of 16)
350 * %ecx : length of (decompressed) data
351 * %edx : total length of block (including any uninitialised data portion)
353 * %esi : next source physical address (will be a multiple of 16)
356 ****************************************************************************
358 .section ".prefix.lib"
364 /* Preserve registers */
370 /* Convert %esi and %edi to segment registers */
378 #else /* KEEP_IT_REAL */
380 /* Call self in protected mode */
387 /* Preserve registers */
391 #endif /* KEEP_IT_REAL */
395 /* Decompress source to destination */
398 /* Copy source to destination */
402 /* Zero .bss portion */
410 /* Round up %esi to start of next source block */
417 /* Convert %ds:esi back to a physical address */
422 /* Restore registers */
428 #else /* KEEP_IT_REAL */
430 /* Restore registers */
437 .size install_block, . - install_block
439 /****************************************************************************
440 * alloc_basemem (real-mode near call)
442 * Allocate space for .text16 and .data16 from top of base memory.
443 * Memory is allocated using the BIOS free base memory counter at
449 * %ax : .text16 segment address
450 * %bx : .data16 segment address
453 ****************************************************************************
455 .section ".prefix.lib"
459 /* FBMS => %ax as segment address */
465 /* .data16 segment address */
466 subw $_data16_size_pgh, %ax
469 /* .text16 segment address */
470 subw $_text16_size_pgh, %ax
481 .size alloc_basemem, . - alloc_basemem
483 /****************************************************************************
484 * install (real-mode near call)
486 * Install all text and data segments.
491 * %ax : .text16 segment address
492 * %bx : .data16 segment address
495 ****************************************************************************
497 .section ".prefix.lib"
501 /* Preserve registers */
504 /* Allocate space for .text16 and .data16 */
506 /* Image source = %cs:0000 */
508 /* Image destination = HIGHMEM_LOADPOINT */
509 movl $HIGHMEM_LOADPOINT, %edi
510 /* Install text and data segments */
511 call install_prealloc
512 /* Restore registers and return */
516 .size install, . - install
518 /****************************************************************************
519 * install_prealloc (real-mode near call)
521 * Install all text and data segments.
524 * %ax : .text16 segment address
525 * %bx : .data16 segment address
526 * %esi : Image source physical address (or zero for %cs:0000)
527 * %edi : Decompression temporary area physical address
530 ****************************************************************************
532 .section ".prefix.lib"
534 .globl install_prealloc
541 /* Sanity: clear the direction flag asap */
544 /* Calculate physical address of payload (i.e. first source) */
549 1: addl $_payload_offset, %esi
551 /* Install .text16 and .data16 */
555 movl $_text16_size, %ecx
557 call install_block /* .text16 */
560 movl $_data16_progbits_size, %ecx
561 movl $_data16_size, %edx
562 call install_block /* .data16 */
565 /* Set up %ds for access to .data16 */
569 /* Initialise libkir */
570 movw %ax, (init_libkir_vector+2)
571 lcall *init_libkir_vector
573 /* Install .text and .data to temporary area in high memory,
574 * prior to reading the E820 memory map and relocating
577 movl $_textdata_progbits_size, %ecx
578 movl $_textdata_size, %edx
581 /* Initialise librm at current location */
582 movw %ax, (init_librm_vector+2)
583 lcall *init_librm_vector
585 /* Call relocate() to determine target address for relocation.
586 * relocate() will return with %esi, %edi and %ecx set up
587 * ready for the copy to the new location.
589 movw %ax, (prot_call_vector+2)
591 lcall *prot_call_vector
592 popl %edx /* discard */
594 /* Copy code to new location */
597 movw $copy_bytes, %ax
602 /* Initialise librm at new location */
603 lcall *init_librm_vector
606 /* Restore registers */
611 .size install_prealloc, . - install_prealloc
613 /* Vectors for far calls to .text16 functions */
619 .size init_libkir_vector, . - init_libkir_vector
624 .size init_librm_vector, . - init_librm_vector
628 .size prot_call_vector, . - prot_call_vector
632 /* File split information for the compressor */
634 .section ".zinfo", "a"
636 .long _prefix_load_offset
637 .long _prefix_progbits_size
640 .long _text16_load_offset
641 .long _text16_progbits_size
644 .long _data16_load_offset
645 .long _data16_progbits_size
648 .long _textdata_load_offset
649 .long _textdata_progbits_size
652 .section ".zinfo", "a"
654 .long _prefix_load_offset
657 #endif /* COMPRESS */