Updated PCI IDs to latest snapshot.
[tangerine.git] / arch / common / boot / grub2 / kern / i386 / pc / startup.S
blob18f61d801c15b4a3e1859078a24b61a013b8a697
1 /*
2  *  GRUB  --  GRand Unified Bootloader
3  *  Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008 Free Software Foundation, Inc.
4  *
5  *  GRUB is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  GRUB is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
17  */
21  * Note: These functions defined in this file may be called from C.
22  *       Be careful of that you must not modify some registers. Quote
23  *       from gcc-2.95.2/gcc/config/i386/i386.h:
24         
25    1 for registers not available across function calls.
26    These must include the FIXED_REGISTERS and also any
27    registers that can be used without being saved.
28    The latter must include the registers where values are returned
29    and the register where structure-value addresses are passed.
30    Aside from that, you can include as many other registers as you like.
32   ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg
33 {  1, 1, 1, 0, 0, 0, 0, 1, 1,  1,  1,  1,  1,  1,  1,  1,  1 }
34  */
37  * Note: GRUB is compiled with the options -mrtd and -mregparm=3.
38  *       So the first three arguments are passed in %eax, %edx, and %ecx,
39  *       respectively, and if a function has a fixed number of arguments
40  *       and the number if greater than three, the function must return
41  *       with "ret $N" where N is ((the number of arguments) - 3) * 4.
42  */
44 #include <config.h>
45 #include <grub/symbol.h>
46 #include <grub/boot.h>
47 #include <grub/machine/boot.h>
48 #include <grub/machine/memory.h>
49 #include <grub/machine/console.h>
50 #include <grub/cpu/linux.h>
51 #include <grub/machine/kernel.h>
52 #include <grub/term.h>
53 #include <multiboot.h>
54 #include <multiboot2.h>
55                 
56 #define ABS(x)  ((x) - EXT_C(start) + GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200)
57         
58         .file   "startup.S"
60         .text
62         /* Tell GAS to generate 16-bit instructions so that this code works
63            in real mode. */
64         .code16
66         .globl  start, _start
67 start:
68 _start:
69         /*
70          *  Guarantee that "main" is loaded at 0x0:0x8200.
71          */
72         ljmp $0, $ABS(codestart)
74         /*
75          *  Compatibility version number
76          *
77          *  These MUST be at byte offset 6 and 7 of the executable
78          *  DO NOT MOVE !!!
79          */
80         . = EXT_C(start) + 0x6
81         .byte   GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR
83         /*
84          *  This is a special data area 8 bytes from the beginning.
85          */
87         . = EXT_C(start) + 0x8
89 VARIABLE(grub_total_module_size)
90         .long   0
91 VARIABLE(grub_kernel_image_size)
92         .long   0
93 VARIABLE(grub_compressed_size)
94         .long   0
95 VARIABLE(grub_install_dos_part)
96         .long   0xFFFFFFFF
97 VARIABLE(grub_install_bsd_part)
98         .long   0xFFFFFFFF
99 VARIABLE(grub_prefix)
100         /* to be filled by grub-mkimage */
102         /*
103          *  Leave some breathing room for the prefix.
104          */
106         . = EXT_C(start) + GRUB_KERNEL_MACHINE_DATA_END
109  * Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself).
110  * This uses the a.out kludge to load raw binary to the area starting at 1MB,
111  * and relocates itself after loaded.
112  */
113         .p2align        2       /* force 4-byte alignment */
114 multiboot_header:
115         /* magic */
116         .long   0x1BADB002
117         /* flags */
118         .long   (1 << 16)
119         /* checksum */
120         .long   -0x1BADB002 - (1 << 16)
121         /* header addr */
122         .long   multiboot_header - _start + 0x100000 + 0x200
123         /* load addr */
124         .long   0x100000
125         /* load end addr */
126         .long   0
127         /* bss end addr */
128         .long   0
129         /* entry addr */
130         .long   multiboot_entry - _start + 0x100000 + 0x200
131         
132 multiboot_entry:
133         .code32
134         /* obtain the boot device */
135         movl    12(%ebx), %edx
137         /* relocate the code */
138         movl    $(GRUB_KERNEL_MACHINE_RAW_SIZE + 0x200), %ecx
139         addl    EXT_C(grub_compressed_size) - _start + 0x100000 + 0x200, %ecx
140         movl    $0x100000, %esi
141         movl    $GRUB_BOOT_MACHINE_KERNEL_ADDR, %edi
142         cld
143         rep
144         movsb
145         /* jump to the real address */
146         movl    $multiboot_trampoline, %eax
147         jmp     *%eax
148         
149 multiboot_trampoline:
150         /* fill the boot information */
151         movl    %edx, %eax
152         shrl    $8, %eax
153         xorl    %ebx, %ebx
154         cmpb    $0xFF, %ah
155         je      1f
156         movb    %ah, %bl
157         movl    %ebx, EXT_C(grub_install_dos_part)
159         cmpb    $0xFF, %al
160         je      2f
161         movb    %al, %bl
162         movl    %ebx, EXT_C(grub_install_bsd_part)
164         shrl    $24, %edx
165         movb    $0xFF, %dh
166         /* enter the usual booting */
167         call    prot_to_real
168         .code16
169         
170 /* the real mode code continues... */
171 codestart:
172         cli             /* we're not safe here! */
174         /* set up %ds, %ss, and %es */
175         xorw    %ax, %ax
176         movw    %ax, %ds
177         movw    %ax, %ss
178         movw    %ax, %es
180         /* set up the real mode/BIOS stack */
181         movl    $GRUB_MEMORY_MACHINE_REAL_STACK, %ebp
182         movl    %ebp, %esp
184         sti             /* we're safe again */
186         /* save boot and root drive references */
187         ADDR32  movb    %dl, EXT_C(grub_boot_drive)
188         ADDR32  movb    %dh, EXT_C(grub_root_drive)
190         /* reset disk system (%ah = 0) */
191         int     $0x13
192         
193         /* transition to protected mode */
194         DATA32  call real_to_prot
196         /* The ".code32" directive takes GAS out of 16-bit mode. */
197         .code32
199         incl    %eax
200         call    EXT_C(grub_gate_a20)
201         
202 #if defined(ENABLE_LZO)
203         /* decompress the compressed part and put the result at 1MB */
204         movl    $GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR, %esi
205         movl    $(START_SYMBOL + GRUB_KERNEL_MACHINE_RAW_SIZE), %edi
207         pushl   %esi
208         pushl   EXT_C(grub_compressed_size)
209         pushl   %edi
210         call    lzo1x_decompress
211         addl    $12, %esp
213         movl    %eax, %ecx
214         cld
215 #elif defined(ENABLE_LZMA)
216         movl    $GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR, %edi
217         movl    $(START_SYMBOL + GRUB_KERNEL_MACHINE_RAW_SIZE), %esi
218         pushl   %edi
219         pushl   %esi
220         movl    EXT_C(grub_kernel_image_size), %ecx
221         addl    EXT_C(grub_total_module_size), %ecx
222         subl    $GRUB_KERNEL_MACHINE_RAW_SIZE, %ecx
223         pushl   %ecx
224         leal    (%edi, %ecx), %ebx
225         call    _LzmaDecodeA
226         /* _LzmaDecodeA clears DF, so no need to run cld */
227         popl    %ecx
228         popl    %edi
229         popl    %esi
230 #endif
232         /* copy back the decompressed part (except the modules) */
233         subl    EXT_C(grub_total_module_size), %ecx
234         rep
235         movsb
237 #if 0
238         /* copy modules before cleaning out the bss */
239         movl    EXT_C(grub_total_module_size), %ecx
240         movl    EXT_C(grub_kernel_image_size), %esi
241         addl    %ecx, %esi
242         addl    $START_SYMBOL, %esi
243         decl    %esi
244         movl    $END_SYMBOL, %edi
245         addl    %ecx, %edi
246         decl    %edi
247         std
248         rep
249         movsb
250 #endif
251         
252         /* clean out the bss */
253         movl    $BSS_START_SYMBOL, %edi
255         /* compute the bss length */
256         movl    $END_SYMBOL, %ecx
257         subl    %edi, %ecx
258                         
259         /* clean out */
260         xorl    %eax, %eax
261         cld
262         rep
263         stosb
264         
265         /*
266          *  Call the start of main body of C code.
267          */
268         call EXT_C(grub_main)
270 #include "../realmode.S"
273  *  This is the area for all of the special variables.
274  */
276         .p2align        2       /* force 4-byte alignment */
278 VARIABLE(grub_boot_drive)
279         .long   0
281 VARIABLE(grub_root_drive)
282         .long   0
284 VARIABLE(grub_start_addr)
285         .long   START_SYMBOL
287 VARIABLE(grub_end_addr)
288         .long   END_SYMBOL
289         
290 VARIABLE(grub_apm_bios_info)
291         .word   0       /* version */
292         .word   0       /* cseg */
293         .long   0       /* offset */
294         .word   0       /* cseg_16 */
295         .word   0       /* dseg_16 */
296         .word   0       /* cseg_len */
297         .word   0       /* cseg_16_len */
298         .word   0       /* dseg_16_len */
299         
300         .p2align        2       /* force 4-byte alignment */
301         
303  *  These next two routines, "real_to_prot" and "prot_to_real" are structured
304  *  in a very specific way.  Be very careful when changing them.
306  *  NOTE:  Use of either one messes up %eax and %ebp.
307  */
309 real_to_prot:
310         .code16
311         cli
313         /* load the GDT register */
314         DATA32  ADDR32  lgdt    %cs:gdtdesc
316         /* turn on protected mode */
317         movl    %cr0, %eax
318         orl     $GRUB_MEMORY_MACHINE_CR0_PE_ON, %eax
319         movl    %eax, %cr0
321         /* jump to relocation, flush prefetch queue, and reload %cs */
322         DATA32  ljmp    $GRUB_MEMORY_MACHINE_PROT_MODE_CSEG, $protcseg
324         .code32
325 protcseg:
326         /* reload other segment registers */
327         movw    $GRUB_MEMORY_MACHINE_PROT_MODE_DSEG, %ax
328         movw    %ax, %ds
329         movw    %ax, %es
330         movw    %ax, %fs
331         movw    %ax, %gs
332         movw    %ax, %ss
334         /* put the return address in a known safe location */
335         movl    (%esp), %eax
336         movl    %eax, GRUB_MEMORY_MACHINE_REAL_STACK
338         /* get protected mode stack */
339         movl    protstack, %eax
340         movl    %eax, %esp
341         movl    %eax, %ebp
343         /* get return address onto the right stack */
344         movl    GRUB_MEMORY_MACHINE_REAL_STACK, %eax
345         movl    %eax, (%esp)
347         /* zero %eax */
348         xorl    %eax, %eax
350         /* return on the old (or initialized) stack! */
351         ret
354  * grub_gate_a20(int on)
356  * Gate address-line 20 for high memory.
358  * This routine is probably overconservative in what it does, but so what?
360  * It also eats any keystrokes in the keyboard buffer.  :-(
361  */
363 FUNCTION(grub_gate_a20)
364         movl    %eax, %edx
366 gate_a20_test_current_state:    
367         /* first of all, test if already in a good state */
368         call    gate_a20_check_state
369         cmpb    %al, %dl
370         jnz     gate_a20_try_bios
371         ret
373 gate_a20_try_bios:
374         /* second, try a BIOS call */
375         pushl   %ebp
376         call    prot_to_real
378         .code16
379         movw    $0x2400, %ax
380         testb   %dl, %dl
381         jz      1f
382         incw    %ax
383 1:      int     $0x15
385         DATA32  call    real_to_prot
386         .code32
388         popl    %ebp
389         call    gate_a20_check_state
390         cmpb    %al, %dl
391         jnz     gate_a20_try_system_control_port_a
392         ret
393         
394 gate_a20_try_system_control_port_a:
395         /*
396          * In macbook, the keyboard test would hang the machine, so we move
397          * this forward.
398          */
399         /* fourth, try the system control port A */
400         inb     $0x92
401         andb    $(~0x03), %al
402         testb   %dl, %dl
403         jz      6f
404         orb     $0x02, %al
405 6:      outb    $0x92
407         /* When turning off Gate A20, do not check the state strictly,
408            because a failure is not fatal usually, and Gate A20 is always
409            on some modern machines.  */
410         testb   %dl, %dl
411         jz      7f
412         call    gate_a20_check_state
413         cmpb    %al, %dl
414         jnz     gate_a20_try_keyboard_controller
415 7:      ret
417 gate_a20_flush_keyboard_buffer:
418         inb     $0x64
419         andb    $0x02, %al
420         jnz     gate_a20_flush_keyboard_buffer
421 2:      
422         inb     $0x64
423         andb    $0x01, %al
424         jz      3f
425         inb     $0x60
426         jmp     2b
428         ret
429         
430 gate_a20_try_keyboard_controller:       
431         /* third, try the keyboard controller */
432         call    gate_a20_flush_keyboard_buffer
434         movb    $0xd1, %al
435         outb    $0x64
436 4:      
437         inb     $0x64
438         andb    $0x02, %al
439         jnz     4b
441         movb    $0xdd, %al
442         testb   %dl, %dl
443         jz      5f
444         orb     $0x02, %al
445 5:      outb    $0x60
446         call    gate_a20_flush_keyboard_buffer
448         /* output a dummy command (USB keyboard hack) */
449         movb    $0xff, %al
450         outb    $0x64
451         call    gate_a20_flush_keyboard_buffer
453         call    gate_a20_check_state
454         cmpb    %al, %dl
455         /* everything failed, so restart from the beginning */
456         jnz     gate_a20_try_bios
457         ret
458         
459 gate_a20_check_state:
460         /* iterate the checking for a while */
461         movl    $100, %ecx
462 1:      
463         call    3f
464         cmpb    %al, %dl
465         jz      2f
466         loop    1b
468         ret
469 3:      
470         pushl   %ebx
471         pushl   %ecx
472         xorl    %eax, %eax
473         /* compare the byte at 0x8000 with that at 0x108000 */
474         movl    $GRUB_BOOT_MACHINE_KERNEL_ADDR, %ebx
475         pushl   %ebx
476         /* save the original byte in CL */
477         movb    (%ebx), %cl
478         /* store the value at 0x108000 in AL */
479         addl    $0x100000, %ebx
480         movb    (%ebx), %al
481         /* try to set one less value at 0x8000 */
482         popl    %ebx
483         movb    %al, %ch
484         decb    %ch
485         movb    %ch, (%ebx)
486         /* serialize */
487         outb    %al, $0x80
488         outb    %al, $0x80
489         /* obtain the value at 0x108000 in CH */
490         pushl   %ebx
491         addl    $0x100000, %ebx
492         movb    (%ebx), %ch
493         /* this result is 1 if A20 is on or 0 if it is off */
494         subb    %ch, %al
495         xorb    $1, %al
496         /* restore the original */
497         popl    %ebx
498         movb    %cl, (%ebx)
499         popl    %ecx
500         popl    %ebx
501         ret
503 #if defined(ENABLE_LZO)
504 #include "lzo1x.S"
505 #elif defined(ENABLE_LZMA)
506 #include "lzma_decode.S"
507 #endif
510  * The code beyond this point is compressed.  Assert that the uncompressed
511  * code fits GRUB_KERNEL_MACHINE_RAW_SIZE.
512  */
513         . = EXT_C(start) + GRUB_KERNEL_MACHINE_RAW_SIZE
516  *  This call is special...  it never returns...  in fact it should simply
517  *  hang at this point!
518  */
520 FUNCTION(grub_stop)
521         call    prot_to_real
523         /*
524          * This next part is sort of evil.  It takes advantage of the
525          * byte ordering on the x86 to work in either 16-bit or 32-bit
526          * mode, so think about it before changing it.
527          */
529 FUNCTION(grub_hard_stop)
530         hlt
531         jmp EXT_C(grub_hard_stop)
535  * grub_stop_floppy()
537  * Stop the floppy drive from spinning, so that other software is
538  * jumped to with a known state.
539  */
540 FUNCTION(grub_stop_floppy)
541         movw    $0x3F2, %dx
542         xorb    %al, %al
543         outb    %al, %dx
544         ret
547  * grub_exit()
549  * Exit the system.
550  */
551 FUNCTION(grub_exit)
552         call    prot_to_real
553         .code16
554         /* Tell the BIOS a boot failure. If this does not work, reboot.  */
555         int     $0x18
556         jmp     cold_reboot
557         .code32
558         
560  * grub_reboot()
562  * Reboot the system. At the moment, rely on BIOS.
563  */
564 FUNCTION(grub_reboot)
565         call    prot_to_real
566         .code16
567 cold_reboot:    
568         /* cold boot */
569         movw    $0x0472, %di
570         movw    %ax, (%di)
571         ljmp    $0xFFFF, $0x0000
572         .code32
573         
575  * grub_halt(int no_apm)
577  * Halt the system, using APM if possible. If NO_APM is true, don't use
578  * APM even if it is available.
579  */
580 FUNCTION(grub_halt)
581         /* see if zero */
582         testl   %eax, %eax
583         jnz     EXT_C(grub_stop)
585         call    prot_to_real
586         .code16
587         
588         /* detect APM */
589         movw    $0x5300, %ax
590         xorw    %bx, %bx
591         int     $0x15
592         jc      EXT_C(grub_hard_stop)
593         /* don't check %bx for buggy BIOSes... */
595         /* disconnect APM first */
596         movw    $0x5304, %ax
597         xorw    %bx, %bx
598         int     $0x15
600         /* connect APM */
601         movw    $0x5301, %ax
602         xorw    %bx, %bx
603         int     $0x15
604         jc      EXT_C(grub_hard_stop)
606         /* set APM protocol level - 1.1 or bust. (this covers APM 1.2 also) */
607         movw    $0x530E, %ax
608         xorw    %bx, %bx
609         movw    $0x0101, %cx
610         int     $0x15
611         jc      EXT_C(grub_hard_stop)
612         
613         /* set the power state to off */
614         movw    $0x5307, %ax
615         movw    $1, %bx
616         movw    $3, %cx
617         int     $0x15
619         /* shouldn't reach here */
620         jmp     EXT_C(grub_hard_stop)
621         .code32
622         
623         
625  *  void grub_chainloader_real_boot (int drive, void *part_addr)
627  *  This starts another boot loader.
628  */
630 FUNCTION(grub_chainloader_real_boot)
631         pushl   %edx
632         pushl   %eax
634         call    EXT_C(grub_dl_unload_all)
636         /* Turn off Gate A20 */
637         xorl    %eax, %eax
638         call    EXT_C(grub_gate_a20)
640         /* set up to pass boot drive */
641         popl    %edx
643         /* ESI must point to a partition table entry */
644         popl    %esi
646         call    prot_to_real
647         .code16
648         ljmp    $0, $GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR
649         .code32
651 #include "../loader.S"
654  *   int grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap)
656  *   Call IBM/MS INT13 Extensions (int 13 %ah=AH) for DRIVE. DAP
657  *   is passed for disk address packet. If an error occurs, return
658  *   non-zero, otherwise zero.
659  */
661 FUNCTION(grub_biosdisk_rw_int13_extensions)
662         pushl   %ebp
663         pushl   %esi
665         /* compute the address of disk_address_packet */
666         movw    %cx, %si
667         xorw    %cx, %cx
668         shrl    $4, %ecx        /* save the segment to cx */
670         /* ah */
671         movb    %al, %dh
672         /* enter real mode */
673         call    prot_to_real
674         
675         .code16
676         movb    %dh, %ah
677         movw    %cx, %ds
678         int     $0x13           /* do the operation */
679         movb    %ah, %dl        /* save return value */
680         /* back to protected mode */
681         DATA32  call    real_to_prot
682         .code32
684         movb    %dl, %al        /* return value in %eax */
686         popl    %esi
687         popl    %ebp
689         ret
690         
692  *   int grub_biosdisk_rw_standard (int ah, int drive, int coff, int hoff,
693  *                                  int soff, int nsec, int segment)
695  *   Call standard and old INT13 (int 13 %ah=AH) for DRIVE. Read/write
696  *   NSEC sectors from COFF/HOFF/SOFF into SEGMENT. If an error occurs,
697  *   return non-zero, otherwise zero.
698  */
700 FUNCTION(grub_biosdisk_rw_standard)
701         pushl   %ebp
702         movl    %esp, %ebp
704         pushl   %ebx
705         pushl   %edi
706         pushl   %esi
708         /* set up CHS information */
710         /* set %ch to low eight bits of cylinder */
711         xchgb   %cl, %ch
712         /* set bits 6-7 of %cl to high two bits of cylinder */
713         shlb    $6, %cl
714         /* set bits 0-5 of %cl to sector */
715         addb    0xc(%ebp), %cl
716         /* set %dh to head */
717         movb    0x8(%ebp), %dh
718         /* set %ah to AH */
719         movb    %al, %ah
720         /* set %al to NSEC */
721         movb    0x10(%ebp), %al
722         /* save %ax in %di */
723         movw    %ax, %di
724         /* save SEGMENT in %bx */
725         movw    0x14(%ebp), %bx
726                 
727         /* enter real mode */
728         call    prot_to_real
730         .code16
731         movw    %bx, %es
732         xorw    %bx, %bx
733         movw    $3, %si         /* attempt at least three times */
735 1:      
736         movw    %di, %ax
737         int     $0x13           /* do the operation */
738         jnc     2f              /* check if successful */
740         movb    %ah, %bl        /* save return value */
741         /* if fail, reset the disk system */
742         xorw    %ax, %ax
743         int     $0x13
744         
745         decw    %si
746         cmpw    $0, %si
747         je      2f
748         xorb    %bl, %bl
749         jmp     1b              /* retry */
750 2:      
751         /* back to protected mode */
752         DATA32  call    real_to_prot
753         .code32
755         movb    %bl, %al        /* return value in %eax */
756         
757         popl    %esi
758         popl    %edi
759         popl    %ebx
760         popl    %ebp
762         ret     $(4 * 4)
766  *   int grub_biosdisk_check_int13_extensions (int drive)
768  *   Check if LBA is supported for DRIVE. If it is supported, then return
769  *   the major version of extensions, otherwise zero.
770  */
772 FUNCTION(grub_biosdisk_check_int13_extensions)
773         pushl   %ebp
774         pushl   %ebx
776         /* drive */
777         movb    %al, %dl
778         /* enter real mode */
779         call    prot_to_real
781         .code16
782         movb    $0x41, %ah
783         movw    $0x55aa, %bx
784         int     $0x13           /* do the operation */
785         
786         /* check the result */
787         jc      1f
788         cmpw    $0xaa55, %bx
789         jne     1f
791         movb    %ah, %bl        /* save the major version into %bl */
793         /* check if AH=0x42 is supported */
794         andw    $1, %cx
795         jnz     2f
796         
798         xorb    %bl, %bl
800         /* back to protected mode */
801         DATA32  call    real_to_prot
802         .code32
804         movb    %bl, %al        /* return value in %eax */
806         popl    %ebx
807         popl    %ebp
809         ret
813  *   int grub_biosdisk_get_cdinfo_int13_extensions (int drive, void *cdrp)
815  *   Return the cdrom information of DRIVE in CDRP. If an error occurs,
816  *   then return non-zero, otherwise zero.
817  */
819 FUNCTION(grub_biosdisk_get_cdinfo_int13_extensions)
820         movw    $0x4B01, %cx
821         jmp     1f
824  *   int grub_biosdisk_get_diskinfo_int13_extensions (int drive, void *drp)
826  *   Return the geometry of DRIVE in a drive parameters, DRP. If an error
827  *   occurs, then return non-zero, otherwise zero.
828  */
830 FUNCTION(grub_biosdisk_get_diskinfo_int13_extensions)
831         movb    $0x48, %ch
833         pushl   %ebp
834         pushl   %ebx
835         pushl   %esi
837         /* compute the address of drive parameters */
838         movw    %dx, %si
839         andl    $0xf, %esi
840         shrl    $4, %edx
841         movw    %dx, %bx        /* save the segment into %bx */
842         /* drive */
843         movb    %al, %dl
844         /* enter real mode */
845         call    prot_to_real
847         .code16
848         movw    %cx, %ax
849         movw    %bx, %ds
850         int     $0x13           /* do the operation */
851         movb    %ah, %bl        /* save return value in %bl */
852         /* back to protected mode */
853         DATA32  call    real_to_prot
854         .code32
856         movb    %bl, %al        /* return value in %eax */
858         popl    %esi
859         popl    %ebx
860         popl    %ebp
861         
862         ret
866  *   int grub_biosdisk_get_diskinfo_standard (int drive,
867  *                                            unsigned long *cylinders, 
868  *                                            unsigned long *heads,
869  *                                            unsigned long *sectors)
871  *   Return the geometry of DRIVE in CYLINDERS, HEADS and SECTORS. If an
872  *   error occurs, then return non-zero, otherwise zero.
873  */
875 FUNCTION(grub_biosdisk_get_diskinfo_standard)
876         pushl   %ebp
877         pushl   %ebx
878         pushl   %edi
880         /* push CYLINDERS */
881         pushl   %edx
882         /* push HEADS */
883         pushl   %ecx
884         /* SECTORS is on the stack */
885         
886         /* drive */
887         movb    %al, %dl
888         /* enter real mode */
889         call    prot_to_real
891         .code16
892         movb    $0x8, %ah
893         int     $0x13           /* do the operation */
894         /* check if successful */
895         testb   %ah, %ah
896         jnz     1f
897         /* bogus BIOSes may not return an error number */
898         testb   $0x3f, %cl      /* 0 sectors means no disk */
899         jnz     1f              /* if non-zero, then succeed */
900         /* XXX 0x60 is one of the unused error numbers */
901         movb    $0x60, %ah
903         movb    %ah, %bl        /* save return value in %bl */
904         /* back to protected mode */
905         DATA32  call    real_to_prot
906         .code32
908         /* pop HEADS */
909         popl    %edi
910         movb    %dh, %al
911         incl    %eax    /* the number of heads is counted from zero */
912         movl    %eax, (%edi)
914         /* pop CYLINDERS */
915         popl    %edi
916         movb    %ch, %al
917         movb    %cl, %ah
918         shrb    $6, %ah /* the number of cylinders is counted from zero */
919         incl    %eax
920         movl    %eax, (%edi)
922         /* SECTORS */
923         movl    0x10(%esp), %edi
924         andb    $0x3f, %cl
925         movzbl  %cl, %eax
926         movl    %eax, (%edi)
927         
928         xorl    %eax, %eax
929         movb    %bl, %al        /* return value in %eax */
931         popl    %edi
932         popl    %ebx
933         popl    %ebp
935         ret     $4
939  * int grub_biosdisk_get_num_floppies (void)
940  */
941 FUNCTION(grub_biosdisk_get_num_floppies)
942         pushl   %ebp
944         xorl    %edx, %edx
945         call    prot_to_real
946         
947         .code16
948         /* reset the disk system first */
949         int     $0x13
951         stc
952         
953         /* call GET DISK TYPE */
954         movb    $0x15, %ah
955         int     $0x13
957         jc      2f
959         /* check if this drive exists */        
960         testb   $0x3, %ah
961         jz      2f
963         incb    %dl
964         cmpb    $2, %dl
965         jne     1b
967         DATA32  call    real_to_prot
968         .code32
970         movl    %edx, %eax
971         popl    %ebp
972         ret
973         
974         
977  * grub_get_memsize(i) :  return the memory size in KB. i == 0 for conventional
978  *              memory, i == 1 for extended memory
979  *      BIOS call "INT 12H" to get conventional memory size
980  *      BIOS call "INT 15H, AH=88H" to get extended memory size
981  *              Both have the return value in AX.
983  */
985 FUNCTION(grub_get_memsize)
986         pushl   %ebp
988         movl    %eax, %edx
990         call    prot_to_real    /* enter real mode */
991         .code16
993         testl   %edx, %edx
994         jnz     xext
996         int     $0x12
997         jmp     xdone
999 xext:
1000         movb    $0x88, %ah
1001         int     $0x15
1003 xdone:
1004         movw    %ax, %dx
1006         DATA32  call    real_to_prot
1007         .code32
1009         movw    %dx, %ax
1011         popl    %ebp
1012         ret
1017  * grub_get_eisa_mmap() :  return packed EISA memory map, lower 16 bits is
1018  *              memory between 1M and 16M in 1K parts, upper 16 bits is
1019  *              memory above 16M in 64K parts.  If error, return zero.
1020  *      BIOS call "INT 15H, AH=E801H" to get EISA memory map,
1021  *              AX = memory between 1M and 16M in 1K parts.
1022  *              BX = memory above 16M in 64K parts.
1024  */
1026 FUNCTION(grub_get_eisa_mmap)
1027         pushl   %ebp
1028         pushl   %ebx
1030         call    prot_to_real    /* enter real mode */
1031         .code16
1033         movw    $0xe801, %ax
1034         int     $0x15
1036         shll    $16, %ebx
1037         movw    %ax, %bx
1039         DATA32  call    real_to_prot
1040         .code32
1042         cmpb    $0x86, %bh
1043         je      xnoteisa
1045         movl    %ebx, %eax
1047 xnoteisa:
1048         popl    %ebx
1049         popl    %ebp
1050         ret
1054  * grub_get_mmap_entry(addr, cont) : address and old continuation value (zero to
1055  *              start), for the Query System Address Map BIOS call.
1057  *  Sets the first 4-byte int value of "addr" to the size returned by
1058  *  the call.  If the call fails, sets it to zero.
1060  *      Returns:  new (non-zero) continuation value, 0 if done.
1061  */
1063 FUNCTION(grub_get_mmap_entry)
1064         pushl   %ebp
1065         pushl   %ebx
1066         pushl   %edi
1067         pushl   %esi
1069         /* push ADDR */
1070         pushl   %eax
1071         
1072         /* place address (+4) in ES:DI */
1073         addl    $4, %eax
1074         movl    %eax, %edi
1075         andl    $0xf, %edi
1076         shrl    $4, %eax
1077         movl    %eax, %esi
1079         /* set continuation value */
1080         movl    %edx, %ebx
1082         /* set default maximum buffer size */
1083         movl    $0x14, %ecx
1085         /* set EDX to 'SMAP' */
1086         movl    $0x534d4150, %edx
1088         call    prot_to_real    /* enter real mode */
1089         .code16
1091         movw    %si, %es
1092         movl    $0xe820, %eax
1093         int     $0x15
1095         DATA32  jc      xnosmap
1097         cmpl    $0x534d4150, %eax
1098         jne     xnosmap
1100         cmpl    $0x14, %ecx
1101         jl      xnosmap
1103         cmpl    $0x400, %ecx
1104         jg      xnosmap
1106         jmp     xsmap
1108 xnosmap:
1109         xorl    %ecx, %ecx
1111 xsmap:
1112         DATA32  call    real_to_prot
1113         .code32
1115         /* write length of buffer (zero if error) into ADDR */
1116         popl    %eax
1117         movl    %ecx, (%eax)
1119         /* set return value to continuation */
1120         movl    %ebx, %eax
1122         popl    %esi
1123         popl    %edi
1124         popl    %ebx
1125         popl    %ebp
1126         ret
1128         
1130  * void grub_console_real_putchar (int c)
1132  * Put the character C on the console. Because GRUB wants to write a
1133  * character with an attribute, this implementation is a bit tricky.
1134  * If C is a control character (CR, LF, BEL, BS), use INT 10, AH = 0Eh
1135  * (TELETYPE OUTPUT). Otherwise, save the original position, put a space,
1136  * save the current position, restore the original position, write the
1137  * character and the attribute, and restore the current position.
1139  * The reason why this is so complicated is that there is no easy way to
1140  * get the height of the screen, and the TELETYPE OUTPUT BIOS call doesn't
1141  * support setting a background attribute.
1142  */
1143 FUNCTION(grub_console_real_putchar)
1144         movl    %eax, %edx
1145         pusha
1146         movb    EXT_C(grub_console_cur_color), %bl
1147         
1148         call    prot_to_real
1149         .code16
1150         movb    %dl, %al
1151         xorb    %bh, %bh
1153         /* use teletype output if control character */
1154         cmpb    $0x7, %al
1155         je      1f
1156         cmpb    $0x8, %al
1157         je      1f
1158         cmpb    $0xa, %al
1159         je      1f
1160         cmpb    $0xd, %al
1161         je      1f
1163         /* save the character and the attribute on the stack */
1164         pushw   %ax
1165         pushw   %bx
1166         
1167         /* get the current position */
1168         movb    $0x3, %ah
1169         int     $0x10
1171         /* check the column with the width */
1172         cmpb    $79, %dl
1173         jl      2f
1174         
1175         /* print CR and LF, if next write will exceed the width */      
1176         movw    $0x0e0d, %ax
1177         int     $0x10
1178         movb    $0x0a, %al
1179         int     $0x10
1180         
1181         /* get the current position */
1182         movb    $0x3, %ah
1183         int     $0x10
1185 2:      
1186         /* restore the character and the attribute */
1187         popw    %bx
1188         popw    %ax
1189         
1190         /* write the character with the attribute */
1191         movb    $0x9, %ah
1192         movw    $1, %cx
1193         int     $0x10
1195         /* move the cursor forward */
1196         incb    %dl
1197         movb    $0x2, %ah
1198         int     $0x10
1200         jmp     3f
1202 1:      movw    $1, %bx
1203         movb    $0xe, %ah
1204         int     $0x10
1205         
1206 3:      DATA32  call    real_to_prot
1207         .code32
1208         
1209         popa
1210         ret
1211         
1214  * int grub_console_getkey (void)
1215  * BIOS call "INT 16H Function 00H" to read character from keyboard
1216  *      Call with       %ah = 0x0
1217  *      Return:         %ah = keyboard scan code
1218  *                      %al = ASCII character
1219  */
1221 /* this table is used in translate_keycode below */
1222 translation_table:
1223         .word   GRUB_CONSOLE_KEY_LEFT, GRUB_TERM_LEFT
1224         .word   GRUB_CONSOLE_KEY_RIGHT, GRUB_TERM_RIGHT
1225         .word   GRUB_CONSOLE_KEY_UP, GRUB_TERM_UP
1226         .word   GRUB_CONSOLE_KEY_DOWN, GRUB_TERM_DOWN
1227         .word   GRUB_CONSOLE_KEY_HOME, GRUB_TERM_HOME
1228         .word   GRUB_CONSOLE_KEY_END, GRUB_TERM_END
1229         .word   GRUB_CONSOLE_KEY_DC, GRUB_TERM_DC
1230         .word   GRUB_CONSOLE_KEY_BACKSPACE, GRUB_TERM_BACKSPACE
1231         .word   GRUB_CONSOLE_KEY_PPAGE, GRUB_TERM_PPAGE
1232         .word   GRUB_CONSOLE_KEY_NPAGE, GRUB_TERM_NPAGE
1233         .word   0
1234         
1236  * translate_keycode translates the key code %dx to an ascii code.
1237  */
1238         .code16
1240 translate_keycode:
1241         pushw   %bx
1242         pushw   %si
1243         
1244         movw    $ABS(translation_table), %si
1245         
1246 1:      lodsw
1247         /* check if this is the end */
1248         testw   %ax, %ax
1249         jz      2f
1250         /* load the ascii code into %ax */
1251         movw    %ax, %bx
1252         lodsw
1253         /* check if this matches the key code */
1254         cmpw    %bx, %dx
1255         jne     1b
1256         /* translate %dx, if successful */
1257         movw    %ax, %dx
1259 2:      popw    %si
1260         popw    %bx
1261         ret
1263         .code32
1264         
1265 FUNCTION(grub_console_getkey)
1266         pushl   %ebp
1268         call    prot_to_real
1269         .code16
1271         /*
1272          * Due to a bug in apple's bootcamp implementation, INT 16/AH = 0 would
1273          * cause the machine to hang at the second keystroke. However, we can
1274          * work around this problem by ensuring the presence of keystroke with
1275          * INT 16/AH = 1 before calling INT 16/AH = 0.
1276          */
1279         movb    $1, %ah
1280         int     $0x16
1281         jnz     2f
1282         hlt
1283         jmp     1b
1287         movb    $0, %ah
1288         int     $0x16
1290         movw    %ax, %dx                /* real_to_prot uses %eax */
1291         call    translate_keycode
1292                 
1293         DATA32  call    real_to_prot
1294         .code32
1296         movw    %dx, %ax
1298         popl    %ebp
1299         ret
1303  * int grub_console_checkkey (void)
1304  *      if there is a character pending, return it; otherwise return -1
1305  * BIOS call "INT 16H Function 01H" to check whether a character is pending
1306  *      Call with       %ah = 0x1
1307  *      Return:
1308  *              If key waiting to be input:
1309  *                      %ah = keyboard scan code
1310  *                      %al = ASCII character
1311  *                      Zero flag = clear
1312  *              else
1313  *                      Zero flag = set
1314  */
1315 FUNCTION(grub_console_checkkey)
1316         pushl   %ebp
1317         xorl    %edx, %edx
1318         
1319         call    prot_to_real    /* enter real mode */
1320         .code16
1322         movb    $0x1, %ah
1323         int     $0x16
1325         jz      notpending
1326         
1327         movw    %ax, %dx
1328         DATA32  jmp     pending
1330 notpending:
1331         decl    %edx
1333 pending:
1334         DATA32  call    real_to_prot
1335         .code32
1337         movl    %edx, %eax
1339         popl    %ebp
1340         ret
1342         
1344  * grub_uint16_t grub_console_getxy (void)
1345  * BIOS call "INT 10H Function 03h" to get cursor position
1346  *      Call with       %ah = 0x03
1347  *                      %bh = page
1348  *      Returns         %ch = starting scan line
1349  *                      %cl = ending scan line
1350  *                      %dh = row (0 is top)
1351  *                      %dl = column (0 is left)
1352  */
1355 FUNCTION(grub_console_getxy)
1356         pushl   %ebp
1357         pushl   %ebx                    /* save EBX */
1359         call    prot_to_real
1360         .code16
1362         xorb    %bh, %bh                /* set page to 0 */
1363         movb    $0x3, %ah
1364         int     $0x10                   /* get cursor position */
1366         DATA32  call    real_to_prot
1367         .code32
1369         movb    %dl, %ah
1370         movb    %dh, %al
1372         popl    %ebx
1373         popl    %ebp
1374         ret
1378  * void grub_console_gotoxy(grub_uint8_t x, grub_uint8_t y)
1379  * BIOS call "INT 10H Function 02h" to set cursor position
1380  *      Call with       %ah = 0x02
1381  *                      %bh = page
1382  *                      %dh = row (0 is top)
1383  *                      %dl = column (0 is left)
1384  */
1387 FUNCTION(grub_console_gotoxy)
1388         pushl   %ebp
1389         pushl   %ebx                    /* save EBX */
1391         movb    %dl, %dh        /* %dh = y */
1392         movb    %al, %dl        /* %dl = x */
1394         call    prot_to_real
1395         .code16
1397         xorb    %bh, %bh                /* set page to 0 */
1398         movb    $0x2, %ah
1399         int     $0x10                   /* set cursor position */
1401         DATA32  call    real_to_prot
1402         .code32
1404         popl    %ebx
1405         popl    %ebp
1406         ret
1408         
1410  * void grub_console_cls (void)
1411  * BIOS call "INT 10H Function 09h" to write character and attribute
1412  *      Call with       %ah = 0x09
1413  *                      %al = (character)
1414  *                      %bh = (page number)
1415  *                      %bl = (attribute)
1416  *                      %cx = (number of times)
1417  */
1419 FUNCTION(grub_console_cls)
1420         pushl   %ebp
1421         pushl   %ebx                    /* save EBX */
1423         call    prot_to_real
1424         .code16
1426         /* move the cursor to the beginning */
1427         movb    $0x02, %ah
1428         xorb    %bh, %bh
1429         xorw    %dx, %dx
1430         int     $0x10
1432         /* write spaces to the entire screen */
1433         movw    $0x0920, %ax
1434         movw    $0x07, %bx
1435         movw    $(80 * 25), %cx
1436         int     $0x10
1438         /* move back the cursor */
1439         movb    $0x02, %ah
1440         int     $0x10
1442         DATA32  call    real_to_prot
1443         .code32
1445         popl    %ebx
1446         popl    %ebp
1447         ret
1449         
1451  * void grub_console_setcursor (int on)
1452  * BIOS call "INT 10H Function 01h" to set cursor type
1453  *      Call with       %ah = 0x01
1454  *                      %ch = cursor starting scanline
1455  *                      %cl = cursor ending scanline
1456  */
1458 console_cursor_state:
1459         .byte   1
1460 console_cursor_shape:
1461         .word   0
1462         
1463 FUNCTION(grub_console_setcursor)
1464         pushl   %ebp
1465         pushl   %ebx
1467         /* push ON */
1468         pushl   %eax
1469         
1470         /* check if the standard cursor shape has already been saved */
1471         movw    console_cursor_shape, %ax
1472         testw   %ax, %ax
1473         jne     1f
1475         call    prot_to_real
1476         .code16
1478         movb    $0x03, %ah
1479         xorb    %bh, %bh
1480         int     $0x10
1482         DATA32  call    real_to_prot
1483         .code32
1485         movw    %cx, console_cursor_shape
1487         /* set %cx to the designated cursor shape */
1488         movw    $0x2000, %cx
1489         popl    %eax
1490         testl   %eax, %eax
1491         jz      2f
1492         movw    console_cursor_shape, %cx
1493 2:      
1494         call    prot_to_real
1495         .code16
1497         movb    $0x1, %ah
1498         int     $0x10 
1500         DATA32  call    real_to_prot
1501         .code32
1503         popl    %ebx
1504         popl    %ebp
1505         ret
1506                 
1508  * grub_getrtsecs()
1509  *      if a seconds value can be read, read it and return it (BCD),
1510  *      otherwise return 0xFF
1511  * BIOS call "INT 1AH Function 02H" to check whether a character is pending
1512  *      Call with       %ah = 0x2
1513  *      Return:
1514  *              If RT Clock can give correct values
1515  *                      %ch = hour (BCD)
1516  *                      %cl = minutes (BCD)
1517  *                      %dh = seconds (BCD)
1518  *                      %dl = daylight savings time (00h std, 01h daylight)
1519  *                      Carry flag = clear
1520  *              else
1521  *                      Carry flag = set
1522  *                         (this indicates that the clock is updating, or
1523  *                          that it isn't running)
1524  */
1525 FUNCTION(grub_getrtsecs)
1526         pushl   %ebp
1528         call    prot_to_real    /* enter real mode */
1529         .code16
1531         clc
1532         movb    $0x2, %ah
1533         int     $0x1a
1535         DATA32  jnc     gottime
1536         movb    $0xff, %dh
1538 gottime:
1539         DATA32  call    real_to_prot
1540         .code32
1542         movb    %dh, %al
1544         popl    %ebp
1545         ret
1547         
1549  * grub_get_rtc()
1550  *      return the real time in ticks, of which there are about
1551  *      18-20 per second
1552  */
1553 FUNCTION(grub_get_rtc)
1554         pushl   %ebp
1556         call    prot_to_real    /* enter real mode */
1557         .code16
1559         /* %ax is already zero */
1560         int     $0x1a
1562         DATA32  call    real_to_prot
1563         .code32
1565         movl    %ecx, %eax
1566         shll    $16, %eax
1567         movw    %dx, %ax
1569         popl    %ebp
1570         ret
1574  * unsigned char grub_vga_set_mode (unsigned char mode)
1575  */
1576 FUNCTION(grub_vga_set_mode)
1577         pushl   %ebp
1578         pushl   %ebx
1579         movl    %eax, %ecx
1581         call    prot_to_real
1582         .code16
1583         /* get current mode */
1584         xorw    %bx, %bx
1585         movb    $0x0f, %ah
1586         int     $0x10
1587         movb    %al, %dl
1589         /* set the new mode */
1590         movb    %cl, %al
1591         xorb    %ah, %ah
1592         int     $0x10
1594         DATA32  call    real_to_prot
1595         .code32
1597         movb    %dl, %al
1598         popl    %ebx
1599         popl    %ebp
1600         ret
1604  * unsigned char *grub_vga_get_font (void)
1605  */
1606 FUNCTION(grub_vga_get_font)
1607         pushl   %ebp
1608         pushl   %ebx
1610         call    prot_to_real
1611         .code16
1612         movw    $0x1130, %ax
1613         movb    $0x06, %bh
1614         int     $0x10
1615         movw    %es, %bx
1616         movw    %bp, %dx
1617         DATA32  call    real_to_prot
1618         .code32
1620         movzwl  %bx, %ecx
1621         shll    $4, %ecx
1622         movw    %dx, %ax
1623         addl    %ecx, %eax
1625         popl    %ebx
1626         popl    %ebp
1627         ret
1630  * grub_vbe_bios_status_t grub_vbe_get_controller_info (struct grub_vbe_info_block *controller_info)
1632  * Register allocations for parameters:
1633  * %eax         *controller_info
1634  */
1635 FUNCTION(grub_vbe_bios_get_controller_info)
1636         pushl   %ebp
1637         pushl   %edi
1638         pushl   %edx
1640         movw    %ax, %di        /* Store *controller_info to %edx:%di.  */
1641         xorw    %ax, %ax
1642         shrl    $4, %eax
1643         mov     %eax, %edx      /* prot_to_real destroys %eax.  */
1644         
1645         call    prot_to_real
1646         .code16
1648         pushw   %es
1650         movw    %dx, %es        /* *controller_info is now on %es:%di.  */
1651         movw    $0x4f00, %ax
1652         int     $0x10
1654         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1656         popw    %es
1658         DATA32 call     real_to_prot
1659         .code32
1661         movl    %edx, %eax
1662         andl    $0x0FFFF, %eax  /* Return value in %eax.  */
1663         
1664         pop     %edx
1665         popl    %edi
1666         popl    %ebp
1667         ret
1670  * grub_vbe_status_t grub_vbe_bios_get_mode_info (grub_uint32_t mode,
1671  *                                                struct grub_vbe_mode_info_block *mode_info)
1673  * Register allocations for parameters:
1674  * %eax         mode
1675  * %edx         *mode_info
1676  */
1677 FUNCTION(grub_vbe_bios_get_mode_info)
1678         pushl   %ebp
1679         pushl   %edi
1681         movl    %eax, %ecx      /* Store mode number to %ecx.  */
1683         movw    %dx, %di        /* Store *mode_info to %edx:%di.  */
1684         xorw    %dx, %dx
1685         shrl    $4, %edx
1687         call    prot_to_real
1688         .code16
1690         pushw   %es
1692         movw    %dx, %es        /* *mode_info is now on %es:%di.  */
1693         movw    $0x4f01, %ax
1694         int     $0x10
1696         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1698         popw    %es
1700         DATA32 call     real_to_prot
1701         .code32
1703         movl    %edx, %eax
1704         andl    $0x0FFFF, %eax  /* Return value in %eax.  */
1706         popl    %edi
1707         popl    %ebp
1708         ret
1711  * grub_vbe_status_t grub_vbe_bios_set_mode (grub_uint32_t mode,
1712  *                                           struct grub_vbe_crtc_info_block *crtc_info)
1714  * Register allocations for parameters:
1715  * %eax         mode
1716  * %edx         *crtc_info
1717  */
1718 FUNCTION(grub_vbe_bios_set_mode)
1719         pushl   %ebp
1720         pushl   %ebx
1721         pushl   %edi
1723         movl    %eax, %ebx      /* Store mode in %ebx.  */
1725         movw    %dx, %di        /* Store *crtc_info to %edx:%di.  */
1726         xorw    %dx, %dx
1727         shrl    $4, %edx
1729         call    prot_to_real
1730         .code16
1732         pushw   %es
1734         movw    %dx, %es        /* *crtc_info is now on %es:%di.  */
1736         movw    $0x4f02, %ax
1737         int     $0x10
1739         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1741         popw    %es
1743         DATA32 call     real_to_prot
1744         .code32
1745         
1746         movw    %dx, %ax
1747         andl    $0xFFFF, %eax   /* Return value in %eax.  */
1749         popl    %edi
1750         popl    %ebx
1751         popl    %ebp
1752         ret
1755  * grub_vbe_status_t grub_vbe_bios_get_mode (grub_uint32_t *mode)
1757  * Register allocations for parameters:
1758  * %eax         *mode
1759  */
1760 FUNCTION(grub_vbe_bios_get_mode)
1761         pushl   %ebp
1762         pushl   %ebx
1763         pushl   %edi
1764         pushl   %edx
1765         pushl   %eax            /* Push *mode to stack.  */
1767         call    prot_to_real
1768         .code16
1770         movw    $0x4f03, %ax
1771         int     $0x10
1773         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1775         DATA32 call     real_to_prot
1776         .code32
1778         popl    %edi            /* Pops *mode from stack to %edi.  */
1779         andl    $0xFFFF, %ebx
1780         movl    %ebx, (%edi)
1782         movw    %dx, %ax
1783         andl    $0xFFFF, %eax   /* Return value in %eax.  */
1785         popl    %edx
1786         popl    %edi
1787         popl    %ebx
1788         popl    %ebp
1789         ret
1792  * grub_vbe_status_t grub_vbe_bios_set_memory_window (grub_uint32_t window,
1793  *                                                    grub_uint32_t position);
1795  * Register allocations for parameters:
1796  * %eax         window
1797  * %edx         position
1798  */
1799 FUNCTION(grub_vbe_bios_set_memory_window)
1800         pushl   %ebp
1801         pushl   %ebx
1803         movl    %eax, %ebx
1805         call    prot_to_real
1806         .code16
1808         movw    $0x4f05, %ax
1809         andw    $0x00ff, %bx    /* BL = window, BH = 0, Set memory window.  */
1810         int     $0x10
1812         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1814         DATA32 call     real_to_prot
1815         .code32
1816         
1817         movw    %dx, %ax
1818         andl    $0xFFFF, %eax   /* Return value in %eax.  */
1820         popl    %ebx
1821         popl    %ebp
1822         ret
1825  * grub_vbe_status_t grub_vbe_bios_get_memory_window (grub_uint32_t window,
1826  *                                                    grub_uint32_t *position);
1828  * Register allocations for parameters:
1829  * %eax         window
1830  * %edx         *position
1831  */
1832 FUNCTION(grub_vbe_bios_get_memory_window)
1833         pushl   %ebp
1834         pushl   %ebx
1835         pushl   %edi
1836         pushl   %edx            /* Push *position to stack.  */
1838         movl    %eax, %ebx      /* Store window in %ebx.  */
1840         call    prot_to_real
1841         .code16
1843         movw    $0x4f05, %ax
1844         andw    $0x00ff, %bx    /* BL = window.  */
1845         orw     $0x0100, %bx    /* BH = 1, Get memory window.  */
1846         int     $0x10
1848         movw    %ax, %bx        /* real_to_prot destroys %eax.  */
1850         DATA32 call     real_to_prot
1851         .code32
1853         popl    %edi            /* pops *position from stack to %edi.  */
1854         andl    $0xFFFF, %edx
1855         movl    %edx, (%edi)    /* Return position to caller.  */
1857         movw    %bx, %ax
1858         andl    $0xFFFF, %eax   /* Return value in %eax.  */
1860         popl    %edi
1861         popl    %ebx
1862         popl    %ebp
1863         ret
1866  * grub_vbe_status_t grub_vbe_bios_set_scanline_length (grub_uint32_t length)
1868  * Register allocations for parameters:
1869  * %eax         length
1870  */
1871 FUNCTION(grub_vbe_bios_set_scanline_length)
1872         pushl   %ebp
1873         pushl   %ebx
1874         pushl   %edx
1876         movl    %eax, %ecx      /* Store length in %ecx.  */
1878         call    prot_to_real
1879         .code16
1881         movw    $0x4f06, %ax
1882         movw    $0x0002, %bx    /* BL = 2, Set Scan Line in Bytes.  */
1883         int     $0x10
1885         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1887         DATA32 call     real_to_prot
1888         .code32
1889         
1890         movw    %dx, %ax
1891         andl    $0xFFFF, %eax   /* Return value in %eax.  */
1893         popl    %edx
1894         popl    %ebx
1895         popl    %ebp
1896         ret
1899  * grub_vbe_status_t grub_vbe_bios_get_scanline_length (grub_uint32_t *length)
1901  * Register allocations for parameters:
1902  * %eax         *length
1903  */
1904 FUNCTION(grub_vbe_bios_get_scanline_length)
1905         pushl   %ebp
1906         pushl   %ebx
1907         pushl   %edi
1908         pushl   %edx            /* Push *length to stack.  */
1910         call    prot_to_real
1911         .code16
1913         movw    $0x4f06, %ax
1914         movw    $0x0001, %bx    /* BL = 1, Get Scan Line Length (in bytes).  */
1915         int     $0x10
1917         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1919         DATA32 call     real_to_prot
1920         .code32
1922         popl    %edi            /* Pops *length from stack to %edi.  */
1923         andl    $0xFFFF, %ebx
1924         movl    %ebx, (%edi)    /* Return length to caller.  */
1926         movw    %dx, %ax
1927         andl    $0xFFFF, %eax   /* Return value in %eax.  */
1929         popl    %edi
1930         popl    %ebx
1931         popl    %ebp
1932         ret
1935  * grub_vbe_status_t grub_vbe_bios_set_display_start (grub_uint32_t x,
1936  *                                                    grub_uint32_t y)
1938  * Register allocations for parameters:
1939  * %eax         x
1940  * %edx         y
1941  */
1942 FUNCTION(grub_vbe_bios_set_display_start)
1943         pushl   %ebp
1944         pushl   %ebx
1946         movl    %eax, %ecx      /* Store x in %ecx.  */
1948         call    prot_to_real
1949         .code16
1951         movw    $0x4f07, %ax
1952         movw    $0x0080, %bx    /* BL = 80h, Set Display Start 
1953                                    during Vertical Retrace.  */
1954         int     $0x10
1956         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1958         DATA32 call     real_to_prot
1959         .code32
1960         
1961         movw    %dx, %ax
1962         andl    $0xFFFF, %eax   /* Return value in %eax.  */
1964         popl    %ebx
1965         popl    %ebp
1966         ret
1969  * grub_vbe_status_t grub_vbe_bios_get_display_start (grub_uint32_t *x,
1970  *                                                    grub_uint32_t *y)
1972  * Register allocations for parameters:
1973  * %eax         *x
1974  * %edx         *y
1975  */
1976 FUNCTION(grub_vbe_bios_get_display_start)
1977         pushl   %ebp
1978         pushl   %ebx
1979         pushl   %edi
1980         pushl   %eax            /* Push *x to stack.  */
1981         pushl   %edx            /* Push *y to stack.  */
1983         call    prot_to_real
1984         .code16
1986         movw    $0x4f07, %ax
1987         movw    $0x0001, %bx    /* BL = 1, Get Display Start.  */
1988         int     $0x10
1990         movw    %ax, %bx        /* real_to_prot destroys %eax.  */
1992         DATA32 call     real_to_prot
1993         .code32
1995         popl    %edi            /* Pops *y from stack to %edi.  */
1996         andl    $0xFFFF, %edx
1997         movl    %edx, (%edi)    /* Return y-position to caller.  */
1999         popl    %edi            /* Pops *x from stack to %edi.  */
2000         andl    $0xFFFF, %ecx
2001         movl    %ecx, (%edi)    /* Return x-position to caller.  */
2003         movw    %bx, %ax
2004         andl    $0xFFFF, %eax   /* Return value in %eax.  */
2006         popl    %edi
2007         popl    %ebx
2008         popl    %ebp
2009         ret
2012  * grub_vbe_status_t grub_vbe_bios_set_palette_data (grub_uint32_t color_count,
2013  *                                                   grub_uint32_t start_index,
2014  *                                                   struct grub_vbe_palette_data *palette_data)
2016  * Register allocations for parameters:
2017  * %eax         color_count
2018  * %edx         start_index
2019  * %ecx         *palette_data
2020  */
2021 FUNCTION(grub_vbe_bios_set_palette_data)
2022         pushl   %ebp
2023         pushl   %ebx
2024         pushl   %edi
2026         movl    %eax, %ebx      /* Store color_count in %ebx.  */
2028         movw    %cx, %di        /* Store *palette_data to %ecx:%di.  */
2029         xorw    %cx, %cx
2030         shrl    $4, %ecx
2032         call    prot_to_real
2033         .code16
2035         pushw   %es
2037         movw    %cx, %es        /* *palette_data is now on %es:%di.  */
2038         movw    %bx, %cx        /* color_count is now on %cx.  */
2040         movw    $0x4f09, %ax
2041         xorw    %bx, %bx        /* BL = 0, Set Palette Data.  */
2042         int     $0x10
2044         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
2046         popw    %es
2048         DATA32 call     real_to_prot
2049         .code32
2050         
2051         movw    %dx, %ax
2052         andl    $0xFFFF, %eax   /* Return value in %eax.  */
2054         popl    %edi
2055         popl    %ebx
2056         popl    %ebp
2057         ret
2060 pxe_rm_entry:
2061         .long   0
2064  * struct grub_pxenv *grub_pxe_scan (void);
2065  */
2066 FUNCTION(grub_pxe_scan)
2067         pushl   %ebp
2068         pushl   %ebx
2070         xorl    %ebx, %ebx
2071         xorl    %ecx, %ecx
2073         call    prot_to_real
2074         .code16
2076         pushw   %es
2078         movw    $0x5650, %ax
2079         int     $0x1A
2080         cmpw    $0x564E, %ax
2081         jnz     1f
2082         cmpl    $0x4E455850, %es:(%bx)          /* PXEN(V+)  */
2083         jnz     1f
2084         cmpw    $0x201, %es:6(%bx)              /* API version  */
2085         jb      1f
2086         lesw    %es:0x28(%bx), %bx              /* !PXE structure  */
2087         cmpl    $0x45585021, %es:(%bx)          /* !PXE  */
2088         jnz     1f
2089         movw    %es, %cx
2090         jmp     2f
2092         xorw    %bx, %bx
2093         xorw    %cx, %cx
2096         popw    %es
2098         DATA32 call     real_to_prot
2099         .code32
2101         xorl    %eax, %eax
2102         leal    (%eax, %ecx, 4), %ecx
2103         leal    (%ebx, %ecx, 4), %eax           /* eax = ecx * 16 + ebx  */
2105         orl     %eax, %eax
2106         jz      1f
2108         movl    0x10(%eax), %ecx
2109         movl    %ecx, pxe_rm_entry
2113         popl    %ebx
2114         popl    %ebp
2115         ret
2118  * int grub_pxe_call (int func, void* data);
2119  */
2120 FUNCTION(grub_pxe_call)
2121         pushl   %ebp
2122         movl    %esp, %ebp
2123         pushl   %esi
2124         pushl   %edi
2125         pushl   %ebx
2127         movl    %eax, %ecx
2128         movl    %edx, %eax
2129         andl    $0xF, %eax
2130         shrl    $4, %edx
2131         shll    $16, %edx
2132         addl    %eax, %edx
2133         movl    pxe_rm_entry, %ebx
2135         call    prot_to_real
2136         .code16
2138         pushl   %ebx
2139         pushl   %edx
2140         pushw   %cx
2141         movw    %sp, %bx
2142         lcall   *%ss:6(%bx)
2143         cld
2144         addw    $10, %sp
2145         movw    %ax, %cx
2147         DATA32  call    real_to_prot
2148         .code32
2150         movzwl  %cx, %eax
2152         popl    %ebx
2153         popl    %edi
2154         popl    %esi
2155         popl    %ebp
2156         ret