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