]> git.proxmox.com Git - grub2.git/blob - kern/i386/pc/startup.S
2006-04-23 Yoshinori K. Okuji <okuji@enbug.org>
[grub2.git] / kern / i386 / pc / startup.S
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 1999,2000,2001,2002,2003,2005,2006 Free Software Foundation, Inc.
4 *
5 * This program 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 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program 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 this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20
21 /*
22 * Note: These functions defined in this file may be called from C.
23 * Be careful of that you must not modify some registers. Quote
24 * from gcc-2.95.2/gcc/config/i386/i386.h:
25
26 1 for registers not available across function calls.
27 These must include the FIXED_REGISTERS and also any
28 registers that can be used without being saved.
29 The latter must include the registers where values are returned
30 and the register where structure-value addresses are passed.
31 Aside from that, you can include as many other registers as you like.
32
33 ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg
34 { 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
35 */
36
37 /*
38 * Note: GRUB is compiled with the options -mrtd and -mregparm=3.
39 * So the first three arguments are passed in %eax, %edx, and %ecx,
40 * respectively, and if a function has a fixed number of arguments
41 * and the number if greater than three, the function must return
42 * with "ret $N" where N is ((the number of arguments) - 3) * 4.
43 */
44
45 #include <config.h>
46 #include <grub/symbol.h>
47 #include <grub/boot.h>
48 #include <grub/machine/boot.h>
49 #include <grub/machine/memory.h>
50 #include <grub/machine/console.h>
51 #include <grub/machine/linux.h>
52 #include <grub/machine/kernel.h>
53 #include <grub/machine/multiboot.h>
54
55 #define ABS(x) ((x) - EXT_C(start) + GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200)
56
57 .file "startup.S"
58
59 .text
60
61 /* Tell GAS to generate 16-bit instructions so that this code works
62 in real mode. */
63 .code16
64
65 .globl start, _start
66 start:
67 _start:
68 /*
69 * Guarantee that "main" is loaded at 0x0:0x8200.
70 */
71 ljmp $0, $ABS(codestart)
72
73 /*
74 * Compatibility version number
75 *
76 * These MUST be at byte offset 6 and 7 of the executable
77 * DO NOT MOVE !!!
78 */
79 . = EXT_C(start) + 0x6
80 .byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR
81
82 /*
83 * This is a special data area 8 bytes from the beginning.
84 */
85
86 . = EXT_C(start) + 0x8
87
88 VARIABLE(grub_total_module_size)
89 .long 0
90 VARIABLE(grub_kernel_image_size)
91 .long 0
92 VARIABLE(grub_compressed_size)
93 .long 0
94 VARIABLE(grub_install_dos_part)
95 .long 0xFFFFFFFF
96 VARIABLE(grub_install_bsd_part)
97 .long 0xFFFFFFFF
98 VARIABLE(grub_prefix)
99 .string "/boot/grub"
100
101 /*
102 * Leave some breathing room for the prefix.
103 */
104
105 . = EXT_C(start) + 0x50
106
107 /*
108 * Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself).
109 * This uses the a.out kludge to load raw binary to the area starting at 1MB,
110 * and relocates itself after loaded.
111 */
112 multiboot_header:
113 /* magic */
114 .long 0x1BADB002
115 /* flags */
116 .long (1 << 16)
117 /* checksum */
118 .long -0x1BADB002 - (1 << 16)
119 /* header addr */
120 .long multiboot_header - _start + 0x100000 + 0x200
121 /* load addr */
122 .long 0x100000
123 /* load end addr */
124 .long 0
125 /* bss end addr */
126 .long 0
127 /* entry addr */
128 .long multiboot_entry - _start + 0x100000 + 0x200
129
130 multiboot_entry:
131 .code32
132 /* obtain the boot device */
133 movl 12(%ebx), %edx
134
135 /* relocate the code */
136 movl $(GRUB_KERNEL_MACHINE_RAW_SIZE + 0x200), %ecx
137 addl EXT_C(grub_compressed_size) - _start + 0x100000 + 0x200, %ecx
138 movl $0x100000, %esi
139 movl $GRUB_BOOT_MACHINE_KERNEL_ADDR, %edi
140 cld
141 rep
142 movsb
143 /* jump to the real address */
144 movl $multiboot_trampoline, %eax
145 jmp *%eax
146
147 multiboot_trampoline:
148 /* fill the boot information */
149 movl %edx, %eax
150 shrl $8, %eax
151 xorl %ebx, %ebx
152 cmpb $0xFF, %ah
153 je 1f
154 movb %ah, %bl
155 movl %ebx, EXT_C(grub_install_dos_part)
156 1:
157 cmpb $0xFF, %al
158 je 2f
159 movb %al, %bl
160 movl %ebx, EXT_C(grub_install_bsd_part)
161 2:
162 shrl $24, %edx
163 /* enter the usual booting */
164 call prot_to_real
165 .code16
166
167 /* the real mode code continues... */
168 codestart:
169 cli /* we're not safe here! */
170
171 /* set up %ds, %ss, and %es */
172 xorw %ax, %ax
173 movw %ax, %ds
174 movw %ax, %ss
175 movw %ax, %es
176
177 /* set up the real mode/BIOS stack */
178 movl $GRUB_MEMORY_MACHINE_REAL_STACK, %ebp
179 movl %ebp, %esp
180
181 sti /* we're safe again */
182
183 /* save boot drive reference */
184 ADDR32 movb %dl, EXT_C(grub_boot_drive)
185
186 /* reset disk system (%ah = 0) */
187 int $0x13
188
189 /* transition to protected mode */
190 DATA32 call real_to_prot
191
192 /* The ".code32" directive takes GAS out of 16-bit mode. */
193 .code32
194
195 incl %eax
196 call EXT_C(grub_gate_a20)
197
198 /* decompress the compressed part and put the result at 1MB */
199 movl $0x100000, %esi
200 movl $(START_SYMBOL + GRUB_KERNEL_MACHINE_RAW_SIZE), %edi
201
202 pushl %esi
203 pushl EXT_C(grub_compressed_size)
204 pushl %edi
205 call lzo1x_decompress
206 addl $12, %esp
207
208 /* copy back the decompressed part */
209 movl %eax, %ecx
210 cld
211 rep
212 movsb
213
214 /* copy modules before cleaning out the bss */
215 movl EXT_C(grub_total_module_size), %ecx
216 movl EXT_C(grub_kernel_image_size), %esi
217 addl %ecx, %esi
218 addl $START_SYMBOL, %esi
219 decl %esi
220 movl $END_SYMBOL, %edi
221 addl %ecx, %edi
222 decl %edi
223 std
224 rep
225 movsb
226
227 /* clean out the bss */
228 movl $BSS_START_SYMBOL, %edi
229
230 /* compute the bss length */
231 movl $END_SYMBOL, %ecx
232 subl %edi, %ecx
233
234 /* clean out */
235 xorl %eax, %eax
236 cld
237 rep
238 stosb
239
240 /*
241 * Call the start of main body of C code.
242 */
243 call EXT_C(grub_main)
244
245
246 /*
247 * This is the area for all of the special variables.
248 */
249
250 .p2align 2 /* force 4-byte alignment */
251
252 protstack:
253 .long GRUB_MEMORY_MACHINE_PROT_STACK
254
255 VARIABLE(grub_boot_drive)
256 .long 0
257
258 VARIABLE(grub_start_addr)
259 .long START_SYMBOL
260
261 VARIABLE(grub_end_addr)
262 .long END_SYMBOL
263
264 VARIABLE(grub_apm_bios_info)
265 .word 0 /* version */
266 .word 0 /* cseg */
267 .long 0 /* offset */
268 .word 0 /* cseg_16 */
269 .word 0 /* dseg_16 */
270 .word 0 /* cseg_len */
271 .word 0 /* cseg_16_len */
272 .word 0 /* dseg_16_len */
273
274 /*
275 * This is the Global Descriptor Table
276 *
277 * An entry, a "Segment Descriptor", looks like this:
278 *
279 * 31 24 19 16 7 0
280 * ------------------------------------------------------------
281 * | | |B| |A| | | |1|0|E|W|A| |
282 * | BASE 31..24 |G|/|L|V| LIMIT |P|DPL| TYPE | BASE 23:16 | 4
283 * | | |D| |L| 19..16| | |1|1|C|R|A| |
284 * ------------------------------------------------------------
285 * | | |
286 * | BASE 15..0 | LIMIT 15..0 | 0
287 * | | |
288 * ------------------------------------------------------------
289 *
290 * Note the ordering of the data items is reversed from the above
291 * description.
292 */
293
294 .p2align 2 /* force 4-byte alignment */
295 gdt:
296 .word 0, 0
297 .byte 0, 0, 0, 0
298
299 /* -- code segment --
300 * base = 0x00000000, limit = 0xFFFFF (4 KiB Granularity), present
301 * type = 32bit code execute/read, DPL = 0
302 */
303 .word 0xFFFF, 0
304 .byte 0, 0x9A, 0xCF, 0
305
306 /* -- data segment --
307 * base = 0x00000000, limit 0xFFFFF (4 KiB Granularity), present
308 * type = 32 bit data read/write, DPL = 0
309 */
310 .word 0xFFFF, 0
311 .byte 0, 0x92, 0xCF, 0
312
313 /* -- 16 bit real mode CS --
314 * base = 0x00000000, limit 0x0FFFF (1 B Granularity), present
315 * type = 16 bit code execute/read only/conforming, DPL = 0
316 */
317 .word 0xFFFF, 0
318 .byte 0, 0x9E, 0, 0
319
320 /* -- 16 bit real mode DS --
321 * base = 0x00000000, limit 0x0FFFF (1 B Granularity), present
322 * type = 16 bit data read/write, DPL = 0
323 */
324 .word 0xFFFF, 0
325 .byte 0, 0x92, 0, 0
326
327
328 /* this is the GDT descriptor */
329 gdtdesc:
330 .word 0x27 /* limit */
331 .long gdt /* addr */
332
333
334 /*
335 * These next two routines, "real_to_prot" and "prot_to_real" are structured
336 * in a very specific way. Be very careful when changing them.
337 *
338 * NOTE: Use of either one messes up %eax and %ebp.
339 */
340
341 real_to_prot:
342 .code16
343 cli
344
345 /* load the GDT register */
346 DATA32 ADDR32 lgdt gdtdesc
347
348 /* turn on protected mode */
349 movl %cr0, %eax
350 orl $GRUB_MEMORY_MACHINE_CR0_PE_ON, %eax
351 movl %eax, %cr0
352
353 /* jump to relocation, flush prefetch queue, and reload %cs */
354 DATA32 ljmp $GRUB_MEMORY_MACHINE_PROT_MODE_CSEG, $protcseg
355
356 .code32
357 protcseg:
358 /* reload other segment registers */
359 movw $GRUB_MEMORY_MACHINE_PROT_MODE_DSEG, %ax
360 movw %ax, %ds
361 movw %ax, %es
362 movw %ax, %fs
363 movw %ax, %gs
364 movw %ax, %ss
365
366 /* put the return address in a known safe location */
367 movl (%esp), %eax
368 movl %eax, GRUB_MEMORY_MACHINE_REAL_STACK
369
370 /* get protected mode stack */
371 movl protstack, %eax
372 movl %eax, %esp
373 movl %eax, %ebp
374
375 /* get return address onto the right stack */
376 movl GRUB_MEMORY_MACHINE_REAL_STACK, %eax
377 movl %eax, (%esp)
378
379 /* zero %eax */
380 xorl %eax, %eax
381
382 /* return on the old (or initialized) stack! */
383 ret
384
385
386 prot_to_real:
387 /* just in case, set GDT */
388 lgdt gdtdesc
389
390 /* save the protected mode stack */
391 movl %esp, %eax
392 movl %eax, protstack
393
394 /* get the return address */
395 movl (%esp), %eax
396 movl %eax, GRUB_MEMORY_MACHINE_REAL_STACK
397
398 /* set up new stack */
399 movl $GRUB_MEMORY_MACHINE_REAL_STACK, %eax
400 movl %eax, %esp
401 movl %eax, %ebp
402
403 /* set up segment limits */
404 movw $GRUB_MEMORY_MACHINE_PSEUDO_REAL_DSEG, %ax
405 movw %ax, %ds
406 movw %ax, %es
407 movw %ax, %fs
408 movw %ax, %gs
409 movw %ax, %ss
410
411 /* this might be an extra step */
412 /* jump to a 16 bit segment */
413 ljmp $GRUB_MEMORY_MACHINE_PSEUDO_REAL_CSEG, $tmpcseg
414
415 tmpcseg:
416 .code16
417
418 /* clear the PE bit of CR0 */
419 movl %cr0, %eax
420 andl $(~GRUB_MEMORY_MACHINE_CR0_PE_ON), %eax
421 movl %eax, %cr0
422
423 /* flush prefetch queue, reload %cs */
424 DATA32 ljmp $0, $realcseg
425
426 realcseg:
427 /* we are in real mode now
428 * set up the real mode segment registers : DS, SS, ES
429 */
430 /* zero %eax */
431 xorl %eax, %eax
432
433 movw %ax, %ds
434 movw %ax, %es
435 movw %ax, %fs
436 movw %ax, %gs
437 movw %ax, %ss
438
439 /* restore interrupts */
440 sti
441
442 /* return on new stack! */
443 DATA32 ret
444
445 .code32
446
447
448 /*
449 * grub_gate_a20(int on)
450 *
451 * Gate address-line 20 for high memory.
452 *
453 * This routine is probably overconservative in what it does, but so what?
454 *
455 * It also eats any keystrokes in the keyboard buffer. :-(
456 */
457
458 FUNCTION(grub_gate_a20)
459 movl %eax, %edx
460
461 gate_a20_test_current_state:
462 /* first of all, test if already in a good state */
463 call gate_a20_check_state
464 cmpb %al, %dl
465 jnz gate_a20_try_bios
466 ret
467
468 gate_a20_try_bios:
469 /* second, try a BIOS call */
470 pushl %ebp
471 call prot_to_real
472
473 .code16
474 movw $0x2400, %ax
475 testb %dl, %dl
476 jz 1f
477 incw %ax
478 1: int $0x15
479
480 DATA32 call real_to_prot
481 .code32
482
483 popl %ebp
484 call gate_a20_check_state
485 cmpb %al, %dl
486 jnz gate_a20_try_keyboard_controller
487 ret
488
489 gate_a20_flush_keyboard_buffer:
490 inb $0x64
491 andb $0x02, %al
492 jnz gate_a20_flush_keyboard_buffer
493 2:
494 inb $0x64
495 andb $0x01, %al
496 jz 3f
497 inb $0x60
498 jmp 2b
499 3:
500 ret
501
502 gate_a20_try_keyboard_controller:
503 /* third, try the keyboard controller */
504 call gate_a20_flush_keyboard_buffer
505
506 movb $0xd1, %al
507 outb $0x64
508 4:
509 inb $0x64
510 andb $0x02, %al
511 jnz 4b
512
513 movb $0xdd, %al
514 testb %dl, %dl
515 jz 5f
516 orb $0x02, %al
517 5: outb $0x60
518 call gate_a20_flush_keyboard_buffer
519
520 /* output a dummy command (USB keyboard hack) */
521 movb $0xff, %al
522 outb $0x64
523 call gate_a20_flush_keyboard_buffer
524
525 call gate_a20_check_state
526 cmpb %al, %dl
527 jnz gate_a20_try_system_control_port_a
528 ret
529
530 gate_a20_try_system_control_port_a:
531 /* fourth, try the system control port A */
532 inb $0x92
533 andb $(~0x03), %al
534 testb %dl, %dl
535 jz 6f
536 orb $0x02, %al
537 6: outb $0x92
538
539 /* When turning off Gate A20, do not check the state strictly,
540 because a failure is not fatal usually, and Gate A20 is always
541 on some modern machines. */
542 testb %dl, %dl
543 jz 7f
544 call gate_a20_check_state
545 cmpb %al, %dl
546 /* everything failed, so restart from the beginning */
547 jnz gate_a20_try_bios
548 7: ret
549
550 gate_a20_check_state:
551 /* iterate the checking for a while */
552 movl $100, %ecx
553 1:
554 call 3f
555 cmpb %al, %dl
556 jz 2f
557 loop 1b
558 2:
559 ret
560 3:
561 pushl %ebx
562 pushl %ecx
563 xorl %eax, %eax
564 /* compare the byte at 0x8000 with that at 0x108000 */
565 movl $GRUB_BOOT_MACHINE_KERNEL_ADDR, %ebx
566 pushl %ebx
567 /* save the original byte in CL */
568 movb (%ebx), %cl
569 /* store the value at 0x108000 in AL */
570 addl $0x100000, %ebx
571 movb (%ebx), %al
572 /* try to set one less value at 0x8000 */
573 popl %ebx
574 movb %al, %ch
575 decb %ch
576 movb %ch, (%ebx)
577 /* serialize */
578 outb %al, $0x80
579 outb %al, $0x80
580 /* obtain the value at 0x108000 in CH */
581 pushl %ebx
582 addl $0x100000, %ebx
583 movb (%ebx), %ch
584 /* this result is 1 if A20 is on or 0 if it is off */
585 subb %ch, %al
586 xorb $1, %al
587 /* restore the original */
588 popl %ebx
589 movb %cl, (%ebx)
590 popl %ecx
591 popl %ebx
592 ret
593
594 #include "lzo1x.S"
595
596
597 /*
598 * This call is special... it never returns... in fact it should simply
599 * hang at this point!
600 */
601
602 FUNCTION(grub_stop)
603 call prot_to_real
604
605 /*
606 * This next part is sort of evil. It takes advantage of the
607 * byte ordering on the x86 to work in either 16-bit or 32-bit
608 * mode, so think about it before changing it.
609 */
610
611 FUNCTION(grub_hard_stop)
612 hlt
613 jmp EXT_C(grub_hard_stop)
614
615
616 /*
617 * grub_stop_floppy()
618 *
619 * Stop the floppy drive from spinning, so that other software is
620 * jumped to with a known state.
621 */
622 FUNCTION(grub_stop_floppy)
623 movw $0x3F2, %dx
624 xorb %al, %al
625 outb %al, %dx
626 ret
627
628 /*
629 * grub_exit()
630 *
631 * Exit the system.
632 */
633 FUNCTION(grub_exit)
634 call prot_to_real
635 .code16
636 /* Tell the BIOS a boot failure. If this does not work, reboot. */
637 int $0x18
638 jmp cold_reboot
639
640 /*
641 * grub_reboot()
642 *
643 * Reboot the system. At the moment, rely on BIOS.
644 */
645 FUNCTION(grub_reboot)
646 call prot_to_real
647 .code16
648 cold_reboot:
649 /* cold boot */
650 movw $0x0472, %di
651 movw %ax, (%di)
652 ljmp $0xFFFF, $0x0000
653 .code32
654
655 /*
656 * grub_halt(int no_apm)
657 *
658 * Halt the system, using APM if possible. If NO_APM is true, don't use
659 * APM even if it is available.
660 */
661 FUNCTION(grub_halt)
662 /* see if zero */
663 testl %eax, %eax
664 jnz EXT_C(grub_stop)
665
666 call prot_to_real
667 .code16
668
669 /* detect APM */
670 movw $0x5300, %ax
671 xorw %bx, %bx
672 int $0x15
673 jc EXT_C(grub_hard_stop)
674 /* don't check %bx for buggy BIOSes... */
675
676 /* disconnect APM first */
677 movw $0x5304, %ax
678 xorw %bx, %bx
679 int $0x15
680
681 /* connect APM */
682 movw $0x5301, %ax
683 xorw %bx, %bx
684 int $0x15
685 jc EXT_C(grub_hard_stop)
686
687 /* set APM protocol level - 1.1 or bust. (this covers APM 1.2 also) */
688 movw $0x530E, %ax
689 xorw %bx, %bx
690 movw $0x0101, %cx
691 int $0x15
692 jc EXT_C(grub_hard_stop)
693
694 /* set the power state to off */
695 movw $0x5307, %ax
696 movw $1, %bx
697 movw $3, %cx
698 int $0x15
699
700 /* shouldn't reach here */
701 jmp EXT_C(grub_hard_stop)
702 .code32
703
704
705 /*
706 * void grub_chainloader_real_boot (int drive, void *part_addr)
707 *
708 * This starts another boot loader.
709 */
710
711 FUNCTION(grub_chainloader_real_boot)
712 pushl %edx
713 pushl %eax
714
715 call EXT_C(grub_dl_unload_all)
716
717 /* set up to pass boot drive */
718 popl %edx
719
720 /* ESI must point to a partition table entry */
721 popl %esi
722
723 /* Turn off Gate A20 */
724 xorl %eax, %eax
725 call EXT_C(grub_gate_a20)
726
727 call prot_to_real
728 .code16
729 ljmp $0, $GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR
730 .code32
731
732
733 /*
734 * void grub_linux_boot_zimage (void)
735 */
736 VARIABLE(grub_linux_prot_size)
737 .long 0
738 VARIABLE(grub_linux_tmp_addr)
739 .long 0
740 VARIABLE(grub_linux_real_addr)
741 .long 0
742
743 FUNCTION(grub_linux_boot_zimage)
744 /* copy the kernel */
745 movl EXT_C(grub_linux_prot_size), %ecx
746 addl $3, %ecx
747 shrl $2, %ecx
748 movl $GRUB_LINUX_BZIMAGE_ADDR, %esi
749 movl $GRUB_LINUX_ZIMAGE_ADDR, %edi
750 cld
751 rep
752 movsl
753
754 FUNCTION(grub_linux_boot_bzimage)
755 call EXT_C(grub_dl_unload_all)
756
757 movl EXT_C(grub_linux_real_addr), %ebx
758
759 /* copy the real mode code */
760 movl EXT_C(grub_linux_tmp_addr), %esi
761 movl %ebx, %edi
762 movl $GRUB_LINUX_SETUP_MOVE_SIZE, %ecx
763 cld
764 rep
765 movsb
766
767 /* change %ebx to the segment address */
768 shrl $4, %ebx
769 movl %ebx, %eax
770 addl $0x20, %eax
771 movw %ax, linux_setup_seg
772
773 /* XXX new stack pointer in safe area for calling functions */
774 movl $0x4000, %esp
775 call EXT_C(grub_stop_floppy)
776
777 /* final setup for linux boot */
778 call prot_to_real
779 .code16
780
781 cli
782 movw %bx, %ss
783 movw $GRUB_LINUX_SETUP_STACK, %sp
784
785 movw %bx, %ds
786 movw %bx, %es
787 movw %bx, %fs
788 movw %bx, %gs
789
790 /* ljmp */
791 .byte 0xea
792 .word 0
793 linux_setup_seg:
794 .word 0
795 .code32
796
797
798 /*
799 * This starts the multiboot kernel.
800 */
801
802 FUNCTION(grub_multiboot_real_boot)
803 /* Push the entry address on the stack. */
804 pushl %eax
805 /* Move the address of the multiboot information structure to ebx. */
806 movl %edx,%ebx
807
808 /* Unload all modules and stop the floppy driver. */
809 call EXT_C(grub_dl_unload_all)
810 call EXT_C(grub_stop_floppy)
811
812 /* Interrupts should be disabled. */
813 cli
814
815 /* Move the magic value into eax and jump to the kernel. */
816 movl $GRUB_MB_MAGIC2,%eax
817 popl %ecx
818 jmp *%ecx
819
820
821 /*
822 * int grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap)
823 *
824 * Call IBM/MS INT13 Extensions (int 13 %ah=AH) for DRIVE. DAP
825 * is passed for disk address packet. If an error occurs, return
826 * non-zero, otherwise zero.
827 */
828
829 FUNCTION(grub_biosdisk_rw_int13_extensions)
830 pushl %ebp
831 pushl %esi
832
833 /* compute the address of disk_address_packet */
834 movw %cx, %si
835 xorw %cx, %cx
836 shrl $4, %ecx /* save the segment to cx */
837
838 /* ah */
839 movb %al, %dh
840 /* enter real mode */
841 call prot_to_real
842
843 .code16
844 movb %dh, %ah
845 movw %cx, %ds
846 int $0x13 /* do the operation */
847 movb %ah, %dl /* save return value */
848 /* clear the data segment */
849 xorw %ax, %ax
850 movw %ax, %ds
851 /* back to protected mode */
852 DATA32 call real_to_prot
853 .code32
854
855 movb %dl, %al /* return value in %eax */
856
857 popl %esi
858 popl %ebp
859
860 ret
861
862 /*
863 * int grub_biosdisk_rw_standard (int ah, int drive, int coff, int hoff,
864 * int soff, int nsec, int segment)
865 *
866 * Call standard and old INT13 (int 13 %ah=AH) for DRIVE. Read/write
867 * NSEC sectors from COFF/HOFF/SOFF into SEGMENT. If an error occurs,
868 * return non-zero, otherwise zero.
869 */
870
871 FUNCTION(grub_biosdisk_rw_standard)
872 pushl %ebp
873 movl %esp, %ebp
874
875 pushl %ebx
876 pushl %edi
877 pushl %esi
878
879 /* set up CHS information */
880
881 /* set %ch to low eight bits of cylinder */
882 xchgb %cl, %ch
883 /* set bits 6-7 of %cl to high two bits of cylinder */
884 shlb $6, %cl
885 /* set bits 0-5 of %cl to sector */
886 addb 0xc(%ebp), %cl
887 /* set %dh to head */
888 movb 0x8(%ebp), %dh
889 /* set %ah to AH */
890 movb %al, %ah
891 /* set %al to NSEC */
892 movb 0x10(%ebp), %al
893 /* save %ax in %di */
894 movw %ax, %di
895 /* save SEGMENT in %bx */
896 movw 0x14(%ebp), %bx
897
898 /* enter real mode */
899 call prot_to_real
900
901 .code16
902 movw %bx, %es
903 xorw %bx, %bx
904 movw $3, %si /* attempt at least three times */
905
906 1:
907 movw %di, %ax
908 int $0x13 /* do the operation */
909 jnc 2f /* check if successful */
910
911 movb %ah, %bl /* save return value */
912 /* if fail, reset the disk system */
913 xorw %ax, %ax
914 int $0x13
915
916 decw %si
917 cmpw $0, %si
918 je 2f
919 xorb %bl, %bl
920 jmp 1b /* retry */
921 2:
922 /* back to protected mode */
923 DATA32 call real_to_prot
924 .code32
925
926 movb %bl, %al /* return value in %eax */
927
928 popl %esi
929 popl %edi
930 popl %ebx
931 popl %ebp
932
933 ret $(4 * 4)
934
935
936 /*
937 * int grub_biosdisk_check_int13_extensions (int drive)
938 *
939 * Check if LBA is supported for DRIVE. If it is supported, then return
940 * the major version of extensions, otherwise zero.
941 */
942
943 FUNCTION(grub_biosdisk_check_int13_extensions)
944 pushl %ebp
945 pushl %ebx
946
947 /* drive */
948 movb %al, %dl
949 /* enter real mode */
950 call prot_to_real
951
952 .code16
953 movb $0x41, %ah
954 movw $0x55aa, %bx
955 int $0x13 /* do the operation */
956
957 /* check the result */
958 jc 1f
959 cmpw $0xaa55, %bx
960 jne 1f
961
962 movb %ah, %bl /* save the major version into %bl */
963
964 /* check if AH=0x42 is supported */
965 andw $1, %cx
966 jnz 2f
967
968 1:
969 xorb %bl, %bl
970 2:
971 /* back to protected mode */
972 DATA32 call real_to_prot
973 .code32
974
975 movb %bl, %al /* return value in %eax */
976
977 popl %ebx
978 popl %ebp
979
980 ret
981
982
983 /*
984 * int grub_biosdisk_get_diskinfo_int13_extensions (int drive, void *drp)
985 *
986 * Return the geometry of DRIVE in a drive parameters, DRP. If an error
987 * occurs, then return non-zero, otherwise zero.
988 */
989
990 FUNCTION(grub_biosdisk_get_diskinfo_int13_extensions)
991 pushl %ebp
992 pushl %ebx
993 pushl %esi
994
995 /* compute the address of drive parameters */
996 movw %dx, %si
997 xorw %dx, %dx
998 shrl $4, %edx
999 movw %dx, %bx /* save the segment into %bx */
1000 /* drive */
1001 movb %al, %dl
1002 /* enter real mode */
1003 call prot_to_real
1004
1005 .code16
1006 movb $0x48, %ah
1007 movw %bx, %ds
1008 int $0x13 /* do the operation */
1009 movb %ah, %bl /* save return value in %bl */
1010 /* clear the data segment */
1011 xorw %ax, %ax
1012 movw %ax, %ds
1013 /* back to protected mode */
1014 DATA32 call real_to_prot
1015 .code32
1016
1017 movb %bl, %al /* return value in %eax */
1018
1019 popl %esi
1020 popl %ebx
1021 popl %ebp
1022
1023 ret
1024
1025
1026 /*
1027 * int grub_biosdisk_get_diskinfo_standard (int drive,
1028 * unsigned long *cylinders,
1029 * unsigned long *heads,
1030 * unsigned long *sectors)
1031 *
1032 * Return the geometry of DRIVE in CYLINDERS, HEADS and SECTORS. If an
1033 * error occurs, then return non-zero, otherwise zero.
1034 */
1035
1036 FUNCTION(grub_biosdisk_get_diskinfo_standard)
1037 pushl %ebp
1038 pushl %ebx
1039 pushl %edi
1040
1041 /* push CYLINDERS */
1042 pushl %edx
1043 /* push HEADS */
1044 pushl %ecx
1045 /* SECTORS is on the stack */
1046
1047 /* drive */
1048 movb %al, %dl
1049 /* enter real mode */
1050 call prot_to_real
1051
1052 .code16
1053 movb $0x8, %ah
1054 int $0x13 /* do the operation */
1055 /* check if successful */
1056 testb %ah, %ah
1057 jnz 1f
1058 /* bogus BIOSes may not return an error number */
1059 testb $0x3f, %cl /* 0 sectors means no disk */
1060 jnz 1f /* if non-zero, then succeed */
1061 /* XXX 0x60 is one of the unused error numbers */
1062 movb $0x60, %ah
1063 1:
1064 movb %ah, %bl /* save return value in %bl */
1065 /* back to protected mode */
1066 DATA32 call real_to_prot
1067 .code32
1068
1069 /* pop HEADS */
1070 popl %edi
1071 movb %dh, %al
1072 incl %eax /* the number of heads is counted from zero */
1073 movl %eax, (%edi)
1074
1075 /* pop CYLINDERS */
1076 popl %edi
1077 movb %ch, %al
1078 movb %cl, %ah
1079 shrb $6, %ah /* the number of cylinders is counted from zero */
1080 incl %eax
1081 movl %eax, (%edi)
1082
1083 /* SECTORS */
1084 movl 0x10(%esp), %edi
1085 andb $0x3f, %cl
1086 movzbl %cl, %eax
1087 movl %eax, (%edi)
1088
1089 xorl %eax, %eax
1090 movb %bl, %al /* return value in %eax */
1091
1092 popl %edi
1093 popl %ebx
1094 popl %ebp
1095
1096 ret $4
1097
1098
1099 /*
1100 * int grub_biosdisk_get_num_floppies (void)
1101 */
1102 FUNCTION(grub_biosdisk_get_num_floppies)
1103 pushl %ebp
1104
1105 xorl %edx, %edx
1106 call prot_to_real
1107
1108 .code16
1109 /* reset the disk system first */
1110 int $0x13
1111 1:
1112 stc
1113
1114 /* call GET DISK TYPE */
1115 movb $0x15, %ah
1116 int $0x13
1117
1118 jc 2f
1119
1120 /* check if this drive exists */
1121 testb $0x3, %ah
1122 jz 2f
1123
1124 incb %dl
1125 cmpb $2, %dl
1126 jne 1b
1127 2:
1128 DATA32 call real_to_prot
1129 .code32
1130
1131 movl %edx, %eax
1132 popl %ebp
1133 ret
1134
1135
1136 /*
1137 *
1138 * grub_get_memsize(i) : return the memory size in KB. i == 0 for conventional
1139 * memory, i == 1 for extended memory
1140 * BIOS call "INT 12H" to get conventional memory size
1141 * BIOS call "INT 15H, AH=88H" to get extended memory size
1142 * Both have the return value in AX.
1143 *
1144 */
1145
1146 FUNCTION(grub_get_memsize)
1147 pushl %ebp
1148
1149 movl %eax, %edx
1150
1151 call prot_to_real /* enter real mode */
1152 .code16
1153
1154 testl %edx, %edx
1155 jnz xext
1156
1157 int $0x12
1158 jmp xdone
1159
1160 xext:
1161 movb $0x88, %ah
1162 int $0x15
1163
1164 xdone:
1165 movw %ax, %dx
1166
1167 DATA32 call real_to_prot
1168 .code32
1169
1170 movw %dx, %ax
1171
1172 popl %ebp
1173 ret
1174
1175
1176 /*
1177 *
1178 * grub_get_eisa_mmap() : return packed EISA memory map, lower 16 bits is
1179 * memory between 1M and 16M in 1K parts, upper 16 bits is
1180 * memory above 16M in 64K parts. If error, return zero.
1181 * BIOS call "INT 15H, AH=E801H" to get EISA memory map,
1182 * AX = memory between 1M and 16M in 1K parts.
1183 * BX = memory above 16M in 64K parts.
1184 *
1185 */
1186
1187 FUNCTION(grub_get_eisa_mmap)
1188 pushl %ebp
1189 pushl %ebx
1190
1191 call prot_to_real /* enter real mode */
1192 .code16
1193
1194 movw $0xe801, %ax
1195 int $0x15
1196
1197 shll $16, %ebx
1198 movw %ax, %bx
1199
1200 DATA32 call real_to_prot
1201 .code32
1202
1203 cmpb $0x86, %bh
1204 je xnoteisa
1205
1206 movl %ebx, %eax
1207
1208 xnoteisa:
1209 popl %ebx
1210 popl %ebp
1211 ret
1212
1213 /*
1214 *
1215 * grub_get_mmap_entry(addr, cont) : address and old continuation value (zero to
1216 * start), for the Query System Address Map BIOS call.
1217 *
1218 * Sets the first 4-byte int value of "addr" to the size returned by
1219 * the call. If the call fails, sets it to zero.
1220 *
1221 * Returns: new (non-zero) continuation value, 0 if done.
1222 */
1223
1224 FUNCTION(grub_get_mmap_entry)
1225 pushl %ebp
1226 pushl %ebx
1227 pushl %edi
1228 pushl %esi
1229
1230 /* push ADDR */
1231 pushl %eax
1232
1233 /* place address (+4) in ES:DI */
1234 addl $4, %eax
1235 movl %eax, %edi
1236 andl $0xf, %edi
1237 shrl $4, %eax
1238 movl %eax, %esi
1239
1240 /* set continuation value */
1241 movl %edx, %ebx
1242
1243 /* set default maximum buffer size */
1244 movl $0x14, %ecx
1245
1246 /* set EDX to 'SMAP' */
1247 movl $0x534d4150, %edx
1248
1249 call prot_to_real /* enter real mode */
1250 .code16
1251
1252 movw %si, %es
1253 movl $0xe820, %eax
1254 int $0x15
1255
1256 DATA32 jc xnosmap
1257
1258 cmpl $0x534d4150, %eax
1259 jne xnosmap
1260
1261 cmpl $0x14, %ecx
1262 jl xnosmap
1263
1264 cmpl $0x400, %ecx
1265 jg xnosmap
1266
1267 jmp xsmap
1268
1269 xnosmap:
1270 xorl %ecx, %ecx
1271
1272 xsmap:
1273 DATA32 call real_to_prot
1274 .code32
1275
1276 /* write length of buffer (zero if error) into ADDR */
1277 popl %eax
1278 movl %ecx, (%eax)
1279
1280 /* set return value to continuation */
1281 movl %ebx, %eax
1282
1283 popl %esi
1284 popl %edi
1285 popl %ebx
1286 popl %ebp
1287 ret
1288
1289
1290 /*
1291 * void grub_console_real_putchar (int c)
1292 *
1293 * Put the character C on the console. Because GRUB wants to write a
1294 * character with an attribute, this implementation is a bit tricky.
1295 * If C is a control character (CR, LF, BEL, BS), use INT 10, AH = 0Eh
1296 * (TELETYPE OUTPUT). Otherwise, save the original position, put a space,
1297 * save the current position, restore the original position, write the
1298 * character and the attribute, and restore the current position.
1299 *
1300 * The reason why this is so complicated is that there is no easy way to
1301 * get the height of the screen, and the TELETYPE OUPUT BIOS call doesn't
1302 * support setting a background attribute.
1303 */
1304 FUNCTION(grub_console_real_putchar)
1305 movl %eax, %edx
1306 pusha
1307 movb EXT_C(grub_console_cur_color), %bl
1308
1309 call prot_to_real
1310 .code16
1311 movb %dl, %al
1312 xorb %bh, %bh
1313
1314 /* use teletype output if control character */
1315 cmpb $0x7, %al
1316 je 1f
1317 cmpb $0x8, %al
1318 je 1f
1319 cmpb $0xa, %al
1320 je 1f
1321 cmpb $0xd, %al
1322 je 1f
1323
1324 /* save the character and the attribute on the stack */
1325 pushw %ax
1326 pushw %bx
1327
1328 /* get the current position */
1329 movb $0x3, %ah
1330 int $0x10
1331
1332 /* check the column with the width */
1333 cmpb $79, %dl
1334 jl 2f
1335
1336 /* print CR and LF, if next write will exceed the width */
1337 movw $0x0e0d, %ax
1338 int $0x10
1339 movb $0x0a, %al
1340 int $0x10
1341
1342 /* get the current position */
1343 movb $0x3, %ah
1344 int $0x10
1345
1346 2:
1347 /* restore the character and the attribute */
1348 popw %bx
1349 popw %ax
1350
1351 /* write the character with the attribute */
1352 movb $0x9, %ah
1353 movw $1, %cx
1354 int $0x10
1355
1356 /* move the cursor forward */
1357 incb %dl
1358 movb $0x2, %ah
1359 int $0x10
1360
1361 jmp 3f
1362
1363 1: movw $1, %bx
1364 movb $0xe, %ah
1365 int $0x10
1366
1367 3: DATA32 call real_to_prot
1368 .code32
1369
1370 popa
1371 ret
1372
1373
1374 /*
1375 * int grub_console_getkey (void)
1376 * BIOS call "INT 16H Function 00H" to read character from keyboard
1377 * Call with %ah = 0x0
1378 * Return: %ah = keyboard scan code
1379 * %al = ASCII character
1380 */
1381
1382 /* this table is used in translate_keycode below */
1383 translation_table:
1384 .word GRUB_CONSOLE_KEY_LEFT, 2
1385 .word GRUB_CONSOLE_KEY_RIGHT, 6
1386 .word GRUB_CONSOLE_KEY_UP, 16
1387 .word GRUB_CONSOLE_KEY_DOWN, 14
1388 .word GRUB_CONSOLE_KEY_HOME, 1
1389 .word GRUB_CONSOLE_KEY_END, 5
1390 .word GRUB_CONSOLE_KEY_DC, 4
1391 .word GRUB_CONSOLE_KEY_BACKSPACE, 8
1392 .word GRUB_CONSOLE_KEY_PPAGE, 7
1393 .word GRUB_CONSOLE_KEY_NPAGE, 3
1394 .word 0
1395
1396 /*
1397 * translate_keycode translates the key code %dx to an ascii code.
1398 */
1399 .code16
1400
1401 translate_keycode:
1402 pushw %bx
1403 pushw %si
1404
1405 movw $ABS(translation_table), %si
1406
1407 1: lodsw
1408 /* check if this is the end */
1409 testw %ax, %ax
1410 jz 2f
1411 /* load the ascii code into %ax */
1412 movw %ax, %bx
1413 lodsw
1414 /* check if this matches the key code */
1415 cmpw %bx, %dx
1416 jne 1b
1417 /* translate %dx, if successful */
1418 movw %ax, %dx
1419
1420 2: popw %si
1421 popw %bx
1422 ret
1423
1424 .code32
1425
1426 FUNCTION(grub_console_getkey)
1427 pushl %ebp
1428
1429 call prot_to_real
1430 .code16
1431
1432 int $0x16
1433
1434 movw %ax, %dx /* real_to_prot uses %eax */
1435 call translate_keycode
1436
1437 DATA32 call real_to_prot
1438 .code32
1439
1440 movw %dx, %ax
1441
1442 popl %ebp
1443 ret
1444
1445
1446 /*
1447 * int grub_console_checkkey (void)
1448 * if there is a character pending, return it; otherwise return -1
1449 * BIOS call "INT 16H Function 01H" to check whether a character is pending
1450 * Call with %ah = 0x1
1451 * Return:
1452 * If key waiting to be input:
1453 * %ah = keyboard scan code
1454 * %al = ASCII character
1455 * Zero flag = clear
1456 * else
1457 * Zero flag = set
1458 */
1459 FUNCTION(grub_console_checkkey)
1460 pushl %ebp
1461 xorl %edx, %edx
1462
1463 call prot_to_real /* enter real mode */
1464 .code16
1465
1466 movb $0x1, %ah
1467 int $0x16
1468
1469 jz notpending
1470
1471 movw %ax, %dx
1472 DATA32 jmp pending
1473
1474 notpending:
1475 decl %edx
1476
1477 pending:
1478 DATA32 call real_to_prot
1479 .code32
1480
1481 movl %edx, %eax
1482
1483 popl %ebp
1484 ret
1485
1486
1487 /*
1488 * grub_uint16_t grub_console_getxy (void)
1489 * BIOS call "INT 10H Function 03h" to get cursor position
1490 * Call with %ah = 0x03
1491 * %bh = page
1492 * Returns %ch = starting scan line
1493 * %cl = ending scan line
1494 * %dh = row (0 is top)
1495 * %dl = column (0 is left)
1496 */
1497
1498
1499 FUNCTION(grub_console_getxy)
1500 pushl %ebp
1501 pushl %ebx /* save EBX */
1502
1503 call prot_to_real
1504 .code16
1505
1506 xorb %bh, %bh /* set page to 0 */
1507 movb $0x3, %ah
1508 int $0x10 /* get cursor position */
1509
1510 DATA32 call real_to_prot
1511 .code32
1512
1513 movb %dl, %ah
1514 movb %dh, %al
1515
1516 popl %ebx
1517 popl %ebp
1518 ret
1519
1520
1521 /*
1522 * void grub_console_gotoxy(grub_uint8_t x, grub_uint8_t y)
1523 * BIOS call "INT 10H Function 02h" to set cursor position
1524 * Call with %ah = 0x02
1525 * %bh = page
1526 * %dh = row (0 is top)
1527 * %dl = column (0 is left)
1528 */
1529
1530
1531 FUNCTION(grub_console_gotoxy)
1532 pushl %ebp
1533 pushl %ebx /* save EBX */
1534
1535 movb %dl, %dh /* %dh = y */
1536 movb %al, %dl /* %dl = x */
1537
1538 call prot_to_real
1539 .code16
1540
1541 xorb %bh, %bh /* set page to 0 */
1542 movb $0x2, %ah
1543 int $0x10 /* set cursor position */
1544
1545 DATA32 call real_to_prot
1546 .code32
1547
1548 popl %ebx
1549 popl %ebp
1550 ret
1551
1552
1553 /*
1554 * void grub_console_cls (void)
1555 * BIOS call "INT 10H Function 09h" to write character and attribute
1556 * Call with %ah = 0x09
1557 * %al = (character)
1558 * %bh = (page number)
1559 * %bl = (attribute)
1560 * %cx = (number of times)
1561 */
1562
1563 FUNCTION(grub_console_cls)
1564 pushl %ebp
1565 pushl %ebx /* save EBX */
1566
1567 call prot_to_real
1568 .code16
1569
1570 /* move the cursor to the beginning */
1571 movb $0x02, %ah
1572 xorb %bh, %bh
1573 xorw %dx, %dx
1574 int $0x10
1575
1576 /* write spaces to the entire screen */
1577 movw $0x0920, %ax
1578 movw $0x07, %bx
1579 movw $(80 * 25), %cx
1580 int $0x10
1581
1582 /* move back the cursor */
1583 movb $0x02, %ah
1584 int $0x10
1585
1586 DATA32 call real_to_prot
1587 .code32
1588
1589 popl %ebx
1590 popl %ebp
1591 ret
1592
1593
1594 /*
1595 * void grub_console_setcursor (int on)
1596 * BIOS call "INT 10H Function 01h" to set cursor type
1597 * Call with %ah = 0x01
1598 * %ch = cursor starting scanline
1599 * %cl = cursor ending scanline
1600 */
1601
1602 console_cursor_state:
1603 .byte 1
1604 console_cursor_shape:
1605 .word 0
1606
1607 FUNCTION(grub_console_setcursor)
1608 pushl %ebp
1609 pushl %ebx
1610
1611 /* push ON */
1612 pushl %eax
1613
1614 /* check if the standard cursor shape has already been saved */
1615 movw console_cursor_shape, %ax
1616 testw %ax, %ax
1617 jne 1f
1618
1619 call prot_to_real
1620 .code16
1621
1622 movb $0x03, %ah
1623 xorb %bh, %bh
1624 int $0x10
1625
1626 DATA32 call real_to_prot
1627 .code32
1628
1629 movw %cx, console_cursor_shape
1630 1:
1631 /* set %cx to the designated cursor shape */
1632 movw $0x2000, %cx
1633 popl %eax
1634 testl %eax, %eax
1635 jz 2f
1636 movw console_cursor_shape, %cx
1637 2:
1638 call prot_to_real
1639 .code16
1640
1641 movb $0x1, %ah
1642 int $0x10
1643
1644 DATA32 call real_to_prot
1645 .code32
1646
1647 popl %ebx
1648 popl %ebp
1649 ret
1650
1651 /*
1652 * grub_getrtsecs()
1653 * if a seconds value can be read, read it and return it (BCD),
1654 * otherwise return 0xFF
1655 * BIOS call "INT 1AH Function 02H" to check whether a character is pending
1656 * Call with %ah = 0x2
1657 * Return:
1658 * If RT Clock can give correct values
1659 * %ch = hour (BCD)
1660 * %cl = minutes (BCD)
1661 * %dh = seconds (BCD)
1662 * %dl = daylight savings time (00h std, 01h daylight)
1663 * Carry flag = clear
1664 * else
1665 * Carry flag = set
1666 * (this indicates that the clock is updating, or
1667 * that it isn't running)
1668 */
1669 FUNCTION(grub_getrtsecs)
1670 pushl %ebp
1671
1672 call prot_to_real /* enter real mode */
1673 .code16
1674
1675 clc
1676 movb $0x2, %ah
1677 int $0x1a
1678
1679 DATA32 jnc gottime
1680 movb $0xff, %dh
1681
1682 gottime:
1683 DATA32 call real_to_prot
1684 .code32
1685
1686 movb %dh, %al
1687
1688 popl %ebp
1689 ret
1690
1691
1692 /*
1693 * grub_get_rtc()
1694 * return the real time in ticks, of which there are about
1695 * 18-20 per second
1696 */
1697 FUNCTION(grub_get_rtc)
1698 pushl %ebp
1699
1700 call prot_to_real /* enter real mode */
1701 .code16
1702
1703 /* %ax is already zero */
1704 int $0x1a
1705
1706 DATA32 call real_to_prot
1707 .code32
1708
1709 movl %ecx, %eax
1710 shll $16, %eax
1711 movw %dx, %ax
1712
1713 popl %ebp
1714 ret
1715
1716
1717 /*
1718 * unsigned char grub_vga_set_mode (unsigned char mode)
1719 */
1720 FUNCTION(grub_vga_set_mode)
1721 pushl %ebp
1722 pushl %ebx
1723 movl %eax, %ecx
1724
1725 call prot_to_real
1726 .code16
1727 /* get current mode */
1728 xorw %bx, %bx
1729 movb $0x0f, %ah
1730 int $0x10
1731 movb %al, %dl
1732
1733 /* set the new mode */
1734 movb %cl, %al
1735 xorb %ah, %ah
1736 int $0x10
1737
1738 DATA32 call real_to_prot
1739 .code32
1740
1741 movb %dl, %al
1742 popl %ebx
1743 popl %ebp
1744 ret
1745
1746
1747 /*
1748 * unsigned char *grub_vga_get_font (void)
1749 */
1750 FUNCTION(grub_vga_get_font)
1751 pushl %ebp
1752 pushl %ebx
1753
1754 call prot_to_real
1755 .code16
1756 movw $0x1130, %ax
1757 movb $0x06, %bh
1758 int $0x10
1759 movw %es, %bx
1760 movw %bp, %dx
1761 DATA32 call real_to_prot
1762 .code32
1763
1764 movzwl %bx, %ecx
1765 shll $4, %ecx
1766 movw %dx, %ax
1767 addl %ecx, %eax
1768
1769 popl %ebx
1770 popl %ebp
1771 ret
1772
1773 /*
1774 * grub_vbe_bios_status_t grub_vbe_get_controller_info (struct grub_vbe_info_block *controller_info)
1775 *
1776 * Register allocations for parameters:
1777 * %eax *controller_info
1778 */
1779 FUNCTION(grub_vbe_bios_get_controller_info)
1780 pushl %ebp
1781 pushl %edi
1782 pushl %edx
1783
1784 movw %ax, %di /* Store *controller_info to %edx:%di. */
1785 xorw %ax, %ax
1786 shrl $4, %eax
1787 mov %eax, %edx /* prot_to_real destroys %eax. */
1788
1789 call prot_to_real
1790 .code16
1791
1792 pushw %es
1793
1794 movw %dx, %es /* *controller_info is now on %es:%di. */
1795 movw $0x4f00, %ax
1796 int $0x10
1797
1798 movw %ax, %dx /* real_to_prot destroys %eax. */
1799
1800 popw %es
1801
1802 DATA32 call real_to_prot
1803 .code32
1804
1805 movl %edx, %eax
1806 andl $0x0FFFF, %eax /* Return value in %eax. */
1807
1808 pop %edx
1809 popl %edi
1810 popl %ebp
1811 ret
1812
1813 /*
1814 * grub_vbe_status_t grub_vbe_bios_get_mode_info (grub_uint32_t mode,
1815 * struct grub_vbe_mode_info_block *mode_info)
1816 *
1817 * Register allocations for parameters:
1818 * %eax mode
1819 * %edx *mode_info
1820 */
1821 FUNCTION(grub_vbe_bios_get_mode_info)
1822 pushl %ebp
1823 pushl %edi
1824
1825 movl %eax, %ecx /* Store mode number to %ecx. */
1826
1827 movw %dx, %di /* Store *mode_info to %edx:%di. */
1828 xorw %dx, %dx
1829 shrl $4, %edx
1830
1831 call prot_to_real
1832 .code16
1833
1834 pushw %es
1835
1836 movw %dx, %es /* *mode_info is now on %es:%di. */
1837 movw $0x4f01, %ax
1838 int $0x10
1839
1840 movw %ax, %dx /* real_to_prot destroys %eax. */
1841
1842 popw %es
1843
1844 DATA32 call real_to_prot
1845 .code32
1846
1847 movl %edx, %eax
1848 andl $0x0FFFF, %eax /* Return value in %eax. */
1849
1850 popl %edi
1851 popl %ebp
1852 ret
1853
1854 /*
1855 * grub_vbe_status_t grub_vbe_bios_set_mode (grub_uint32_t mode,
1856 * struct grub_vbe_crtc_info_block *crtc_info)
1857 *
1858 * Register allocations for parameters:
1859 * %eax mode
1860 * %edx *crtc_info
1861 */
1862 FUNCTION(grub_vbe_bios_set_mode)
1863 pushl %ebp
1864 pushl %ebx
1865 pushl %edi
1866
1867 movl %eax, %ebx /* Store mode in %ebx. */
1868
1869 movw %dx, %di /* Store *crtc_info to %edx:%di. */
1870 xorw %dx, %dx
1871 shrl $4, %edx
1872
1873 call prot_to_real
1874 .code16
1875
1876 pushw %es
1877
1878 movw %dx, %es /* *crtc_info is now on %es:%di. */
1879
1880 movw $0x4f02, %ax
1881 int $0x10
1882
1883 movw %ax, %dx /* real_to_prot destroys %eax. */
1884
1885 popw %es
1886
1887 DATA32 call real_to_prot
1888 .code32
1889
1890 movw %dx, %ax
1891 andl $0xFFFF, %eax /* Return value in %eax. */
1892
1893 popl %edi
1894 popl %ebx
1895 popl %ebp
1896 ret
1897
1898 /*
1899 * grub_vbe_status_t grub_vbe_bios_get_mode (grub_uint32_t *mode)
1900 *
1901 * Register allocations for parameters:
1902 * %eax *mode
1903 */
1904 FUNCTION(grub_vbe_bios_get_mode)
1905 pushl %ebp
1906 pushl %ebx
1907 pushl %edi
1908 pushl %edx
1909 pushl %eax /* Push *mode to stack. */
1910
1911 call prot_to_real
1912 .code16
1913
1914 movw $0x4f03, %ax
1915 int $0x10
1916
1917 movw %ax, %dx /* real_to_prot destroys %eax. */
1918
1919 DATA32 call real_to_prot
1920 .code32
1921
1922 popl %edi /* Pops *mode from stack to %edi. */
1923 andl $0xFFFF, %ebx
1924 movl %ebx, (%edi)
1925
1926 movw %dx, %ax
1927 andl $0xFFFF, %eax /* Return value in %eax. */
1928
1929 popl %edx
1930 popl %edi
1931 popl %ebx
1932 popl %ebp
1933 ret
1934
1935 /*
1936 * grub_vbe_status_t grub_vbe_bios_set_memory_window (grub_uint32_t window,
1937 * grub_uint32_t position);
1938 *
1939 * Register allocations for parameters:
1940 * %eax window
1941 * %edx position
1942 */
1943 FUNCTION(grub_vbe_bios_set_memory_window)
1944 pushl %ebp
1945 pushl %ebx
1946
1947 movl %eax, %ebx
1948
1949 call prot_to_real
1950 .code16
1951
1952 movw $0x4f05, %ax
1953 andw $0x00ff, %bx /* BL = window, BH = 0, Set memory window. */
1954 int $0x10
1955
1956 movw %ax, %dx /* real_to_prot destroys %eax. */
1957
1958 DATA32 call real_to_prot
1959 .code32
1960
1961 movw %dx, %ax
1962 andl $0xFFFF, %eax /* Return value in %eax. */
1963
1964 popl %ebx
1965 popl %ebp
1966 ret
1967
1968 /*
1969 * grub_vbe_status_t grub_vbe_bios_get_memory_window (grub_uint32_t window,
1970 * grub_uint32_t *position);
1971 *
1972 * Register allocations for parameters:
1973 * %eax window
1974 * %edx *position
1975 */
1976 FUNCTION(grub_vbe_bios_get_memory_window)
1977 pushl %ebp
1978 pushl %ebx
1979 pushl %edi
1980 pushl %edx /* Push *position to stack. */
1981
1982 movl %eax, %ebx /* Store window in %ebx. */
1983
1984 call prot_to_real
1985 .code16
1986
1987 movw $0x4f05, %ax
1988 andw $0x00ff, %bx /* BL = window. */
1989 orw $0x0100, %bx /* BH = 1, Get memory window. */
1990 int $0x10
1991
1992 movw %ax, %bx /* real_to_prot destroys %eax. */
1993
1994 DATA32 call real_to_prot
1995 .code32
1996
1997 popl %edi /* pops *position from stack to %edi. */
1998 andl $0xFFFF, %edx
1999 movl %edx, (%edi) /* Return position to caller. */
2000
2001 movw %bx, %ax
2002 andl $0xFFFF, %eax /* Return value in %eax. */
2003
2004 popl %edi
2005 popl %ebx
2006 popl %ebp
2007 ret
2008
2009 /*
2010 * grub_vbe_status_t grub_vbe_bios_set_scanline_length (grub_uint32_t length)
2011 *
2012 * Register allocations for parameters:
2013 * %eax length
2014 */
2015 FUNCTION(grub_vbe_bios_set_scanline_length)
2016 pushl %ebp
2017 pushl %ebx
2018 pushl %edx
2019
2020 movl %eax, %ecx /* Store length in %ecx. */
2021
2022 call prot_to_real
2023 .code16
2024
2025 movw $0x4f06, %ax
2026 movw $0x0002, %bx /* BL = 2, Set Scan Line in Bytes. */
2027 int $0x10
2028
2029 movw %ax, %dx /* real_to_prot destroys %eax. */
2030
2031 DATA32 call real_to_prot
2032 .code32
2033
2034 movw %dx, %ax
2035 andl $0xFFFF, %eax /* Return value in %eax. */
2036
2037 popl %edx
2038 popl %ebx
2039 popl %ebp
2040 ret
2041
2042 /*
2043 * grub_vbe_status_t grub_vbe_bios_get_scanline_length (grub_uint32_t *length)
2044 *
2045 * Register allocations for parameters:
2046 * %eax *length
2047 */
2048 FUNCTION(grub_vbe_bios_get_scanline_length)
2049 pushl %ebp
2050 pushl %ebx
2051 pushl %edi
2052 pushl %edx /* Push *length to stack. */
2053
2054 call prot_to_real
2055 .code16
2056
2057 movw $0x4f06, %ax
2058 movw $0x0001, %bx /* BL = 1, Get Scan Line Length (in bytes). */
2059 int $0x10
2060
2061 movw %ax, %dx /* real_to_prot destroys %eax. */
2062
2063 DATA32 call real_to_prot
2064 .code32
2065
2066 popl %edi /* Pops *length from stack to %edi. */
2067 andl $0xFFFF, %ebx
2068 movl %ebx, (%edi) /* Return length to caller. */
2069
2070 movw %dx, %ax
2071 andl $0xFFFF, %eax /* Return value in %eax. */
2072
2073 popl %edi
2074 popl %ebx
2075 popl %ebp
2076 ret
2077
2078 /*
2079 * grub_vbe_status_t grub_vbe_bios_set_display_start (grub_uint32_t x,
2080 * grub_uint32_t y)
2081 *
2082 * Register allocations for parameters:
2083 * %eax x
2084 * %edx y
2085 */
2086 FUNCTION(grub_vbe_bios_set_display_start)
2087 pushl %ebp
2088 pushl %ebx
2089
2090 movl %eax, %ecx /* Store x in %ecx. */
2091
2092 call prot_to_real
2093 .code16
2094
2095 movw $0x4f07, %ax
2096 movw $0x0080, %bx /* BL = 80h, Set Display Start
2097 during Vertical Retrace. */
2098 int $0x10
2099
2100 movw %ax, %dx /* real_to_prot destroys %eax. */
2101
2102 DATA32 call real_to_prot
2103 .code32
2104
2105 movw %dx, %ax
2106 andl $0xFFFF, %eax /* Return value in %eax. */
2107
2108 popl %ebx
2109 popl %ebp
2110 ret
2111
2112 /*
2113 * grub_vbe_status_t grub_vbe_bios_get_display_start (grub_uint32_t *x,
2114 * grub_uint32_t *y)
2115 *
2116 * Register allocations for parameters:
2117 * %eax *x
2118 * %edx *y
2119 */
2120 FUNCTION(grub_vbe_bios_get_display_start)
2121 pushl %ebp
2122 pushl %ebx
2123 pushl %edi
2124 pushl %eax /* Push *x to stack. */
2125 pushl %edx /* Push *y to stack. */
2126
2127 call prot_to_real
2128 .code16
2129
2130 movw $0x4f07, %ax
2131 movw $0x0001, %bx /* BL = 1, Get Display Start. */
2132 int $0x10
2133
2134 movw %ax, %bx /* real_to_prot destroys %eax. */
2135
2136 DATA32 call real_to_prot
2137 .code32
2138
2139 popl %edi /* Pops *y from stack to %edi. */
2140 andl $0xFFFF, %edx
2141 movl %edx, (%edi) /* Return y-position to caller. */
2142
2143 popl %edi /* Pops *x from stack to %edi. */
2144 andl $0xFFFF, %ecx
2145 movl %ecx, (%edi) /* Return x-position to caller. */
2146
2147 movw %bx, %ax
2148 andl $0xFFFF, %eax /* Return value in %eax. */
2149
2150 popl %edi
2151 popl %ebx
2152 popl %ebp
2153 ret
2154
2155 /*
2156 * grub_vbe_status_t grub_vbe_bios_set_palette_data (grub_uint32_t color_count,
2157 * grub_uint32_t start_index,
2158 * struct grub_vbe_palette_data *palette_data)
2159 *
2160 * Register allocations for parameters:
2161 * %eax color_count
2162 * %edx start_index
2163 * %ecx *palette_data
2164 */
2165 FUNCTION(grub_vbe_bios_set_palette_data)
2166 pushl %ebp
2167 pushl %ebx
2168 pushl %edi
2169
2170 movl %eax, %ebx /* Store color_count in %ebx. */
2171
2172 movw %cx, %di /* Store *palette_data to %ecx:%di. */
2173 xorw %cx, %cx
2174 shrl $4, %ecx
2175
2176 call prot_to_real
2177 .code16
2178
2179 pushw %es
2180
2181 movw %cx, %es /* *palette_data is now on %es:%di. */
2182 movw %bx, %cx /* color_count is now on %cx. */
2183
2184 movw $0x4f09, %ax
2185 xorw %bx, %bx /* BL = 0, Set Palette Data. */
2186 int $0x10
2187
2188 movw %ax, %dx /* real_to_prot destroys %eax. */
2189
2190 popw %es
2191
2192 DATA32 call real_to_prot
2193 .code32
2194
2195 movw %dx, %ax
2196 andl $0xFFFF, %eax /* Return value in %eax. */
2197
2198 popl %edi
2199 popl %ebx
2200 popl %ebp
2201 ret