[prefix] Use CRC32 to verify each block prior to decompression
[ipxe.git] / src / arch / x86 / prefix / libprefix.S
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., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  *
23  */
24
25 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
26
27 #include <librm.h>
28
29         .arch i386
30
31 /* Image compression enabled */
32 #define COMPRESS 1
33
34 /* Protected mode flag */
35 #define CR0_PE 1
36
37 /* Allow for DBG()-style messages within libprefix */
38 #ifdef NDEBUG
39         .macro  progress message
40         .endm
41 #else
42         .macro  progress message
43         pushfl
44         pushw   %ds
45         pushw   %si
46         pushw   %di
47         pushw   %cs
48         popw    %ds
49         xorw    %di, %di
50         movw    $progress_\@, %si
51         call    print_message
52         popw    %di
53         popw    %si
54         popw    %ds
55         popfl
56         .section ".prefix.data", "aw", @progbits
57 progress_\@:
58         .asciz  "\message"
59         .size   progress_\@, . - progress_\@
60         .previous
61         .endm
62 #endif
63
64 /*****************************************************************************
65  * Utility function: print character (with LF -> LF,CR translation)
66  *
67  * Parameters:
68  *   %al : character to print
69  *   %ds:di : output buffer (or %di=0 to print to console)
70  * Returns:
71  *   %ds:di : next character in output buffer (if applicable)
72  *****************************************************************************
73  */
74         .section ".prefix.print_character", "awx", @progbits
75         .code16
76         .globl  print_character
77 print_character:
78         /* Preserve registers */
79         pushw   %ax
80         pushw   %bx
81         pushw   %bp
82         /* If %di is non-zero, write character to buffer and exit */
83         testw   %di, %di
84         jz      1f
85         movb    %al, %ds:(%di)
86         incw    %di
87         jmp     3f
88 1:      /* Print character */
89         movw    $0x0007, %bx            /* page 0, attribute 7 (normal) */
90         movb    $0x0e, %ah              /* write char, tty mode */
91         cmpb    $0x0a, %al              /* '\n'? */
92         jne     2f
93         int     $0x10
94         movb    $0x0d, %al
95 2:      int     $0x10
96         /* Restore registers and return */
97 3:      popw    %bp
98         popw    %bx
99         popw    %ax
100         ret
101         .size   print_character, . - print_character
102
103 /*****************************************************************************
104  * Utility function: print space
105  *
106  * Parameters:
107  *   %ds:di : output buffer (or %di=0 to print to console)
108  * Returns:
109  *   %ds:di : next character in output buffer (if applicable)
110  *****************************************************************************
111  */
112         .section ".prefix.print_space", "awx", @progbits
113         .code16
114         .globl  print_space
115 print_space:
116         /* Preserve registers */
117         pushw   %ax
118         /* Print space */
119         movb    $( ' ' ), %al
120         call    print_character
121         /* Restore registers and return */
122         popw    %ax
123         ret
124         .size   print_space, . - print_space
125
126 /*****************************************************************************
127  * Utility function: print a NUL-terminated string
128  *
129  * Parameters:
130  *   %ds:si : string to print
131  *   %ds:di : output buffer (or %di=0 to print to console)
132  * Returns:
133  *   %ds:si : character after terminating NUL
134  *   %ds:di : next character in output buffer (if applicable)
135  *****************************************************************************
136  */
137         .section ".prefix.print_message", "awx", @progbits
138         .code16
139         .globl  print_message
140 print_message:
141         /* Preserve registers */
142         pushw   %ax
143         /* Print string */
144 1:      lodsb
145         testb   %al, %al
146         je      2f
147         call    print_character
148         jmp     1b
149 2:      /* Restore registers and return */
150         popw    %ax
151         ret
152         .size   print_message, . - print_message
153
154 /*****************************************************************************
155  * Utility functions: print hex digit/byte/word/dword
156  *
157  * Parameters:
158  *   %al (low nibble) : digit to print
159  *   %al : byte to print
160  *   %ax : word to print
161  *   %eax : dword to print
162  *   %ds:di : output buffer (or %di=0 to print to console)
163  * Returns:
164  *   %ds:di : next character in output buffer (if applicable)
165  *****************************************************************************
166  */
167         .section ".prefix.print_hex", "awx", @progbits
168         .code16
169         .globl  print_hex_dword
170 print_hex_dword:
171         rorl    $16, %eax
172         call    print_hex_word
173         rorl    $16, %eax
174         /* Fall through */
175         .size   print_hex_dword, . - print_hex_dword
176         .globl  print_hex_word
177 print_hex_word:
178         xchgb   %al, %ah
179         call    print_hex_byte
180         xchgb   %al, %ah
181         /* Fall through */
182         .size   print_hex_word, . - print_hex_word
183         .globl  print_hex_byte
184 print_hex_byte:
185         rorb    $4, %al
186         call    print_hex_nibble
187         rorb    $4, %al
188         /* Fall through */
189         .size   print_hex_byte, . - print_hex_byte
190         .globl  print_hex_nibble
191 print_hex_nibble:
192         /* Preserve registers */
193         pushw   %ax
194         /* Print digit (technique by Norbert Juffa <norbert.juffa@amd.com> */
195         andb    $0x0f, %al
196         cmpb    $10, %al
197         sbbb    $0x69, %al
198         das
199         call    print_character
200         /* Restore registers and return */
201         popw    %ax
202         ret
203         .size   print_hex_nibble, . - print_hex_nibble
204
205 /*****************************************************************************
206  * Utility function: print PCI bus:dev.fn
207  *
208  * Parameters:
209  *   %ax : PCI bus:dev.fn to print
210  *   %ds:di : output buffer (or %di=0 to print to console)
211  * Returns:
212  *   %ds:di : next character in output buffer (if applicable)
213  *****************************************************************************
214  */
215         .section ".prefix.print_pci_busdevfn", "awx", @progbits
216         .code16
217         .globl  print_pci_busdevfn
218 print_pci_busdevfn:
219         /* Preserve registers */
220         pushw   %ax
221         /* Print bus */
222         xchgb   %al, %ah
223         call    print_hex_byte
224         /* Print ":" */
225         movb    $( ':' ), %al
226         call    print_character
227         /* Print device */
228         movb    %ah, %al
229         shrb    $3, %al
230         call    print_hex_byte
231         /* Print "." */
232         movb    $( '.' ), %al
233         call    print_character
234         /* Print function */
235         movb    %ah, %al
236         andb    $0x07, %al
237         call    print_hex_nibble
238         /* Restore registers and return */
239         popw    %ax
240         ret
241         .size   print_pci_busdevfn, . - print_pci_busdevfn
242
243 /*****************************************************************************
244  * Utility function: clear current line
245  *
246  * Parameters:
247  *   %ds:di : output buffer (or %di=0 to print to console)
248  * Returns:
249  *   %ds:di : next character in output buffer (if applicable)
250  *****************************************************************************
251  */
252         .section ".prefix.print_kill_line", "awx", @progbits
253         .code16
254         .globl  print_kill_line
255 print_kill_line:
256         /* Preserve registers */
257         pushw   %ax
258         pushw   %cx
259         /* Print CR */
260         movb    $( '\r' ), %al
261         call    print_character
262         /* Print 79 spaces */
263         movw    $79, %cx
264 1:      call    print_space
265         loop    1b
266         /* Print CR */
267         call    print_character
268         /* Restore registers and return */
269         popw    %cx
270         popw    %ax
271         ret
272         .size   print_kill_line, . - print_kill_line
273
274 /****************************************************************************
275  * copy_bytes
276  *
277  * Copy bytes
278  *
279  * Parameters:
280  *   %ds:esi : source address
281  *   %es:edi : destination address
282  *   %ecx : length
283  * Returns:
284  *   %ds:esi : next source address
285  *   %es:edi : next destination address
286  * Corrupts:
287  *   None
288  ****************************************************************************
289  */
290         .section ".prefix.copy_bytes", "awx", @progbits
291         .code16
292 copy_bytes:
293         pushl   %ecx
294         rep addr32 movsb
295         popl    %ecx
296         ret
297         .size   copy_bytes, . - copy_bytes
298
299 /****************************************************************************
300  * zero_bytes
301  *
302  * Zero bytes
303  *
304  * Parameters:
305  *   %es:edi : destination address
306  *   %ecx : length
307  * Returns:
308  *   %es:edi : next destination address
309  * Corrupts:
310  *   None
311  ****************************************************************************
312  */
313         .section ".prefix.zero_bytes", "awx", @progbits
314         .code16
315 zero_bytes:
316         pushl   %ecx
317         pushw   %ax
318         xorw    %ax, %ax
319         rep addr32 stosb
320         popw    %ax
321         popl    %ecx
322         ret
323         .size   zero_bytes, . - zero_bytes
324
325 /****************************************************************************
326  * process_bytes
327  *
328  * Call memcpy()-like function
329  *
330  * Parameters:
331  *   %esi : source physical address
332  *   %edi : destination physical address
333  *   %ecx : length
334  *   %bx : memcpy()-like function to call, passing parameters:
335  *           %ds:esi : source address
336  *           %es:edi : destination address
337  *           %ecx : length
338  *         and returning:
339  *           %ds:esi : next source address
340  *           %es:edi : next destination address
341  * Returns:
342  *   %esi : next source physical address
343  *   %edi : next destination physical address
344  *   CF : as returned by memcpy()-like function
345  * Corrupts:
346  *   None
347  ****************************************************************************
348  */
349         .section ".prefix.process_bytes", "awx", @progbits
350         .code16
351 process_bytes:
352
353 #ifndef KEEP_IT_REAL
354
355         /* Preserve registers */
356         pushl   %eax
357         pushl   %ebp
358
359         /* Construct GDT on stack (since .prefix may not be writable) */
360         .equ    GDT_LEN, 0x20
361         .equ    PM_DS, 0x18     /* Flat data segment */
362         pushl   $0x00cf9300
363         pushl   $0x0000ffff
364         .equ    PM_SS, 0x10     /* Stack segment based at %ss:0000 */
365         pushl   $0x008f0930
366         pushw   %ss
367         pushw   $0xffff
368         .equ    PM_CS, 0x08     /* Code segment based at %cs:0000 */
369         pushl   $0x008f09b0
370         pushw   %cs
371         pushw   $0xffff
372         pushl   $0              /* Base and length */
373         pushw   %ss
374         pushw   $( GDT_LEN - 1 )
375         movzwl  %sp, %ebp
376         shll    $4, 0x02(%bp)
377         addl    %ebp, 0x02(%bp)
378         shll    $4, 0x0a(%bp)
379         shll    $4, 0x12(%bp)
380         subw    $8, %sp
381         sgdt    -8(%bp)
382
383         /* Switch to protected mode */
384         pushw   %gs
385         pushw   %fs
386         pushw   %es
387         pushw   %ds
388         pushw   %ss
389         pushw   %cs
390         pushw   $2f
391         cli
392         data32 lgdt (%bp)
393         movl    %cr0, %eax
394         orb     $CR0_PE, %al
395         movl    %eax, %cr0
396         ljmp    $PM_CS, $1f
397 1:      movw    $PM_SS, %ax
398         movw    %ax, %ss
399         movw    $PM_DS, %ax
400         movw    %ax, %ds
401         movw    %ax, %es
402         movw    %ax, %fs
403         movw    %ax, %gs
404
405 #ifdef NDEBUG
406         /* Call memcpy()-like function */
407         call    *%bx
408 #endif
409
410         /* Return to (flat) real mode */
411         movl    %cr0, %eax
412         pushfw
413         andb    $0!CR0_PE, %al
414         popfw
415         movl    %eax, %cr0
416         lret
417 2:      /* lret will ljmp to here */
418         popw    %ss
419         popw    %ds
420         popw    %es
421         popw    %fs
422         popw    %gs
423
424 #ifndef NDEBUG
425         /* Call memcpy()-like function in flat real mode (to allow for
426          * debug output via INT 10).
427          */
428         pushw   %ds
429         pushw   %es
430         xorw    %ax, %ax
431         movw    %ax, %ds
432         movw    %ax, %es
433         call    *%bx
434         popw    %es
435         popw    %ds
436 #endif
437
438         /* Restore GDT */
439         data32 lgdt -8(%bp)
440         leaw    GDT_LEN(%bp), %sp
441
442         /* Restore registers and return */
443         popl    %ebp
444         popl    %eax
445         ret
446
447 #else /* KEEP_IT_REAL */
448
449         /* Preserve registers */
450         pushl   %eax
451         pushw   %ds
452         pushw   %es
453         
454         /* Convert %esi and %edi to %ds:esi and %es:edi */
455         shrl    $4, %esi
456         movw    %si, %ds
457         xorw    %si, %si
458         shll    $4, %esi
459         shrl    $4, %edi
460         movw    %di, %es
461         xorw    %di, %di
462         shll    $4, %edi
463
464         /* Call memcpy()-like function */
465         call    *%bx
466
467         /* Convert %ds:esi and %es:edi back to physical addresses */
468         pushfw
469         xorl    %eax, %eax
470         movw    %ds, %ax
471         shll    $4, %eax
472         addl    %eax, %esi
473         xorl    %eax, %eax
474         movw    %es, %ax
475         shll    $4, %eax
476         addl    %eax, %edi
477         popfw
478
479         /* Restore registers and return */
480         popw    %es
481         popw    %ds
482         popl    %eax
483         ret
484
485 #endif /* KEEP_IT_REAL */
486
487         .size   process_bytes, . - process_bytes
488
489 /****************************************************************************
490  * install_block
491  *
492  * Install block to specified address
493  *
494  * Parameters:
495  *   %esi : source physical address (must be a multiple of 16)
496  *   %edi : destination physical address (must be a multiple of 16)
497  *   %ecx : length of (decompressed) data
498  *   %edx : total length of block (including any uninitialised data portion)
499  * Returns:
500  *   %esi : next source physical address (will be a multiple of 16)
501  *   %edi : next destination physical address (will be a multiple of 16)
502  *   CF set on failure
503  * Corrupts:
504  *   none
505  ****************************************************************************
506  */
507         .section ".prefix.install_block", "awx", @progbits
508         .code16
509 install_block:
510         /* Preserve registers */
511         pushl   %ecx
512         pushw   %bx
513
514         /* Decompress (or copy) source to destination */
515 #if COMPRESS
516         movw    $decompress16, %bx
517 #else
518         movw    $copy_bytes, %bx
519 #endif
520         call    process_bytes
521         jc      99f
522
523         /* Zero .bss portion */
524         negl    %ecx
525         addl    %edx, %ecx
526         movw    $zero_bytes, %bx
527         call    process_bytes
528
529         /* Round up %esi and %edi to start of next blocks */
530         addl    $0xf, %esi
531         andl    $~0xf, %esi
532         addl    $0xf, %edi
533         andl    $~0xf, %edi /* Will also clear CF */
534
535 99:     /* Restore registers and return */
536         popw    %bx
537         popl    %ecx
538         ret
539         .size install_block, . - install_block
540
541 /****************************************************************************
542  * alloc_basemem
543  *
544  * Allocate space for .text16 and .data16 from top of base memory.
545  * Memory is allocated using the BIOS free base memory counter at
546  * 0x40:13.
547  *
548  * Parameters: 
549  *   none
550  * Returns:
551  *   %ax : .text16 segment address
552  *   %bx : .data16 segment address
553  * Corrupts:
554  *   none
555  ****************************************************************************
556  */
557         .section ".prefix.alloc_basemem", "awx", @progbits
558         .code16
559         .globl  alloc_basemem
560 alloc_basemem:
561         /* Preserve registers */
562         pushw   %fs
563
564         /* FBMS => %ax as segment address */
565         pushw   $0x40
566         popw    %fs
567         movw    %fs:0x13, %ax
568         shlw    $6, %ax
569
570         /* Calculate .data16 segment address */
571         subw    $_data16_memsz_ppgh, %ax
572         pushw   %ax
573
574         /* Calculate .text16 segment address */
575         subw    $_text16_memsz_ppgh, %ax
576         pushw   %ax
577
578         /* Update FBMS */
579         shrw    $6, %ax
580         movw    %ax, %fs:0x13
581
582         /* Retrieve .text16 and .data16 segment addresses */
583         popw    %ax
584         popw    %bx
585
586         /* Restore registers and return */
587         popw    %fs
588         ret
589         .size alloc_basemem, . - alloc_basemem
590
591 /****************************************************************************
592  * free_basemem
593  *
594  * Free space allocated with alloc_basemem.
595  *
596  * Parameters:
597  *   none (.text16 segment address is implicit in %cs)
598  * Returns:
599  *   %ax : 0 if successfully freed
600  * Corrupts:
601  *   none
602  ****************************************************************************
603  */
604         .section ".text16.free_basemem", "ax", @progbits
605         .code16
606         .globl  free_basemem
607 free_basemem:
608         /* Preserve registers */
609         pushw   %fs
610         pushw   %ax
611
612         /* Check FBMS counter */
613         movw    %cs, %ax
614         shrw    $6, %ax
615         pushw   $0x40
616         popw    %fs
617         cmpw    %ax, %fs:0x13
618         jne     1f
619
620         /* Check hooked interrupt count */
621         cmpw    $0, %cs:hooked_bios_interrupts
622         jne     1f
623
624         /* OK to free memory */
625         movw    %cs, %ax
626         addw    $_text16_memsz_ppgh, %ax
627         addw    $_data16_memsz_ppgh, %ax
628         shrw    $6, %ax
629         movw    %ax, %fs:0x13
630         xorw    %ax, %ax
631
632 1:      /* Restore registers and return */
633         popw    %ax
634         popw    %fs
635         ret
636         .size free_basemem, . - free_basemem
637
638         .section ".text16.data.hooked_bios_interrupts", "aw", @progbits
639         .globl  hooked_bios_interrupts
640 hooked_bios_interrupts:
641         .word   0
642         .size   hooked_bios_interrupts, . - hooked_bios_interrupts
643
644 /****************************************************************************
645  * install
646  *
647  * Install all text and data segments.
648  *
649  * Parameters:
650  *   none
651  * Returns:
652  *   %ax  : .text16 segment address
653  *   %bx  : .data16 segment address
654  * Corrupts:
655  *   none
656  ****************************************************************************
657  */
658         .section ".prefix.install", "awx", @progbits
659         .code16
660         .globl install
661 install:
662         progress "install:\n"
663         /* Preserve registers */
664         pushl   %esi
665         pushl   %edi
666         pushl   %ebp
667         /* Allocate space for .text16 and .data16 */
668         call    alloc_basemem
669         /* Image source = %cs:0000 */
670         xorl    %esi, %esi
671         /* Image destination = default */
672         xorl    %edi, %edi
673         /* Allow arbitrary relocation */
674         orl     $0xffffffff, %ebp
675         /* Install text and data segments */
676         call    install_prealloc
677         /* Restore registers and return */
678         popl    %ebp
679         popl    %edi
680         popl    %esi
681         ret
682         .size install, . - install
683
684 /****************************************************************************
685  * install_prealloc
686  *
687  * Install all text and data segments.
688  *
689  * Parameters:
690  *   %ax  : .text16 segment address
691  *   %bx  : .data16 segment address
692  *   %esi : Image source physical address (or zero for %cs:0000)
693  *   %edi : Decompression temporary area physical address (or zero for default)
694  *   %ebp : Maximum end address for relocation
695  *          - 0xffffffff for no maximum
696  *          - 0x00000000 to inhibit use of INT 15,e820 and INT 15,e801
697  * Corrupts:
698  *   none
699  ****************************************************************************
700  */
701         .section ".prefix.install_prealloc", "awx", @progbits
702         .code16
703         .globl install_prealloc
704 install_prealloc:
705         progress "install_prealloc:\n"
706         /* Save registers on external stack */
707         pushal
708         pushw   %ds
709         pushw   %es
710         cld                     /* Sanity: clear the direction flag asap */
711
712         /* Switch to temporary stack in .bss16 */
713         pushw   %ss
714         popw    %ds
715         movl    %esp, %ecx
716         movw    %bx, %ss
717         movl    $_data16_memsz, %esp
718         pushw   %ds
719         pushl   %ecx
720
721         /* Set up %ds for (read-only) access to .prefix */
722         pushw   %cs
723         popw    %ds
724
725         /* Save decompression temporary area physical address */
726         pushl   %edi
727
728         /* Install .text16.early and calculate %ecx as offset to next block */
729         progress "  .text16.early\n"
730         pushl   %esi
731         xorl    %esi, %esi
732         movw    %cs, %si
733         shll    $4, %esi
734         pushl   %esi                    /* Save original %cs:0000 */
735         addl    $_text16_early_lma, %esi
736         movzwl  %ax, %edi
737         shll    $4, %edi
738         movl    $_text16_early_filesz, %ecx
739         movl    $_text16_early_memsz, %edx
740         call    install_block           /* .text16.early */
741         jc      install_block_death
742         popl    %ecx                    /* Calculate offset to next block */
743         subl    %esi, %ecx
744         negl    %ecx
745         popl    %esi
746
747 #ifndef KEEP_IT_REAL
748
749         /* Access high memory by enabling the A20 gate.  (We will
750          * already have 4GB segment limits as a result of calling
751          * install_block.)
752          */
753         progress "  access_highmem\n"
754         pushw   %cs
755         pushw   $1f
756         pushw   %ax
757         pushw   $access_highmem
758         lret
759 1:      /* Die if we could not access high memory */
760         jc      access_highmem_death
761
762 #endif
763
764         /* Open payload (which may not yet be in memory) */
765         progress "  open_payload\n"
766         pushw   %cs
767         pushw   $1f
768         pushw   %ax
769         pushw   $open_payload
770         lret
771 1:      /* Die if we could not access the payload */
772         jc      open_payload_death
773
774         /* Calculate physical address of payload (i.e. first source) */
775         testl   %esi, %esi
776         jnz     1f
777         movw    %cs, %si
778         shll    $4, %esi
779 1:      addl    %ecx, %esi
780
781         /* Install .text16.late and .data16 */
782         progress "  .text16.late\n"
783         movl    $_text16_late_filesz, %ecx
784         movl    $_text16_late_memsz, %edx
785         call    install_block           /* .text16.late */
786         jc      install_block_death
787         progress "  .data16\n"
788         movzwl  %bx, %edi
789         shll    $4, %edi
790         movl    $_data16_filesz, %ecx
791         movl    $_data16_filesz, %edx   /* do not zero our temporary stack */
792         call    install_block           /* .data16 */
793         jc      install_block_death
794
795         /* Set up %ds for access to .data16 */
796         movw    %bx, %ds
797
798         /* Restore decompression temporary area physical address */
799         popl    %edi
800
801 #ifndef KEEP_IT_REAL
802
803         /* Find a suitable decompression temporary area, if none specified */
804         pushl   %eax
805         testl   %edi, %edi
806         jnz     1f
807         /* Use INT 15,88 to find the highest available address via INT
808          * 15,88.  This limits us to around 64MB, which should avoid
809          * all of the POST-time memory map failure modes.
810          */
811         movb    $0x88, %ah
812         int     $0x15
813         movw    %ax, %di
814         addl    $0x400, %edi
815         subl    $_textdata_memsz_kb, %edi
816         andw    $~0x03, %di
817         shll    $10, %edi
818         /* Sanity check: if we have ended up below 1MB, use 1MB */
819         cmpl    $0x100000, %edi
820         jae     1f
821         movl    $0x100000, %edi
822 1:      popl    %eax
823
824         /* Install .text and .data to temporary area in high memory,
825          * prior to reading the E820 memory map and relocating
826          * properly.
827          */
828         progress "  .textdata\n"
829         pushl   %edi
830         movl    $_textdata_filesz, %ecx
831         movl    $_textdata_memsz, %edx
832         call    install_block
833         jc      install_block_death
834         popl    %edi
835
836 #endif /* KEEP_IT_REAL */
837
838         /* Switch back to original stack and zero .bss16 */
839         addr32 lss %ss:(%esp), %esp
840         pushl   %edi
841         pushw   %es
842         movw    %bx, %es
843         movl    $_data16_filesz, %edi
844         movl    $_data16_memsz, %ecx
845         subl    %edi, %ecx
846         call    zero_bytes
847         popw    %es
848         popl    %edi
849
850 #ifndef KEEP_IT_REAL
851
852         /* Initialise librm at current location */
853         progress "  init_librm\n"
854         movw    %ax, (init_librm_vector+2)
855         lcall   *init_librm_vector
856
857         /* Prepare for return to .prefix segment */
858         pushw   %cs
859
860         /* Jump to .text16 segment */
861         pushw   %ax
862         pushw   $1f
863         lret
864         .section ".text16.install_prealloc", "ax", @progbits
865 1:
866         /* Inhibit INT 15,e820 and INT 15,e801 if applicable */
867         testl   %ebp, %ebp
868         jnz     1f
869         incb    memmap_post
870         decl    %ebp
871 1:
872         /* Call relocate() to determine target address for relocation.
873          * relocate() will return with %esi, %edi and %ecx set up
874          * ready for the copy to the new location.
875          */
876         progress "  relocate\n"
877         virtcall relocate
878
879         /* Jump back to .prefix segment */
880         pushw   $1f
881         lret
882         .section ".prefix.install_prealloc", "awx", @progbits
883 1:
884         /* Copy code to new location */
885         progress "  copy\n"
886         pushl   %edi
887         pushw   %bx
888         movw    $copy_bytes, %bx
889         call    process_bytes
890         popw    %bx
891         popl    %edi
892
893         /* Initialise librm at new location */
894         progress "  init_librm\n"
895         lcall   *init_librm_vector
896
897 #else /* KEEP_IT_REAL */
898
899         /* Initialise libkir */
900         movw    %ax, (init_libkir_vector+2)
901         lcall   *init_libkir_vector
902
903 #endif /* KEEP_IT_REAL */
904
905         /* Close access to payload */
906         progress "  close_payload\n"
907         movw    %ax, (close_payload_vector+2)
908         lcall   *close_payload_vector
909
910         /* Restore registers */
911         popw    %es
912         popw    %ds
913         popal
914         ret
915         .size install_prealloc, . - install_prealloc
916
917         /* Vectors for far calls to .text16 functions.  Must be in
918          * .data16, since .prefix may not be writable.
919          */
920         .section ".data16.install_prealloc", "aw", @progbits
921 #ifdef KEEP_IT_REAL
922 init_libkir_vector:
923         .word init_libkir
924         .word 0
925         .size init_libkir_vector, . - init_libkir_vector
926 #else
927 init_librm_vector:
928         .word init_librm
929         .word 0
930         .size init_librm_vector, . - init_librm_vector
931 #endif
932 close_payload_vector:
933         .word close_payload
934         .word 0
935         .size close_payload_vector, . - close_payload_vector
936
937         /* Dummy routines to open and close payload */
938         .section ".text16.early.data.open_payload", "aw", @progbits
939         .weak   open_payload
940         .weak   close_payload
941 open_payload:
942 close_payload:
943         clc
944         lret
945         .size   open_payload, . - open_payload
946         .size   close_payload, . - close_payload
947
948         /* Report installation failure */
949         .section ".prefix.install_death", "ax", @progbits
950 install_death:
951         pushw   %cs
952         popw    %ds
953         xorw    %di, %di
954         call    print_hex_dword
955         call    print_space
956         movl    %esi, %eax
957         call    print_hex_dword
958         call    print_space
959         movl    %ecx, %eax
960         call    print_hex_dword
961         movw    $install_death_message, %si
962         call    print_message
963 2:      /* Halt system */
964         cli
965         hlt
966         jmp     2b
967         .size   install_death, . - install_death
968         .section ".prefix.data.install_death_message", "aw", @progbits
969 install_death_message:
970         .asciz  "\nInstallation failed - cannot continue\n"
971         .size   install_death_message, . - install_death_message
972
973         /* Report failure to access high memory */
974         .section ".prefix.install_block_death", "ax", @progbits
975 install_block_death:
976         movl    $0x1b101b10, %eax
977         jmp     install_death
978         .size   install_block_death, . - install_block_death
979
980         /* Report failure to access high memory */
981         .section ".prefix.access_highmem_death", "ax", @progbits
982 access_highmem_death:
983         movl    $0x0a200a20, %eax
984         jmp     install_death
985         .size   access_highmem_death, . - access_highmem_death
986
987         /* Report failure to open payload */
988         .section ".prefix.open_payload_death", "ax", @progbits
989 open_payload_death:
990         xorl    %eax, %eax
991         jmp     install_death
992         .size   open_payload_death, . - open_payload_death
993
994 /****************************************************************************
995  * uninstall
996  *
997  * Uninstall all text and data segments.
998  *
999  * Parameters:
1000  *   none (.text16 segment address is implicit in %cs)
1001  * Returns:
1002  *   none
1003  * Corrupts:
1004  *   none
1005  ****************************************************************************
1006  */
1007         .section ".text16.uninstall", "ax", @progbits
1008         .code16
1009         .globl uninstall
1010 uninstall:
1011         call    free_basemem
1012         ret
1013         .size uninstall, . - uninstall
1014
1015
1016
1017         /* File split information for the compressor */
1018 #if COMPRESS
1019 #define PACK_OR_COPY    "PACK"
1020 #else
1021 #define PACK_OR_COPY    "COPY"
1022 #endif
1023         .section ".zinfo", "a", @progbits
1024         .ascii  "COPY"
1025         .long   _prefix_lma
1026         .long   _prefix_filesz
1027         .long   _max_align
1028         .ascii  PACK_OR_COPY
1029         .long   _text16_early_lma
1030         .long   _text16_early_filesz
1031         .long   _max_align
1032         .ascii  "PAYL"
1033         .long   0
1034         .long   0
1035         .long   _payload_align
1036         .ascii  "COPY"
1037         .long   _pprefix_lma
1038         .long   _pprefix_filesz
1039         .long   _max_align
1040         .ascii  PACK_OR_COPY
1041         .long   _text16_late_lma
1042         .long   _text16_late_filesz
1043         .long   _max_align
1044         .ascii  PACK_OR_COPY
1045         .long   _data16_lma
1046         .long   _data16_filesz
1047         .long   _max_align
1048         .ascii  PACK_OR_COPY
1049         .long   _textdata_lma
1050         .long   _textdata_filesz
1051         .long   _max_align
1052
1053         .weak   _payload_align
1054         .equ    _payload_align, 1