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