source: bootcd/isolinux/syslinux-6.03/gpxe/src/arch/i386/prefix/libprefix.S

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 18.3 KB
Line 
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
20FILE_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 * We use the start of an even megabyte so that we don't have to worry
32 * about the current state of the A20 line.
33 *
34 * We use 4MB rather than 2MB because some PXE stack / PMM BIOS
35 * combinations are known to place data required by other UNDI ROMs
36 * loader around the 2MB mark.
37 */
38        .globl  HIGHMEM_LOADPOINT
39        .equ    HIGHMEM_LOADPOINT, ( 4 << 20 )
40
41/* Image compression enabled */
42#define COMPRESS 1
43
44#define CR0_PE 1
45
46/*****************************************************************************
47 * Utility function: print character (with LF -> LF,CR translation)
48 *
49 * Parameters:
50 *   %al : character to print
51 *   %ds:di : output buffer (or %di=0 to print to console)
52 * Returns:
53 *   %ds:di : next character in output buffer (if applicable)
54 *****************************************************************************
55 */
56        .section ".prefix.lib", "awx", @progbits
57        .code16
58        .globl  print_character
59print_character:
60        /* Preserve registers */
61        pushw   %ax
62        pushw   %bx
63        pushw   %bp
64        /* If %di is non-zero, write character to buffer and exit */
65        testw   %di, %di
66        jz      1f
67        movb    %al, %ds:(%di)
68        incw    %di
69        jmp     3f
701:      /* Print character */
71        movw    $0x0007, %bx            /* page 0, attribute 7 (normal) */
72        movb    $0x0e, %ah              /* write char, tty mode */
73        cmpb    $0x0a, %al              /* '\n'? */
74        jne     2f
75        int     $0x10
76        movb    $0x0d, %al
772:      int     $0x10
78        /* Restore registers and return */
793:      popw    %bp
80        popw    %bx
81        popw    %ax
82        ret
83        .size   print_character, . - print_character
84
85/*****************************************************************************
86 * Utility function: print a NUL-terminated string
87 *
88 * Parameters:
89 *   %ds:si : string to print
90 *   %ds:di : output buffer (or %di=0 to print to console)
91 * Returns:
92 *   %ds:si : character after terminating NUL
93 *   %ds:di : next character in output buffer (if applicable)
94 *****************************************************************************
95 */
96        .section ".prefix.lib", "awx", @progbits
97        .code16
98        .globl  print_message
99print_message:
100        /* Preserve registers */
101        pushw   %ax
102        /* Print string */
1031:      lodsb
104        testb   %al, %al
105        je      2f
106        call    print_character
107        jmp     1b
1082:      /* Restore registers and return */
109        popw    %ax
110        ret
111        .size   print_message, . - print_message
112
113/*****************************************************************************
114 * Utility functions: print hex digit/byte/word/dword
115 *
116 * Parameters:
117 *   %al (low nibble) : digit to print
118 *   %al : byte to print
119 *   %ax : word to print
120 *   %eax : dword to print
121 *   %ds:di : output buffer (or %di=0 to print to console)
122 * Returns:
123 *   %ds:di : next character in output buffer (if applicable)
124 *****************************************************************************
125 */
126        .section ".prefix.lib", "awx", @progbits
127        .code16
128        .globl  print_hex_dword
129print_hex_dword:
130        rorl    $16, %eax
131        call    print_hex_word
132        rorl    $16, %eax
133        /* Fall through */
134        .size   print_hex_dword, . - print_hex_dword
135        .globl  print_hex_word
136print_hex_word:
137        xchgb   %al, %ah
138        call    print_hex_byte
139        xchgb   %al, %ah
140        /* Fall through */
141        .size   print_hex_word, . - print_hex_word
142        .globl  print_hex_byte
143print_hex_byte:
144        rorb    $4, %al
145        call    print_hex_nibble
146        rorb    $4, %al
147        /* Fall through */
148        .size   print_hex_byte, . - print_hex_byte
149        .globl  print_hex_nibble
150print_hex_nibble:
151        /* Preserve registers */
152        pushw   %ax
153        /* Print digit (technique by Norbert Juffa <norbert.juffa@amd.com> */
154        andb    $0x0f, %al
155        cmpb    $10, %al
156        sbbb    $0x69, %al
157        das
158        call    print_character
159        /* Restore registers and return */
160        popw    %ax
161        ret
162        .size   print_hex_nibble, . - print_hex_nibble
163
164/*****************************************************************************
165 * Utility function: print PCI bus:dev.fn
166 *
167 * Parameters:
168 *   %ax : PCI bus:dev.fn to print
169 *   %ds:di : output buffer (or %di=0 to print to console)
170 * Returns:
171 *   %ds:di : next character in output buffer (if applicable)
172 *****************************************************************************
173 */
174        .section ".prefix.lib", "awx", @progbits
175        .code16
176        .globl  print_pci_busdevfn
177print_pci_busdevfn:
178        /* Preserve registers */
179        pushw   %ax
180        /* Print bus */
181        xchgb   %al, %ah
182        call    print_hex_byte
183        /* Print ":" */
184        movb    $( ':' ), %al
185        call    print_character
186        /* Print device */
187        movb    %ah, %al
188        shrb    $3, %al
189        call    print_hex_byte
190        /* Print "." */
191        movb    $( '.' ), %al
192        call    print_character
193        /* Print function */
194        movb    %ah, %al
195        andb    $0x07, %al
196        call    print_hex_nibble
197        /* Restore registers and return */
198        popw    %ax
199        ret
200        .size   print_pci_busdevfn, . - print_pci_busdevfn
201
202/*****************************************************************************
203 * Utility function: clear current line
204 *
205 * Parameters:
206 *   %ds:di : output buffer (or %di=0 to print to console)
207 * Returns:
208 *   %ds:di : next character in output buffer (if applicable)
209 *****************************************************************************
210 */
211        .section ".prefix.lib", "awx", @progbits
212        .code16
213        .globl  print_kill_line
214print_kill_line:
215        /* Preserve registers */
216        pushw   %ax
217        pushw   %cx
218        /* Print CR */
219        movb    $( '\r' ), %al
220        call    print_character
221        /* Print 79 spaces */
222        movb    $( ' ' ), %al
223        movw    $79, %cx
2241:      call    print_character
225        loop    1b
226        /* Print CR */
227        movb    $( '\r' ), %al
228        call    print_character
229        /* Restore registers and return */
230        popw    %cx
231        popw    %ax
232        ret
233        .size   print_kill_line, . - print_kill_line
234
235/****************************************************************************
236 * pm_call (real-mode near call)
237 *
238 * Call routine in 16-bit protected mode for access to extended memory
239 *
240 * Parameters:
241 *   %ax : address of routine to call in 16-bit protected mode
242 * Returns:
243 *   none
244 * Corrupts:
245 *   %ax
246 *
247 * The specified routine is called in 16-bit protected mode, with:
248 *
249 *   %cs : 16-bit code segment with base matching real-mode %cs
250 *   %ss : 16-bit data segment with base matching real-mode %ss
251 *   %ds,%es,%fs,%gs : 32-bit data segment with zero base and 4GB limit
252 *
253 ****************************************************************************
254 */
255
256#ifndef KEEP_IT_REAL
257
258        /* GDT for protected-mode calls */
259        .section ".prefix.lib", "awx", @progbits
260        .align 16
261pm_call_vars:
262gdt:
263gdt_limit:              .word gdt_length - 1
264gdt_base:               .long 0
265                        .word 0 /* padding */
266pm_cs:          /* 16-bit protected-mode code segment */       
267        .equ    PM_CS, pm_cs - gdt
268        .word   0xffff, 0
269        .byte   0, 0x9b, 0x00, 0
270pm_ss:          /* 16-bit protected-mode stack segment */
271        .equ    PM_SS, pm_ss - gdt
272        .word   0xffff, 0
273        .byte   0, 0x93, 0x00, 0
274pm_ds:          /* 32-bit protected-mode flat data segment */
275        .equ    PM_DS, pm_ds - gdt
276        .word   0xffff, 0
277        .byte   0, 0x93, 0xcf, 0
278gdt_end:
279        .equ    gdt_length, . - gdt
280        .size   gdt, . - gdt
281
282        .section ".prefix.lib", "awx", @progbits
283        .align 16
284pm_saved_gdt:   
285        .long   0, 0
286        .size   pm_saved_gdt, . - pm_saved_gdt
287
288        .equ    pm_call_vars_size, . - pm_call_vars
289#define PM_CALL_VAR(x) ( -pm_call_vars_size + ( (x) - pm_call_vars ) )
290
291        .section ".prefix.lib", "awx", @progbits
292        .code16
293pm_call:
294        /* Preserve registers, flags, and RM return point */
295        pushw   %bp
296        movw    %sp, %bp
297        subw    $pm_call_vars_size, %sp
298        andw    $0xfff0, %sp
299        pushfl
300        pushw   %gs
301        pushw   %fs
302        pushw   %es
303        pushw   %ds
304        pushw   %ss
305        pushw   %cs
306        pushw   $99f
307
308        /* Set up local variable block, and preserve GDT */
309        pushw   %cx
310        pushw   %si
311        pushw   %di
312        pushw   %ss
313        popw    %es
314        movw    $pm_call_vars, %si
315        leaw    PM_CALL_VAR(pm_call_vars)(%bp), %di
316        movw    $pm_call_vars_size, %cx
317        cs rep movsb
318        popw    %di
319        popw    %si
320        popw    %cx
321        sgdt    PM_CALL_VAR(pm_saved_gdt)(%bp)
322
323        /* Set up GDT bases */
324        pushl   %eax
325        pushl   %edi
326        xorl    %eax, %eax
327        movw    %ss, %ax
328        shll    $4, %eax
329        movzwl  %bp, %edi
330        addr32 leal PM_CALL_VAR(gdt)(%eax, %edi), %eax
331        movl    %eax, PM_CALL_VAR(gdt_base)(%bp)
332        movw    %cs, %ax
333        movw    $PM_CALL_VAR(pm_cs), %di
334        call    set_seg_base
335        movw    %ss, %ax
336        movw    $PM_CALL_VAR(pm_ss), %di
337        call    set_seg_base
338        popl    %edi
339        popl    %eax
340
341        /* Switch CPU to protected mode and load up segment registers */
342        pushl   %eax
343        cli
344        data32 lgdt PM_CALL_VAR(gdt)(%bp)
345        movl    %cr0, %eax
346        orb     $CR0_PE, %al
347        movl    %eax, %cr0
348        ljmp    $PM_CS, $1f
3491:      movw    $PM_SS, %ax
350        movw    %ax, %ss
351        movw    $PM_DS, %ax
352        movw    %ax, %ds
353        movw    %ax, %es
354        movw    %ax, %fs
355        movw    %ax, %gs
356        popl    %eax
357
358        /* Call PM routine */
359        call    *%ax
360
361        /* Set real-mode segment limits on %ds, %es, %fs and %gs */
362        movw    %ss, %ax
363        movw    %ax, %ds
364        movw    %ax, %es
365        movw    %ax, %fs
366        movw    %ax, %gs
367
368        /* Return CPU to real mode */
369        movl    %cr0, %eax
370        andb    $0!CR0_PE, %al
371        movl    %eax, %cr0
372
373        /* Restore registers and flags */
374        lret    /* will ljmp to 99f */
37599:     popw    %ss
376        popw    %ds
377        popw    %es
378        popw    %fs
379        popw    %gs
380        data32 lgdt PM_CALL_VAR(pm_saved_gdt)(%bp)
381        popfl
382        movw    %bp, %sp
383        popw    %bp
384        ret
385        .size pm_call, . - pm_call
386
387set_seg_base:
388        rolw    $4, %ax
389        movw    %ax, 2(%bp,%di)
390        andw    $0xfff0, 2(%bp,%di)
391        movb    %al, 4(%bp,%di)
392        andb    $0x0f, 4(%bp,%di)
393        ret
394        .size set_seg_base, . - set_seg_base
395
396#endif /* KEEP_IT_REAL */
397
398/****************************************************************************
399 * copy_bytes (real-mode or 16-bit protected-mode near call)
400 *
401 * Copy bytes
402 *
403 * Parameters:
404 *   %ds:esi : source address
405 *   %es:edi : destination address
406 *   %ecx : length
407 * Returns:
408 *   %ds:esi : next source address
409 *   %es:edi : next destination address
410 * Corrupts:
411 *   None
412 ****************************************************************************
413 */
414        .section ".prefix.lib", "awx", @progbits
415        .code16
416copy_bytes:
417        pushl %ecx
418        rep addr32 movsb
419        popl %ecx
420        ret
421        .size copy_bytes, . - copy_bytes
422
423/****************************************************************************
424 * install_block (real-mode near call)
425 *
426 * Install block to specified address
427 *
428 * Parameters:
429 *   %esi : source physical address (must be a multiple of 16)
430 *   %edi : destination physical address (must be a multiple of 16)
431 *   %ecx : length of (decompressed) data
432 *   %edx : total length of block (including any uninitialised data portion)
433 * Returns:
434 *   %esi : next source physical address (will be a multiple of 16)
435 * Corrupts:
436 *   none
437 ****************************************************************************
438 */
439        .section ".prefix.lib", "awx", @progbits
440        .code16
441install_block:
442       
443#ifdef KEEP_IT_REAL
444
445        /* Preserve registers */
446        pushw   %ds
447        pushw   %es
448        pushl   %ecx
449        pushl   %edi
450       
451        /* Convert %esi and %edi to segment registers */
452        shrl    $4, %esi
453        movw    %si, %ds
454        xorw    %si, %si
455        shrl    $4, %edi
456        movw    %di, %es
457        xorw    %di, %di
458
459#else /* KEEP_IT_REAL */
460
461        /* Call self in protected mode */
462        pushw   %ax
463        movw    $1f, %ax
464        call    pm_call
465        popw    %ax
466        ret
4671:
468        /* Preserve registers */
469        pushl   %ecx
470        pushl   %edi
471       
472#endif /* KEEP_IT_REAL */
473
474       
475#if COMPRESS
476        /* Decompress source to destination */
477        call    decompress16
478#else
479        /* Copy source to destination */
480        call    copy_bytes
481#endif
482
483        /* Zero .bss portion */
484        negl    %ecx
485        addl    %edx, %ecx
486        pushw   %ax
487        xorw    %ax, %ax
488        rep addr32 stosb
489        popw    %ax
490
491        /* Round up %esi to start of next source block */
492        addl    $0xf, %esi
493        andl    $~0xf, %esi
494
495
496#ifdef KEEP_IT_REAL
497
498        /* Convert %ds:esi back to a physical address */
499        movzwl  %ds, %cx
500        shll    $4, %ecx
501        addl    %ecx, %esi
502
503        /* Restore registers */
504        popl    %edi
505        popl    %ecx
506        popw    %es
507        popw    %ds
508
509#else /* KEEP_IT_REAL */
510
511        /* Restore registers */
512        popl    %edi
513        popl    %ecx
514
515#endif
516
517        ret
518        .size install_block, . - install_block
519       
520/****************************************************************************
521 * alloc_basemem (real-mode near call)
522 *
523 * Allocate space for .text16 and .data16 from top of base memory.
524 * Memory is allocated using the BIOS free base memory counter at
525 * 0x40:13.
526 *
527 * Parameters:
528 *   none
529 * Returns:
530 *   %ax : .text16 segment address
531 *   %bx : .data16 segment address
532 * Corrupts:
533 *   none
534 ****************************************************************************
535 */
536        .section ".prefix.lib", "awx", @progbits
537        .code16
538        .globl  alloc_basemem
539alloc_basemem:
540        /* Preserve registers */
541        pushw   %fs
542
543        /* FBMS => %ax as segment address */
544        pushw   $0x40
545        popw    %fs
546        movw    %fs:0x13, %ax
547        shlw    $6, %ax
548
549        /* Calculate .data16 segment address */
550        subw    $_data16_memsz_pgh, %ax
551        pushw   %ax
552
553        /* Calculate .text16 segment address */
554        subw    $_text16_memsz_pgh, %ax
555        pushw   %ax
556
557        /* Update FBMS */
558        shrw    $6, %ax
559        movw    %ax, %fs:0x13
560
561        /* Retrieve .text16 and .data16 segment addresses */
562        popw    %ax
563        popw    %bx
564
565        /* Restore registers and return */
566        popw    %fs
567        ret
568        .size alloc_basemem, . - alloc_basemem
569
570/****************************************************************************
571 * free_basemem (real-mode near call)
572 *
573 * Free space allocated with alloc_basemem.
574 *
575 * Parameters:
576 *   %ax : .text16 segment address
577 *   %bx : .data16 segment address
578 * Returns:
579 *   %ax : 0 if successfully freed
580 * Corrupts:
581 *   none
582 ****************************************************************************
583 */
584        .section ".text16", "ax", @progbits
585        .code16
586        .globl  free_basemem
587free_basemem:
588        /* Preserve registers */
589        pushw   %fs
590
591        /* Check FBMS counter */
592        pushw   %ax
593        shrw    $6, %ax
594        pushw   $0x40
595        popw    %fs
596        cmpw    %ax, %fs:0x13
597        popw    %ax
598        jne     1f
599
600        /* Check hooked interrupt count */
601        cmpw    $0, %cs:hooked_bios_interrupts
602        jne     1f
603
604        /* OK to free memory */
605        addw    $_text16_memsz_pgh, %ax
606        addw    $_data16_memsz_pgh, %ax
607        shrw    $6, %ax
608        movw    %ax, %fs:0x13
609        xorw    %ax, %ax
610
6111:      /* Restore registers and return */
612        popw    %fs
613        ret
614        .size free_basemem, . - free_basemem
615
616        .section ".text16.data", "aw", @progbits
617        .globl  hooked_bios_interrupts
618hooked_bios_interrupts:
619        .word   0
620        .size   hooked_bios_interrupts, . - hooked_bios_interrupts
621
622/****************************************************************************
623 * install (real-mode near call)
624 *
625 * Install all text and data segments.
626 *
627 * Parameters:
628 *   none
629 * Returns:
630 *   %ax  : .text16 segment address
631 *   %bx  : .data16 segment address
632 * Corrupts:
633 *   none
634 ****************************************************************************
635 */
636        .section ".prefix.lib", "awx", @progbits
637        .code16
638        .globl install
639install:
640        /* Preserve registers */
641        pushl   %esi
642        pushl   %edi
643        /* Allocate space for .text16 and .data16 */
644        call    alloc_basemem
645        /* Image source = %cs:0000 */
646        xorl    %esi, %esi
647        /* Image destination = HIGHMEM_LOADPOINT */
648        movl    $HIGHMEM_LOADPOINT, %edi
649        /* Install text and data segments */
650        call    install_prealloc
651        /* Restore registers and return */
652        popl    %edi
653        popl    %esi
654        ret
655        .size install, . - install
656
657/****************************************************************************
658 * install_prealloc (real-mode near call)
659 *
660 * Install all text and data segments.
661 *
662 * Parameters:
663 *   %ax  : .text16 segment address
664 *   %bx  : .data16 segment address
665 *   %esi : Image source physical address (or zero for %cs:0000)
666 *   %edi : Decompression temporary area physical address
667 * Corrupts:
668 *   none
669 ****************************************************************************
670 */
671        .section ".prefix.lib", "awx", @progbits
672        .code16
673        .globl install_prealloc
674install_prealloc:
675        /* Save registers */
676        pushal
677        pushw   %ds
678        pushw   %es
679
680        /* Sanity: clear the direction flag asap */
681        cld
682
683        /* Calculate physical address of payload (i.e. first source) */
684        testl   %esi, %esi
685        jnz     1f
686        movw    %cs, %si
687        shll    $4, %esi
6881:      addl    $_payload_lma, %esi
689
690        /* Install .text16 and .data16 */
691        pushl   %edi
692        movzwl  %ax, %edi
693        shll    $4, %edi
694        movl    $_text16_memsz, %ecx
695        movl    %ecx, %edx
696        call    install_block           /* .text16 */
697        movzwl  %bx, %edi
698        shll    $4, %edi
699        movl    $_data16_filesz, %ecx
700        movl    $_data16_memsz, %edx
701        call    install_block           /* .data16 */
702        popl    %edi
703
704        /* Set up %ds for access to .data16 */
705        movw    %bx, %ds
706
707#ifdef KEEP_IT_REAL
708        /* Initialise libkir */
709        movw    %ax, (init_libkir_vector+2)
710        lcall   *init_libkir_vector
711#else
712        /* Install .text and .data to temporary area in high memory,
713         * prior to reading the E820 memory map and relocating
714         * properly.
715         */
716        movl    $_textdata_filesz, %ecx
717        movl    $_textdata_memsz, %edx
718        call    install_block
719
720        /* Initialise librm at current location */
721        movw    %ax, (init_librm_vector+2)
722        lcall   *init_librm_vector
723
724        /* Call relocate() to determine target address for relocation.
725         * relocate() will return with %esi, %edi and %ecx set up
726         * ready for the copy to the new location.
727         */
728        movw    %ax, (prot_call_vector+2)
729        pushl   $relocate
730        lcall   *prot_call_vector
731        popl    %edx /* discard */
732
733        /* Copy code to new location */
734        pushl   %edi
735        pushw   %ax
736        movw    $copy_bytes, %ax
737        call    pm_call
738        popw    %ax
739        popl    %edi
740
741        /* Initialise librm at new location */
742        lcall   *init_librm_vector
743
744#endif
745        /* Restore registers */
746        popw    %es
747        popw    %ds
748        popal
749        ret
750        .size install_prealloc, . - install_prealloc
751
752        /* Vectors for far calls to .text16 functions */
753        .section ".data16", "aw", @progbits
754#ifdef KEEP_IT_REAL
755init_libkir_vector:
756        .word init_libkir
757        .word 0
758        .size init_libkir_vector, . - init_libkir_vector
759#else
760init_librm_vector:
761        .word init_librm
762        .word 0
763        .size init_librm_vector, . - init_librm_vector
764prot_call_vector:
765        .word prot_call
766        .word 0
767        .size prot_call_vector, . - prot_call_vector
768#endif
769
770/****************************************************************************
771 * uninstall (real-mode near call)
772 *
773 * Uninstall all text and data segments.
774 *
775 * Parameters:
776 *   %ax  : .text16 segment address
777 *   %bx  : .data16 segment address
778 * Returns:
779 *   none
780 * Corrupts:
781 *   none
782 ****************************************************************************
783 */
784        .section ".text16", "ax", @progbits
785        .code16
786        .globl uninstall
787uninstall:
788        call    free_basemem
789        ret
790        .size uninstall, . - uninstall
791
792
793
794        /* File split information for the compressor */
795#if COMPRESS
796        .section ".zinfo", "a", @progbits
797        .ascii  "COPY"
798        .long   _prefix_lma
799        .long   _prefix_filesz
800        .long   _max_align
801        .ascii  "PACK"
802        .long   _text16_lma
803        .long   _text16_filesz
804        .long   _max_align
805        .ascii  "PACK"
806        .long   _data16_lma
807        .long   _data16_filesz
808        .long   _max_align
809        .ascii  "PACK"
810        .long   _textdata_lma
811        .long   _textdata_filesz
812        .long   _max_align
813#else /* COMPRESS */
814        .section ".zinfo", "a", @progbits
815        .ascii  "COPY"
816        .long   _prefix_lma
817        .long   _filesz
818        .long   _max_align
819#endif /* COMPRESS */
Note: See TracBrowser for help on using the repository browser.