[contrib] Allow Network Protocol header to display in rom-o-matic
[gpxe.git] / src / arch / i386 / prefix / libprefix.S
blob340e74be23a026aa6c0312f807601b51f74e61ea
1 /*
2  * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3  *
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.
8  *
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.
13  *
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.
17  *
18  */
20 FILE_LICENCE ( GPL2_OR_LATER )
22         .arch i386
24 /* Image compression enabled */
25 #define COMPRESS 1
27 /*****************************************************************************
28  * Utility function: print character (with LF -> LF,CR translation)
29  *
30  * Parameters:
31  *   %al : character to print
32  *   %ds:di : output buffer (or %di=0 to print to console)
33  * Returns:
34  *   %ds:di : next character in output buffer (if applicable)
35  *****************************************************************************
36  */
37         .section ".prefix.lib", "awx", @progbits
38         .code16
39         .globl  print_character
40 print_character:
41         /* Preserve registers */
42         pushw   %ax
43         pushw   %bx
44         pushw   %bp
45         /* If %di is non-zero, write character to buffer and exit */
46         testw   %di, %di
47         jz      1f
48         movb    %al, %ds:(%di)
49         incw    %di
50         jmp     3f
51 1:      /* Print character */
52         movw    $0x0007, %bx            /* page 0, attribute 7 (normal) */
53         movb    $0x0e, %ah              /* write char, tty mode */
54         cmpb    $0x0a, %al              /* '\n'? */
55         jne     2f
56         int     $0x10
57         movb    $0x0d, %al
58 2:      int     $0x10
59         /* Restore registers and return */
60 3:      popw    %bp
61         popw    %bx
62         popw    %ax
63         ret
64         .size   print_character, . - print_character
66 /*****************************************************************************
67  * Utility function: print a NUL-terminated string
68  *
69  * Parameters:
70  *   %ds:si : string to print
71  *   %ds:di : output buffer (or %di=0 to print to console)
72  * Returns:
73  *   %ds:si : character after terminating NUL
74  *   %ds:di : next character in output buffer (if applicable)
75  *****************************************************************************
76  */
77         .section ".prefix.lib", "awx", @progbits
78         .code16
79         .globl  print_message
80 print_message:
81         /* Preserve registers */
82         pushw   %ax
83         /* Print string */
84 1:      lodsb
85         testb   %al, %al
86         je      2f
87         call    print_character
88         jmp     1b
89 2:      /* Restore registers and return */
90         popw    %ax
91         ret
92         .size   print_message, . - print_message
94 /*****************************************************************************
95  * Utility functions: print hex digit/byte/word/dword
96  *
97  * Parameters:
98  *   %al (low nibble) : digit to print
99  *   %al : byte to print
100  *   %ax : word to print
101  *   %eax : dword to print
102  *   %ds:di : output buffer (or %di=0 to print to console)
103  * Returns:
104  *   %ds:di : next character in output buffer (if applicable)
105  *****************************************************************************
106  */
107         .section ".prefix.lib", "awx", @progbits
108         .code16
109         .globl  print_hex_dword
110 print_hex_dword:
111         rorl    $16, %eax
112         call    print_hex_word
113         rorl    $16, %eax
114         /* Fall through */
115         .size   print_hex_dword, . - print_hex_dword
116         .globl  print_hex_word
117 print_hex_word:
118         xchgb   %al, %ah
119         call    print_hex_byte
120         xchgb   %al, %ah
121         /* Fall through */
122         .size   print_hex_word, . - print_hex_word
123         .globl  print_hex_byte
124 print_hex_byte:
125         rorb    $4, %al
126         call    print_hex_nibble
127         rorb    $4, %al
128         /* Fall through */
129         .size   print_hex_byte, . - print_hex_byte
130         .globl  print_hex_nibble
131 print_hex_nibble:
132         /* Preserve registers */
133         pushw   %ax
134         /* Print digit (technique by Norbert Juffa <norbert.juffa@amd.com> */
135         andb    $0x0f, %al
136         cmpb    $10, %al
137         sbbb    $0x69, %al
138         das
139         call    print_character
140         /* Restore registers and return */
141         popw    %ax
142         ret
143         .size   print_hex_nibble, . - print_hex_nibble
145 /*****************************************************************************
146  * Utility function: print PCI bus:dev.fn
148  * Parameters:
149  *   %ax : PCI bus:dev.fn to print
150  *   %ds:di : output buffer (or %di=0 to print to console)
151  * Returns:
152  *   %ds:di : next character in output buffer (if applicable)
153  *****************************************************************************
154  */
155         .section ".prefix.lib", "awx", @progbits
156         .code16
157         .globl  print_pci_busdevfn
158 print_pci_busdevfn:
159         /* Preserve registers */
160         pushw   %ax
161         /* Print bus */
162         xchgb   %al, %ah
163         call    print_hex_byte
164         /* Print ":" */
165         movb    $( ':' ), %al
166         call    print_character
167         /* Print device */
168         movb    %ah, %al
169         shrb    $3, %al
170         call    print_hex_byte
171         /* Print "." */
172         movb    $( '.' ), %al
173         call    print_character
174         /* Print function */
175         movb    %ah, %al
176         andb    $0x07, %al
177         call    print_hex_nibble
178         /* Restore registers and return */
179         popw    %ax
180         ret
181         .size   print_pci_busdevfn, . - print_pci_busdevfn
183 /*****************************************************************************
184  * Utility function: clear current line
186  * Parameters:
187  *   %ds:di : output buffer (or %di=0 to print to console)
188  * Returns:
189  *   %ds:di : next character in output buffer (if applicable)
190  *****************************************************************************
191  */
192         .section ".prefix.lib", "awx", @progbits
193         .code16
194         .globl  print_kill_line
195 print_kill_line:
196         /* Preserve registers */
197         pushw   %ax
198         pushw   %cx
199         /* Print CR */
200         movb    $( '\r' ), %al
201         call    print_character
202         /* Print 79 spaces */
203         movb    $( ' ' ), %al
204         movw    $79, %cx
205 1:      call    print_character
206         loop    1b
207         /* Print CR */
208         movb    $( '\r' ), %al
209         call    print_character
210         /* Restore registers and return */
211         popw    %cx
212         popw    %ax
213         ret
214         .size   print_kill_line, . - print_kill_line
216 /****************************************************************************
217  * copy_bytes
219  * Copy bytes
221  * Parameters:
222  *   %ds:esi : source address
223  *   %es:edi : destination address
224  *   %ecx : length
225  * Returns:
226  *   %ds:esi : next source address
227  *   %es:edi : next destination address
228  * Corrupts:
229  *   None
230  ****************************************************************************
231  */
232 #if ! COMPRESS
233         .section ".prefix.lib", "awx", @progbits
234         .code16
235 copy_bytes:
236         pushl %ecx
237         rep addr32 movsb
238         popl %ecx
239         ret
240         .size copy_bytes, . - copy_bytes
241 #endif /* COMPRESS */
243 /****************************************************************************
244  * install_block
246  * Install block to specified address
248  * Parameters:
249  *   %esi : source physical address (must be a multiple of 16)
250  *   %edi : destination physical address (must be a multiple of 16)
251  *   %ecx : length of (decompressed) data
252  *   %edx : total length of block (including any uninitialised data portion)
253  * Returns:
254  *   %esi : next source physical address (will be a multiple of 16)
255  *   %edi : next destination physical address (will be a multiple of 16)
256  * Corrupts:
257  *   none
258  ****************************************************************************
259  */
260         .section ".prefix.lib", "awx", @progbits
261         .code16
262 install_block:
263         /* Preserve registers */
264         pushw   %ds
265         pushw   %es
266         pushl   %ecx
267         
268         /* Convert %esi and %edi to %ds:esi and %es:edi */
269         shrl    $4, %esi
270         movw    %si, %ds
271         xorw    %si, %si
272         shll    $4, %esi
273         shrl    $4, %edi
274         movw    %di, %es
275         xorw    %di, %di
276         shll    $4, %edi
278 #if COMPRESS
279         /* Decompress source to destination */
280         call    decompress16
281 #else
282         /* Copy source to destination */
283         call    copy_bytes
284 #endif
286         /* Zero .bss portion */
287         negl    %ecx
288         addl    %edx, %ecx
289         pushw   %ax
290         xorw    %ax, %ax
291         rep addr32 stosb
292         popw    %ax
294         /* Round up %esi and %edi to start of next blocks */
295         addl    $0xf, %esi
296         andl    $~0xf, %esi
297         addl    $0xf, %edi
298         andl    $~0xf, %edi
300         /* Convert %ds:esi and %es:edi back to physical addresses */
301         xorl    %ecx, %ecx
302         movw    %ds, %cx
303         shll    $4, %ecx
304         addl    %ecx, %esi
305         xorl    %ecx, %ecx
306         movw    %es, %cx
307         shll    $4, %ecx
308         addl    %ecx, %edi
310         /* Restore registers and return */
311         popl    %ecx
312         popw    %es
313         popw    %ds
314         ret
315         .size install_block, . - install_block
317 /****************************************************************************
318  * alloc_basemem
320  * Allocate space for .text16 and .data16 from top of base memory.
321  * Memory is allocated using the BIOS free base memory counter at
322  * 0x40:13.
324  * Parameters: 
325  *   none
326  * Returns:
327  *   %ax : .text16 segment address
328  *   %bx : .data16 segment address
329  * Corrupts:
330  *   none
331  ****************************************************************************
332  */
333         .section ".prefix.lib", "awx", @progbits
334         .code16
335         .globl  alloc_basemem
336 alloc_basemem:
337         /* Preserve registers */
338         pushw   %fs
340         /* FBMS => %ax as segment address */
341         pushw   $0x40
342         popw    %fs
343         movw    %fs:0x13, %ax
344         shlw    $6, %ax
346         /* Calculate .data16 segment address */
347         subw    $_data16_memsz_pgh, %ax
348         pushw   %ax
350         /* Calculate .text16 segment address */
351         subw    $_text16_memsz_pgh, %ax
352         pushw   %ax
354         /* Update FBMS */
355         shrw    $6, %ax
356         movw    %ax, %fs:0x13
358         /* Retrieve .text16 and .data16 segment addresses */
359         popw    %ax
360         popw    %bx
362         /* Restore registers and return */
363         popw    %fs
364         ret
365         .size alloc_basemem, . - alloc_basemem
367 /****************************************************************************
368  * free_basemem
370  * Free space allocated with alloc_basemem.
372  * Parameters:
373  *   %ax : .text16 segment address
374  *   %bx : .data16 segment address
375  * Returns:
376  *   %ax : 0 if successfully freed
377  * Corrupts:
378  *   none
379  ****************************************************************************
380  */
381         .section ".text16", "ax", @progbits
382         .code16
383         .globl  free_basemem
384 free_basemem:
385         /* Preserve registers */
386         pushw   %fs
388         /* Check FBMS counter */
389         pushw   %ax
390         shrw    $6, %ax
391         pushw   $0x40
392         popw    %fs
393         cmpw    %ax, %fs:0x13
394         popw    %ax
395         jne     1f
397         /* Check hooked interrupt count */
398         cmpw    $0, %cs:hooked_bios_interrupts
399         jne     1f
401         /* OK to free memory */
402         addw    $_text16_memsz_pgh, %ax
403         addw    $_data16_memsz_pgh, %ax
404         shrw    $6, %ax
405         movw    %ax, %fs:0x13
406         xorw    %ax, %ax
408 1:      /* Restore registers and return */
409         popw    %fs
410         ret
411         .size free_basemem, . - free_basemem
413         .section ".text16.data", "aw", @progbits
414         .globl  hooked_bios_interrupts
415 hooked_bios_interrupts:
416         .word   0
417         .size   hooked_bios_interrupts, . - hooked_bios_interrupts
419 /****************************************************************************
420  * install
422  * Install all text and data segments.
424  * Parameters:
425  *   none
426  * Returns:
427  *   %ax  : .text16 segment address
428  *   %bx  : .data16 segment address
429  * Corrupts:
430  *   none
431  ****************************************************************************
432  */
433         .section ".prefix.lib", "awx", @progbits
434         .code16
435         .globl install
436 install:
437         /* Preserve registers */
438         pushl   %esi
439         pushl   %edi
440         /* Allocate space for .text16 and .data16 */
441         call    alloc_basemem
442         /* Image source = %cs:0000 */
443         xorl    %esi, %esi
444         /* Image destination = default */
445         xorl    %edi, %edi
446         /* Allow relocation */
447         clc
448         /* Install text and data segments */
449         call    install_prealloc
450         /* Restore registers and return */
451         popl    %edi
452         popl    %esi
453         ret
454         .size install, . - install
456 /****************************************************************************
457  * install_prealloc
459  * Install all text and data segments.
461  * Parameters:
462  *   %ax  : .text16 segment address
463  *   %bx  : .data16 segment address
464  *   %esi : Image source physical address (or zero for %cs:0000)
465  *   %edi : Decompression temporary area physical address (or zero for default)
466  *   CF set : Avoid relocating to top of memory
467  * Corrupts:
468  *   none
469  ****************************************************************************
470  */
471         .section ".prefix.lib", "awx", @progbits
472         .code16
473         .globl install_prealloc
474 install_prealloc:
475         /* Save registers */
476         pushal
477         pushw   %ds
478         pushw   %es
479         cld                     /* Sanity: clear the direction flag asap */
480         pushfw
482         /* Set up %ds for (read-only) access to .prefix */
483         pushw   %cs
484         popw    %ds
486         /* Copy decompression temporary area physical address to %ebp */
487         movl    %edi, %ebp
489         /* Install .text16.early */
490         pushl   %esi
491         xorl    %esi, %esi
492         movw    %cs, %si
493         shll    $4, %esi
494         addl    $_text16_early_lma, %esi
495         movzwl  %ax, %edi
496         shll    $4, %edi
497         movl    $_text16_early_filesz, %ecx
498         movl    $_text16_early_memsz, %edx
499         call    install_block           /* .text16.early */
500         popl    %esi
502 #ifndef KEEP_IT_REAL
503         /* Access high memory */
504         pushw   %cs
505         pushw   $1f
506         pushw   %ax
507         pushw   $access_highmem
508         lret
509 1:      /* Die if we could not access high memory */
510         jnc     3f
511         movw    $a20_death_message, %si
512         xorw    %di, %di
513         call    print_message
514 2:      jmp     2b
515         .section ".prefix.data", "aw", @progbits
516 a20_death_message:
517         .asciz  "\nHigh memory inaccessible - cannot continue\n"
518         .size   a20_death_message, . - a20_death_message
519         .previous
521 #endif
523         /* Open payload (which may not yet be in memory) */
524         pushw   %cs
525         pushw   $1f
526         pushw   %ax
527         pushw   $open_payload
528         lret
529 1:      /* Die if we could not access the payload */
530         jnc     3f
531         xorw    %di, %di
532         movl    %esi, %eax
533         call    print_hex_dword
534         movw    $payload_death_message, %si
535         call    print_message
536 2:      jmp     2b
537         .section ".prefix.data", "aw", @progbits
538 payload_death_message:
539         .asciz  "\nPayload inaccessible - cannot continue\n"
540         .size   payload_death_message, . - payload_death_message
541         .previous
544         /* Calculate physical address of payload (i.e. first source) */
545         testl   %esi, %esi
546         jnz     1f
547         movw    %cs, %si
548         shll    $4, %esi
549 1:      addl    payload_lma, %esi
551         /* Install .text16.late and .data16 */
552         movl    $_text16_late_filesz, %ecx
553         movl    $_text16_late_memsz, %edx
554         call    install_block           /* .text16.late */
555         movzwl  %bx, %edi
556         shll    $4, %edi
557         movl    $_data16_filesz, %ecx
558         movl    $_data16_memsz, %edx
559         call    install_block           /* .data16 */
561         /* Set up %ds for access to .data16 */
562         movw    %bx, %ds
564 #ifdef KEEP_IT_REAL
565         /* Initialise libkir */
566         movw    %ax, (init_libkir_vector+2)
567         lcall   *init_libkir_vector
568 #else
569         /* Find a suitable decompression temporary area, if none specified */
570         testl   %ebp, %ebp
571         jnz     1f
572         /* Use INT 15,88 to find the highest available address via INT
573          * 15,88.  This limits us to around 64MB, which should avoid
574          * all of the POST-time memory map failure modes.
575          */
576         pushl   %eax
577         movb    $0x88, %ah
578         int     $0x15
579         movw    %ax, %bp
580         addl    $0x400, %ebp
581         subl    $_textdata_memsz_kb, %ebp
582         shll    $10, %ebp
583         popl    %eax
585         /* Install .text and .data to temporary area in high memory,
586          * prior to reading the E820 memory map and relocating
587          * properly.
588          */
589         movl    %ebp, %edi
590         movl    $_textdata_filesz, %ecx
591         movl    $_textdata_memsz, %edx
592         call    install_block
594         /* Initialise librm at current location */
595         movw    %ax, (init_librm_vector+2)
596         movl    %ebp, %edi
597         lcall   *init_librm_vector
599         /* Skip relocation if CF was set on entry */
600         popfw
601         pushfw
602         jc      skip_relocate
604         /* Call relocate() to determine target address for relocation.
605          * relocate() will return with %esi, %edi and %ecx set up
606          * ready for the copy to the new location.
607          */
608         movw    %ax, (prot_call_vector+2)
609         pushl   $relocate
610         lcall   *prot_call_vector
611         popl    %edx /* discard */
613         /* Copy code to new location */
614         pushl   %edi
615         pushw   %ax
616         xorw    %ax, %ax
617         movw    %ax, %es
618         es rep addr32 movsb
619         popw    %ax
620         popl    %edi
622         /* Initialise librm at new location */
623         lcall   *init_librm_vector
624 skip_relocate:
625 #endif
627         /* Close access to payload */
628         movw    %ax, (close_payload_vector+2)
629         lcall   *close_payload_vector
631         /* Restore registers */
632         popfw
633         popw    %es
634         popw    %ds
635         popal
636         ret
637         .size install_prealloc, . - install_prealloc
639         /* Vectors for far calls to .text16 functions.  Must be in
640          * .data16, since .prefix may not be writable.
641          */
642         .section ".data16", "aw", @progbits
643 #ifdef KEEP_IT_REAL
644 init_libkir_vector:
645         .word init_libkir
646         .word 0
647         .size init_libkir_vector, . - init_libkir_vector
648 #else
649 init_librm_vector:
650         .word init_librm
651         .word 0
652         .size init_librm_vector, . - init_librm_vector
653 prot_call_vector:
654         .word prot_call
655         .word 0
656         .size prot_call_vector, . - prot_call_vector
657 #endif
658 close_payload_vector:
659         .word close_payload
660         .word 0
661         .size close_payload_vector, . - close_payload_vector
663         /* Payload address */
664         .section ".prefix.lib", "awx", @progbits
665 payload_lma:
666         .long 0
667         .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
668         .ascii  "ADHL"
669         .long   payload_lma
670         .long   1
671         .long   0
672         .previous
674         /* Dummy routines to open and close payload */
675         .section ".text16.early.data", "aw", @progbits
676         .weak   open_payload
677         .weak   close_payload
678 open_payload:
679 close_payload:
680         clc
681         lret
682         .size   open_payload, . - open_payload
683         .size   close_payload, . - close_payload
685 /****************************************************************************
686  * uninstall
688  * Uninstall all text and data segments.
690  * Parameters:
691  *   %ax  : .text16 segment address
692  *   %bx  : .data16 segment address
693  * Returns:
694  *   none
695  * Corrupts:
696  *   none
697  ****************************************************************************
698  */
699         .section ".text16", "ax", @progbits
700         .code16
701         .globl uninstall
702 uninstall:
703         call    free_basemem
704         ret
705         .size uninstall, . - uninstall
709         /* File split information for the compressor */
710 #if COMPRESS
711 #define PACK_OR_COPY    "PACK"
712 #else
713 #define PACK_OR_COPY    "COPY"
714 #endif
715         .section ".zinfo", "a", @progbits
716         .ascii  "COPY"
717         .long   _prefix_lma
718         .long   _prefix_filesz
719         .long   _max_align
720         .ascii  PACK_OR_COPY
721         .long   _text16_early_lma
722         .long   _text16_early_filesz
723         .long   _max_align
724         .ascii  "PAYL"
725         .long   0
726         .long   0
727         .long   _max_align
728         .ascii  PACK_OR_COPY
729         .long   _text16_late_lma
730         .long   _text16_late_filesz
731         .long   _max_align
732         .ascii  PACK_OR_COPY
733         .long   _data16_lma
734         .long   _data16_filesz
735         .long   _max_align
736         .ascii  PACK_OR_COPY
737         .long   _textdata_lma
738         .long   _textdata_filesz
739         .long   _max_align