remove all trailing whitespace
[grub2/phcoder/solaris.git] / kern / i386 / pc / startup.S
blob0f80e8ab87af5606af92a579dfe0183aa8110b63
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:
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>
56 #define ABS(x)  ((x) - _start + GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200)
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 #ifdef APPLE_CC
73         codestart_abs = ABS(codestart) - 0x10000
74         ljmp $0, $(codestart_abs)
75 #else
76         ljmp $0, $ABS(codestart)
77 #endif
79         /*
80          *  Compatibility version number
81          *
82          *  These MUST be at byte offset 6 and 7 of the executable
83          *  DO NOT MOVE !!!
84          */
85         . = _start + 0x6
86         .byte   GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR
88         /*
89          *  This is a special data area 8 bytes from the beginning.
90          */
92         . = _start + 0x8
94 VARIABLE(grub_total_module_size)
95         .long   0
96 VARIABLE(grub_kernel_image_size)
97         .long   0
98 VARIABLE(grub_compressed_size)
99         .long   0
100 VARIABLE(grub_install_dos_part)
101         .long   0xFFFFFFFF
102 VARIABLE(grub_install_bsd_part)
103         .long   0xFFFFFFFF
104 VARIABLE(grub_prefix)
105         /* to be filled by grub-mkimage */
107         /*
108          *  Leave some breathing room for the prefix.
109          */
111         . = _start + GRUB_KERNEL_MACHINE_DATA_END
113 #ifdef APPLE_CC
114 bss_start:
115         .long 0
116 bss_end:
117         .long 0
118 #endif
121  * Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself).
122  * This uses the a.out kludge to load raw binary to the area starting at 1MB,
123  * and relocates itself after loaded.
124  */
125         .p2align        2       /* force 4-byte alignment */
126 multiboot_header:
127         /* magic */
128         .long   0x1BADB002
129         /* flags */
130         .long   (1 << 16)
131         /* checksum */
132         .long   -0x1BADB002 - (1 << 16)
133         /* header addr */
134         .long   multiboot_header - _start + 0x100000 + 0x200
135         /* load addr */
136         .long   0x100000
137         /* load end addr */
138         .long   0
139         /* bss end addr */
140         .long   0
141         /* entry addr */
142         .long   multiboot_entry - _start + 0x100000 + 0x200
144 multiboot_entry:
145         .code32
146         /* obtain the boot device */
147         movl    12(%ebx), %edx
149         /* relocate the code */
150         movl    $(GRUB_KERNEL_MACHINE_RAW_SIZE + 0x200), %ecx
151         addl    EXT_C(grub_compressed_size) - _start + 0x100000 + 0x200, %ecx
152         movl    $0x100000, %esi
153         movl    $GRUB_BOOT_MACHINE_KERNEL_ADDR, %edi
154         cld
155         rep
156         movsb
157         /* jump to the real address */
158         movl    $multiboot_trampoline, %eax
159         jmp     *%eax
161 multiboot_trampoline:
162         /* fill the boot information */
163         movl    %edx, %eax
164         shrl    $8, %eax
165         xorl    %ebx, %ebx
166         cmpb    $0xFF, %ah
167         je      1f
168         movb    %ah, %bl
169         movl    %ebx, EXT_C(grub_install_dos_part)
171         cmpb    $0xFF, %al
172         je      2f
173         movb    %al, %bl
174         movl    %ebx, EXT_C(grub_install_bsd_part)
176         shrl    $24, %edx
177         movb    $0xFF, %dh
178         /* enter the usual booting */
179         call    prot_to_real
180         .code16
182 /* the real mode code continues... */
183 codestart:
184         cli             /* we're not safe here! */
186         /* set up %ds, %ss, and %es */
187         xorw    %ax, %ax
188         movw    %ax, %ds
189         movw    %ax, %ss
190         movw    %ax, %es
192         /* set up the real mode/BIOS stack */
193         movl    $GRUB_MEMORY_MACHINE_REAL_STACK, %ebp
194         movl    %ebp, %esp
196         sti             /* we're safe again */
198         /* save boot and root drive references */
199         ADDR32  movb    %dl, EXT_C(grub_boot_drive)
200         ADDR32  movb    %dh, EXT_C(grub_root_drive)
202         /* reset disk system (%ah = 0) */
203         int     $0x13
205         /* transition to protected mode */
206         DATA32  call real_to_prot
208         /* The ".code32" directive takes GAS out of 16-bit mode. */
209         .code32
211         incl    %eax
212         call    EXT_C(grub_gate_a20)
214 #if defined(ENABLE_LZO)
215         /* decompress the compressed part and put the result at 1MB */
216         movl    $GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR, %esi
217         movl    $(_start + GRUB_KERNEL_MACHINE_RAW_SIZE), %edi
219         pushl   %esi
220         pushl   EXT_C(grub_compressed_size)
221         pushl   %edi
222         call    lzo1x_decompress
223         addl    $12, %esp
225         movl    %eax, %ecx
226         cld
227 #elif defined(ENABLE_LZMA)
228         movl    $GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR, %edi
229         movl    $(_start + GRUB_KERNEL_MACHINE_RAW_SIZE), %esi
230         pushl   %edi
231         pushl   %esi
232         movl    EXT_C(grub_kernel_image_size), %ecx
233         addl    EXT_C(grub_total_module_size), %ecx
234         subl    $GRUB_KERNEL_MACHINE_RAW_SIZE, %ecx
235         pushl   %ecx
236         leal    (%edi, %ecx), %ebx
237         call    _LzmaDecodeA
238         /* _LzmaDecodeA clears DF, so no need to run cld */
239         popl    %ecx
240         popl    %edi
241         popl    %esi
242 #endif
244         /* copy back the decompressed part (except the modules) */
245         subl    EXT_C(grub_total_module_size), %ecx
246         rep
247         movsb
249 #if 0
250         /* copy modules before cleaning out the bss */
251         movl    EXT_C(grub_total_module_size), %ecx
252         movl    EXT_C(grub_kernel_image_size), %esi
253         addl    %ecx, %esi
254         addl    $_start, %esi
255         decl    %esi
256         movl    $END_SYMBOL, %edi
257         addl    %ecx, %edi
258         decl    %edi
259         std
260         rep
261         movsb
262 #endif
264 #ifdef APPLE_CC
265         /* clean out the bss */
266         bss_start_abs = ABS (bss_start)
267         bss_end_abs = ABS (bss_end)
269         movl    bss_start_abs, %edi
271         /* compute the bss length */
272         movl    bss_end_abs, %ecx
273         subl    %edi, %ecx
274 #else
275         /* clean out the bss */
276         movl    $BSS_START_SYMBOL, %edi
278         /* compute the bss length */
279         movl    $END_SYMBOL, %ecx
280         subl    %edi, %ecx
281 #endif
283         /* clean out */
284         xorl    %eax, %eax
285         cld
286         rep
287         stosb
289         /*
290          *  Call the start of main body of C code.
291          */
292         call EXT_C(grub_main)
294 #include "../realmode.S"
297  *  This is the area for all of the special variables.
298  */
300 VARIABLE(grub_boot_drive)
301         .byte   0
303 VARIABLE(grub_root_drive)
304         .byte   0
306         .p2align        2       /* force 4-byte alignment */
309  *  These next two routines, "real_to_prot" and "prot_to_real" are structured
310  *  in a very specific way.  Be very careful when changing them.
312  *  NOTE:  Use of either one messes up %eax and %ebp.
313  */
315 real_to_prot:
316         .code16
317         cli
319         /* load the GDT register */
320 #ifdef APPLE_CC
321         mov %cs, %ax
322         mov %ax, %ds
323         DATA32  ADDR32  lgdt    gdtdesc
324 #else
325         DATA32  ADDR32  lgdt    %cs:gdtdesc
326 #endif
328         /* turn on protected mode */
329         movl    %cr0, %eax
330         orl     $GRUB_MEMORY_MACHINE_CR0_PE_ON, %eax
331         movl    %eax, %cr0
333         /* jump to relocation, flush prefetch queue, and reload %cs */
334         DATA32  ljmp    $GRUB_MEMORY_MACHINE_PROT_MODE_CSEG, $protcseg
336         .code32
337 protcseg:
338         /* reload other segment registers */
339         movw    $GRUB_MEMORY_MACHINE_PROT_MODE_DSEG, %ax
340         movw    %ax, %ds
341         movw    %ax, %es
342         movw    %ax, %fs
343         movw    %ax, %gs
344         movw    %ax, %ss
346         /* put the return address in a known safe location */
347         movl    (%esp), %eax
348         movl    %eax, GRUB_MEMORY_MACHINE_REAL_STACK
350         /* get protected mode stack */
351         movl    protstack, %eax
352         movl    %eax, %esp
353         movl    %eax, %ebp
355         /* get return address onto the right stack */
356         movl    GRUB_MEMORY_MACHINE_REAL_STACK, %eax
357         movl    %eax, (%esp)
359         /* zero %eax */
360         xorl    %eax, %eax
362         /* return on the old (or initialized) stack! */
363         ret
366  * grub_gate_a20(int on)
368  * Gate address-line 20 for high memory.
370  * This routine is probably overconservative in what it does, but so what?
372  * It also eats any keystrokes in the keyboard buffer.  :-(
373  */
375 FUNCTION(grub_gate_a20)
376         movl    %eax, %edx
378 gate_a20_test_current_state:
379         /* first of all, test if already in a good state */
380         call    gate_a20_check_state
381         cmpb    %al, %dl
382         jnz     gate_a20_try_bios
383         ret
385 gate_a20_try_bios:
386         /* second, try a BIOS call */
387         pushl   %ebp
388         call    prot_to_real
390         .code16
391         movw    $0x2400, %ax
392         testb   %dl, %dl
393         jz      1f
394         incw    %ax
395 1:      int     $0x15
397         DATA32  call    real_to_prot
398         .code32
400         popl    %ebp
401         call    gate_a20_check_state
402         cmpb    %al, %dl
403         jnz     gate_a20_try_system_control_port_a
404         ret
406 gate_a20_try_system_control_port_a:
407         /*
408          * In macbook, the keyboard test would hang the machine, so we move
409          * this forward.
410          */
411         /* fourth, try the system control port A */
412         inb     $0x92
413         andb    $(~0x03), %al
414         testb   %dl, %dl
415         jz      6f
416         orb     $0x02, %al
417 6:      outb    $0x92
419         /* When turning off Gate A20, do not check the state strictly,
420            because a failure is not fatal usually, and Gate A20 is always
421            on some modern machines.  */
422         testb   %dl, %dl
423         jz      7f
424         call    gate_a20_check_state
425         cmpb    %al, %dl
426         jnz     gate_a20_try_keyboard_controller
427 7:      ret
429 gate_a20_flush_keyboard_buffer:
430         inb     $0x64
431         andb    $0x02, %al
432         jnz     gate_a20_flush_keyboard_buffer
434         inb     $0x64
435         andb    $0x01, %al
436         jz      3f
437         inb     $0x60
438         jmp     2b
440         ret
442 gate_a20_try_keyboard_controller:
443         /* third, try the keyboard controller */
444         call    gate_a20_flush_keyboard_buffer
446         movb    $0xd1, %al
447         outb    $0x64
449         inb     $0x64
450         andb    $0x02, %al
451         jnz     4b
453         movb    $0xdd, %al
454         testb   %dl, %dl
455         jz      5f
456         orb     $0x02, %al
457 5:      outb    $0x60
458         call    gate_a20_flush_keyboard_buffer
460         /* output a dummy command (USB keyboard hack) */
461         movb    $0xff, %al
462         outb    $0x64
463         call    gate_a20_flush_keyboard_buffer
465         call    gate_a20_check_state
466         cmpb    %al, %dl
467         /* everything failed, so restart from the beginning */
468         jnz     gate_a20_try_bios
469         ret
471 gate_a20_check_state:
472         /* iterate the checking for a while */
473         movl    $100, %ecx
475         call    3f
476         cmpb    %al, %dl
477         jz      2f
478         loop    1b
480         ret
482         pushl   %ebx
483         pushl   %ecx
484         xorl    %eax, %eax
485         /* compare the byte at 0x8000 with that at 0x108000 */
486         movl    $GRUB_BOOT_MACHINE_KERNEL_ADDR, %ebx
487         pushl   %ebx
488         /* save the original byte in CL */
489         movb    (%ebx), %cl
490         /* store the value at 0x108000 in AL */
491         addl    $0x100000, %ebx
492         movb    (%ebx), %al
493         /* try to set one less value at 0x8000 */
494         popl    %ebx
495         movb    %al, %ch
496         decb    %ch
497         movb    %ch, (%ebx)
498         /* serialize */
499         outb    %al, $0x80
500         outb    %al, $0x80
501         /* obtain the value at 0x108000 in CH */
502         pushl   %ebx
503         addl    $0x100000, %ebx
504         movb    (%ebx), %ch
505         /* this result is 1 if A20 is on or 0 if it is off */
506         subb    %ch, %al
507         xorb    $1, %al
508         /* restore the original */
509         popl    %ebx
510         movb    %cl, (%ebx)
511         popl    %ecx
512         popl    %ebx
513         ret
515 #if defined(ENABLE_LZO)
516 #include "lzo1x.S"
517 #elif defined(ENABLE_LZMA)
518 #include "lzma_decode.S"
519 #endif
522  * The code beyond this point is compressed.  Assert that the uncompressed
523  * code fits GRUB_KERNEL_MACHINE_RAW_SIZE.
524  */
525         . = _start + GRUB_KERNEL_MACHINE_RAW_SIZE
528  *  This call is special...  it never returns...  in fact it should simply
529  *  hang at this point!
530  */
532 FUNCTION(grub_stop)
533         call    prot_to_real
535         /*
536          * This next part is sort of evil.  It takes advantage of the
537          * byte ordering on the x86 to work in either 16-bit or 32-bit
538          * mode, so think about it before changing it.
539          */
541 FUNCTION(grub_hard_stop)
542         hlt
543         jmp EXT_C(grub_hard_stop)
547  * grub_stop_floppy()
549  * Stop the floppy drive from spinning, so that other software is
550  * jumped to with a known state.
551  */
552 FUNCTION(grub_stop_floppy)
553         movw    $0x3F2, %dx
554         xorb    %al, %al
555         outb    %al, %dx
556         ret
559  * grub_exit()
561  * Exit the system.
562  */
563 FUNCTION(grub_exit)
564         call    prot_to_real
565         .code16
566         /* Tell the BIOS a boot failure. If this does not work, reboot.  */
567         int     $0x18
568         jmp     cold_reboot
569         .code32
572  * grub_reboot()
574  * Reboot the system. At the moment, rely on BIOS.
575  */
576 FUNCTION(grub_reboot)
577         call    prot_to_real
578         .code16
579 cold_reboot:
580         /* cold boot */
581         movw    $0x0472, %di
582         movw    %ax, (%di)
583         ljmp    $0xFFFF, $0x0000
584         .code32
587  * grub_halt(int no_apm)
589  * Halt the system, using APM if possible. If NO_APM is true, don't use
590  * APM even if it is available.
591  */
592 FUNCTION(grub_halt)
593         /* see if zero */
594         testl   %eax, %eax
595         jnz     EXT_C(grub_stop)
597         call    prot_to_real
598         .code16
600         /* detect APM */
601         movw    $0x5300, %ax
602         xorw    %bx, %bx
603         int     $0x15
604         jc      EXT_C(grub_hard_stop)
605         /* don't check %bx for buggy BIOSes... */
607         /* disconnect APM first */
608         movw    $0x5304, %ax
609         xorw    %bx, %bx
610         int     $0x15
612         /* connect APM */
613         movw    $0x5301, %ax
614         xorw    %bx, %bx
615         int     $0x15
616         jc      EXT_C(grub_hard_stop)
618         /* set APM protocol level - 1.1 or bust. (this covers APM 1.2 also) */
619         movw    $0x530E, %ax
620         xorw    %bx, %bx
621         movw    $0x0101, %cx
622         int     $0x15
623         jc      EXT_C(grub_hard_stop)
625         /* set the power state to off */
626         movw    $0x5307, %ax
627         movw    $1, %bx
628         movw    $3, %cx
629         int     $0x15
631         /* shouldn't reach here */
632         jmp     EXT_C(grub_hard_stop)
633         .code32
637  *  void grub_chainloader_real_boot (int drive, void *part_addr)
639  *  This starts another boot loader.
640  */
642 FUNCTION(grub_chainloader_real_boot)
643         pushl   %edx
644         pushl   %eax
646         call    EXT_C(grub_dl_unload_all)
648         /* Turn off Gate A20 */
649         xorl    %eax, %eax
650         call    EXT_C(grub_gate_a20)
652         /* set up to pass boot drive */
653         popl    %edx
655         /* ESI must point to a partition table entry */
656         popl    %esi
658         call    prot_to_real
659         .code16
660         ljmp    $0, $GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR
661         .code32
663 #include "../loader.S"
666  *   int grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap)
668  *   Call IBM/MS INT13 Extensions (int 13 %ah=AH) for DRIVE. DAP
669  *   is passed for disk address packet. If an error occurs, return
670  *   non-zero, otherwise zero.
671  */
673 FUNCTION(grub_biosdisk_rw_int13_extensions)
674         pushl   %ebp
675         pushl   %esi
677         /* compute the address of disk_address_packet */
678         movw    %cx, %si
679         xorw    %cx, %cx
680         shrl    $4, %ecx        /* save the segment to cx */
682         /* ah */
683         movb    %al, %dh
684         /* enter real mode */
685         call    prot_to_real
687         .code16
688         movb    %dh, %ah
689         movw    %cx, %ds
690         int     $0x13           /* do the operation */
691         movb    %ah, %dl        /* save return value */
692         /* back to protected mode */
693         DATA32  call    real_to_prot
694         .code32
696         movb    %dl, %al        /* return value in %eax */
698         popl    %esi
699         popl    %ebp
701         ret
704  *   int grub_biosdisk_rw_standard (int ah, int drive, int coff, int hoff,
705  *                                  int soff, int nsec, int segment)
707  *   Call standard and old INT13 (int 13 %ah=AH) for DRIVE. Read/write
708  *   NSEC sectors from COFF/HOFF/SOFF into SEGMENT. If an error occurs,
709  *   return non-zero, otherwise zero.
710  */
712 FUNCTION(grub_biosdisk_rw_standard)
713         pushl   %ebp
714         movl    %esp, %ebp
716         pushl   %ebx
717         pushl   %edi
718         pushl   %esi
720         /* set up CHS information */
722         /* set %ch to low eight bits of cylinder */
723         xchgb   %cl, %ch
724         /* set bits 6-7 of %cl to high two bits of cylinder */
725         shlb    $6, %cl
726         /* set bits 0-5 of %cl to sector */
727         addb    0xc(%ebp), %cl
728         /* set %dh to head */
729         movb    0x8(%ebp), %dh
730         /* set %ah to AH */
731         movb    %al, %ah
732         /* set %al to NSEC */
733         movb    0x10(%ebp), %al
734         /* save %ax in %di */
735         movw    %ax, %di
736         /* save SEGMENT in %bx */
737         movw    0x14(%ebp), %bx
739         /* enter real mode */
740         call    prot_to_real
742         .code16
743         movw    %bx, %es
744         xorw    %bx, %bx
745         movw    $3, %si         /* attempt at least three times */
748         movw    %di, %ax
749         int     $0x13           /* do the operation */
750         jnc     2f              /* check if successful */
752         movb    %ah, %bl        /* save return value */
753         /* if fail, reset the disk system */
754         xorw    %ax, %ax
755         int     $0x13
757         decw    %si
758         cmpw    $0, %si
759         je      2f
760         xorb    %bl, %bl
761         jmp     1b              /* retry */
763         /* back to protected mode */
764         DATA32  call    real_to_prot
765         .code32
767         movb    %bl, %al        /* return value in %eax */
769         popl    %esi
770         popl    %edi
771         popl    %ebx
772         popl    %ebp
774         ret     $(4 * 4)
778  *   int grub_biosdisk_check_int13_extensions (int drive)
780  *   Check if LBA is supported for DRIVE. If it is supported, then return
781  *   the major version of extensions, otherwise zero.
782  */
784 FUNCTION(grub_biosdisk_check_int13_extensions)
785         pushl   %ebp
786         pushl   %ebx
788         /* drive */
789         movb    %al, %dl
790         /* enter real mode */
791         call    prot_to_real
793         .code16
794         movb    $0x41, %ah
795         movw    $0x55aa, %bx
796         int     $0x13           /* do the operation */
798         /* check the result */
799         jc      1f
800         cmpw    $0xaa55, %bx
801         jne     1f
803         movb    %ah, %bl        /* save the major version into %bl */
805         /* check if AH=0x42 is supported */
806         andw    $1, %cx
807         jnz     2f
810         xorb    %bl, %bl
812         /* back to protected mode */
813         DATA32  call    real_to_prot
814         .code32
816         movb    %bl, %al        /* return value in %eax */
818         popl    %ebx
819         popl    %ebp
821         ret
825  *   int grub_biosdisk_get_cdinfo_int13_extensions (int drive, void *cdrp)
827  *   Return the cdrom information of DRIVE in CDRP. If an error occurs,
828  *   then return non-zero, otherwise zero.
829  */
831 FUNCTION(grub_biosdisk_get_cdinfo_int13_extensions)
832         movw    $0x4B01, %cx
833         jmp     1f
836  *   int grub_biosdisk_get_diskinfo_int13_extensions (int drive, void *drp)
838  *   Return the geometry of DRIVE in a drive parameters, DRP. If an error
839  *   occurs, then return non-zero, otherwise zero.
840  */
842 FUNCTION(grub_biosdisk_get_diskinfo_int13_extensions)
843         movb    $0x48, %ch
845         pushl   %ebp
846         pushl   %ebx
847         pushl   %esi
849         /* compute the address of drive parameters */
850         movw    %dx, %si
851         andl    $0xf, %esi
852         shrl    $4, %edx
853         movw    %dx, %bx        /* save the segment into %bx */
854         /* drive */
855         movb    %al, %dl
856         /* enter real mode */
857         call    prot_to_real
859         .code16
860         movw    %cx, %ax
861         movw    %bx, %ds
862         int     $0x13           /* do the operation */
863         movb    %ah, %bl        /* save return value in %bl */
864         /* back to protected mode */
865         DATA32  call    real_to_prot
866         .code32
868         movb    %bl, %al        /* return value in %eax */
870         popl    %esi
871         popl    %ebx
872         popl    %ebp
874         ret
878  *   int grub_biosdisk_get_diskinfo_standard (int drive,
879  *                                            unsigned long *cylinders,
880  *                                            unsigned long *heads,
881  *                                            unsigned long *sectors)
883  *   Return the geometry of DRIVE in CYLINDERS, HEADS and SECTORS. If an
884  *   error occurs, then return non-zero, otherwise zero.
885  */
887 FUNCTION(grub_biosdisk_get_diskinfo_standard)
888         pushl   %ebp
889         pushl   %ebx
890         pushl   %edi
892         /* push CYLINDERS */
893         pushl   %edx
894         /* push HEADS */
895         pushl   %ecx
896         /* SECTORS is on the stack */
898         /* drive */
899         movb    %al, %dl
900         /* enter real mode */
901         call    prot_to_real
903         .code16
904         movb    $0x8, %ah
905         int     $0x13           /* do the operation */
906         /* check if successful */
907         testb   %ah, %ah
908         jnz     1f
909         /* bogus BIOSes may not return an error number */
910         testb   $0x3f, %cl      /* 0 sectors means no disk */
911         jnz     1f              /* if non-zero, then succeed */
912         /* XXX 0x60 is one of the unused error numbers */
913         movb    $0x60, %ah
915         movb    %ah, %bl        /* save return value in %bl */
916         /* back to protected mode */
917         DATA32  call    real_to_prot
918         .code32
920         /* pop HEADS */
921         popl    %edi
922         movb    %dh, %al
923         incl    %eax    /* the number of heads is counted from zero */
924         movl    %eax, (%edi)
926         /* pop CYLINDERS */
927         popl    %edi
928         movb    %ch, %al
929         movb    %cl, %ah
930         shrb    $6, %ah /* the number of cylinders is counted from zero */
931         incl    %eax
932         movl    %eax, (%edi)
934         /* SECTORS */
935         movl    0x10(%esp), %edi
936         andb    $0x3f, %cl
937         movzbl  %cl, %eax
938         movl    %eax, (%edi)
940         xorl    %eax, %eax
941         movb    %bl, %al        /* return value in %eax */
943         popl    %edi
944         popl    %ebx
945         popl    %ebp
947         ret     $4
951  * int grub_biosdisk_get_num_floppies (void)
952  */
953 FUNCTION(grub_biosdisk_get_num_floppies)
954         pushl   %ebp
956         xorl    %edx, %edx
957         call    prot_to_real
959         .code16
960         /* reset the disk system first */
961         int     $0x13
963         stc
965         /* call GET DISK TYPE */
966         movb    $0x15, %ah
967         int     $0x13
969         jc      2f
971         /* check if this drive exists */
972         testb   $0x3, %ah
973         jz      2f
975         incb    %dl
976         cmpb    $2, %dl
977         jne     1b
979         DATA32  call    real_to_prot
980         .code32
982         movl    %edx, %eax
983         popl    %ebp
984         ret
989  * grub_get_memsize(i) :  return the memory size in KB. i == 0 for conventional
990  *              memory, i == 1 for extended memory
991  *      BIOS call "INT 12H" to get conventional memory size
992  *      BIOS call "INT 15H, AH=88H" to get extended memory size
993  *              Both have the return value in AX.
995  */
997 FUNCTION(grub_get_memsize)
998         pushl   %ebp
1000         movl    %eax, %edx
1002         call    prot_to_real    /* enter real mode */
1003         .code16
1005         testl   %edx, %edx
1006         jnz     xext
1008         int     $0x12
1009         jmp     xdone
1011 xext:
1012         movb    $0x88, %ah
1013         int     $0x15
1015 xdone:
1016         movw    %ax, %dx
1018         DATA32  call    real_to_prot
1019         .code32
1021         movw    %dx, %ax
1023         popl    %ebp
1024         ret
1029  * grub_get_eisa_mmap() :  return packed EISA memory map, lower 16 bits is
1030  *              memory between 1M and 16M in 1K parts, upper 16 bits is
1031  *              memory above 16M in 64K parts.  If error, return zero.
1032  *      BIOS call "INT 15H, AH=E801H" to get EISA memory map,
1033  *              AX = memory between 1M and 16M in 1K parts.
1034  *              BX = memory above 16M in 64K parts.
1036  */
1038 FUNCTION(grub_get_eisa_mmap)
1039         pushl   %ebp
1040         pushl   %ebx
1042         call    prot_to_real    /* enter real mode */
1043         .code16
1045         movw    $0xe801, %ax
1046         int     $0x15
1048         shll    $16, %ebx
1049         movw    %ax, %bx
1051         DATA32  call    real_to_prot
1052         .code32
1054         cmpb    $0x86, %bh
1055         je      xnoteisa
1057         movl    %ebx, %eax
1059 xnoteisa:
1060         popl    %ebx
1061         popl    %ebp
1062         ret
1066  * grub_get_mmap_entry(addr, cont) : address and old continuation value (zero to
1067  *              start), for the Query System Address Map BIOS call.
1069  *  Sets the first 4-byte int value of "addr" to the size returned by
1070  *  the call.  If the call fails, sets it to zero.
1072  *      Returns:  new (non-zero) continuation value, 0 if done.
1073  */
1075 FUNCTION(grub_get_mmap_entry)
1076         pushl   %ebp
1077         pushl   %ebx
1078         pushl   %edi
1079         pushl   %esi
1081         /* push ADDR */
1082         pushl   %eax
1084         /* place address (+4) in ES:DI */
1085         addl    $4, %eax
1086         movl    %eax, %edi
1087         andl    $0xf, %edi
1088         shrl    $4, %eax
1089         movl    %eax, %esi
1091         /* set continuation value */
1092         movl    %edx, %ebx
1094         /* set default maximum buffer size */
1095         movl    $0x14, %ecx
1097         /* set EDX to 'SMAP' */
1098         movl    $0x534d4150, %edx
1100         call    prot_to_real    /* enter real mode */
1101         .code16
1103         movw    %si, %es
1104         movl    $0xe820, %eax
1105         int     $0x15
1107         DATA32  jc      xnosmap
1109         cmpl    $0x534d4150, %eax
1110         jne     xnosmap
1112         cmpl    $0x14, %ecx
1113         jl      xnosmap
1115         cmpl    $0x400, %ecx
1116         jg      xnosmap
1118         jmp     xsmap
1120 xnosmap:
1121         xorl    %ecx, %ecx
1123 /*      Apple's cc jumps few bytes before the correct
1124         label in this context. Hence nops. */
1125 #ifdef APPLE_CC
1126         nop
1127         nop
1128         nop
1129         nop
1130         nop
1131         nop
1132 #endif
1134 xsmap:
1135         DATA32  call    real_to_prot
1136         .code32
1138         /* write length of buffer (zero if error) into ADDR */
1139         popl    %eax
1140         movl    %ecx, (%eax)
1142         /* set return value to continuation */
1143         movl    %ebx, %eax
1145         popl    %esi
1146         popl    %edi
1147         popl    %ebx
1148         popl    %ebp
1149         ret
1153  * void grub_console_real_putchar (int c)
1155  * Put the character C on the console. Because GRUB wants to write a
1156  * character with an attribute, this implementation is a bit tricky.
1157  * If C is a control character (CR, LF, BEL, BS), use INT 10, AH = 0Eh
1158  * (TELETYPE OUTPUT). Otherwise, save the original position, put a space,
1159  * save the current position, restore the original position, write the
1160  * character and the attribute, and restore the current position.
1162  * The reason why this is so complicated is that there is no easy way to
1163  * get the height of the screen, and the TELETYPE OUTPUT BIOS call doesn't
1164  * support setting a background attribute.
1165  */
1166 FUNCTION(grub_console_real_putchar)
1167         movl    %eax, %edx
1168         pusha
1169         movb    EXT_C(grub_console_cur_color), %bl
1171         call    prot_to_real
1172         .code16
1173         movb    %dl, %al
1174         xorb    %bh, %bh
1176         /* use teletype output if control character */
1177         cmpb    $0x7, %al
1178         je      1f
1179         cmpb    $0x8, %al
1180         je      1f
1181         cmpb    $0xa, %al
1182         je      1f
1183         cmpb    $0xd, %al
1184         je      1f
1186         /* save the character and the attribute on the stack */
1187         pushw   %ax
1188         pushw   %bx
1190         /* get the current position */
1191         movb    $0x3, %ah
1192         int     $0x10
1194         /* check the column with the width */
1195         cmpb    $79, %dl
1196         jl      2f
1198         /* print CR and LF, if next write will exceed the width */
1199         movw    $0x0e0d, %ax
1200         int     $0x10
1201         movb    $0x0a, %al
1202         int     $0x10
1204         /* get the current position */
1205         movb    $0x3, %ah
1206         int     $0x10
1209         /* restore the character and the attribute */
1210         popw    %bx
1211         popw    %ax
1213         /* write the character with the attribute */
1214         movb    $0x9, %ah
1215         movw    $1, %cx
1216         int     $0x10
1218         /* move the cursor forward */
1219         incb    %dl
1220         movb    $0x2, %ah
1221         int     $0x10
1223         jmp     3f
1225 1:      movw    $1, %bx
1226         movb    $0xe, %ah
1227         int     $0x10
1229 3:      DATA32  call    real_to_prot
1230         .code32
1232         popa
1233         ret
1237  * int grub_console_getkey (void)
1238  * BIOS call "INT 16H Function 00H" to read character from keyboard
1239  *      Call with       %ah = 0x0
1240  *      Return:         %ah = keyboard scan code
1241  *                      %al = ASCII character
1242  */
1244 /* this table is used in translate_keycode below */
1245 translation_table:
1246         .word   GRUB_CONSOLE_KEY_LEFT, GRUB_TERM_LEFT
1247         .word   GRUB_CONSOLE_KEY_RIGHT, GRUB_TERM_RIGHT
1248         .word   GRUB_CONSOLE_KEY_UP, GRUB_TERM_UP
1249         .word   GRUB_CONSOLE_KEY_DOWN, GRUB_TERM_DOWN
1250         .word   GRUB_CONSOLE_KEY_HOME, GRUB_TERM_HOME
1251         .word   GRUB_CONSOLE_KEY_END, GRUB_TERM_END
1252         .word   GRUB_CONSOLE_KEY_DC, GRUB_TERM_DC
1253         .word   GRUB_CONSOLE_KEY_BACKSPACE, GRUB_TERM_BACKSPACE
1254         .word   GRUB_CONSOLE_KEY_PPAGE, GRUB_TERM_PPAGE
1255         .word   GRUB_CONSOLE_KEY_NPAGE, GRUB_TERM_NPAGE
1256         .word   0
1259  * translate_keycode translates the key code %dx to an ascii code.
1260  */
1261         .code16
1263 translate_keycode:
1264         pushw   %bx
1265         pushw   %si
1267 #ifdef APPLE_CC
1268         translation_table_abs = ABS (translation_table) - 0x10000
1269         movw    $(translation_table_abs), %si
1270 #else
1271         movw    $ABS(translation_table), %si
1272 #endif
1274 1:      lodsw
1275         /* check if this is the end */
1276         testw   %ax, %ax
1277         jz      2f
1278         /* load the ascii code into %ax */
1279         movw    %ax, %bx
1280         lodsw
1281         /* check if this matches the key code */
1282         cmpw    %bx, %dx
1283         jne     1b
1284         /* translate %dx, if successful */
1285         movw    %ax, %dx
1287 2:      popw    %si
1288         popw    %bx
1289         ret
1291         .code32
1293 FUNCTION(grub_console_getkey)
1294         pushl   %ebp
1296         call    prot_to_real
1297         .code16
1299         /*
1300          * Due to a bug in apple's bootcamp implementation, INT 16/AH = 0 would
1301          * cause the machine to hang at the second keystroke. However, we can
1302          * work around this problem by ensuring the presence of keystroke with
1303          * INT 16/AH = 1 before calling INT 16/AH = 0.
1304          */
1307         movb    $1, %ah
1308         int     $0x16
1309         jnz     2f
1310         hlt
1311         jmp     1b
1315         movb    $0, %ah
1316         int     $0x16
1318         movw    %ax, %dx                /* real_to_prot uses %eax */
1319         call    translate_keycode
1321         DATA32  call    real_to_prot
1322         .code32
1324         movw    %dx, %ax
1326         popl    %ebp
1327         ret
1331  * int grub_console_checkkey (void)
1332  *      if there is a character pending, return it; otherwise return -1
1333  * BIOS call "INT 16H Function 01H" to check whether a character is pending
1334  *      Call with       %ah = 0x1
1335  *      Return:
1336  *              If key waiting to be input:
1337  *                      %ah = keyboard scan code
1338  *                      %al = ASCII character
1339  *                      Zero flag = clear
1340  *              else
1341  *                      Zero flag = set
1342  */
1343 FUNCTION(grub_console_checkkey)
1344         pushl   %ebp
1345         xorl    %edx, %edx
1347         call    prot_to_real    /* enter real mode */
1348         .code16
1350         movb    $0x1, %ah
1351         int     $0x16
1353         jz      notpending
1355         movw    %ax, %dx
1356         DATA32  jmp     pending
1358 notpending:
1359         decl    %edx
1361 pending:
1362         DATA32  call    real_to_prot
1363         .code32
1365         movl    %edx, %eax
1367         popl    %ebp
1368         ret
1372  * grub_uint16_t grub_console_getxy (void)
1373  * BIOS call "INT 10H Function 03h" to get cursor position
1374  *      Call with       %ah = 0x03
1375  *                      %bh = page
1376  *      Returns         %ch = starting scan line
1377  *                      %cl = ending scan line
1378  *                      %dh = row (0 is top)
1379  *                      %dl = column (0 is left)
1380  */
1383 FUNCTION(grub_console_getxy)
1384         pushl   %ebp
1385         pushl   %ebx                    /* save EBX */
1387         call    prot_to_real
1388         .code16
1390         xorb    %bh, %bh                /* set page to 0 */
1391         movb    $0x3, %ah
1392         int     $0x10                   /* get cursor position */
1394         DATA32  call    real_to_prot
1395         .code32
1397         movb    %dl, %ah
1398         movb    %dh, %al
1400         popl    %ebx
1401         popl    %ebp
1402         ret
1406  * void grub_console_gotoxy(grub_uint8_t x, grub_uint8_t y)
1407  * BIOS call "INT 10H Function 02h" to set cursor position
1408  *      Call with       %ah = 0x02
1409  *                      %bh = page
1410  *                      %dh = row (0 is top)
1411  *                      %dl = column (0 is left)
1412  */
1415 FUNCTION(grub_console_gotoxy)
1416         pushl   %ebp
1417         pushl   %ebx                    /* save EBX */
1419         movb    %dl, %dh        /* %dh = y */
1420         movb    %al, %dl        /* %dl = x */
1422         call    prot_to_real
1423         .code16
1425         xorb    %bh, %bh                /* set page to 0 */
1426         movb    $0x2, %ah
1427         int     $0x10                   /* set cursor position */
1429         DATA32  call    real_to_prot
1430         .code32
1432         popl    %ebx
1433         popl    %ebp
1434         ret
1438  * void grub_console_cls (void)
1439  * BIOS call "INT 10H Function 09h" to write character and attribute
1440  *      Call with       %ah = 0x09
1441  *                      %al = (character)
1442  *                      %bh = (page number)
1443  *                      %bl = (attribute)
1444  *                      %cx = (number of times)
1445  */
1447 FUNCTION(grub_console_cls)
1448         pushl   %ebp
1449         pushl   %ebx                    /* save EBX */
1451         call    prot_to_real
1452         .code16
1454         /* move the cursor to the beginning */
1455         movb    $0x02, %ah
1456         xorb    %bh, %bh
1457         xorw    %dx, %dx
1458         int     $0x10
1460         /* write spaces to the entire screen */
1461         movw    $0x0920, %ax
1462         movw    $0x07, %bx
1463         movw    $(80 * 25), %cx
1464         int     $0x10
1466         /* move back the cursor */
1467         movb    $0x02, %ah
1468         int     $0x10
1470         DATA32  call    real_to_prot
1471         .code32
1473         popl    %ebx
1474         popl    %ebp
1475         ret
1479  * void grub_console_setcursor (int on)
1480  * BIOS call "INT 10H Function 01h" to set cursor type
1481  *      Call with       %ah = 0x01
1482  *                      %ch = cursor starting scanline
1483  *                      %cl = cursor ending scanline
1484  */
1486 console_cursor_state:
1487         .byte   1
1488 console_cursor_shape:
1489         .word   0
1491 FUNCTION(grub_console_setcursor)
1492         pushl   %ebp
1493         pushl   %ebx
1495         /* push ON */
1496         pushl   %eax
1498         /* check if the standard cursor shape has already been saved */
1499         movw    console_cursor_shape, %ax
1500         testw   %ax, %ax
1501         jne     1f
1503         call    prot_to_real
1504         .code16
1506         movb    $0x03, %ah
1507         xorb    %bh, %bh
1508         int     $0x10
1510         DATA32  call    real_to_prot
1511         .code32
1513         movw    %cx, console_cursor_shape
1515         /* set %cx to the designated cursor shape */
1516         movw    $0x2000, %cx
1517         popl    %eax
1518         testl   %eax, %eax
1519         jz      2f
1520         movw    console_cursor_shape, %cx
1522         call    prot_to_real
1523         .code16
1525         movb    $0x1, %ah
1526         int     $0x10
1528         DATA32  call    real_to_prot
1529         .code32
1531         popl    %ebx
1532         popl    %ebp
1533         ret
1536  * grub_getrtsecs()
1537  *      if a seconds value can be read, read it and return it (BCD),
1538  *      otherwise return 0xFF
1539  * BIOS call "INT 1AH Function 02H" to check whether a character is pending
1540  *      Call with       %ah = 0x2
1541  *      Return:
1542  *              If RT Clock can give correct values
1543  *                      %ch = hour (BCD)
1544  *                      %cl = minutes (BCD)
1545  *                      %dh = seconds (BCD)
1546  *                      %dl = daylight savings time (00h std, 01h daylight)
1547  *                      Carry flag = clear
1548  *              else
1549  *                      Carry flag = set
1550  *                         (this indicates that the clock is updating, or
1551  *                          that it isn't running)
1552  */
1553 FUNCTION(grub_getrtsecs)
1554         pushl   %ebp
1556         call    prot_to_real    /* enter real mode */
1557         .code16
1559         clc
1560         movb    $0x2, %ah
1561         int     $0x1a
1563         DATA32  jnc     gottime
1564         movb    $0xff, %dh
1566 gottime:
1567         DATA32  call    real_to_prot
1568         .code32
1570         movb    %dh, %al
1572         popl    %ebp
1573         ret
1577  * grub_get_rtc()
1578  *      return the real time in ticks, of which there are about
1579  *      18-20 per second
1580  */
1581 FUNCTION(grub_get_rtc)
1582         pushl   %ebp
1584         call    prot_to_real    /* enter real mode */
1585         .code16
1587         /* %ax is already zero */
1588         int     $0x1a
1590         DATA32  call    real_to_prot
1591         .code32
1593         movl    %ecx, %eax
1594         shll    $16, %eax
1595         movw    %dx, %ax
1597         popl    %ebp
1598         ret
1602  * unsigned char grub_vga_set_mode (unsigned char mode)
1603  */
1604 FUNCTION(grub_vga_set_mode)
1605         pushl   %ebp
1606         pushl   %ebx
1607         movl    %eax, %ecx
1609         call    prot_to_real
1610         .code16
1611         /* get current mode */
1612         xorw    %bx, %bx
1613         movb    $0x0f, %ah
1614         int     $0x10
1615         movb    %al, %dl
1617         /* set the new mode */
1618         movb    %cl, %al
1619         xorb    %ah, %ah
1620         int     $0x10
1622         DATA32  call    real_to_prot
1623         .code32
1625         movb    %dl, %al
1626         popl    %ebx
1627         popl    %ebp
1628         ret
1632  * unsigned char *grub_vga_get_font (void)
1633  */
1634 FUNCTION(grub_vga_get_font)
1635         pushl   %ebp
1636         pushl   %ebx
1638         call    prot_to_real
1639         .code16
1640         movw    $0x1130, %ax
1641         movb    $0x06, %bh
1642         int     $0x10
1643         movw    %es, %bx
1644         movw    %bp, %dx
1645         DATA32  call    real_to_prot
1646         .code32
1648         movzwl  %bx, %ecx
1649         shll    $4, %ecx
1650         movw    %dx, %ax
1651         addl    %ecx, %eax
1653         popl    %ebx
1654         popl    %ebp
1655         ret
1658  * grub_vbe_bios_status_t grub_vbe_get_controller_info (struct grub_vbe_info_block *controller_info)
1660  * Register allocations for parameters:
1661  * %eax         *controller_info
1662  */
1663 FUNCTION(grub_vbe_bios_get_controller_info)
1664         pushl   %ebp
1665         pushl   %edi
1666         pushl   %edx
1668         movw    %ax, %di        /* Store *controller_info to %edx:%di.  */
1669         xorw    %ax, %ax
1670         shrl    $4, %eax
1671         mov     %eax, %edx      /* prot_to_real destroys %eax.  */
1673         call    prot_to_real
1674         .code16
1676         pushw   %es
1678         movw    %dx, %es        /* *controller_info is now on %es:%di.  */
1679         movw    $0x4f00, %ax
1680         int     $0x10
1682         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1684         popw    %es
1686         DATA32 call     real_to_prot
1687         .code32
1689         movl    %edx, %eax
1690         andl    $0x0FFFF, %eax  /* Return value in %eax.  */
1692         pop     %edx
1693         popl    %edi
1694         popl    %ebp
1695         ret
1698  * grub_vbe_status_t grub_vbe_bios_get_mode_info (grub_uint32_t mode,
1699  *                                                struct grub_vbe_mode_info_block *mode_info)
1701  * Register allocations for parameters:
1702  * %eax         mode
1703  * %edx         *mode_info
1704  */
1705 FUNCTION(grub_vbe_bios_get_mode_info)
1706         pushl   %ebp
1707         pushl   %edi
1709         movl    %eax, %ecx      /* Store mode number to %ecx.  */
1711         movw    %dx, %di        /* Store *mode_info to %edx:%di.  */
1712         xorw    %dx, %dx
1713         shrl    $4, %edx
1715         call    prot_to_real
1716         .code16
1718         pushw   %es
1720         movw    %dx, %es        /* *mode_info is now on %es:%di.  */
1721         movw    $0x4f01, %ax
1722         int     $0x10
1724         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1726         popw    %es
1728         DATA32 call     real_to_prot
1729         .code32
1731         movl    %edx, %eax
1732         andl    $0x0FFFF, %eax  /* Return value in %eax.  */
1734         popl    %edi
1735         popl    %ebp
1736         ret
1739  * grub_vbe_status_t grub_vbe_bios_set_mode (grub_uint32_t mode,
1740  *                                           struct grub_vbe_crtc_info_block *crtc_info)
1742  * Register allocations for parameters:
1743  * %eax         mode
1744  * %edx         *crtc_info
1745  */
1746 FUNCTION(grub_vbe_bios_set_mode)
1747         pushl   %ebp
1748         pushl   %ebx
1749         pushl   %edi
1751         movl    %eax, %ebx      /* Store mode in %ebx.  */
1753         movw    %dx, %di        /* Store *crtc_info to %edx:%di.  */
1754         xorw    %dx, %dx
1755         shrl    $4, %edx
1757         call    prot_to_real
1758         .code16
1760         pushw   %es
1762         movw    %dx, %es        /* *crtc_info is now on %es:%di.  */
1764         movw    $0x4f02, %ax
1765         int     $0x10
1767         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1769         popw    %es
1771         DATA32 call     real_to_prot
1772         .code32
1774         movw    %dx, %ax
1775         andl    $0xFFFF, %eax   /* Return value in %eax.  */
1777         popl    %edi
1778         popl    %ebx
1779         popl    %ebp
1780         ret
1783  * grub_vbe_status_t grub_vbe_bios_get_mode (grub_uint32_t *mode)
1785  * Register allocations for parameters:
1786  * %eax         *mode
1787  */
1788 FUNCTION(grub_vbe_bios_get_mode)
1789         pushl   %ebp
1790         pushl   %ebx
1791         pushl   %edi
1792         pushl   %edx
1793         pushl   %eax            /* Push *mode to stack.  */
1795         call    prot_to_real
1796         .code16
1798         movw    $0x4f03, %ax
1799         int     $0x10
1801         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1803         DATA32 call     real_to_prot
1804         .code32
1806         popl    %edi            /* Pops *mode from stack to %edi.  */
1807         andl    $0xFFFF, %ebx
1808         movl    %ebx, (%edi)
1810         movw    %dx, %ax
1811         andl    $0xFFFF, %eax   /* Return value in %eax.  */
1813         popl    %edx
1814         popl    %edi
1815         popl    %ebx
1816         popl    %ebp
1817         ret
1820  * grub_vbe_status_t grub_vbe_bios_set_memory_window (grub_uint32_t window,
1821  *                                                    grub_uint32_t position);
1823  * Register allocations for parameters:
1824  * %eax         window
1825  * %edx         position
1826  */
1827 FUNCTION(grub_vbe_bios_set_memory_window)
1828         pushl   %ebp
1829         pushl   %ebx
1831         movl    %eax, %ebx
1833         call    prot_to_real
1834         .code16
1836         movw    $0x4f05, %ax
1837         andw    $0x00ff, %bx    /* BL = window, BH = 0, Set memory window.  */
1838         int     $0x10
1840         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1842         DATA32 call     real_to_prot
1843         .code32
1845         movw    %dx, %ax
1846         andl    $0xFFFF, %eax   /* Return value in %eax.  */
1848         popl    %ebx
1849         popl    %ebp
1850         ret
1853  * grub_vbe_status_t grub_vbe_bios_get_memory_window (grub_uint32_t window,
1854  *                                                    grub_uint32_t *position);
1856  * Register allocations for parameters:
1857  * %eax         window
1858  * %edx         *position
1859  */
1860 FUNCTION(grub_vbe_bios_get_memory_window)
1861         pushl   %ebp
1862         pushl   %ebx
1863         pushl   %edi
1864         pushl   %edx            /* Push *position to stack.  */
1866         movl    %eax, %ebx      /* Store window in %ebx.  */
1868         call    prot_to_real
1869         .code16
1871         movw    $0x4f05, %ax
1872         andw    $0x00ff, %bx    /* BL = window.  */
1873         orw     $0x0100, %bx    /* BH = 1, Get memory window.  */
1874         int     $0x10
1876         movw    %ax, %bx        /* real_to_prot destroys %eax.  */
1878         DATA32 call     real_to_prot
1879         .code32
1881         popl    %edi            /* pops *position from stack to %edi.  */
1882         andl    $0xFFFF, %edx
1883         movl    %edx, (%edi)    /* Return position to caller.  */
1885         movw    %bx, %ax
1886         andl    $0xFFFF, %eax   /* Return value in %eax.  */
1888         popl    %edi
1889         popl    %ebx
1890         popl    %ebp
1891         ret
1894  * grub_vbe_status_t grub_vbe_bios_set_scanline_length (grub_uint32_t length)
1896  * Register allocations for parameters:
1897  * %eax         length
1898  */
1899 FUNCTION(grub_vbe_bios_set_scanline_length)
1900         pushl   %ebp
1901         pushl   %ebx
1902         pushl   %edx
1904         movl    %eax, %ecx      /* Store length in %ecx.  */
1906         call    prot_to_real
1907         .code16
1909         movw    $0x4f06, %ax
1910         movw    $0x0002, %bx    /* BL = 2, Set Scan Line in Bytes.  */
1911         int     $0x10
1913         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1915         DATA32 call     real_to_prot
1916         .code32
1918         movw    %dx, %ax
1919         andl    $0xFFFF, %eax   /* Return value in %eax.  */
1921         popl    %edx
1922         popl    %ebx
1923         popl    %ebp
1924         ret
1927  * grub_vbe_status_t grub_vbe_bios_get_scanline_length (grub_uint32_t *length)
1929  * Register allocations for parameters:
1930  * %eax         *length
1931  */
1932 FUNCTION(grub_vbe_bios_get_scanline_length)
1933         pushl   %ebp
1934         pushl   %ebx
1935         pushl   %edi
1936         pushl   %edx            /* Push *length to stack.  */
1938         call    prot_to_real
1939         .code16
1941         movw    $0x4f06, %ax
1942         movw    $0x0001, %bx    /* BL = 1, Get Scan Line Length (in bytes).  */
1943         int     $0x10
1945         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1947         DATA32 call     real_to_prot
1948         .code32
1950         popl    %edi            /* Pops *length from stack to %edi.  */
1951         andl    $0xFFFF, %ebx
1952         movl    %ebx, (%edi)    /* Return length to caller.  */
1954         movw    %dx, %ax
1955         andl    $0xFFFF, %eax   /* Return value in %eax.  */
1957         popl    %edi
1958         popl    %ebx
1959         popl    %ebp
1960         ret
1963  * grub_vbe_status_t grub_vbe_bios_set_display_start (grub_uint32_t x,
1964  *                                                    grub_uint32_t y)
1966  * Register allocations for parameters:
1967  * %eax         x
1968  * %edx         y
1969  */
1970 FUNCTION(grub_vbe_bios_set_display_start)
1971         pushl   %ebp
1972         pushl   %ebx
1974         movl    %eax, %ecx      /* Store x in %ecx.  */
1976         call    prot_to_real
1977         .code16
1979         movw    $0x4f07, %ax
1980         movw    $0x0080, %bx    /* BL = 80h, Set Display Start
1981                                    during Vertical Retrace.  */
1982         int     $0x10
1984         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
1986         DATA32 call     real_to_prot
1987         .code32
1989         movw    %dx, %ax
1990         andl    $0xFFFF, %eax   /* Return value in %eax.  */
1992         popl    %ebx
1993         popl    %ebp
1994         ret
1997  * grub_vbe_status_t grub_vbe_bios_get_display_start (grub_uint32_t *x,
1998  *                                                    grub_uint32_t *y)
2000  * Register allocations for parameters:
2001  * %eax         *x
2002  * %edx         *y
2003  */
2004 FUNCTION(grub_vbe_bios_get_display_start)
2005         pushl   %ebp
2006         pushl   %ebx
2007         pushl   %edi
2008         pushl   %eax            /* Push *x to stack.  */
2009         pushl   %edx            /* Push *y to stack.  */
2011         call    prot_to_real
2012         .code16
2014         movw    $0x4f07, %ax
2015         movw    $0x0001, %bx    /* BL = 1, Get Display Start.  */
2016         int     $0x10
2018         movw    %ax, %bx        /* real_to_prot destroys %eax.  */
2020         DATA32 call     real_to_prot
2021         .code32
2023         popl    %edi            /* Pops *y from stack to %edi.  */
2024         andl    $0xFFFF, %edx
2025         movl    %edx, (%edi)    /* Return y-position to caller.  */
2027         popl    %edi            /* Pops *x from stack to %edi.  */
2028         andl    $0xFFFF, %ecx
2029         movl    %ecx, (%edi)    /* Return x-position to caller.  */
2031         movw    %bx, %ax
2032         andl    $0xFFFF, %eax   /* Return value in %eax.  */
2034         popl    %edi
2035         popl    %ebx
2036         popl    %ebp
2037         ret
2040  * grub_vbe_status_t grub_vbe_bios_set_palette_data (grub_uint32_t color_count,
2041  *                                                   grub_uint32_t start_index,
2042  *                                                   struct grub_vbe_palette_data *palette_data)
2044  * Register allocations for parameters:
2045  * %eax         color_count
2046  * %edx         start_index
2047  * %ecx         *palette_data
2048  */
2049 FUNCTION(grub_vbe_bios_set_palette_data)
2050         pushl   %ebp
2051         pushl   %ebx
2052         pushl   %edi
2054         movl    %eax, %ebx      /* Store color_count in %ebx.  */
2056         movw    %cx, %di        /* Store *palette_data to %ecx:%di.  */
2057         xorw    %cx, %cx
2058         shrl    $4, %ecx
2060         call    prot_to_real
2061         .code16
2063         pushw   %es
2065         movw    %cx, %es        /* *palette_data is now on %es:%di.  */
2066         movw    %bx, %cx        /* color_count is now on %cx.  */
2068         movw    $0x4f09, %ax
2069         xorw    %bx, %bx        /* BL = 0, Set Palette Data.  */
2070         int     $0x10
2072         movw    %ax, %dx        /* real_to_prot destroys %eax.  */
2074         popw    %es
2076         DATA32 call     real_to_prot
2077         .code32
2079         movw    %dx, %ax
2080         andl    $0xFFFF, %eax   /* Return value in %eax.  */
2082         popl    %edi
2083         popl    %ebx
2084         popl    %ebp
2085         ret
2088 pxe_rm_entry:
2089         .long   0
2092  * struct grub_pxenv *grub_pxe_scan (void);
2093  */
2094 FUNCTION(grub_pxe_scan)
2095         pushl   %ebp
2096         pushl   %ebx
2098         xorl    %ebx, %ebx
2099         xorl    %ecx, %ecx
2101         call    prot_to_real
2102         .code16
2104         pushw   %es
2106         movw    $0x5650, %ax
2107         int     $0x1A
2108         cmpw    $0x564E, %ax
2109         jnz     1f
2110         cmpl    $0x4E455850, %es:(%bx)          /* PXEN(V+)  */
2111         jnz     1f
2112         cmpw    $0x201, %es:6(%bx)              /* API version  */
2113         jb      1f
2114         lesw    %es:0x28(%bx), %bx              /* !PXE structure  */
2115         cmpl    $0x45585021, %es:(%bx)          /* !PXE  */
2116         jnz     1f
2117         movw    %es, %cx
2118         jmp     2f
2120         xorw    %bx, %bx
2121         xorw    %cx, %cx
2124         popw    %es
2126         DATA32 call     real_to_prot
2127         .code32
2129         xorl    %eax, %eax
2130         leal    (%eax, %ecx, 4), %ecx
2131         leal    (%ebx, %ecx, 4), %eax           /* eax = ecx * 16 + ebx  */
2133         orl     %eax, %eax
2134         jz      1f
2136         movl    0x10(%eax), %ecx
2137         movl    %ecx, pxe_rm_entry
2141         popl    %ebx
2142         popl    %ebp
2143         ret
2146  * int grub_pxe_call (int func, void* data);
2147  */
2148 FUNCTION(grub_pxe_call)
2149         pushl   %ebp
2150         movl    %esp, %ebp
2151         pushl   %esi
2152         pushl   %edi
2153         pushl   %ebx
2155         movl    %eax, %ecx
2156         movl    %edx, %eax
2157         andl    $0xF, %eax
2158         shrl    $4, %edx
2159         shll    $16, %edx
2160         addl    %eax, %edx
2161         movl    pxe_rm_entry, %ebx
2163         call    prot_to_real
2164         .code16
2166         pushl   %ebx
2167         pushl   %edx
2168         pushw   %cx
2169         movw    %sp, %bx
2170         lcall   *%ss:6(%bx)
2171         cld
2172         addw    $10, %sp
2173         movw    %ax, %cx
2175         DATA32  call    real_to_prot
2176         .code32
2178         movzwl  %cx, %eax
2180         popl    %ebx
2181         popl    %edi
2182         popl    %esi
2183         popl    %ebp
2184         ret