]> git.proxmox.com Git - grub2.git/blob - kern/i386/pc/startup.S
2006-03-14 Vesa Jaaskelainen <chaac@nic.fi>
[grub2.git] / kern / i386 / pc / startup.S
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 1999,2000,2001,2002,2003,2005 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_reboot()
630 *
631 * Reboot the system. At the moment, rely on BIOS.
632 */
633 FUNCTION(grub_reboot)
634 call prot_to_real
635 .code16
636 /* cold boot */
637 movw $0x0472, %di
638 movw %ax, (%di)
639 ljmp $0xFFFF, $0x0000
640 .code32
641
642 /*
643 * grub_halt(int no_apm)
644 *
645 * Halt the system, using APM if possible. If NO_APM is true, don't use
646 * APM even if it is available.
647 */
648 FUNCTION(grub_halt)
649 /* see if zero */
650 testl %eax, %eax
651 jnz EXT_C(grub_stop)
652
653 call prot_to_real
654 .code16
655
656 /* detect APM */
657 movw $0x5300, %ax
658 xorw %bx, %bx
659 int $0x15
660 jc EXT_C(grub_hard_stop)
661 /* don't check %bx for buggy BIOSes... */
662
663 /* disconnect APM first */
664 movw $0x5304, %ax
665 xorw %bx, %bx
666 int $0x15
667
668 /* connect APM */
669 movw $0x5301, %ax
670 xorw %bx, %bx
671 int $0x15
672 jc EXT_C(grub_hard_stop)
673
674 /* set APM protocol level - 1.1 or bust. (this covers APM 1.2 also) */
675 movw $0x530E, %ax
676 xorw %bx, %bx
677 movw $0x0101, %cx
678 int $0x15
679 jc EXT_C(grub_hard_stop)
680
681 /* set the power state to off */
682 movw $0x5307, %ax
683 movw $1, %bx
684 movw $3, %cx
685 int $0x15
686
687 /* shouldn't reach here */
688 jmp EXT_C(grub_hard_stop)
689 .code32
690
691
692 /*
693 * void grub_chainloader_real_boot (int drive, void *part_addr)
694 *
695 * This starts another boot loader.
696 */
697
698 FUNCTION(grub_chainloader_real_boot)
699 pushl %edx
700 pushl %eax
701
702 call EXT_C(grub_dl_unload_all)
703
704 /* set up to pass boot drive */
705 popl %edx
706
707 /* ESI must point to a partition table entry */
708 popl %esi
709
710 /* Turn off Gate A20 */
711 xorl %eax, %eax
712 call EXT_C(grub_gate_a20)
713
714 call prot_to_real
715 .code16
716 ljmp $0, $GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR
717 .code32
718
719
720 /*
721 * void grub_linux_boot_zimage (void)
722 */
723 VARIABLE(grub_linux_prot_size)
724 .long 0
725 VARIABLE(grub_linux_tmp_addr)
726 .long 0
727 VARIABLE(grub_linux_real_addr)
728 .long 0
729
730 FUNCTION(grub_linux_boot_zimage)
731 /* copy the kernel */
732 movl EXT_C(grub_linux_prot_size), %ecx
733 addl $3, %ecx
734 shrl $2, %ecx
735 movl $GRUB_LINUX_BZIMAGE_ADDR, %esi
736 movl $GRUB_LINUX_ZIMAGE_ADDR, %edi
737 cld
738 rep
739 movsl
740
741 FUNCTION(grub_linux_boot_bzimage)
742 call EXT_C(grub_dl_unload_all)
743
744 movl EXT_C(grub_linux_real_addr), %ebx
745
746 /* copy the real mode code */
747 movl EXT_C(grub_linux_tmp_addr), %esi
748 movl %ebx, %edi
749 movl $GRUB_LINUX_SETUP_MOVE_SIZE, %ecx
750 cld
751 rep
752 movsb
753
754 /* change %ebx to the segment address */
755 shrl $4, %ebx
756 movl %ebx, %eax
757 addl $0x20, %eax
758 movw %ax, linux_setup_seg
759
760 /* XXX new stack pointer in safe area for calling functions */
761 movl $0x4000, %esp
762 call EXT_C(grub_stop_floppy)
763
764 /* final setup for linux boot */
765 call prot_to_real
766 .code16
767
768 cli
769 movw %bx, %ss
770 movw $GRUB_LINUX_SETUP_STACK, %sp
771
772 movw %bx, %ds
773 movw %bx, %es
774 movw %bx, %fs
775 movw %bx, %gs
776
777 /* ljmp */
778 .byte 0xea
779 .word 0
780 linux_setup_seg:
781 .word 0
782 .code32
783
784
785 /*
786 * This starts the multiboot kernel.
787 */
788
789 FUNCTION(grub_multiboot_real_boot)
790 /* Push the entry address on the stack. */
791 pushl %eax
792 /* Move the address of the multiboot information structure to ebx. */
793 movl %edx,%ebx
794
795 /* Unload all modules and stop the floppy driver. */
796 call EXT_C(grub_dl_unload_all)
797 call EXT_C(grub_stop_floppy)
798
799 /* Interrupts should be disabled. */
800 cli
801
802 /* Move the magic value into eax and jump to the kernel. */
803 movl $GRUB_MB_MAGIC2,%eax
804 popl %ecx
805 jmp *%ecx
806
807
808 /*
809 * int grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap)
810 *
811 * Call IBM/MS INT13 Extensions (int 13 %ah=AH) for DRIVE. DAP
812 * is passed for disk address packet. If an error occurs, return
813 * non-zero, otherwise zero.
814 */
815
816 FUNCTION(grub_biosdisk_rw_int13_extensions)
817 pushl %ebp
818 pushl %esi
819
820 /* compute the address of disk_address_packet */
821 movw %cx, %si
822 xorw %cx, %cx
823 shrl $4, %ecx /* save the segment to cx */
824
825 /* ah */
826 movb %al, %dh
827 /* enter real mode */
828 call prot_to_real
829
830 .code16
831 movb %dh, %ah
832 movw %cx, %ds
833 int $0x13 /* do the operation */
834 movb %ah, %dl /* save return value */
835 /* clear the data segment */
836 xorw %ax, %ax
837 movw %ax, %ds
838 /* back to protected mode */
839 DATA32 call real_to_prot
840 .code32
841
842 movb %dl, %al /* return value in %eax */
843
844 popl %esi
845 popl %ebp
846
847 ret
848
849 /*
850 * int grub_biosdisk_rw_standard (int ah, int drive, int coff, int hoff,
851 * int soff, int nsec, int segment)
852 *
853 * Call standard and old INT13 (int 13 %ah=AH) for DRIVE. Read/write
854 * NSEC sectors from COFF/HOFF/SOFF into SEGMENT. If an error occurs,
855 * return non-zero, otherwise zero.
856 */
857
858 FUNCTION(grub_biosdisk_rw_standard)
859 pushl %ebp
860 movl %esp, %ebp
861
862 pushl %ebx
863 pushl %edi
864 pushl %esi
865
866 /* set up CHS information */
867
868 /* set %ch to low eight bits of cylinder */
869 xchgb %cl, %ch
870 /* set bits 6-7 of %cl to high two bits of cylinder */
871 shlb $6, %cl
872 /* set bits 0-5 of %cl to sector */
873 addb 0xc(%ebp), %cl
874 /* set %dh to head */
875 movb 0x8(%ebp), %dh
876 /* set %ah to AH */
877 movb %al, %ah
878 /* set %al to NSEC */
879 movb 0x10(%ebp), %al
880 /* save %ax in %di */
881 movw %ax, %di
882 /* save SEGMENT in %bx */
883 movw 0x14(%ebp), %bx
884
885 /* enter real mode */
886 call prot_to_real
887
888 .code16
889 movw %bx, %es
890 xorw %bx, %bx
891 movw $3, %si /* attempt at least three times */
892
893 1:
894 movw %di, %ax
895 int $0x13 /* do the operation */
896 jnc 2f /* check if successful */
897
898 movb %ah, %bl /* save return value */
899 /* if fail, reset the disk system */
900 xorw %ax, %ax
901 int $0x13
902
903 decw %si
904 cmpw $0, %si
905 je 2f
906 xorb %bl, %bl
907 jmp 1b /* retry */
908 2:
909 /* back to protected mode */
910 DATA32 call real_to_prot
911 .code32
912
913 movb %bl, %al /* return value in %eax */
914
915 popl %esi
916 popl %edi
917 popl %ebx
918 popl %ebp
919
920 ret $(4 * 4)
921
922
923 /*
924 * int grub_biosdisk_check_int13_extensions (int drive)
925 *
926 * Check if LBA is supported for DRIVE. If it is supported, then return
927 * the major version of extensions, otherwise zero.
928 */
929
930 FUNCTION(grub_biosdisk_check_int13_extensions)
931 pushl %ebp
932 pushl %ebx
933
934 /* drive */
935 movb %al, %dl
936 /* enter real mode */
937 call prot_to_real
938
939 .code16
940 movb $0x41, %ah
941 movw $0x55aa, %bx
942 int $0x13 /* do the operation */
943
944 /* check the result */
945 jc 1f
946 cmpw $0xaa55, %bx
947 jne 1f
948
949 movb %ah, %bl /* save the major version into %bl */
950
951 /* check if AH=0x42 is supported */
952 andw $1, %cx
953 jnz 2f
954
955 1:
956 xorb %bl, %bl
957 2:
958 /* back to protected mode */
959 DATA32 call real_to_prot
960 .code32
961
962 movb %bl, %al /* return value in %eax */
963
964 popl %ebx
965 popl %ebp
966
967 ret
968
969
970 /*
971 * int grub_biosdisk_get_diskinfo_int13_extensions (int drive, void *drp)
972 *
973 * Return the geometry of DRIVE in a drive parameters, DRP. If an error
974 * occurs, then return non-zero, otherwise zero.
975 */
976
977 FUNCTION(grub_biosdisk_get_diskinfo_int13_extensions)
978 pushl %ebp
979 pushl %ebx
980 pushl %esi
981
982 /* compute the address of drive parameters */
983 movw %dx, %si
984 xorw %dx, %dx
985 shrl $4, %edx
986 movw %dx, %bx /* save the segment into %bx */
987 /* drive */
988 movb %al, %dl
989 /* enter real mode */
990 call prot_to_real
991
992 .code16
993 movb $0x48, %ah
994 movw %bx, %ds
995 int $0x13 /* do the operation */
996 movb %ah, %bl /* save return value in %bl */
997 /* clear the data segment */
998 xorw %ax, %ax
999 movw %ax, %ds
1000 /* back to protected mode */
1001 DATA32 call real_to_prot
1002 .code32
1003
1004 movb %bl, %al /* return value in %eax */
1005
1006 popl %esi
1007 popl %ebx
1008 popl %ebp
1009
1010 ret
1011
1012
1013 /*
1014 * int grub_biosdisk_get_diskinfo_standard (int drive,
1015 * unsigned long *cylinders,
1016 * unsigned long *heads,
1017 * unsigned long *sectors)
1018 *
1019 * Return the geometry of DRIVE in CYLINDERS, HEADS and SECTORS. If an
1020 * error occurs, then return non-zero, otherwise zero.
1021 */
1022
1023 FUNCTION(grub_biosdisk_get_diskinfo_standard)
1024 pushl %ebp
1025 pushl %ebx
1026 pushl %edi
1027
1028 /* push CYLINDERS */
1029 pushl %edx
1030 /* push HEADS */
1031 pushl %ecx
1032 /* SECTORS is on the stack */
1033
1034 /* drive */
1035 movb %al, %dl
1036 /* enter real mode */
1037 call prot_to_real
1038
1039 .code16
1040 movb $0x8, %ah
1041 int $0x13 /* do the operation */
1042 /* check if successful */
1043 testb %ah, %ah
1044 jnz 1f
1045 /* bogus BIOSes may not return an error number */
1046 testb $0x3f, %cl /* 0 sectors means no disk */
1047 jnz 1f /* if non-zero, then succeed */
1048 /* XXX 0x60 is one of the unused error numbers */
1049 movb $0x60, %ah
1050 1:
1051 movb %ah, %bl /* save return value in %bl */
1052 /* back to protected mode */
1053 DATA32 call real_to_prot
1054 .code32
1055
1056 /* pop HEADS */
1057 popl %edi
1058 movb %dh, %al
1059 incl %eax /* the number of heads is counted from zero */
1060 movl %eax, (%edi)
1061
1062 /* pop CYLINDERS */
1063 popl %edi
1064 movb %ch, %al
1065 movb %cl, %ah
1066 shrb $6, %ah /* the number of cylinders is counted from zero */
1067 incl %eax
1068 movl %eax, (%edi)
1069
1070 /* SECTORS */
1071 movl 0x10(%esp), %edi
1072 andb $0x3f, %cl
1073 movzbl %cl, %eax
1074 movl %eax, (%edi)
1075
1076 xorl %eax, %eax
1077 movb %bl, %al /* return value in %eax */
1078
1079 popl %edi
1080 popl %ebx
1081 popl %ebp
1082
1083 ret $4
1084
1085
1086 /*
1087 * int grub_biosdisk_get_num_floppies (void)
1088 */
1089 FUNCTION(grub_biosdisk_get_num_floppies)
1090 pushl %ebp
1091
1092 xorl %edx, %edx
1093 call prot_to_real
1094
1095 .code16
1096 /* reset the disk system first */
1097 int $0x13
1098 1:
1099 stc
1100
1101 /* call GET DISK TYPE */
1102 movb $0x15, %ah
1103 int $0x13
1104
1105 jc 2f
1106
1107 /* check if this drive exists */
1108 testb $0x3, %ah
1109 jz 2f
1110
1111 incb %dl
1112 cmpb $2, %dl
1113 jne 1b
1114 2:
1115 DATA32 call real_to_prot
1116 .code32
1117
1118 movl %edx, %eax
1119 popl %ebp
1120 ret
1121
1122
1123 /*
1124 *
1125 * grub_get_memsize(i) : return the memory size in KB. i == 0 for conventional
1126 * memory, i == 1 for extended memory
1127 * BIOS call "INT 12H" to get conventional memory size
1128 * BIOS call "INT 15H, AH=88H" to get extended memory size
1129 * Both have the return value in AX.
1130 *
1131 */
1132
1133 FUNCTION(grub_get_memsize)
1134 pushl %ebp
1135
1136 movl %eax, %edx
1137
1138 call prot_to_real /* enter real mode */
1139 .code16
1140
1141 testl %edx, %edx
1142 jnz xext
1143
1144 int $0x12
1145 jmp xdone
1146
1147 xext:
1148 movb $0x88, %ah
1149 int $0x15
1150
1151 xdone:
1152 movw %ax, %dx
1153
1154 DATA32 call real_to_prot
1155 .code32
1156
1157 movw %dx, %ax
1158
1159 popl %ebp
1160 ret
1161
1162
1163 /*
1164 *
1165 * grub_get_eisa_mmap() : return packed EISA memory map, lower 16 bits is
1166 * memory between 1M and 16M in 1K parts, upper 16 bits is
1167 * memory above 16M in 64K parts. If error, return zero.
1168 * BIOS call "INT 15H, AH=E801H" to get EISA memory map,
1169 * AX = memory between 1M and 16M in 1K parts.
1170 * BX = memory above 16M in 64K parts.
1171 *
1172 */
1173
1174 FUNCTION(grub_get_eisa_mmap)
1175 pushl %ebp
1176 pushl %ebx
1177
1178 call prot_to_real /* enter real mode */
1179 .code16
1180
1181 movw $0xe801, %ax
1182 int $0x15
1183
1184 shll $16, %ebx
1185 movw %ax, %bx
1186
1187 DATA32 call real_to_prot
1188 .code32
1189
1190 cmpb $0x86, %bh
1191 je xnoteisa
1192
1193 movl %ebx, %eax
1194
1195 xnoteisa:
1196 popl %ebx
1197 popl %ebp
1198 ret
1199
1200 /*
1201 *
1202 * grub_get_mmap_entry(addr, cont) : address and old continuation value (zero to
1203 * start), for the Query System Address Map BIOS call.
1204 *
1205 * Sets the first 4-byte int value of "addr" to the size returned by
1206 * the call. If the call fails, sets it to zero.
1207 *
1208 * Returns: new (non-zero) continuation value, 0 if done.
1209 */
1210
1211 FUNCTION(grub_get_mmap_entry)
1212 pushl %ebp
1213 pushl %ebx
1214 pushl %edi
1215 pushl %esi
1216
1217 /* push ADDR */
1218 pushl %eax
1219
1220 /* place address (+4) in ES:DI */
1221 addl $4, %eax
1222 movl %eax, %edi
1223 andl $0xf, %edi
1224 shrl $4, %eax
1225 movl %eax, %esi
1226
1227 /* set continuation value */
1228 movl %edx, %ebx
1229
1230 /* set default maximum buffer size */
1231 movl $0x14, %ecx
1232
1233 /* set EDX to 'SMAP' */
1234 movl $0x534d4150, %edx
1235
1236 call prot_to_real /* enter real mode */
1237 .code16
1238
1239 movw %si, %es
1240 movl $0xe820, %eax
1241 int $0x15
1242
1243 DATA32 jc xnosmap
1244
1245 cmpl $0x534d4150, %eax
1246 jne xnosmap
1247
1248 cmpl $0x14, %ecx
1249 jl xnosmap
1250
1251 cmpl $0x400, %ecx
1252 jg xnosmap
1253
1254 jmp xsmap
1255
1256 xnosmap:
1257 xorl %ecx, %ecx
1258
1259 xsmap:
1260 DATA32 call real_to_prot
1261 .code32
1262
1263 /* write length of buffer (zero if error) into ADDR */
1264 popl %eax
1265 movl %ecx, (%eax)
1266
1267 /* set return value to continuation */
1268 movl %ebx, %eax
1269
1270 popl %esi
1271 popl %edi
1272 popl %ebx
1273 popl %ebp
1274 ret
1275
1276
1277 /*
1278 * void grub_console_real_putchar (int c)
1279 *
1280 * Put the character C on the console. Because GRUB wants to write a
1281 * character with an attribute, this implementation is a bit tricky.
1282 * If C is a control character (CR, LF, BEL, BS), use INT 10, AH = 0Eh
1283 * (TELETYPE OUTPUT). Otherwise, save the original position, put a space,
1284 * save the current position, restore the original position, write the
1285 * character and the attribute, and restore the current position.
1286 *
1287 * The reason why this is so complicated is that there is no easy way to
1288 * get the height of the screen, and the TELETYPE OUPUT BIOS call doesn't
1289 * support setting a background attribute.
1290 */
1291 FUNCTION(grub_console_real_putchar)
1292 movl %eax, %edx
1293 pusha
1294 movb EXT_C(grub_console_cur_color), %bl
1295
1296 call prot_to_real
1297 .code16
1298 movb %dl, %al
1299 xorb %bh, %bh
1300
1301 /* use teletype output if control character */
1302 cmpb $0x7, %al
1303 je 1f
1304 cmpb $0x8, %al
1305 je 1f
1306 cmpb $0xa, %al
1307 je 1f
1308 cmpb $0xd, %al
1309 je 1f
1310
1311 /* save the character and the attribute on the stack */
1312 pushw %ax
1313 pushw %bx
1314
1315 /* get the current position */
1316 movb $0x3, %ah
1317 int $0x10
1318
1319 /* check the column with the width */
1320 cmpb $79, %dl
1321 jl 2f
1322
1323 /* print CR and LF, if next write will exceed the width */
1324 movw $0x0e0d, %ax
1325 int $0x10
1326 movb $0x0a, %al
1327 int $0x10
1328
1329 /* get the current position */
1330 movb $0x3, %ah
1331 int $0x10
1332
1333 2:
1334 /* restore the character and the attribute */
1335 popw %bx
1336 popw %ax
1337
1338 /* write the character with the attribute */
1339 movb $0x9, %ah
1340 movw $1, %cx
1341 int $0x10
1342
1343 /* move the cursor forward */
1344 incb %dl
1345 movb $0x2, %ah
1346 int $0x10
1347
1348 jmp 3f
1349
1350 1: movw $1, %bx
1351 movb $0xe, %ah
1352 int $0x10
1353
1354 3: DATA32 call real_to_prot
1355 .code32
1356
1357 popa
1358 ret
1359
1360
1361 /*
1362 * int grub_console_getkey (void)
1363 * BIOS call "INT 16H Function 00H" to read character from keyboard
1364 * Call with %ah = 0x0
1365 * Return: %ah = keyboard scan code
1366 * %al = ASCII character
1367 */
1368
1369 /* this table is used in translate_keycode below */
1370 translation_table:
1371 .word GRUB_CONSOLE_KEY_LEFT, 2
1372 .word GRUB_CONSOLE_KEY_RIGHT, 6
1373 .word GRUB_CONSOLE_KEY_UP, 16
1374 .word GRUB_CONSOLE_KEY_DOWN, 14
1375 .word GRUB_CONSOLE_KEY_HOME, 1
1376 .word GRUB_CONSOLE_KEY_END, 5
1377 .word GRUB_CONSOLE_KEY_DC, 4
1378 .word GRUB_CONSOLE_KEY_BACKSPACE, 8
1379 .word GRUB_CONSOLE_KEY_PPAGE, 7
1380 .word GRUB_CONSOLE_KEY_NPAGE, 3
1381 .word 0
1382
1383 /*
1384 * translate_keycode translates the key code %dx to an ascii code.
1385 */
1386 .code16
1387
1388 translate_keycode:
1389 pushw %bx
1390 pushw %si
1391
1392 movw $ABS(translation_table), %si
1393
1394 1: lodsw
1395 /* check if this is the end */
1396 testw %ax, %ax
1397 jz 2f
1398 /* load the ascii code into %ax */
1399 movw %ax, %bx
1400 lodsw
1401 /* check if this matches the key code */
1402 cmpw %bx, %dx
1403 jne 1b
1404 /* translate %dx, if successful */
1405 movw %ax, %dx
1406
1407 2: popw %si
1408 popw %bx
1409 ret
1410
1411 .code32
1412
1413 FUNCTION(grub_console_getkey)
1414 pushl %ebp
1415
1416 call prot_to_real
1417 .code16
1418
1419 int $0x16
1420
1421 movw %ax, %dx /* real_to_prot uses %eax */
1422 call translate_keycode
1423
1424 DATA32 call real_to_prot
1425 .code32
1426
1427 movw %dx, %ax
1428
1429 popl %ebp
1430 ret
1431
1432
1433 /*
1434 * int grub_console_checkkey (void)
1435 * if there is a character pending, return it; otherwise return -1
1436 * BIOS call "INT 16H Function 01H" to check whether a character is pending
1437 * Call with %ah = 0x1
1438 * Return:
1439 * If key waiting to be input:
1440 * %ah = keyboard scan code
1441 * %al = ASCII character
1442 * Zero flag = clear
1443 * else
1444 * Zero flag = set
1445 */
1446 FUNCTION(grub_console_checkkey)
1447 pushl %ebp
1448 xorl %edx, %edx
1449
1450 call prot_to_real /* enter real mode */
1451 .code16
1452
1453 movb $0x1, %ah
1454 int $0x16
1455
1456 jz notpending
1457
1458 movw %ax, %dx
1459 DATA32 jmp pending
1460
1461 notpending:
1462 decl %edx
1463
1464 pending:
1465 DATA32 call real_to_prot
1466 .code32
1467
1468 movl %edx, %eax
1469
1470 popl %ebp
1471 ret
1472
1473
1474 /*
1475 * grub_uint16_t grub_console_getxy (void)
1476 * BIOS call "INT 10H Function 03h" to get cursor position
1477 * Call with %ah = 0x03
1478 * %bh = page
1479 * Returns %ch = starting scan line
1480 * %cl = ending scan line
1481 * %dh = row (0 is top)
1482 * %dl = column (0 is left)
1483 */
1484
1485
1486 FUNCTION(grub_console_getxy)
1487 pushl %ebp
1488 pushl %ebx /* save EBX */
1489
1490 call prot_to_real
1491 .code16
1492
1493 xorb %bh, %bh /* set page to 0 */
1494 movb $0x3, %ah
1495 int $0x10 /* get cursor position */
1496
1497 DATA32 call real_to_prot
1498 .code32
1499
1500 movb %dl, %ah
1501 movb %dh, %al
1502
1503 popl %ebx
1504 popl %ebp
1505 ret
1506
1507
1508 /*
1509 * void grub_console_gotoxy(grub_uint8_t x, grub_uint8_t y)
1510 * BIOS call "INT 10H Function 02h" to set cursor position
1511 * Call with %ah = 0x02
1512 * %bh = page
1513 * %dh = row (0 is top)
1514 * %dl = column (0 is left)
1515 */
1516
1517
1518 FUNCTION(grub_console_gotoxy)
1519 pushl %ebp
1520 pushl %ebx /* save EBX */
1521
1522 movb %dl, %dh /* %dh = y */
1523 movb %al, %dl /* %dl = x */
1524
1525 call prot_to_real
1526 .code16
1527
1528 xorb %bh, %bh /* set page to 0 */
1529 movb $0x2, %ah
1530 int $0x10 /* set cursor position */
1531
1532 DATA32 call real_to_prot
1533 .code32
1534
1535 popl %ebx
1536 popl %ebp
1537 ret
1538
1539
1540 /*
1541 * void grub_console_cls (void)
1542 * BIOS call "INT 10H Function 09h" to write character and attribute
1543 * Call with %ah = 0x09
1544 * %al = (character)
1545 * %bh = (page number)
1546 * %bl = (attribute)
1547 * %cx = (number of times)
1548 */
1549
1550 FUNCTION(grub_console_cls)
1551 pushl %ebp
1552 pushl %ebx /* save EBX */
1553
1554 call prot_to_real
1555 .code16
1556
1557 /* move the cursor to the beginning */
1558 movb $0x02, %ah
1559 xorb %bh, %bh
1560 xorw %dx, %dx
1561 int $0x10
1562
1563 /* write spaces to the entire screen */
1564 movw $0x0920, %ax
1565 movw $0x07, %bx
1566 movw $(80 * 25), %cx
1567 int $0x10
1568
1569 /* move back the cursor */
1570 movb $0x02, %ah
1571 int $0x10
1572
1573 DATA32 call real_to_prot
1574 .code32
1575
1576 popl %ebx
1577 popl %ebp
1578 ret
1579
1580
1581 /*
1582 * void grub_console_setcursor (int on)
1583 * BIOS call "INT 10H Function 01h" to set cursor type
1584 * Call with %ah = 0x01
1585 * %ch = cursor starting scanline
1586 * %cl = cursor ending scanline
1587 */
1588
1589 console_cursor_state:
1590 .byte 1
1591 console_cursor_shape:
1592 .word 0
1593
1594 FUNCTION(grub_console_setcursor)
1595 pushl %ebp
1596 pushl %ebx
1597
1598 /* push ON */
1599 pushl %eax
1600
1601 /* check if the standard cursor shape has already been saved */
1602 movw console_cursor_shape, %ax
1603 testw %ax, %ax
1604 jne 1f
1605
1606 call prot_to_real
1607 .code16
1608
1609 movb $0x03, %ah
1610 xorb %bh, %bh
1611 int $0x10
1612
1613 DATA32 call real_to_prot
1614 .code32
1615
1616 movw %cx, console_cursor_shape
1617 1:
1618 /* set %cx to the designated cursor shape */
1619 movw $0x2000, %cx
1620 popl %eax
1621 testl %eax, %eax
1622 jz 2f
1623 movw console_cursor_shape, %cx
1624 2:
1625 call prot_to_real
1626 .code16
1627
1628 movb $0x1, %ah
1629 int $0x10
1630
1631 DATA32 call real_to_prot
1632 .code32
1633
1634 popl %ebx
1635 popl %ebp
1636 ret
1637
1638 /*
1639 * grub_getrtsecs()
1640 * if a seconds value can be read, read it and return it (BCD),
1641 * otherwise return 0xFF
1642 * BIOS call "INT 1AH Function 02H" to check whether a character is pending
1643 * Call with %ah = 0x2
1644 * Return:
1645 * If RT Clock can give correct values
1646 * %ch = hour (BCD)
1647 * %cl = minutes (BCD)
1648 * %dh = seconds (BCD)
1649 * %dl = daylight savings time (00h std, 01h daylight)
1650 * Carry flag = clear
1651 * else
1652 * Carry flag = set
1653 * (this indicates that the clock is updating, or
1654 * that it isn't running)
1655 */
1656 FUNCTION(grub_getrtsecs)
1657 pushl %ebp
1658
1659 call prot_to_real /* enter real mode */
1660 .code16
1661
1662 clc
1663 movb $0x2, %ah
1664 int $0x1a
1665
1666 DATA32 jnc gottime
1667 movb $0xff, %dh
1668
1669 gottime:
1670 DATA32 call real_to_prot
1671 .code32
1672
1673 movb %dh, %al
1674
1675 popl %ebp
1676 ret
1677
1678
1679 /*
1680 * grub_get_rtc()
1681 * return the real time in ticks, of which there are about
1682 * 18-20 per second
1683 */
1684 FUNCTION(grub_get_rtc)
1685 pushl %ebp
1686
1687 call prot_to_real /* enter real mode */
1688 .code16
1689
1690 /* %ax is already zero */
1691 int $0x1a
1692
1693 DATA32 call real_to_prot
1694 .code32
1695
1696 movl %ecx, %eax
1697 shll $16, %eax
1698 movw %dx, %ax
1699
1700 popl %ebp
1701 ret
1702
1703
1704 /*
1705 * unsigned char grub_vga_set_mode (unsigned char mode)
1706 */
1707 FUNCTION(grub_vga_set_mode)
1708 pushl %ebp
1709 pushl %ebx
1710 movl %eax, %ecx
1711
1712 call prot_to_real
1713 .code16
1714 /* get current mode */
1715 xorw %bx, %bx
1716 movb $0x0f, %ah
1717 int $0x10
1718 movb %al, %dl
1719
1720 /* set the new mode */
1721 movb %cl, %al
1722 xorb %ah, %ah
1723 int $0x10
1724
1725 DATA32 call real_to_prot
1726 .code32
1727
1728 movb %dl, %al
1729 popl %ebx
1730 popl %ebp
1731 ret
1732
1733
1734 /*
1735 * unsigned char *grub_vga_get_font (void)
1736 */
1737 FUNCTION(grub_vga_get_font)
1738 pushl %ebp
1739 pushl %ebx
1740
1741 call prot_to_real
1742 .code16
1743 movw $0x1130, %ax
1744 movb $0x06, %bh
1745 int $0x10
1746 movw %es, %bx
1747 movw %bp, %dx
1748 DATA32 call real_to_prot
1749 .code32
1750
1751 movzwl %bx, %ecx
1752 shll $4, %ecx
1753 movw %dx, %ax
1754 addl %ecx, %eax
1755
1756 popl %ebx
1757 popl %ebp
1758 ret
1759
1760 /*
1761 * grub_vbe_bios_status_t grub_vbe_get_controller_info (struct grub_vbe_info_block *controller_info)
1762 *
1763 * Register allocations for parameters:
1764 * %eax *controller_info
1765 */
1766 FUNCTION(grub_vbe_bios_get_controller_info)
1767 pushl %ebp
1768 pushl %edi
1769 pushl %edx
1770
1771 movw %ax, %di /* Store *controller_info to %edx:%di. */
1772 xorw %ax, %ax
1773 shrl $4, %eax
1774 mov %eax, %edx /* prot_to_real destroys %eax. */
1775
1776 call prot_to_real
1777 .code16
1778
1779 pushw %es
1780
1781 movw %dx, %es /* *controller_info is now on %es:%di. */
1782 movw $0x4f00, %ax
1783 int $0x10
1784
1785 movw %ax, %dx /* real_to_prot destroys %eax. */
1786
1787 popw %es
1788
1789 DATA32 call real_to_prot
1790 .code32
1791
1792 movl %edx, %eax
1793 andl $0x0FFFF, %eax /* Return value in %eax. */
1794
1795 pop %edx
1796 popl %edi
1797 popl %ebp
1798 ret
1799
1800 /*
1801 * grub_vbe_status_t grub_vbe_bios_get_mode_info (grub_uint32_t mode,
1802 * struct grub_vbe_mode_info_block *mode_info)
1803 *
1804 * Register allocations for parameters:
1805 * %eax mode
1806 * %edx *mode_info
1807 */
1808 FUNCTION(grub_vbe_bios_get_mode_info)
1809 pushl %ebp
1810 pushl %edi
1811
1812 movl %eax, %ecx /* Store mode number to %ecx. */
1813
1814 movw %dx, %di /* Store *mode_info to %edx:%di. */
1815 xorw %dx, %dx
1816 shrl $4, %edx
1817
1818 call prot_to_real
1819 .code16
1820
1821 pushw %es
1822
1823 movw %dx, %es /* *mode_info is now on %es:%di. */
1824 movw $0x4f01, %ax
1825 int $0x10
1826
1827 movw %ax, %dx /* real_to_prot destroys %eax. */
1828
1829 popw %es
1830
1831 DATA32 call real_to_prot
1832 .code32
1833
1834 movl %edx, %eax
1835 andl $0x0FFFF, %eax /* Return value in %eax. */
1836
1837 popl %edi
1838 popl %ebp
1839 ret
1840
1841 /*
1842 * grub_vbe_status_t grub_vbe_bios_set_mode (grub_uint32_t mode,
1843 * struct grub_vbe_crtc_info_block *crtc_info)
1844 *
1845 * Register allocations for parameters:
1846 * %eax mode
1847 * %edx *crtc_info
1848 */
1849 FUNCTION(grub_vbe_bios_set_mode)
1850 pushl %ebp
1851 pushl %ebx
1852 pushl %edi
1853
1854 movl %eax, %ebx /* Store mode in %ebx. */
1855
1856 movw %dx, %di /* Store *crtc_info to %edx:%di. */
1857 xorw %dx, %dx
1858 shrl $4, %edx
1859
1860 call prot_to_real
1861 .code16
1862
1863 pushw %es
1864
1865 movw %dx, %es /* *crtc_info is now on %es:%di. */
1866
1867 movw $0x4f02, %ax
1868 int $0x10
1869
1870 movw %ax, %dx /* real_to_prot destroys %eax. */
1871
1872 popw %es
1873
1874 DATA32 call real_to_prot
1875 .code32
1876
1877 movw %dx, %ax
1878 andl $0xFFFF, %eax /* Return value in %eax. */
1879
1880 popl %edi
1881 popl %ebx
1882 popl %ebp
1883 ret
1884
1885 /*
1886 * grub_vbe_status_t grub_vbe_bios_get_mode (grub_uint32_t *mode)
1887 *
1888 * Register allocations for parameters:
1889 * %eax *mode
1890 */
1891 FUNCTION(grub_vbe_bios_get_mode)
1892 pushl %ebp
1893 pushl %ebx
1894 pushl %edi
1895 pushl %edx
1896 pushl %eax /* Push *mode to stack. */
1897
1898 call prot_to_real
1899 .code16
1900
1901 movw $0x4f03, %ax
1902 int $0x10
1903
1904 movw %ax, %dx /* real_to_prot destroys %eax. */
1905
1906 DATA32 call real_to_prot
1907 .code32
1908
1909 popl %edi /* Pops *mode from stack to %edi. */
1910 andl $0xFFFF, %ebx
1911 movl %ebx, (%edi)
1912
1913 movw %dx, %ax
1914 andl $0xFFFF, %eax /* Return value in %eax. */
1915
1916 popl %edx
1917 popl %edi
1918 popl %ebx
1919 popl %ebp
1920 ret
1921
1922 /*
1923 * grub_vbe_status_t grub_vbe_bios_set_memory_window (grub_uint32_t window,
1924 * grub_uint32_t position);
1925 *
1926 * Register allocations for parameters:
1927 * %eax window
1928 * %edx position
1929 */
1930 FUNCTION(grub_vbe_bios_set_memory_window)
1931 pushl %ebp
1932 pushl %ebx
1933
1934 movl %eax, %ebx
1935
1936 call prot_to_real
1937 .code16
1938
1939 movw $0x4f05, %ax
1940 andw $0x00ff, %bx /* BL = window, BH = 0, Set memory window. */
1941 int $0x10
1942
1943 movw %ax, %dx /* real_to_prot destroys %eax. */
1944
1945 DATA32 call real_to_prot
1946 .code32
1947
1948 movw %dx, %ax
1949 andl $0xFFFF, %eax /* Return value in %eax. */
1950
1951 popl %ebx
1952 popl %ebp
1953 ret
1954
1955 /*
1956 * grub_vbe_status_t grub_vbe_bios_get_memory_window (grub_uint32_t window,
1957 * grub_uint32_t *position);
1958 *
1959 * Register allocations for parameters:
1960 * %eax window
1961 * %edx *position
1962 */
1963 FUNCTION(grub_vbe_bios_get_memory_window)
1964 pushl %ebp
1965 pushl %ebx
1966 pushl %edi
1967 pushl %edx /* Push *position to stack. */
1968
1969 movl %eax, %ebx /* Store window in %ebx. */
1970
1971 call prot_to_real
1972 .code16
1973
1974 movw $0x4f05, %ax
1975 andw $0x00ff, %bx /* BL = window. */
1976 orw $0x0100, %bx /* BH = 1, Get memory window. */
1977 int $0x10
1978
1979 movw %ax, %bx /* real_to_prot destroys %eax. */
1980
1981 DATA32 call real_to_prot
1982 .code32
1983
1984 popl %edi /* pops *position from stack to %edi. */
1985 andl $0xFFFF, %edx
1986 movl %edx, (%edi) /* Return position to caller. */
1987
1988 movw %bx, %ax
1989 andl $0xFFFF, %eax /* Return value in %eax. */
1990
1991 popl %edi
1992 popl %ebx
1993 popl %ebp
1994 ret
1995
1996 /*
1997 * grub_vbe_status_t grub_vbe_bios_set_scanline_length (grub_uint32_t length)
1998 *
1999 * Register allocations for parameters:
2000 * %eax length
2001 */
2002 FUNCTION(grub_vbe_bios_set_scanline_length)
2003 pushl %ebp
2004 pushl %ebx
2005 pushl %edx
2006
2007 movl %eax, %ecx /* Store length in %ecx. */
2008
2009 call prot_to_real
2010 .code16
2011
2012 movw $0x4f06, %ax
2013 movw $0x0002, %bx /* BL = 2, Set Scan Line in Bytes. */
2014 int $0x10
2015
2016 movw %ax, %dx /* real_to_prot destroys %eax. */
2017
2018 DATA32 call real_to_prot
2019 .code32
2020
2021 movw %dx, %ax
2022 andl $0xFFFF, %eax /* Return value in %eax. */
2023
2024 popl %edx
2025 popl %ebx
2026 popl %ebp
2027 ret
2028
2029 /*
2030 * grub_vbe_status_t grub_vbe_bios_get_scanline_length (grub_uint32_t *length)
2031 *
2032 * Register allocations for parameters:
2033 * %eax *length
2034 */
2035 FUNCTION(grub_vbe_bios_get_scanline_length)
2036 pushl %ebp
2037 pushl %ebx
2038 pushl %edi
2039 pushl %edx /* Push *length to stack. */
2040
2041 call prot_to_real
2042 .code16
2043
2044 movw $0x4f06, %ax
2045 movw $0x0001, %bx /* BL = 1, Get Scan Line Length (in bytes). */
2046 int $0x10
2047
2048 movw %ax, %dx /* real_to_prot destroys %eax. */
2049
2050 DATA32 call real_to_prot
2051 .code32
2052
2053 popl %edi /* Pops *length from stack to %edi. */
2054 andl $0xFFFF, %ebx
2055 movl %ebx, (%edi) /* Return length to caller. */
2056
2057 movw %dx, %ax
2058 andl $0xFFFF, %eax /* Return value in %eax. */
2059
2060 popl %edi
2061 popl %ebx
2062 popl %ebp
2063 ret
2064
2065 /*
2066 * grub_vbe_status_t grub_vbe_bios_set_display_start (grub_uint32_t x,
2067 * grub_uint32_t y)
2068 *
2069 * Register allocations for parameters:
2070 * %eax x
2071 * %edx y
2072 */
2073 FUNCTION(grub_vbe_bios_set_display_start)
2074 pushl %ebp
2075 pushl %ebx
2076
2077 movl %eax, %ecx /* Store x in %ecx. */
2078
2079 call prot_to_real
2080 .code16
2081
2082 movw $0x4f07, %ax
2083 movw $0x0080, %bx /* BL = 80h, Set Display Start
2084 during Vertical Retrace. */
2085 int $0x10
2086
2087 movw %ax, %dx /* real_to_prot destroys %eax. */
2088
2089 DATA32 call real_to_prot
2090 .code32
2091
2092 movw %dx, %ax
2093 andl $0xFFFF, %eax /* Return value in %eax. */
2094
2095 popl %ebx
2096 popl %ebp
2097 ret
2098
2099 /*
2100 * grub_vbe_status_t grub_vbe_bios_get_display_start (grub_uint32_t *x,
2101 * grub_uint32_t *y)
2102 *
2103 * Register allocations for parameters:
2104 * %eax *x
2105 * %edx *y
2106 */
2107 FUNCTION(grub_vbe_bios_get_display_start)
2108 pushl %ebp
2109 pushl %ebx
2110 pushl %edi
2111 pushl %eax /* Push *x to stack. */
2112 pushl %edx /* Push *y to stack. */
2113
2114 call prot_to_real
2115 .code16
2116
2117 movw $0x4f07, %ax
2118 movw $0x0001, %bx /* BL = 1, Get Display Start. */
2119 int $0x10
2120
2121 movw %ax, %bx /* real_to_prot destroys %eax. */
2122
2123 DATA32 call real_to_prot
2124 .code32
2125
2126 popl %edi /* Pops *y from stack to %edi. */
2127 andl $0xFFFF, %edx
2128 movl %edx, (%edi) /* Return y-position to caller. */
2129
2130 popl %edi /* Pops *x from stack to %edi. */
2131 andl $0xFFFF, %ecx
2132 movl %ecx, (%edi) /* Return x-position to caller. */
2133
2134 movw %bx, %ax
2135 andl $0xFFFF, %eax /* Return value in %eax. */
2136
2137 popl %edi
2138 popl %ebx
2139 popl %ebp
2140 ret
2141
2142 /*
2143 * grub_vbe_status_t grub_vbe_bios_set_palette_data (grub_uint32_t color_count,
2144 * grub_uint32_t start_index,
2145 * struct grub_vbe_palette_data *palette_data)
2146 *
2147 * Register allocations for parameters:
2148 * %eax color_count
2149 * %edx start_index
2150 * %ecx *palette_data
2151 */
2152 FUNCTION(grub_vbe_bios_set_palette_data)
2153 pushl %ebp
2154 pushl %ebx
2155 pushl %edi
2156
2157 movl %eax, %ebx /* Store color_count in %ebx. */
2158
2159 movw %cx, %di /* Store *palette_data to %ecx:%di. */
2160 xorw %cx, %cx
2161 shrl $4, %ecx
2162
2163 call prot_to_real
2164 .code16
2165
2166 pushw %es
2167
2168 movw %cx, %es /* *palette_data is now on %es:%di. */
2169 movw %bx, %cx /* color_count is now on %cx. */
2170
2171 movw $0x4f09, %ax
2172 xorw %bx, %bx /* BL = 0, Set Palette Data. */
2173 int $0x10
2174
2175 movw %ax, %dx /* real_to_prot destroys %eax. */
2176
2177 popw %es
2178
2179 DATA32 call real_to_prot
2180 .code32
2181
2182 movw %dx, %ax
2183 andl $0xFFFF, %eax /* Return value in %eax. */
2184
2185 popl %edi
2186 popl %ebx
2187 popl %ebp
2188 ret