]> git.proxmox.com Git - grub2.git/blob - grub-core/kern/i386/pc/startup.S
01825396cbb8a5ae405b45c140dbaebb561cdda3
[grub2.git] / grub-core / kern / i386 / pc / startup.S
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
4 *
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19
20 /*
21 * Note: These functions defined in this file may be called from C.
22 * Be careful of that you must not modify some registers. Quote
23 * from gcc-2.95.2/gcc/config/i386/i386.h:
24
25 1 for registers not available across function calls.
26 These must include the FIXED_REGISTERS and also any
27 registers that can be used without being saved.
28 The latter must include the registers where values are returned
29 and the register where structure-value addresses are passed.
30 Aside from that, you can include as many other registers as you like.
31
32 ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg
33 { 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
34 */
35
36 /*
37 * Note: GRUB is compiled with the options -mrtd and -mregparm=3.
38 * So the first three arguments are passed in %eax, %edx, and %ecx,
39 * respectively, and if a function has a fixed number of arguments
40 * and the number is greater than three, the function must return
41 * with "ret $N" where N is ((the number of arguments) - 3) * 4.
42 */
43
44 #include <config.h>
45 #include <grub/symbol.h>
46 #include <grub/boot.h>
47 #include <grub/machine/boot.h>
48 #include <grub/machine/memory.h>
49 #include <grub/machine/console.h>
50 #include <grub/cpu/linux.h>
51 #include <grub/machine/kernel.h>
52 #include <grub/term.h>
53 #include <multiboot.h>
54 #include <multiboot2.h>
55
56 #define ABS(x) ((x) - LOCAL (base) + GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200)
57
58 .file "startup.S"
59
60 .text
61
62 /* Tell GAS to generate 16-bit instructions so that this code works
63 in real mode. */
64 .code16
65
66 .globl start, _start
67 start:
68 _start:
69 LOCAL (base):
70 /*
71 * Guarantee that "main" is loaded at 0x0:0x8200.
72 */
73 #ifdef __APPLE__
74 ljmp $0, $(ABS(LOCAL (codestart)) - 0x10000)
75 #else
76 ljmp $0, $ABS(LOCAL (codestart))
77 #endif
78 /*
79 * Compatibility version number
80 *
81 * These MUST be at byte offset 6 and 7 of the executable
82 * DO NOT MOVE !!!
83 */
84 . = _start + 0x6
85 .byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR
86
87 /*
88 * This is a special data area 8 bytes from the beginning.
89 */
90
91 . = _start + 0x8
92
93 VARIABLE(grub_total_module_size)
94 .long 0
95 VARIABLE(grub_kernel_image_size)
96 .long 0
97 VARIABLE(grub_compressed_size)
98 .long 0
99 VARIABLE(grub_install_dos_part)
100 .long 0xFFFFFFFF
101 VARIABLE(grub_install_bsd_part)
102 .long 0xFFFFFFFF
103 reed_solomon_redundancy:
104 .long 0
105
106 #ifdef APPLE_CC
107 bss_start:
108 .long 0
109 bss_end:
110 .long 0
111 #endif
112
113 /*
114 * Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself).
115 * This uses the a.out kludge to load raw binary to the area starting at 1MB,
116 * and relocates itself after loaded.
117 */
118 .p2align 2 /* force 4-byte alignment */
119 multiboot_header:
120 /* magic */
121 .long 0x1BADB002
122 /* flags */
123 .long (1 << 16)
124 /* checksum */
125 .long -0x1BADB002 - (1 << 16)
126 /* header addr */
127 .long multiboot_header - _start + 0x100000 + 0x200
128 /* load addr */
129 .long 0x100000
130 /* load end addr */
131 .long 0
132 /* bss end addr */
133 .long 0
134 /* entry addr */
135 .long multiboot_entry - _start + 0x100000 + 0x200
136
137 multiboot_entry:
138 .code32
139 /* obtain the boot device */
140 movl 12(%ebx), %edx
141
142 movl $GRUB_MEMORY_MACHINE_PROT_STACK, %ebp
143 movl %ebp, %esp
144
145 /* relocate the code */
146 movl $(GRUB_KERNEL_MACHINE_RAW_SIZE + 0x200), %ecx
147 addl EXT_C(grub_compressed_size) - _start + 0x100000 + 0x200, %ecx
148 movl $0x100000, %esi
149 movl $GRUB_BOOT_MACHINE_KERNEL_ADDR, %edi
150 cld
151 rep
152 movsb
153 /* jump to the real address */
154 movl $multiboot_trampoline, %eax
155 jmp *%eax
156
157 multiboot_trampoline:
158 /* fill the boot information */
159 movl %edx, %eax
160 shrl $8, %eax
161 xorl %ebx, %ebx
162 cmpb $0xFF, %ah
163 je 1f
164 movb %ah, %bl
165 movl %ebx, EXT_C(grub_install_dos_part)
166 1:
167 cmpb $0xFF, %al
168 je 2f
169 movb %al, %bl
170 movl %ebx, EXT_C(grub_install_bsd_part)
171 2:
172 shrl $24, %edx
173 movb $0xFF, %dh
174 /* enter the usual booting */
175 call prot_to_real
176 .code16
177
178 /* the real mode code continues... */
179 LOCAL (codestart):
180 cli /* we're not safe here! */
181
182 /* set up %ds, %ss, and %es */
183 xorw %ax, %ax
184 movw %ax, %ds
185 movw %ax, %ss
186 movw %ax, %es
187
188 /* set up the real mode/BIOS stack */
189 movl $GRUB_MEMORY_MACHINE_REAL_STACK, %ebp
190 movl %ebp, %esp
191
192 sti /* we're safe again */
193
194 /* save the boot drive */
195 ADDR32 movb %dl, EXT_C(grub_boot_drive)
196
197 /* reset disk system (%ah = 0) */
198 int $0x13
199
200 /* transition to protected mode */
201 DATA32 call real_to_prot
202
203 /* The ".code32" directive takes GAS out of 16-bit mode. */
204 .code32
205
206 incl %eax
207 call grub_gate_a20
208
209 #ifdef ENABLE_LZMA
210 movl $GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR, %edi
211 movl $(_start + GRUB_KERNEL_MACHINE_RAW_SIZE), %esi
212 pushl %edi
213 pushl %esi
214 movl EXT_C(grub_kernel_image_size), %ecx
215 addl EXT_C(grub_total_module_size), %ecx
216 subl $GRUB_KERNEL_MACHINE_RAW_SIZE, %ecx
217 pushl %ecx
218 leal (%edi, %ecx), %ebx
219 call _LzmaDecodeA
220 /* _LzmaDecodeA clears DF, so no need to run cld */
221 popl %ecx
222 popl %edi
223 popl %esi
224 #endif
225
226 /* copy back the decompressed part (except the modules) */
227 subl EXT_C(grub_total_module_size), %ecx
228 rep
229 movsb
230
231 #if 0
232 /* copy modules before cleaning out the bss */
233 movl EXT_C(grub_total_module_size), %ecx
234 movl EXT_C(grub_kernel_image_size), %esi
235 addl %ecx, %esi
236 addl $_start, %esi
237 decl %esi
238 movl $END_SYMBOL, %edi
239 addl %ecx, %edi
240 decl %edi
241 std
242 rep
243 movsb
244 #endif
245
246 #ifdef APPLE_CC
247 /* clean out the bss */
248 bss_start_abs = ABS (bss_start)
249 bss_end_abs = ABS (bss_end)
250
251 movl bss_start_abs, %edi
252
253 /* compute the bss length */
254 movl bss_end_abs, %ecx
255 subl %edi, %ecx
256 #else
257 /* clean out the bss */
258 movl $BSS_START_SYMBOL, %edi
259
260 /* compute the bss length */
261 movl $END_SYMBOL, %ecx
262 subl %edi, %ecx
263 #endif
264
265 /* clean out */
266 xorl %eax, %eax
267 cld
268 rep
269 stosb
270
271 /*
272 * Call the start of main body of C code.
273 */
274 call EXT_C(grub_main)
275
276 /*
277 * This is the area for all of the special variables.
278 */
279
280 VARIABLE(grub_boot_drive)
281 .byte 0
282
283 .p2align 2 /* force 4-byte alignment */
284
285 #include "../realmode.S"
286
287 /*
288 * grub_gate_a20(int on)
289 *
290 * Gate address-line 20 for high memory.
291 *
292 * This routine is probably overconservative in what it does, but so what?
293 *
294 * It also eats any keystrokes in the keyboard buffer. :-(
295 */
296
297 grub_gate_a20:
298 movl %eax, %edx
299
300 gate_a20_test_current_state:
301 /* first of all, test if already in a good state */
302 call gate_a20_check_state
303 cmpb %al, %dl
304 jnz gate_a20_try_bios
305 ret
306
307 gate_a20_try_bios:
308 /* second, try a BIOS call */
309 pushl %ebp
310 call prot_to_real
311
312 .code16
313 movw $0x2400, %ax
314 testb %dl, %dl
315 jz 1f
316 incw %ax
317 1: int $0x15
318
319 DATA32 call real_to_prot
320 .code32
321
322 popl %ebp
323 call gate_a20_check_state
324 cmpb %al, %dl
325 jnz gate_a20_try_system_control_port_a
326 ret
327
328 gate_a20_try_system_control_port_a:
329 /*
330 * In macbook, the keyboard test would hang the machine, so we move
331 * this forward.
332 */
333 /* fourth, try the system control port A */
334 inb $0x92
335 andb $(~0x03), %al
336 testb %dl, %dl
337 jz 6f
338 orb $0x02, %al
339 6: outb $0x92
340
341 /* When turning off Gate A20, do not check the state strictly,
342 because a failure is not fatal usually, and Gate A20 is always
343 on some modern machines. */
344 testb %dl, %dl
345 jz 7f
346 call gate_a20_check_state
347 cmpb %al, %dl
348 jnz gate_a20_try_keyboard_controller
349 7: ret
350
351 gate_a20_flush_keyboard_buffer:
352 inb $0x64
353 andb $0x02, %al
354 jnz gate_a20_flush_keyboard_buffer
355 2:
356 inb $0x64
357 andb $0x01, %al
358 jz 3f
359 inb $0x60
360 jmp 2b
361 3:
362 ret
363
364 gate_a20_try_keyboard_controller:
365 /* third, try the keyboard controller */
366 call gate_a20_flush_keyboard_buffer
367
368 movb $0xd1, %al
369 outb $0x64
370 4:
371 inb $0x64
372 andb $0x02, %al
373 jnz 4b
374
375 movb $0xdd, %al
376 testb %dl, %dl
377 jz 5f
378 orb $0x02, %al
379 5: outb $0x60
380 call gate_a20_flush_keyboard_buffer
381
382 /* output a dummy command (USB keyboard hack) */
383 movb $0xff, %al
384 outb $0x64
385 call gate_a20_flush_keyboard_buffer
386
387 call gate_a20_check_state
388 cmpb %al, %dl
389 /* everything failed, so restart from the beginning */
390 jnz gate_a20_try_bios
391 ret
392
393 gate_a20_check_state:
394 /* iterate the checking for a while */
395 movl $100, %ecx
396 1:
397 call 3f
398 cmpb %al, %dl
399 jz 2f
400 loop 1b
401 2:
402 ret
403 3:
404 pushl %ebx
405 pushl %ecx
406 xorl %eax, %eax
407 /* compare the byte at 0x8000 with that at 0x108000 */
408 movl $GRUB_BOOT_MACHINE_KERNEL_ADDR, %ebx
409 pushl %ebx
410 /* save the original byte in CL */
411 movb (%ebx), %cl
412 /* store the value at 0x108000 in AL */
413 addl $0x100000, %ebx
414 movb (%ebx), %al
415 /* try to set one less value at 0x8000 */
416 popl %ebx
417 movb %al, %ch
418 decb %ch
419 movb %ch, (%ebx)
420 /* serialize */
421 outb %al, $0x80
422 outb %al, $0x80
423 /* obtain the value at 0x108000 in CH */
424 pushl %ebx
425 addl $0x100000, %ebx
426 movb (%ebx), %ch
427 /* this result is 1 if A20 is on or 0 if it is off */
428 subb %ch, %al
429 xorb $1, %al
430 /* restore the original */
431 popl %ebx
432 movb %cl, (%ebx)
433 popl %ecx
434 popl %ebx
435 ret
436
437 #ifdef ENABLE_LZMA
438 #include "lzma_decode.S"
439 #endif
440
441 /*
442 * The code beyond this point is compressed. Assert that the uncompressed
443 * code fits GRUB_KERNEL_MACHINE_RAW_SIZE.
444 */
445 . = _start + GRUB_KERNEL_MACHINE_RAW_SIZE
446
447 . = _start + GRUB_KERNEL_MACHINE_PREFIX
448 VARIABLE(grub_prefix)
449 /* to be filled by grub-mkimage */
450
451 /*
452 * Leave some breathing room for the prefix.
453 */
454 . = _start + GRUB_KERNEL_MACHINE_PREFIX_END
455
456
457
458 /*
459 * grub_exit()
460 *
461 * Exit the system.
462 */
463 FUNCTION(grub_exit)
464 call prot_to_real
465 .code16
466 /* Tell the BIOS a boot failure. If this does not work, reboot. */
467 int $0x18
468 jmp cold_reboot
469 .code32
470
471 /*
472 * void grub_chainloader_real_boot (int drive, void *part_addr)
473 *
474 * This starts another boot loader.
475 */
476
477 FUNCTION(grub_chainloader_real_boot)
478 pushl %edx
479 pushl %eax
480
481 /* Turn off Gate A20 */
482 xorl %eax, %eax
483 call grub_gate_a20
484
485 /* set up to pass boot drive */
486 popl %edx
487
488 /* ESI must point to a partition table entry */
489 popl %esi
490
491 call prot_to_real
492 .code16
493 ljmp $0, $GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR
494 .code32
495
496 /*
497 * void grub_console_putchar (int c)
498 *
499 * Put the character C on the console. Because GRUB wants to write a
500 * character with an attribute, this implementation is a bit tricky.
501 * If C is a control character (CR, LF, BEL, BS), use INT 10, AH = 0Eh
502 * (TELETYPE OUTPUT). Otherwise, save the original position, put a space,
503 * save the current position, restore the original position, write the
504 * character and the attribute, and restore the current position.
505 *
506 * The reason why this is so complicated is that there is no easy way to
507 * get the height of the screen, and the TELETYPE OUTPUT BIOS call doesn't
508 * support setting a background attribute.
509 */
510 FUNCTION(grub_console_putchar)
511 /* Retrieve the base character. */
512 movl 0(%edx), %edx
513 pusha
514 movb EXT_C(grub_console_cur_color), %bl
515
516 call prot_to_real
517 .code16
518 movb %dl, %al
519 xorb %bh, %bh
520
521 /* use teletype output if control character */
522 cmpb $0x7, %al
523 je 1f
524 cmpb $0x8, %al
525 je 1f
526 cmpb $0xa, %al
527 je 1f
528 cmpb $0xd, %al
529 je 1f
530
531 /* save the character and the attribute on the stack */
532 pushw %ax
533 pushw %bx
534
535 /* get the current position */
536 movb $0x3, %ah
537 int $0x10
538
539 /* check the column with the width */
540 cmpb $79, %dl
541 jl 2f
542
543 /* print CR and LF, if next write will exceed the width */
544 movw $0x0e0d, %ax
545 int $0x10
546 movb $0x0a, %al
547 int $0x10
548
549 /* get the current position */
550 movb $0x3, %ah
551 int $0x10
552
553 2:
554 /* restore the character and the attribute */
555 popw %bx
556 popw %ax
557
558 /* write the character with the attribute */
559 movb $0x9, %ah
560 movw $1, %cx
561 int $0x10
562
563 /* move the cursor forward */
564 incb %dl
565 movb $0x2, %ah
566 int $0x10
567
568 jmp 3f
569
570 1: movw $1, %bx
571 movb $0xe, %ah
572 int $0x10
573
574 3: DATA32 call real_to_prot
575 .code32
576
577 popa
578 ret
579
580
581 LOCAL(bypass_table):
582 .word 0x0100 | '\e',0x0f00 | '\t', 0x0e00 | '\b', 0x1c00 | '\r'
583 .word 0x1c00 | '\n'
584 LOCAL(bypass_table_end):
585
586 /*
587 * int grub_console_getkey (void)
588 * if there is a character pending, return it; otherwise return -1
589 * BIOS call "INT 16H Function 01H" to check whether a character is pending
590 * Call with %ah = 0x1
591 * Return:
592 * If key waiting to be input:
593 * %ah = keyboard scan code
594 * %al = ASCII character
595 * Zero flag = clear
596 * else
597 * Zero flag = set
598 * BIOS call "INT 16H Function 00H" to read character from keyboard
599 * Call with %ah = 0x0
600 * Return: %ah = keyboard scan code
601 * %al = ASCII character
602 */
603
604 FUNCTION(grub_console_getkey)
605 pushl %ebp
606
607 call prot_to_real
608 .code16
609
610 /*
611 * Due to a bug in apple's bootcamp implementation, INT 16/AH = 0 would
612 * cause the machine to hang at the second keystroke. However, we can
613 * work around this problem by ensuring the presence of keystroke with
614 * INT 16/AH = 1 before calling INT 16/AH = 0.
615 */
616
617 movb $1, %ah
618 int $0x16
619 jz notpending
620
621 movb $0, %ah
622 int $0x16
623
624 xorl %edx, %edx
625 movw %ax, %dx /* real_to_prot uses %eax */
626
627 DATA32 call real_to_prot
628 .code32
629
630 movl $0xff, %eax
631 testl %eax, %edx
632 jz 1f
633
634 andl %edx, %eax
635 cmp %eax, 0x20
636 ja 2f
637 movl %edx, %eax
638 leal LOCAL(bypass_table), %esi
639 movl $((LOCAL(bypass_table_end) - LOCAL(bypass_table)) / 2), %ecx
640 repne cmpsw
641 jz 3f
642
643 addl $('a' - 1 | GRUB_TERM_CTRL), %eax
644 jmp 2f
645 3:
646 andl $0xff, %eax
647 jmp 2f
648
649 1: movl %edx, %eax
650 shrl $8, %eax
651 orl $GRUB_TERM_EXTENDED, %eax
652 2:
653 popl %ebp
654 ret
655
656 notpending:
657 .code16
658 DATA32 call real_to_prot
659 .code32
660 #if GRUB_TERM_NO_KEY != 0
661 #error Fix this asm code
662 #endif
663 jmp 2b
664
665
666 /*
667 * grub_uint16_t grub_console_getxy (void)
668 * BIOS call "INT 10H Function 03h" to get cursor position
669 * Call with %ah = 0x03
670 * %bh = page
671 * Returns %ch = starting scan line
672 * %cl = ending scan line
673 * %dh = row (0 is top)
674 * %dl = column (0 is left)
675 */
676
677
678 FUNCTION(grub_console_getxy)
679 pushl %ebp
680 pushl %ebx /* save EBX */
681
682 call prot_to_real
683 .code16
684
685 xorb %bh, %bh /* set page to 0 */
686 movb $0x3, %ah
687 int $0x10 /* get cursor position */
688
689 DATA32 call real_to_prot
690 .code32
691
692 movb %dl, %ah
693 movb %dh, %al
694
695 popl %ebx
696 popl %ebp
697 ret
698
699
700 /*
701 * void grub_console_gotoxy(grub_uint8_t x, grub_uint8_t y)
702 * BIOS call "INT 10H Function 02h" to set cursor position
703 * Call with %ah = 0x02
704 * %bh = page
705 * %dh = row (0 is top)
706 * %dl = column (0 is left)
707 */
708
709
710 FUNCTION(grub_console_gotoxy)
711 pushl %ebp
712 pushl %ebx /* save EBX */
713
714 movb %cl, %dh /* %dh = y */
715 /* %dl = x */
716
717 call prot_to_real
718 .code16
719
720 xorb %bh, %bh /* set page to 0 */
721 movb $0x2, %ah
722 int $0x10 /* set cursor position */
723
724 DATA32 call real_to_prot
725 .code32
726
727 popl %ebx
728 popl %ebp
729 ret
730
731
732 /*
733 * void grub_console_cls (void)
734 * BIOS call "INT 10H Function 09h" to write character and attribute
735 * Call with %ah = 0x09
736 * %al = (character)
737 * %bh = (page number)
738 * %bl = (attribute)
739 * %cx = (number of times)
740 */
741
742 FUNCTION(grub_console_cls)
743 pushl %ebp
744 pushl %ebx /* save EBX */
745
746 call prot_to_real
747 .code16
748
749 /* move the cursor to the beginning */
750 movb $0x02, %ah
751 xorb %bh, %bh
752 xorw %dx, %dx
753 int $0x10
754
755 /* write spaces to the entire screen */
756 movw $0x0920, %ax
757 movw $0x07, %bx
758 movw $(80 * 25), %cx
759 int $0x10
760
761 /* move back the cursor */
762 movb $0x02, %ah
763 int $0x10
764
765 DATA32 call real_to_prot
766 .code32
767
768 popl %ebx
769 popl %ebp
770 ret
771
772
773 /*
774 * void grub_console_setcursor (int on)
775 * BIOS call "INT 10H Function 01h" to set cursor type
776 * Call with %ah = 0x01
777 * %ch = cursor starting scanline
778 * %cl = cursor ending scanline
779 */
780
781 console_cursor_state:
782 .byte 1
783 console_cursor_shape:
784 .word 0
785
786 FUNCTION(grub_console_setcursor)
787 pushl %ebp
788 pushl %ebx
789
790 /* push ON */
791 pushl %edx
792
793 /* check if the standard cursor shape has already been saved */
794 movw console_cursor_shape, %ax
795 testw %ax, %ax
796 jne 1f
797
798 call prot_to_real
799 .code16
800
801 movb $0x03, %ah
802 xorb %bh, %bh
803 int $0x10
804
805 DATA32 call real_to_prot
806 .code32
807
808 movw %cx, console_cursor_shape
809 1:
810 /* set %cx to the designated cursor shape */
811 movw $0x2000, %cx
812 popl %eax
813 testl %eax, %eax
814 jz 2f
815 movw console_cursor_shape, %cx
816 2:
817 call prot_to_real
818 .code16
819
820 movb $0x1, %ah
821 int $0x10
822
823 DATA32 call real_to_prot
824 .code32
825
826 popl %ebx
827 popl %ebp
828 ret
829
830 /*
831 * grub_get_rtc()
832 * return the real time in ticks, of which there are about
833 * 18-20 per second
834 */
835 FUNCTION(grub_get_rtc)
836 pushl %ebp
837
838 call prot_to_real /* enter real mode */
839 .code16
840
841 /* %ax is already zero */
842 int $0x1a
843
844 DATA32 call real_to_prot
845 .code32
846
847 movl %ecx, %eax
848 shll $16, %eax
849 movw %dx, %ax
850
851 popl %ebp
852 ret
853
854 /*
855 * int grub_pxe_call (int func, void* data, grub_uint32_t pxe_rm_entry);
856 */
857 FUNCTION(grub_pxe_call)
858 pushl %ebp
859 movl %esp, %ebp
860 pushl %esi
861 pushl %edi
862 pushl %ebx
863
864 movl %ecx, %ebx
865 movl %eax, %ecx
866 movl %edx, %eax
867 andl $0xF, %eax
868 shrl $4, %edx
869 shll $16, %edx
870 addl %eax, %edx
871
872 call prot_to_real
873 .code16
874
875 pushl %ebx
876 pushl %edx
877 pushw %cx
878 movw %sp, %bx
879 lcall *%ss:6(%bx)
880 cld
881 addw $10, %sp
882 movw %ax, %cx
883
884 DATA32 call real_to_prot
885 .code32
886
887 movzwl %cx, %eax
888
889 popl %ebx
890 popl %edi
891 popl %esi
892 popl %ebp
893 ret
894
895 FUNCTION(grub_bios_interrupt)
896 pushl %ebp
897 pushl %ecx
898 pushl %eax
899 pushl %ebx
900 pushl %esi
901 pushl %edi
902 pushl %edx
903
904 movb %al, intno
905 movl (%edx), %eax
906 movl %eax, LOCAL(bios_register_eax)
907 movw 4(%edx), %ax
908 movw %ax, LOCAL(bios_register_es)
909 movw 6(%edx), %ax
910 movw %ax, LOCAL(bios_register_ds)
911 movw 8(%edx), %ax
912 movw %ax, LOCAL(bios_register_flags)
913
914 movl 12(%edx), %ebx
915 movl 16(%edx), %ecx
916 movl 20(%edx), %edi
917 movl 24(%edx), %esi
918 movl 28(%edx), %edx
919
920 call prot_to_real
921 .code16
922
923 mov %ds, %ax
924 push %ax
925
926 /* movw imm16, %ax*/
927 .byte 0xb8
928 LOCAL(bios_register_es):
929 .short 0
930 movw %ax, %es
931 /* movw imm16, %ax*/
932 .byte 0xb8
933 LOCAL(bios_register_ds):
934 .short 0
935 movw %ax, %ds
936
937 /* movw imm16, %ax*/
938 .byte 0xb8
939 LOCAL(bios_register_flags):
940 .short 0
941 push %ax
942 popf
943
944 /* movl imm32, %eax*/
945 .byte 0x66, 0xb8
946 LOCAL(bios_register_eax):
947 .long 0
948
949 /* int imm8. */
950 .byte 0xcd
951 intno:
952 .byte 0
953
954 movl %eax, %cs:LOCAL(bios_register_eax)
955 movw %ds, %ax
956 movw %ax, %cs:LOCAL(bios_register_ds)
957 pop %ax
958 mov %ax, %ds
959 pushf
960 pop %ax
961 movw %ax, LOCAL(bios_register_flags)
962 mov %es, %ax
963 movw %ax, LOCAL(bios_register_es)
964
965 DATA32 call real_to_prot
966 .code32
967
968 popl %eax
969
970 movl %ebx, 12(%eax)
971 movl %ecx, 16(%eax)
972 movl %edi, 20(%eax)
973 movl %esi, 24(%eax)
974 movl %edx, 28(%eax)
975
976 movl %eax, %edx
977
978 movl LOCAL(bios_register_eax), %eax
979 movl %eax, (%edx)
980 movw LOCAL(bios_register_es), %ax
981 movw %ax, 4(%edx)
982 movw LOCAL(bios_register_ds), %ax
983 movw %ax, 6(%edx)
984 movw LOCAL(bios_register_flags), %ax
985 movw %ax, 8(%edx)
986
987 popl %edi
988 popl %esi
989 popl %ebx
990 popl %eax
991 popl %ecx
992 popl %ebp
993 ret