make the linux-ppc packags be in synch with other platforms
[tangerine.git] / arch / common / boot / grub2 / kern / i386 / pc / startup.S
blob5d4bbcb99a020c5cdb482b89c396b73fc1c2405e
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_memdisk_image_size)
100         .long   0
101 VARIABLE(grub_prefix)
102         /* to be filled by grub-mkimage */
104         /*
105          *  Leave some breathing room for the prefix.
106          */
108         . = EXT_C(start) + 0x50
111  * Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself).
112  * This uses the a.out kludge to load raw binary to the area starting at 1MB,
113  * and relocates itself after loaded.
114  */
115 multiboot_header:
116         /* magic */
117         .long   0x1BADB002
118         /* flags */
119         .long   (1 << 16)
120         /* checksum */
121         .long   -0x1BADB002 - (1 << 16)
122         /* header addr */
123         .long   multiboot_header - _start + 0x100000 + 0x200
124         /* load addr */
125         .long   0x100000
126         /* load end addr */
127         .long   0
128         /* bss end addr */
129         .long   0
130         /* entry addr */
131         .long   multiboot_entry - _start + 0x100000 + 0x200
132         
133 multiboot_entry:
134         .code32
135         /* obtain the boot device */
136         movl    12(%ebx), %edx
138         /* relocate the code */
139         movl    $(GRUB_KERNEL_MACHINE_RAW_SIZE + 0x200), %ecx
140         addl    EXT_C(grub_compressed_size) - _start + 0x100000 + 0x200, %ecx
141         movl    $0x100000, %esi
142         movl    $GRUB_BOOT_MACHINE_KERNEL_ADDR, %edi
143         cld
144         rep
145         movsb
146         /* jump to the real address */
147         movl    $multiboot_trampoline, %eax
148         jmp     *%eax
149         
150 multiboot_trampoline:
151         /* fill the boot information */
152         movl    %edx, %eax
153         shrl    $8, %eax
154         xorl    %ebx, %ebx
155         cmpb    $0xFF, %ah
156         je      1f
157         movb    %ah, %bl
158         movl    %ebx, EXT_C(grub_install_dos_part)
160         cmpb    $0xFF, %al
161         je      2f
162         movb    %al, %bl
163         movl    %ebx, EXT_C(grub_install_bsd_part)
165         shrl    $24, %edx
166         movb    $0xFF, %dh
167         /* enter the usual booting */
168         call    prot_to_real
169         .code16
170         
171 /* the real mode code continues... */
172 codestart:
173         cli             /* we're not safe here! */
175         /* set up %ds, %ss, and %es */
176         xorw    %ax, %ax
177         movw    %ax, %ds
178         movw    %ax, %ss
179         movw    %ax, %es
181         /* set up the real mode/BIOS stack */
182         movl    $GRUB_MEMORY_MACHINE_REAL_STACK, %ebp
183         movl    %ebp, %esp
185         sti             /* we're safe again */
187         /* save boot and root drive references */
188         ADDR32  movb    %dl, EXT_C(grub_boot_drive)
189         ADDR32  movb    %dh, EXT_C(grub_root_drive)
191         /* reset disk system (%ah = 0) */
192         int     $0x13
193         
194         /* transition to protected mode */
195         DATA32  call real_to_prot
197         /* The ".code32" directive takes GAS out of 16-bit mode. */
198         .code32
200         incl    %eax
201         call    EXT_C(grub_gate_a20)
202         
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         /* copy back the decompressed part */
214         movl    %eax, %ecx
215         cld
216         rep
217         movsb
219         /* copy modules before cleaning out the bss */
220         movl    EXT_C(grub_total_module_size), %ecx
221         movl    EXT_C(grub_kernel_image_size), %esi
222         addl    %ecx, %esi
223         addl    $START_SYMBOL, %esi
224         decl    %esi
225         movl    $END_SYMBOL, %edi
226         addl    %ecx, %edi
227         decl    %edi
228         std
229         rep
230         movsb
231         
232         /* clean out the bss */
233         movl    $BSS_START_SYMBOL, %edi
235         /* compute the bss length */
236         movl    $END_SYMBOL, %ecx
237         subl    %edi, %ecx
238                         
239         /* clean out */
240         xorl    %eax, %eax
241         cld
242         rep
243         stosb
244         
245         /*
246          *  Call the start of main body of C code.
247          */
248         call EXT_C(grub_main)
250 #include "../realmode.S"
253  *  This is the area for all of the special variables.
254  */
256         .p2align        2       /* force 4-byte alignment */
258 VARIABLE(grub_boot_drive)
259         .long   0
261 VARIABLE(grub_root_drive)
262         .long   0
264 VARIABLE(grub_start_addr)
265         .long   START_SYMBOL
267 VARIABLE(grub_end_addr)
268         .long   END_SYMBOL
269         
270 VARIABLE(grub_apm_bios_info)
271         .word   0       /* version */
272         .word   0       /* cseg */
273         .long   0       /* offset */
274         .word   0       /* cseg_16 */
275         .word   0       /* dseg_16 */
276         .word   0       /* cseg_len */
277         .word   0       /* cseg_16_len */
278         .word   0       /* dseg_16_len */
279         
280         .p2align        2       /* force 4-byte alignment */
281         
283  *  These next two routines, "real_to_prot" and "prot_to_real" are structured
284  *  in a very specific way.  Be very careful when changing them.
286  *  NOTE:  Use of either one messes up %eax and %ebp.
287  */
289 real_to_prot:
290         .code16
291         cli
293         /* load the GDT register */
294         DATA32  ADDR32  lgdt    %cs:gdtdesc
296         /* turn on protected mode */
297         movl    %cr0, %eax
298         orl     $GRUB_MEMORY_MACHINE_CR0_PE_ON, %eax
299         movl    %eax, %cr0
301         /* jump to relocation, flush prefetch queue, and reload %cs */
302         DATA32  ljmp    $GRUB_MEMORY_MACHINE_PROT_MODE_CSEG, $protcseg
304         .code32
305 protcseg:
306         /* reload other segment registers */
307         movw    $GRUB_MEMORY_MACHINE_PROT_MODE_DSEG, %ax
308         movw    %ax, %ds
309         movw    %ax, %es
310         movw    %ax, %fs
311         movw    %ax, %gs
312         movw    %ax, %ss
314         /* put the return address in a known safe location */
315         movl    (%esp), %eax
316         movl    %eax, GRUB_MEMORY_MACHINE_REAL_STACK
318         /* get protected mode stack */
319         movl    protstack, %eax
320         movl    %eax, %esp
321         movl    %eax, %ebp
323         /* get return address onto the right stack */
324         movl    GRUB_MEMORY_MACHINE_REAL_STACK, %eax
325         movl    %eax, (%esp)
327         /* zero %eax */
328         xorl    %eax, %eax
330         /* return on the old (or initialized) stack! */
331         ret
334  * grub_gate_a20(int on)
336  * Gate address-line 20 for high memory.
338  * This routine is probably overconservative in what it does, but so what?
340  * It also eats any keystrokes in the keyboard buffer.  :-(
341  */
343 FUNCTION(grub_gate_a20)
344         movl    %eax, %edx
346 gate_a20_test_current_state:    
347         /* first of all, test if already in a good state */
348         call    gate_a20_check_state
349         cmpb    %al, %dl
350         jnz     gate_a20_try_bios
351         ret
353 gate_a20_try_bios:
354         /* second, try a BIOS call */
355         pushl   %ebp
356         call    prot_to_real
358         .code16
359         movw    $0x2400, %ax
360         testb   %dl, %dl
361         jz      1f
362         incw    %ax
363 1:      int     $0x15
365         DATA32  call    real_to_prot
366         .code32
368         popl    %ebp
369         call    gate_a20_check_state
370         cmpb    %al, %dl
371         jnz     gate_a20_try_keyboard_controller
372         ret
373         
374 gate_a20_flush_keyboard_buffer:
375         inb     $0x64
376         andb    $0x02, %al
377         jnz     gate_a20_flush_keyboard_buffer
378 2:      
379         inb     $0x64
380         andb    $0x01, %al
381         jz      3f
382         inb     $0x60
383         jmp     2b
385         ret
386         
387 gate_a20_try_keyboard_controller:       
388         /* third, try the keyboard controller */
389         call    gate_a20_flush_keyboard_buffer
391         movb    $0xd1, %al
392         outb    $0x64
393 4:      
394         inb     $0x64
395         andb    $0x02, %al
396         jnz     4b
398         movb    $0xdd, %al
399         testb   %dl, %dl
400         jz      5f
401         orb     $0x02, %al
402 5:      outb    $0x60
403         call    gate_a20_flush_keyboard_buffer
405         /* output a dummy command (USB keyboard hack) */
406         movb    $0xff, %al
407         outb    $0x64
408         call    gate_a20_flush_keyboard_buffer
410         call    gate_a20_check_state
411         cmpb    %al, %dl
412         jnz     gate_a20_try_system_control_port_a
413         ret
415 gate_a20_try_system_control_port_a:
416         /* fourth, try the system control port A */
417         inb     $0x92
418         andb    $(~0x03), %al
419         testb   %dl, %dl
420         jz      6f
421         orb     $0x02, %al
422 6:      outb    $0x92
424         /* When turning off Gate A20, do not check the state strictly,
425            because a failure is not fatal usually, and Gate A20 is always
426            on some modern machines.  */
427         testb   %dl, %dl
428         jz      7f      
429         call    gate_a20_check_state
430         cmpb    %al, %dl
431         /* everything failed, so restart from the beginning */
432         jnz     gate_a20_try_bios
433 7:      ret
434         
435 gate_a20_check_state:
436         /* iterate the checking for a while */
437         movl    $100, %ecx
438 1:      
439         call    3f
440         cmpb    %al, %dl
441         jz      2f
442         loop    1b
444         ret
445 3:      
446         pushl   %ebx
447         pushl   %ecx
448         xorl    %eax, %eax
449         /* compare the byte at 0x8000 with that at 0x108000 */
450         movl    $GRUB_BOOT_MACHINE_KERNEL_ADDR, %ebx
451         pushl   %ebx
452         /* save the original byte in CL */
453         movb    (%ebx), %cl
454         /* store the value at 0x108000 in AL */
455         addl    $0x100000, %ebx
456         movb    (%ebx), %al
457         /* try to set one less value at 0x8000 */
458         popl    %ebx
459         movb    %al, %ch
460         decb    %ch
461         movb    %ch, (%ebx)
462         /* serialize */
463         outb    %al, $0x80
464         outb    %al, $0x80
465         /* obtain the value at 0x108000 in CH */
466         pushl   %ebx
467         addl    $0x100000, %ebx
468         movb    (%ebx), %ch
469         /* this result is 1 if A20 is on or 0 if it is off */
470         subb    %ch, %al
471         xorb    $1, %al
472         /* restore the original */
473         popl    %ebx
474         movb    %cl, (%ebx)
475         popl    %ecx
476         popl    %ebx
477         ret
479 #include "lzo1x.S"
482  * The code beyond this point is compressed.  Assert that the uncompressed
483  * code fits GRUB_KERNEL_MACHINE_RAW_SIZE.
484  */
485         . = EXT_C(start) + GRUB_KERNEL_MACHINE_RAW_SIZE
488  *  This call is special...  it never returns...  in fact it should simply
489  *  hang at this point!
490  */
492 FUNCTION(grub_stop)
493         call    prot_to_real
495         /*
496          * This next part is sort of evil.  It takes advantage of the
497          * byte ordering on the x86 to work in either 16-bit or 32-bit
498          * mode, so think about it before changing it.
499          */
501 FUNCTION(grub_hard_stop)
502         hlt
503         jmp EXT_C(grub_hard_stop)
507  * grub_stop_floppy()
509  * Stop the floppy drive from spinning, so that other software is
510  * jumped to with a known state.
511  */
512 FUNCTION(grub_stop_floppy)
513         movw    $0x3F2, %dx
514         xorb    %al, %al
515         outb    %al, %dx
516         ret
519  * grub_exit()
521  * Exit the system.
522  */
523 FUNCTION(grub_exit)
524         call    prot_to_real
525         .code16
526         /* Tell the BIOS a boot failure. If this does not work, reboot.  */
527         int     $0x18
528         jmp     cold_reboot
529         .code32
530         
532  * grub_reboot()
534  * Reboot the system. At the moment, rely on BIOS.
535  */
536 FUNCTION(grub_reboot)
537         call    prot_to_real
538         .code16
539 cold_reboot:    
540         /* cold boot */
541         movw    $0x0472, %di
542         movw    %ax, (%di)
543         ljmp    $0xFFFF, $0x0000
544         .code32
545         
547  * grub_halt(int no_apm)
549  * Halt the system, using APM if possible. If NO_APM is true, don't use
550  * APM even if it is available.
551  */
552 FUNCTION(grub_halt)
553         /* see if zero */
554         testl   %eax, %eax
555         jnz     EXT_C(grub_stop)
557         call    prot_to_real
558         .code16
559         
560         /* detect APM */
561         movw    $0x5300, %ax
562         xorw    %bx, %bx
563         int     $0x15
564         jc      EXT_C(grub_hard_stop)
565         /* don't check %bx for buggy BIOSes... */
567         /* disconnect APM first */
568         movw    $0x5304, %ax
569         xorw    %bx, %bx
570         int     $0x15
572         /* connect APM */
573         movw    $0x5301, %ax
574         xorw    %bx, %bx
575         int     $0x15
576         jc      EXT_C(grub_hard_stop)
578         /* set APM protocol level - 1.1 or bust. (this covers APM 1.2 also) */
579         movw    $0x530E, %ax
580         xorw    %bx, %bx
581         movw    $0x0101, %cx
582         int     $0x15
583         jc      EXT_C(grub_hard_stop)
584         
585         /* set the power state to off */
586         movw    $0x5307, %ax
587         movw    $1, %bx
588         movw    $3, %cx
589         int     $0x15
591         /* shouldn't reach here */
592         jmp     EXT_C(grub_hard_stop)
593         .code32
594         
595         
597  *  void grub_chainloader_real_boot (int drive, void *part_addr)
599  *  This starts another boot loader.
600  */
602 FUNCTION(grub_chainloader_real_boot)
603         pushl   %edx
604         pushl   %eax
606         call    EXT_C(grub_dl_unload_all)
608         /* Turn off Gate A20 */
609         xorl    %eax, %eax
610         call    EXT_C(grub_gate_a20)
612         /* set up to pass boot drive */
613         popl    %edx
615         /* ESI must point to a partition table entry */
616         popl    %esi
618         call    prot_to_real
619         .code16
620         ljmp    $0, $GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR
621         .code32
623 #include "../loader.S"
626  *   int grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap)
628  *   Call IBM/MS INT13 Extensions (int 13 %ah=AH) for DRIVE. DAP
629  *   is passed for disk address packet. If an error occurs, return
630  *   non-zero, otherwise zero.
631  */
633 FUNCTION(grub_biosdisk_rw_int13_extensions)
634         pushl   %ebp
635         pushl   %esi
637         /* compute the address of disk_address_packet */
638         movw    %cx, %si
639         xorw    %cx, %cx
640         shrl    $4, %ecx        /* save the segment to cx */
642         /* ah */
643         movb    %al, %dh
644         /* enter real mode */
645         call    prot_to_real
646         
647         .code16
648         movb    %dh, %ah
649         movw    %cx, %ds
650         int     $0x13           /* do the operation */
651         movb    %ah, %dl        /* save return value */
652         /* back to protected mode */
653         DATA32  call    real_to_prot
654         .code32
656         movb    %dl, %al        /* return value in %eax */
658         popl    %esi
659         popl    %ebp
661         ret
662         
664  *   int grub_biosdisk_rw_standard (int ah, int drive, int coff, int hoff,
665  *                                  int soff, int nsec, int segment)
667  *   Call standard and old INT13 (int 13 %ah=AH) for DRIVE. Read/write
668  *   NSEC sectors from COFF/HOFF/SOFF into SEGMENT. If an error occurs,
669  *   return non-zero, otherwise zero.
670  */
672 FUNCTION(grub_biosdisk_rw_standard)
673         pushl   %ebp
674         movl    %esp, %ebp
676         pushl   %ebx
677         pushl   %edi
678         pushl   %esi
680         /* set up CHS information */
682         /* set %ch to low eight bits of cylinder */
683         xchgb   %cl, %ch
684         /* set bits 6-7 of %cl to high two bits of cylinder */
685         shlb    $6, %cl
686         /* set bits 0-5 of %cl to sector */
687         addb    0xc(%ebp), %cl
688         /* set %dh to head */
689         movb    0x8(%ebp), %dh
690         /* set %ah to AH */
691         movb    %al, %ah
692         /* set %al to NSEC */
693         movb    0x10(%ebp), %al
694         /* save %ax in %di */
695         movw    %ax, %di
696         /* save SEGMENT in %bx */
697         movw    0x14(%ebp), %bx
698                 
699         /* enter real mode */
700         call    prot_to_real
702         .code16
703         movw    %bx, %es
704         xorw    %bx, %bx
705         movw    $3, %si         /* attempt at least three times */
707 1:      
708         movw    %di, %ax
709         int     $0x13           /* do the operation */
710         jnc     2f              /* check if successful */
712         movb    %ah, %bl        /* save return value */
713         /* if fail, reset the disk system */
714         xorw    %ax, %ax
715         int     $0x13
716         
717         decw    %si
718         cmpw    $0, %si
719         je      2f
720         xorb    %bl, %bl
721         jmp     1b              /* retry */
722 2:      
723         /* back to protected mode */
724         DATA32  call    real_to_prot
725         .code32
727         movb    %bl, %al        /* return value in %eax */
728         
729         popl    %esi
730         popl    %edi
731         popl    %ebx
732         popl    %ebp
734         ret     $(4 * 4)
738  *   int grub_biosdisk_check_int13_extensions (int drive)
740  *   Check if LBA is supported for DRIVE. If it is supported, then return
741  *   the major version of extensions, otherwise zero.
742  */
744 FUNCTION(grub_biosdisk_check_int13_extensions)
745         pushl   %ebp
746         pushl   %ebx
748         /* drive */
749         movb    %al, %dl
750         /* enter real mode */
751         call    prot_to_real
753         .code16
754         movb    $0x41, %ah
755         movw    $0x55aa, %bx
756         int     $0x13           /* do the operation */
757         
758         /* check the result */
759         jc      1f
760         cmpw    $0xaa55, %bx
761         jne     1f
763         movb    %ah, %bl        /* save the major version into %bl */
765         /* check if AH=0x42 is supported */
766         andw    $1, %cx
767         jnz     2f
768         
770         xorb    %bl, %bl
772         /* back to protected mode */
773         DATA32  call    real_to_prot
774         .code32
776         movb    %bl, %al        /* return value in %eax */
778         popl    %ebx
779         popl    %ebp
781         ret
785  *   int grub_biosdisk_get_cdinfo_int13_extensions (int drive, void *cdrp)
787  *   Return the cdrom information of DRIVE in CDRP. If an error occurs,
788  *   then return non-zero, otherwise zero.
789  */
791 FUNCTION(grub_biosdisk_get_cdinfo_int13_extensions)
792         movw    $0x4B01, %cx
793         jmp     1f
796  *   int grub_biosdisk_get_diskinfo_int13_extensions (int drive, void *drp)
798  *   Return the geometry of DRIVE in a drive parameters, DRP. If an error
799  *   occurs, then return non-zero, otherwise zero.
800  */
802 FUNCTION(grub_biosdisk_get_diskinfo_int13_extensions)
803         movb    $0x48, %ch
805         pushl   %ebp
806         pushl   %ebx
807         pushl   %esi
809         /* compute the address of drive parameters */
810         movw    %dx, %si
811         andl    $0xf, %esi
812         shrl    $4, %edx
813         movw    %dx, %bx        /* save the segment into %bx */
814         /* drive */
815         movb    %al, %dl
816         /* enter real mode */
817         call    prot_to_real
819         .code16
820         movw    %cx, %ax
821         movw    %bx, %ds
822         int     $0x13           /* do the operation */
823         movb    %ah, %bl        /* save return value in %bl */
824         /* back to protected mode */
825         DATA32  call    real_to_prot
826         .code32
828         movb    %bl, %al        /* return value in %eax */
830         popl    %esi
831         popl    %ebx
832         popl    %ebp
833         
834         ret
838  *   int grub_biosdisk_get_diskinfo_standard (int drive,
839  *                                            unsigned long *cylinders, 
840  *                                            unsigned long *heads,
841  *                                            unsigned long *sectors)
843  *   Return the geometry of DRIVE in CYLINDERS, HEADS and SECTORS. If an
844  *   error occurs, then return non-zero, otherwise zero.
845  */
847 FUNCTION(grub_biosdisk_get_diskinfo_standard)
848         pushl   %ebp
849         pushl   %ebx
850         pushl   %edi
852         /* push CYLINDERS */
853         pushl   %edx
854         /* push HEADS */
855         pushl   %ecx
856         /* SECTORS is on the stack */
857         
858         /* drive */
859         movb    %al, %dl
860         /* enter real mode */
861         call    prot_to_real
863         .code16
864         movb    $0x8, %ah
865         int     $0x13           /* do the operation */
866         /* check if successful */
867         testb   %ah, %ah
868         jnz     1f
869         /* bogus BIOSes may not return an error number */
870         testb   $0x3f, %cl      /* 0 sectors means no disk */
871         jnz     1f              /* if non-zero, then succeed */
872         /* XXX 0x60 is one of the unused error numbers */
873         movb    $0x60, %ah
875         movb    %ah, %bl        /* save return value in %bl */
876         /* back to protected mode */
877         DATA32  call    real_to_prot
878         .code32
880         /* pop HEADS */
881         popl    %edi
882         movb    %dh, %al
883         incl    %eax    /* the number of heads is counted from zero */
884         movl    %eax, (%edi)
886         /* pop CYLINDERS */
887         popl    %edi
888         movb    %ch, %al
889         movb    %cl, %ah
890         shrb    $6, %ah /* the number of cylinders is counted from zero */
891         incl    %eax
892         movl    %eax, (%edi)
894         /* SECTORS */
895         movl    0x10(%esp), %edi
896         andb    $0x3f, %cl
897         movzbl  %cl, %eax
898         movl    %eax, (%edi)
899         
900         xorl    %eax, %eax
901         movb    %bl, %al        /* return value in %eax */
903         popl    %edi
904         popl    %ebx
905         popl    %ebp
907         ret     $4
911  * int grub_biosdisk_get_num_floppies (void)
912  */
913 FUNCTION(grub_biosdisk_get_num_floppies)
914         pushl   %ebp
916         xorl    %edx, %edx
917         call    prot_to_real
918         
919         .code16
920         /* reset the disk system first */
921         int     $0x13
923         stc
924         
925         /* call GET DISK TYPE */
926         movb    $0x15, %ah
927         int     $0x13
929         jc      2f
931         /* check if this drive exists */        
932         testb   $0x3, %ah
933         jz      2f
935         incb    %dl
936         cmpb    $2, %dl
937         jne     1b
939         DATA32  call    real_to_prot
940         .code32
942         movl    %edx, %eax
943         popl    %ebp
944         ret
945         
946         
949  * grub_get_memsize(i) :  return the memory size in KB. i == 0 for conventional
950  *              memory, i == 1 for extended memory
951  *      BIOS call "INT 12H" to get conventional memory size
952  *      BIOS call "INT 15H, AH=88H" to get extended memory size
953  *              Both have the return value in AX.
955  */
957 FUNCTION(grub_get_memsize)
958         pushl   %ebp
960         movl    %eax, %edx
962         call    prot_to_real    /* enter real mode */
963         .code16
965         testl   %edx, %edx
966         jnz     xext
968         int     $0x12
969         jmp     xdone
971 xext:
972         movb    $0x88, %ah
973         int     $0x15
975 xdone:
976         movw    %ax, %dx
978         DATA32  call    real_to_prot
979         .code32
981         movw    %dx, %ax
983         popl    %ebp
984         ret
989  * grub_get_eisa_mmap() :  return packed EISA memory map, lower 16 bits is
990  *              memory between 1M and 16M in 1K parts, upper 16 bits is
991  *              memory above 16M in 64K parts.  If error, return zero.
992  *      BIOS call "INT 15H, AH=E801H" to get EISA memory map,
993  *              AX = memory between 1M and 16M in 1K parts.
994  *              BX = memory above 16M in 64K parts.
996  */
998 FUNCTION(grub_get_eisa_mmap)
999         pushl   %ebp
1000         pushl   %ebx
1002         call    prot_to_real    /* enter real mode */
1003         .code16
1005         movw    $0xe801, %ax
1006         int     $0x15
1008         shll    $16, %ebx
1009         movw    %ax, %bx
1011         DATA32  call    real_to_prot
1012         .code32
1014         cmpb    $0x86, %bh
1015         je      xnoteisa
1017         movl    %ebx, %eax
1019 xnoteisa:
1020         popl    %ebx
1021         popl    %ebp
1022         ret
1026  * grub_get_mmap_entry(addr, cont) : address and old continuation value (zero to
1027  *              start), for the Query System Address Map BIOS call.
1029  *  Sets the first 4-byte int value of "addr" to the size returned by
1030  *  the call.  If the call fails, sets it to zero.
1032  *      Returns:  new (non-zero) continuation value, 0 if done.
1033  */
1035 FUNCTION(grub_get_mmap_entry)
1036         pushl   %ebp
1037         pushl   %ebx
1038         pushl   %edi
1039         pushl   %esi
1041         /* push ADDR */
1042         pushl   %eax
1043         
1044         /* place address (+4) in ES:DI */
1045         addl    $4, %eax
1046         movl    %eax, %edi
1047         andl    $0xf, %edi
1048         shrl    $4, %eax
1049         movl    %eax, %esi
1051         /* set continuation value */
1052         movl    %edx, %ebx
1054         /* set default maximum buffer size */
1055         movl    $0x14, %ecx
1057         /* set EDX to 'SMAP' */
1058         movl    $0x534d4150, %edx
1060         call    prot_to_real    /* enter real mode */
1061         .code16
1063         movw    %si, %es
1064         movl    $0xe820, %eax
1065         int     $0x15
1067         DATA32  jc      xnosmap
1069         cmpl    $0x534d4150, %eax
1070         jne     xnosmap
1072         cmpl    $0x14, %ecx
1073         jl      xnosmap
1075         cmpl    $0x400, %ecx
1076         jg      xnosmap
1078         jmp     xsmap
1080 xnosmap:
1081         xorl    %ecx, %ecx
1083 xsmap:
1084         DATA32  call    real_to_prot
1085         .code32
1087         /* write length of buffer (zero if error) into ADDR */
1088         popl    %eax
1089         movl    %ecx, (%eax)
1091         /* set return value to continuation */
1092         movl    %ebx, %eax
1094         popl    %esi
1095         popl    %edi
1096         popl    %ebx
1097         popl    %ebp
1098         ret
1100         
1102  * void grub_console_real_putchar (int c)
1104  * Put the character C on the console. Because GRUB wants to write a
1105  * character with an attribute, this implementation is a bit tricky.
1106  * If C is a control character (CR, LF, BEL, BS), use INT 10, AH = 0Eh
1107  * (TELETYPE OUTPUT). Otherwise, save the original position, put a space,
1108  * save the current position, restore the original position, write the
1109  * character and the attribute, and restore the current position.
1111  * The reason why this is so complicated is that there is no easy way to
1112  * get the height of the screen, and the TELETYPE OUTPUT BIOS call doesn't
1113  * support setting a background attribute.
1114  */
1115 FUNCTION(grub_console_real_putchar)
1116         movl    %eax, %edx
1117         pusha
1118         movb    EXT_C(grub_console_cur_color), %bl
1119         
1120         call    prot_to_real
1121         .code16
1122         movb    %dl, %al
1123         xorb    %bh, %bh
1125         /* use teletype output if control character */
1126         cmpb    $0x7, %al
1127         je      1f
1128         cmpb    $0x8, %al
1129         je      1f
1130         cmpb    $0xa, %al
1131         je      1f
1132         cmpb    $0xd, %al
1133         je      1f
1135         /* save the character and the attribute on the stack */
1136         pushw   %ax
1137         pushw   %bx
1138         
1139         /* get the current position */
1140         movb    $0x3, %ah
1141         int     $0x10
1143         /* check the column with the width */
1144         cmpb    $79, %dl
1145         jl      2f
1146         
1147         /* print CR and LF, if next write will exceed the width */      
1148         movw    $0x0e0d, %ax
1149         int     $0x10
1150         movb    $0x0a, %al
1151         int     $0x10
1152         
1153         /* get the current position */
1154         movb    $0x3, %ah
1155         int     $0x10
1157 2:      
1158         /* restore the character and the attribute */
1159         popw    %bx
1160         popw    %ax
1161         
1162         /* write the character with the attribute */
1163         movb    $0x9, %ah
1164         movw    $1, %cx
1165         int     $0x10
1167         /* move the cursor forward */
1168         incb    %dl
1169         movb    $0x2, %ah
1170         int     $0x10
1172         jmp     3f
1174 1:      movw    $1, %bx
1175         movb    $0xe, %ah
1176         int     $0x10
1177         
1178 3:      DATA32  call    real_to_prot
1179         .code32
1180         
1181         popa
1182         ret
1183         
1186  * int grub_console_getkey (void)
1187  * BIOS call "INT 16H Function 00H" to read character from keyboard
1188  *      Call with       %ah = 0x0
1189  *      Return:         %ah = keyboard scan code
1190  *                      %al = ASCII character
1191  */
1193 /* this table is used in translate_keycode below */
1194 translation_table:
1195         .word   GRUB_CONSOLE_KEY_LEFT, GRUB_TERM_LEFT
1196         .word   GRUB_CONSOLE_KEY_RIGHT, GRUB_TERM_RIGHT
1197         .word   GRUB_CONSOLE_KEY_UP, GRUB_TERM_UP
1198         .word   GRUB_CONSOLE_KEY_DOWN, GRUB_TERM_DOWN
1199         .word   GRUB_CONSOLE_KEY_HOME, GRUB_TERM_HOME
1200         .word   GRUB_CONSOLE_KEY_END, GRUB_TERM_END
1201         .word   GRUB_CONSOLE_KEY_DC, GRUB_TERM_DC
1202         .word   GRUB_CONSOLE_KEY_BACKSPACE, GRUB_TERM_BACKSPACE
1203         .word   GRUB_CONSOLE_KEY_PPAGE, GRUB_TERM_PPAGE
1204         .word   GRUB_CONSOLE_KEY_NPAGE, GRUB_TERM_NPAGE
1205         .word   0
1206         
1208  * translate_keycode translates the key code %dx to an ascii code.
1209  */
1210         .code16
1212 translate_keycode:
1213         pushw   %bx
1214         pushw   %si
1215         
1216         movw    $ABS(translation_table), %si
1217         
1218 1:      lodsw
1219         /* check if this is the end */
1220         testw   %ax, %ax
1221         jz      2f
1222         /* load the ascii code into %ax */
1223         movw    %ax, %bx
1224         lodsw
1225         /* check if this matches the key code */
1226         cmpw    %bx, %dx
1227         jne     1b
1228         /* translate %dx, if successful */
1229         movw    %ax, %dx
1231 2:      popw    %si
1232         popw    %bx
1233         ret
1235         .code32
1236         
1237 FUNCTION(grub_console_getkey)
1238         pushl   %ebp
1240         call    prot_to_real
1241         .code16
1243         int     $0x16
1245         movw    %ax, %dx                /* real_to_prot uses %eax */
1246         call    translate_keycode
1247                 
1248         DATA32  call    real_to_prot
1249         .code32
1251         movw    %dx, %ax
1253         popl    %ebp
1254         ret
1258  * int grub_console_checkkey (void)
1259  *      if there is a character pending, return it; otherwise return -1
1260  * BIOS call "INT 16H Function 01H" to check whether a character is pending
1261  *      Call with       %ah = 0x1
1262  *      Return:
1263  *              If key waiting to be input:
1264  *                      %ah = keyboard scan code
1265  *                      %al = ASCII character
1266  *                      Zero flag = clear
1267  *              else
1268  *                      Zero flag = set
1269  */
1270 FUNCTION(grub_console_checkkey)
1271         pushl   %ebp
1272         xorl    %edx, %edx
1273         
1274         call    prot_to_real    /* enter real mode */
1275         .code16
1277         movb    $0x1, %ah
1278         int     $0x16
1280         jz      notpending
1281         
1282         movw    %ax, %dx
1283         DATA32  jmp     pending
1285 notpending:
1286         decl    %edx
1288 pending:
1289         DATA32  call    real_to_prot
1290         .code32
1292         movl    %edx, %eax
1294         popl    %ebp
1295         ret
1297         
1299  * grub_uint16_t grub_console_getxy (void)
1300  * BIOS call "INT 10H Function 03h" to get cursor position
1301  *      Call with       %ah = 0x03
1302  *                      %bh = page
1303  *      Returns         %ch = starting scan line
1304  *                      %cl = ending scan line
1305  *                      %dh = row (0 is top)
1306  *                      %dl = column (0 is left)
1307  */
1310 FUNCTION(grub_console_getxy)
1311         pushl   %ebp
1312         pushl   %ebx                    /* save EBX */
1314         call    prot_to_real
1315         .code16
1317         xorb    %bh, %bh                /* set page to 0 */
1318         movb    $0x3, %ah
1319         int     $0x10                   /* get cursor position */
1321         DATA32  call    real_to_prot
1322         .code32
1324         movb    %dl, %ah
1325         movb    %dh, %al
1327         popl    %ebx
1328         popl    %ebp
1329         ret
1333  * void grub_console_gotoxy(grub_uint8_t x, grub_uint8_t y)
1334  * BIOS call "INT 10H Function 02h" to set cursor position
1335  *      Call with       %ah = 0x02
1336  *                      %bh = page
1337  *                      %dh = row (0 is top)
1338  *                      %dl = column (0 is left)
1339  */
1342 FUNCTION(grub_console_gotoxy)
1343         pushl   %ebp
1344         pushl   %ebx                    /* save EBX */
1346         movb    %dl, %dh        /* %dh = y */
1347         movb    %al, %dl        /* %dl = x */
1349         call    prot_to_real
1350         .code16
1352         xorb    %bh, %bh                /* set page to 0 */
1353         movb    $0x2, %ah
1354         int     $0x10                   /* set cursor position */
1356         DATA32  call    real_to_prot
1357         .code32
1359         popl    %ebx
1360         popl    %ebp
1361         ret
1363         
1365  * void grub_console_cls (void)
1366  * BIOS call "INT 10H Function 09h" to write character and attribute
1367  *      Call with       %ah = 0x09
1368  *                      %al = (character)
1369  *                      %bh = (page number)
1370  *                      %bl = (attribute)
1371  *                      %cx = (number of times)
1372  */
1374 FUNCTION(grub_console_cls)
1375         pushl   %ebp
1376         pushl   %ebx                    /* save EBX */
1378         call    prot_to_real
1379         .code16
1381         /* move the cursor to the beginning */
1382         movb    $0x02, %ah
1383         xorb    %bh, %bh
1384         xorw    %dx, %dx
1385         int     $0x10
1387         /* write spaces to the entire screen */
1388         movw    $0x0920, %ax
1389         movw    $0x07, %bx
1390         movw    $(80 * 25), %cx
1391         int     $0x10
1393         /* move back the cursor */
1394         movb    $0x02, %ah
1395         int     $0x10
1397         DATA32  call    real_to_prot
1398         .code32
1400         popl    %ebx
1401         popl    %ebp
1402         ret
1404         
1406  * void grub_console_setcursor (int on)
1407  * BIOS call "INT 10H Function 01h" to set cursor type
1408  *      Call with       %ah = 0x01
1409  *                      %ch = cursor starting scanline
1410  *                      %cl = cursor ending scanline
1411  */
1413 console_cursor_state:
1414         .byte   1
1415 console_cursor_shape:
1416         .word   0
1417         
1418 FUNCTION(grub_console_setcursor)
1419         pushl   %ebp
1420         pushl   %ebx
1422         /* push ON */
1423         pushl   %eax
1424         
1425         /* check if the standard cursor shape has already been saved */
1426         movw    console_cursor_shape, %ax
1427         testw   %ax, %ax
1428         jne     1f
1430         call    prot_to_real
1431         .code16
1433         movb    $0x03, %ah
1434         xorb    %bh, %bh
1435         int     $0x10
1437         DATA32  call    real_to_prot
1438         .code32
1440         movw    %cx, console_cursor_shape
1442         /* set %cx to the designated cursor shape */
1443         movw    $0x2000, %cx
1444         popl    %eax
1445         testl   %eax, %eax
1446         jz      2f
1447         movw    console_cursor_shape, %cx
1448 2:      
1449         call    prot_to_real
1450         .code16
1452         movb    $0x1, %ah
1453         int     $0x10 
1455         DATA32  call    real_to_prot
1456         .code32
1458         popl    %ebx
1459         popl    %ebp
1460         ret
1461                 
1463  * grub_getrtsecs()
1464  *      if a seconds value can be read, read it and return it (BCD),
1465  *      otherwise return 0xFF
1466  * BIOS call "INT 1AH Function 02H" to check whether a character is pending
1467  *      Call with       %ah = 0x2
1468  *      Return:
1469  *              If RT Clock can give correct values
1470  *                      %ch = hour (BCD)
1471  *                      %cl = minutes (BCD)
1472  *                      %dh = seconds (BCD)
1473  *                      %dl = daylight savings time (00h std, 01h daylight)
1474  *                      Carry flag = clear
1475  *              else
1476  *                      Carry flag = set
1477  *                         (this indicates that the clock is updating, or
1478  *                          that it isn't running)
1479  */
1480 FUNCTION(grub_getrtsecs)
1481         pushl   %ebp
1483         call    prot_to_real    /* enter real mode */
1484         .code16
1486         clc
1487         movb    $0x2, %ah
1488         int     $0x1a
1490         DATA32  jnc     gottime
1491         movb    $0xff, %dh
1493 gottime:
1494         DATA32  call    real_to_prot
1495         .code32
1497         movb    %dh, %al
1499         popl    %ebp
1500         ret
1502         
1504  * grub_get_rtc()
1505  *      return the real time in ticks, of which there are about
1506  *      18-20 per second
1507  */
1508 FUNCTION(grub_get_rtc)
1509         pushl   %ebp
1511         call    prot_to_real    /* enter real mode */
1512         .code16
1514         /* %ax is already zero */
1515         int     $0x1a
1517         DATA32  call    real_to_prot
1518         .code32
1520         movl    %ecx, %eax
1521         shll    $16, %eax
1522         movw    %dx, %ax
1524         popl    %ebp
1525         ret
1529  * unsigned char grub_vga_set_mode (unsigned char mode)
1530  */
1531 FUNCTION(grub_vga_set_mode)
1532         pushl   %ebp
1533         pushl   %ebx
1534         movl    %eax, %ecx
1536         call    prot_to_real
1537         .code16
1538         /* get current mode */
1539         xorw    %bx, %bx
1540         movb    $0x0f, %ah
1541         int     $0x10
1542         movb    %al, %dl
1544         /* set the new mode */
1545         movb    %cl, %al
1546         xorb    %ah, %ah
1547         int     $0x10
1549         DATA32  call    real_to_prot
1550         .code32
1552         movb    %dl, %al
1553         popl    %ebx
1554         popl    %ebp
1555         ret
1559  * unsigned char *grub_vga_get_font (void)
1560  */
1561 FUNCTION(grub_vga_get_font)
1562         pushl   %ebp
1563         pushl   %ebx
1565         call    prot_to_real
1566         .code16
1567         movw    $0x1130, %ax
1568         movb    $0x06, %bh
1569         int     $0x10
1570         movw    %es, %bx
1571         movw    %bp, %dx
1572         DATA32  call    real_to_prot
1573         .code32
1575         movzwl  %bx, %ecx
1576         shll    $4, %ecx
1577         movw    %dx, %ax
1578         addl    %ecx, %eax
1580         popl    %ebx
1581         popl    %ebp
1582         ret
1585  * grub_vbe_bios_status_t grub_vbe_get_controller_info (struct grub_vbe_info_block *controller_info)
1587  * Register allocations for parameters:
1588  * %eax         *controller_info
1589  */
1590 FUNCTION(grub_vbe_bios_get_controller_info)
1591         pushl   %ebp
1592         pushl   %edi
1593         pushl   %edx
1595         movw    %ax, %di        /* Store *controller_info to %edx:%di.  */
1596         xorw    %ax, %ax
1597         shrl    $4, %eax
1598         mov     %eax, %edx      /* prot_to_real destroys %eax.  */
1599         
1600         call    prot_to_real
1601         .code16
1603         pushw   %es
1605         movw    %dx, %es        /* *controller_info is now on %es:%di.  */
1606         movw    $0x4f00, %ax
1607         int     $0x10
1609         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1611         popw    %es
1613         DATA32 call     real_to_prot
1614         .code32
1616         movl    %edx, %eax
1617         andl    $0x0FFFF, %eax  /* Return value in %eax.  */
1618         
1619         pop     %edx
1620         popl    %edi
1621         popl    %ebp
1622         ret
1625  * grub_vbe_status_t grub_vbe_bios_get_mode_info (grub_uint32_t mode,
1626  *                                                struct grub_vbe_mode_info_block *mode_info)
1628  * Register allocations for parameters:
1629  * %eax         mode
1630  * %edx         *mode_info
1631  */
1632 FUNCTION(grub_vbe_bios_get_mode_info)
1633         pushl   %ebp
1634         pushl   %edi
1636         movl    %eax, %ecx      /* Store mode number to %ecx.  */
1638         movw    %dx, %di        /* Store *mode_info to %edx:%di.  */
1639         xorw    %dx, %dx
1640         shrl    $4, %edx
1642         call    prot_to_real
1643         .code16
1645         pushw   %es
1647         movw    %dx, %es        /* *mode_info is now on %es:%di.  */
1648         movw    $0x4f01, %ax
1649         int     $0x10
1651         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1653         popw    %es
1655         DATA32 call     real_to_prot
1656         .code32
1658         movl    %edx, %eax
1659         andl    $0x0FFFF, %eax  /* Return value in %eax.  */
1661         popl    %edi
1662         popl    %ebp
1663         ret
1666  * grub_vbe_status_t grub_vbe_bios_set_mode (grub_uint32_t mode,
1667  *                                           struct grub_vbe_crtc_info_block *crtc_info)
1669  * Register allocations for parameters:
1670  * %eax         mode
1671  * %edx         *crtc_info
1672  */
1673 FUNCTION(grub_vbe_bios_set_mode)
1674         pushl   %ebp
1675         pushl   %ebx
1676         pushl   %edi
1678         movl    %eax, %ebx      /* Store mode in %ebx.  */
1680         movw    %dx, %di        /* Store *crtc_info to %edx:%di.  */
1681         xorw    %dx, %dx
1682         shrl    $4, %edx
1684         call    prot_to_real
1685         .code16
1687         pushw   %es
1689         movw    %dx, %es        /* *crtc_info is now on %es:%di.  */
1691         movw    $0x4f02, %ax
1692         int     $0x10
1694         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1696         popw    %es
1698         DATA32 call     real_to_prot
1699         .code32
1700         
1701         movw    %dx, %ax
1702         andl    $0xFFFF, %eax   /* Return value in %eax.  */
1704         popl    %edi
1705         popl    %ebx
1706         popl    %ebp
1707         ret
1710  * grub_vbe_status_t grub_vbe_bios_get_mode (grub_uint32_t *mode)
1712  * Register allocations for parameters:
1713  * %eax         *mode
1714  */
1715 FUNCTION(grub_vbe_bios_get_mode)
1716         pushl   %ebp
1717         pushl   %ebx
1718         pushl   %edi
1719         pushl   %edx
1720         pushl   %eax            /* Push *mode to stack.  */
1722         call    prot_to_real
1723         .code16
1725         movw    $0x4f03, %ax
1726         int     $0x10
1728         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1730         DATA32 call     real_to_prot
1731         .code32
1733         popl    %edi            /* Pops *mode from stack to %edi.  */
1734         andl    $0xFFFF, %ebx
1735         movl    %ebx, (%edi)
1737         movw    %dx, %ax
1738         andl    $0xFFFF, %eax   /* Return value in %eax.  */
1740         popl    %edx
1741         popl    %edi
1742         popl    %ebx
1743         popl    %ebp
1744         ret
1747  * grub_vbe_status_t grub_vbe_bios_set_memory_window (grub_uint32_t window,
1748  *                                                    grub_uint32_t position);
1750  * Register allocations for parameters:
1751  * %eax         window
1752  * %edx         position
1753  */
1754 FUNCTION(grub_vbe_bios_set_memory_window)
1755         pushl   %ebp
1756         pushl   %ebx
1758         movl    %eax, %ebx
1760         call    prot_to_real
1761         .code16
1763         movw    $0x4f05, %ax
1764         andw    $0x00ff, %bx    /* BL = window, BH = 0, Set memory window.  */
1765         int     $0x10
1767         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1769         DATA32 call     real_to_prot
1770         .code32
1771         
1772         movw    %dx, %ax
1773         andl    $0xFFFF, %eax   /* Return value in %eax.  */
1775         popl    %ebx
1776         popl    %ebp
1777         ret
1780  * grub_vbe_status_t grub_vbe_bios_get_memory_window (grub_uint32_t window,
1781  *                                                    grub_uint32_t *position);
1783  * Register allocations for parameters:
1784  * %eax         window
1785  * %edx         *position
1786  */
1787 FUNCTION(grub_vbe_bios_get_memory_window)
1788         pushl   %ebp
1789         pushl   %ebx
1790         pushl   %edi
1791         pushl   %edx            /* Push *position to stack.  */
1793         movl    %eax, %ebx      /* Store window in %ebx.  */
1795         call    prot_to_real
1796         .code16
1798         movw    $0x4f05, %ax
1799         andw    $0x00ff, %bx    /* BL = window.  */
1800         orw     $0x0100, %bx    /* BH = 1, Get memory window.  */
1801         int     $0x10
1803         movw    %ax, %bx        /* real_to_prot destroys %eax.  */
1805         DATA32 call     real_to_prot
1806         .code32
1808         popl    %edi            /* pops *position from stack to %edi.  */
1809         andl    $0xFFFF, %edx
1810         movl    %edx, (%edi)    /* Return position to caller.  */
1812         movw    %bx, %ax
1813         andl    $0xFFFF, %eax   /* Return value in %eax.  */
1815         popl    %edi
1816         popl    %ebx
1817         popl    %ebp
1818         ret
1821  * grub_vbe_status_t grub_vbe_bios_set_scanline_length (grub_uint32_t length)
1823  * Register allocations for parameters:
1824  * %eax         length
1825  */
1826 FUNCTION(grub_vbe_bios_set_scanline_length)
1827         pushl   %ebp
1828         pushl   %ebx
1829         pushl   %edx
1831         movl    %eax, %ecx      /* Store length in %ecx.  */
1833         call    prot_to_real
1834         .code16
1836         movw    $0x4f06, %ax
1837         movw    $0x0002, %bx    /* BL = 2, Set Scan Line in Bytes.  */
1838         int     $0x10
1840         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1842         DATA32 call     real_to_prot
1843         .code32
1844         
1845         movw    %dx, %ax
1846         andl    $0xFFFF, %eax   /* Return value in %eax.  */
1848         popl    %edx
1849         popl    %ebx
1850         popl    %ebp
1851         ret
1854  * grub_vbe_status_t grub_vbe_bios_get_scanline_length (grub_uint32_t *length)
1856  * Register allocations for parameters:
1857  * %eax         *length
1858  */
1859 FUNCTION(grub_vbe_bios_get_scanline_length)
1860         pushl   %ebp
1861         pushl   %ebx
1862         pushl   %edi
1863         pushl   %edx            /* Push *length to stack.  */
1865         call    prot_to_real
1866         .code16
1868         movw    $0x4f06, %ax
1869         movw    $0x0001, %bx    /* BL = 1, Get Scan Line Length (in bytes).  */
1870         int     $0x10
1872         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1874         DATA32 call     real_to_prot
1875         .code32
1877         popl    %edi            /* Pops *length from stack to %edi.  */
1878         andl    $0xFFFF, %ebx
1879         movl    %ebx, (%edi)    /* Return length to caller.  */
1881         movw    %dx, %ax
1882         andl    $0xFFFF, %eax   /* Return value in %eax.  */
1884         popl    %edi
1885         popl    %ebx
1886         popl    %ebp
1887         ret
1890  * grub_vbe_status_t grub_vbe_bios_set_display_start (grub_uint32_t x,
1891  *                                                    grub_uint32_t y)
1893  * Register allocations for parameters:
1894  * %eax         x
1895  * %edx         y
1896  */
1897 FUNCTION(grub_vbe_bios_set_display_start)
1898         pushl   %ebp
1899         pushl   %ebx
1901         movl    %eax, %ecx      /* Store x in %ecx.  */
1903         call    prot_to_real
1904         .code16
1906         movw    $0x4f07, %ax
1907         movw    $0x0080, %bx    /* BL = 80h, Set Display Start 
1908                                    during Vertical Retrace.  */
1909         int     $0x10
1911         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1913         DATA32 call     real_to_prot
1914         .code32
1915         
1916         movw    %dx, %ax
1917         andl    $0xFFFF, %eax   /* Return value in %eax.  */
1919         popl    %ebx
1920         popl    %ebp
1921         ret
1924  * grub_vbe_status_t grub_vbe_bios_get_display_start (grub_uint32_t *x,
1925  *                                                    grub_uint32_t *y)
1927  * Register allocations for parameters:
1928  * %eax         *x
1929  * %edx         *y
1930  */
1931 FUNCTION(grub_vbe_bios_get_display_start)
1932         pushl   %ebp
1933         pushl   %ebx
1934         pushl   %edi
1935         pushl   %eax            /* Push *x to stack.  */
1936         pushl   %edx            /* Push *y to stack.  */
1938         call    prot_to_real
1939         .code16
1941         movw    $0x4f07, %ax
1942         movw    $0x0001, %bx    /* BL = 1, Get Display Start.  */
1943         int     $0x10
1945         movw    %ax, %bx        /* real_to_prot destroys %eax.  */
1947         DATA32 call     real_to_prot
1948         .code32
1950         popl    %edi            /* Pops *y from stack to %edi.  */
1951         andl    $0xFFFF, %edx
1952         movl    %edx, (%edi)    /* Return y-position to caller.  */
1954         popl    %edi            /* Pops *x from stack to %edi.  */
1955         andl    $0xFFFF, %ecx
1956         movl    %ecx, (%edi)    /* Return x-position to caller.  */
1958         movw    %bx, %ax
1959         andl    $0xFFFF, %eax   /* Return value in %eax.  */
1961         popl    %edi
1962         popl    %ebx
1963         popl    %ebp
1964         ret
1967  * grub_vbe_status_t grub_vbe_bios_set_palette_data (grub_uint32_t color_count,
1968  *                                                   grub_uint32_t start_index,
1969  *                                                   struct grub_vbe_palette_data *palette_data)
1971  * Register allocations for parameters:
1972  * %eax         color_count
1973  * %edx         start_index
1974  * %ecx         *palette_data
1975  */
1976 FUNCTION(grub_vbe_bios_set_palette_data)
1977         pushl   %ebp
1978         pushl   %ebx
1979         pushl   %edi
1981         movl    %eax, %ebx      /* Store color_count in %ebx.  */
1983         movw    %cx, %di        /* Store *palette_data to %ecx:%di.  */
1984         xorw    %cx, %cx
1985         shrl    $4, %ecx
1987         call    prot_to_real
1988         .code16
1990         pushw   %es
1992         movw    %cx, %es        /* *palette_data is now on %es:%di.  */
1993         movw    %bx, %cx        /* color_count is now on %cx.  */
1995         movw    $0x4f09, %ax
1996         xorw    %bx, %bx        /* BL = 0, Set Palette Data.  */
1997         int     $0x10
1999         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
2001         popw    %es
2003         DATA32 call     real_to_prot
2004         .code32
2005         
2006         movw    %dx, %ax
2007         andl    $0xFFFF, %eax   /* Return value in %eax.  */
2009         popl    %edi
2010         popl    %ebx
2011         popl    %ebp
2012         ret