1/* 2 * GRUB -- GRand Unified Bootloader 3 * Copyright (C) 1999,2000,2001,2002,2004 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#define ASM_FILE 38 39#include "shared.h" 40 41#ifdef STAGE1_5 42# define ABS(x) ((x) - EXT_C(main) + 0x2200) 43#else 44# define ABS(x) ((x) - EXT_C(main) + 0x8200) 45#endif 46 47 .file "asm.S" 48 49 .text 50 51 /* Tell GAS to generate 16-bit instructions so that this code works 52 in real mode. */ 53 .code16 54 55#ifndef STAGE1_5 56 /* 57 * In stage2, do not link start.S with the rest of the source 58 * files directly, so define the start symbols here just to 59 * force ld quiet. These are not referred anyway. 60 */ 61 .globl start, _start 62start: 63_start: 64#endif /* ! STAGE1_5 */ 65 66ENTRY(main) 67 /* 68 * Guarantee that "main" is loaded at 0x0:0x8200 in stage2 and 69 * at 0x0:0x2200 in stage1.5. 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(main) + 0x6 80 .byte COMPAT_VERSION_MAJOR, COMPAT_VERSION_MINOR 81 82 /* 83 * This is a special data area 8 bytes from the beginning. 84 */ 85 86 . = EXT_C(main) + 0x8 87 88VARIABLE(install_partition) 89 .long 0xFFFFFF 90/* This variable is here only because of a historical reason. */ 91VARIABLE(saved_entryno) 92 .long 0 93VARIABLE(stage2_id) 94 .byte STAGE2_ID 95VARIABLE(force_lba) 96 .byte 0 97VARIABLE(version_string) 98 .string VERSION 99VARIABLE(config_file) 100#ifndef STAGE1_5 101 .string "/boot/grub/menu.lst" 102#else /* STAGE1_5 */ 103 .long 0xffffffff 104 .string "/boot/grub/stage2" 105#endif /* STAGE1_5 */ 106 107 /* 108 * Leave some breathing room for the config file name. 109 */ 110 111 . = EXT_C(main) + 0x60 112VARIABLE(fake_mboot) 113 .long 0x1BADB002 114 .long 0x00010003 115 .long -0x1BAEB005 116 /* 117 * installgrub will place the rest of the fake 118 * multiboot header here. 119 */ 120 .= EXT_C(main) + 0x140 121/* the real mode code continues... */ 122codestart: 123 cli /* we're not safe here! */ 124 125 /* set up %ds, %ss, and %es */ 126 xorw %ax, %ax 127 movw %ax, %ds 128 movw %ax, %ss 129 movw %ax, %es 130 131#ifndef SUPPORT_DISKLESS 132 /* 133 * Save the sector number of the second sector (i.e. this sector) 134 * in INSTALL_SECOND_SECTOR. See also "stage2/start.S". 135 */ 136 ADDR32 movl %ebp, EXT_C(install_second_sector) 137#endif 138 139 /* set up the real mode/BIOS stack */ 140 movl $STACKOFF, %ebp 141 movl %ebp, %esp 142 143 sti /* we're safe again */ 144 145#ifndef SUPPORT_DISKLESS 146 /* save boot drive reference */ 147 ADDR32 movb %dl, EXT_C(boot_drive) 148 149 /* reset disk system (%ah = 0) */ 150 int $0x13 151#endif 152 153 /* transition to protected mode */ 154 DATA32 call EXT_C(real_to_prot) 155 156 /* The ".code32" directive takes GAS out of 16-bit mode. */ 157 .code32 158 159 /* clean out the bss */ 160 161 /* set %edi to the bss starting address */ 162#if defined(HAVE_USCORE_USCORE_BSS_START_SYMBOL) 163 movl $__bss_start, %edi 164#elif defined(HAVE_USCORE_EDATA_SYMBOL) 165 movl $_edata, %edi 166#elif defined(HAVE_EDATA_SYMBOL) 167 movl $edata, %edi 168#endif 169 170 /* set %ecx to the bss end */ 171#if defined(HAVE_END_SYMBOL) 172 movl $end, %ecx 173#elif defined(HAVE_USCORE_END_SYMBOL) 174 movl $_end, %ecx 175#endif 176 177 /* compute the bss length */ 178 subl %edi, %ecx 179 180 /* zero %al */ 181 xorb %al, %al 182 183 /* set the direction */ 184 cld 185 186 /* clean out */ 187 rep 188 stosb 189 190 /* 191 * Call the start of main body of C code, which does some 192 * of it's own initialization before transferring to "cmain". 193 */ 194 call EXT_C(init_bios_info) 195 196 197/* 198 * This call is special... it never returns... in fact it should simply 199 * hang at this point! 200 */ 201 202ENTRY(stop) 203 call EXT_C(prot_to_real) 204 205 /* 206 * This next part is sort of evil. It takes advantage of the 207 * byte ordering on the x86 to work in either 16-bit or 32-bit 208 * mode, so think about it before changing it. 209 */ 210 211ENTRY(hard_stop) 212 hlt 213 jmp EXT_C(hard_stop) 214 215#ifndef STAGE1_5 216 217/************************************************************************** 218UNDI_CALL - wrapper around real-mode UNDI API calls 219**************************************************************************/ 220ENTRY(__undi_call) 221 pushl %ebp 222 movl %esp,%ebp 223 pushl %esi 224 pushl %edi 225 pushl %ebx 226 227 movw 8(%ebp),%cx /* Seg:off addr of undi_call_info_t struct */ 228 movw 12(%ebp),%dx /* Pass to 16-bit code in %cx:%dx */ 229 230 call EXT_C(prot_to_real) 231 .code16 232 233 movw %cx,%es /* Seg:off addr of undi_call_info_t struct */ 234 movw %dx,%bx /* into %es:%bx */ 235 236 movw %es:8(%bx),%ax /* Transfer contents of undi_call_info_t */ 237 pushw %ax /* structure to the real-mode stack */ 238 movw %es:6(%bx),%ax 239 pushw %ax 240 movw %es:4(%bx),%ax 241 pushw %ax 242 243 lcall *%es:0(%bx) /* Do the UNDI call */ 244 cld /* Don't know whether or not we need this */ 245 /* but pxelinux includes it for some reason, */ 246 /* so we put it in just in case. */ 247 248 popw %cx /* Tidy up the stack */ 249 popw %cx 250 popw %cx 251 movw %ax,%cx /* Return %ax via %cx */ 252 253 DATA32 call EXT_C(real_to_prot) 254 .code32 255 256 xorl %eax,%eax /* %ax is returned via %cx */ 257 movw %cx,%ax 258 259 popl %ebx 260 popl %edi 261 popl %esi 262 popl %ebp 263 ret 264 265/************************************************************************** 266UNDI_IRQ_HANDLER - UNDI IRQ handler: calls PXENV_UNDI_ISR and send EOI 267NOTE: For some reason, this handler needs to be aligned. Else, the 268 undi driver won't get the trigger count on some platforms. 269**************************************************************************/ 270 .align 4 271ENTRY(_undi_irq_handler) 272 .code16 273 pushw %ax 274 pushw %bx 275 pushw %cx 276 call 1f /* Position-independent access to */ 2771: popw %bx /* various locations. */ 278 pushw %bx /* save for after UNDI call */ 279 280 /* set funcflag to PXENV_UNDI_ISR_IN_START */ 281 movw $1,%cs:(pxenv_undi_isr-1b+2)(%bx) 282 283 /* push pxenv_undi_isr struct on stack */ 284 movl $(ABS(pxenv_undi_isr)),%eax 285 movw %ax,%cx 286 shrl $4,%eax /* get segment */ 287 pushw %ax 288 andw $0xf,%cx /* get offset */ 289 pushw %cx 290 movw $0x14,%ax /* opcode PXENV_UNDI_ISR */ 291 pushw %ax 292 293 lcall *%cs:(pxenv_entrypointsp-1b)(%bx) /* Do the UNDI call */ 294 cld /* Don't know whether or not we need this */ 295 /* but pxelinux includes it for some reason, */ 296 /* so we put it in just in case. */ 297 popw %cx /* Tidy up the stack */ 298 popw %cx 299 popw %cx 300 301 popw %bx /* restore old position reg */ 302 303 cmpw $0,%ax /* did the UNDI call succeed? */ 304 jne 3f 305 movw %cs:(pxenv_undi_isr-1b+2)(%bx),%ax 306 cmpw $0,%ax /* is this our interrupt? */ 307 jne 3f 308 309 /* send EOI -- non specific for now */ 310 movw $0x20,%ax /* ICR_EOI_NON_SPECIFIC */ 311 movb %cs:(pxenv_undi_irq-1b),%cl 312 cmpb $8,%cl 313 jg 2f 314 outb $0xa0 /* PIC2_ICR */ 3152: outb $0x20 /* PIC1_ICR */ 316 317 /* increment trigger count */ 318 incw %cs:(EXT_C(_undi_irq_trigger_count)-1b)(%bx) 319 320 /* restore other registers */ 3213: popw %cx 322 popw %bx 323 popw %ax 324 iret 325ENTRY(_undi_irq_trigger_count) 326undi_irq_trigger_count: 327 .word 0 328ENTRY(_undi_irq_chain_to) 329 .long 0 330ENTRY(_undi_irq_chain) 331 .byte 0 332ENTRY(_pxenv_undi_irq) 333pxenv_undi_irq: 334 .byte 0 335ENTRY(_pxenv_undi_entrypointsp) 336pxenv_entrypointsp: 337 .word 0 /* offset */ 338 .word 0 /* segment */ 339pxenv_undi_isr: 340 .word 0 /* status */ 341 .word 0 /* funcflag */ 342 .long 0 /* struct padding not used by ISR */ 343 .long 0 344 .long 0 345 346 .code32 347 348/* 349 * stop_floppy() 350 * 351 * Stops the floppy drive from spinning, so that other software is 352 * jumped to with a known state. 353 */ 354ENTRY(stop_floppy) 355 pusha 356 call EXT_C(prot_to_real) 357 .code16 358 xorb %dl, %dl 359 int $0x13 360 DATA32 call EXT_C(real_to_prot) 361 .code32 362 popa 363 ret 364 365/* 366 * grub_reboot() 367 * 368 * Reboot the system. At the moment, rely on BIOS. 369 */ 370ENTRY(grub_reboot) 371 call EXT_C(prot_to_real) 372 .code16 373 /* cold boot */ 374 movw $0x0472, %di 375 movw %ax, (%di) 376 ljmp $0xFFFF, $0x0000 377 .code32 378 379/* 380 * grub_halt(int no_apm) 381 * 382 * Halt the system, using APM if possible. If NO_APM is true, don't use 383 * APM even if it is available. 384 */ 385ENTRY(grub_halt) 386 /* get the argument */ 387 movl 4(%esp), %eax 388 389 /* see if zero */ 390 testl %eax, %eax 391 jnz EXT_C(stop) 392 393 call EXT_C(prot_to_real) 394 .code16 395 396 /* detect APM */ 397 movw $0x5300, %ax 398 xorw %bx, %bx 399 int $0x15 400 jc EXT_C(hard_stop) 401 /* don't check %bx for buggy BIOSes... */ 402 403 /* disconnect APM first */ 404 movw $0x5304, %ax 405 xorw %bx, %bx 406 int $0x15 407 408 /* connect APM */ 409 movw $0x5301, %ax 410 xorw %bx, %bx 411 int $0x15 412 jc EXT_C(hard_stop) 413 414 /* set APM protocol level - 1.1 or bust. (this covers APM 1.2 also) */ 415 movw $0x530E, %ax 416 xorw %bx, %bx 417 movw $0x0101, %cx 418 int $0x15 419 jc EXT_C(hard_stop) 420 421 /* set the power state to off */ 422 movw $0x5307, %ax 423 movw $1, %bx 424 movw $3, %cx 425 int $0x15 426 427 /* shouldn't reach here */ 428 jmp EXT_C(hard_stop) 429 .code32 430 431/* 432 * track_int13(int drive) 433 * 434 * Track the int13 handler to probe I/O address space. 435 */ 436ENTRY(track_int13) 437 pushl %ebp 438 movl %esp, %ebp 439 440 pushl %ebx 441 pushl %edi 442 443 /* copy the original int13 handler segment:offset */ 444 movl $0x4c, %edi 445 movl (%edi), %eax 446 movl %eax, track_int13_addr 447 448 /* replace the int1 handler */ 449 movl $0x4, %edi 450 pushl (%edi) 451 movl $ABS(int1_handler), %eax 452 movl %eax, (%edi) 453 454 /* read the MBR to call int13 successfully */ 455 movb 8(%ebp), %dl 456 457 call EXT_C(prot_to_real) 458 .code16 459 460 movw $SCRATCHSEG, %ax 461 movw %ax, %es 462 xorw %bx, %bx 463 movw $1, %cx 464 xorb %dh, %dh 465 466 /* save FLAGS on the stack to emulate int13 */ 467 pushfw 468 469 /* set the TF flag */ 470 /* FIXME: this can be simplified not to use AX */ 471 pushfw 472 popw %ax 473 orw $0x100, %ax 474 pushw %ax 475 popfw 476 477 movw $0x0201, %ax 478 479 .byte 0x9a /* lcall */ 480track_int13_addr: 481 .word 0 /* offset */ 482 .word 0 /* segment */ 483 484 /* TF is cleared here automatically */ 485 486 DATA32 call EXT_C(real_to_prot) 487 .code32 488 489 /* restore the int1 handler */ 490 movl $0x4, %edi 491 popl (%edi) 492 493 popl %edi 494 popl %ebx 495 popl %ebp 496 497 ret 498 499 500/* 501 * Check if the next instruction is I/O, and if this is true, add the 502 * port into the io map. 503 * 504 * Note: Probably this will make the execution of int13 very slow. 505 * 506 * Note2: In this implementation, all we can know is I/O-mapped I/O. It 507 * is impossible to detect memory-mapped I/O. 508 */ 509int1_handler: 510 .code16 511 512 pushw %bp 513 movw %sp, %bp 514 pushw %ds 515 pushw %ax 516 pushw %si 517 pushw %dx 518 519 /* IP */ 520 movw 2(%bp), %si 521 /* CS */ 522 movw 4(%bp), %ax 523 movw %ax, %ds 524 525 /* examine the next instruction */ 5261: lodsb (%si), %al 527 /* skip this code if it is a prefix */ 528 cmpb $0x2E, %al 529 je 1b 530 cmpb $0x36, %al 531 je 1b 532 cmpb $0x3E, %al 533 je 1b 534 cmpb $0x26, %al 535 je 1b 536 cmpb $0x64, %al 537 jl 2f 538 cmpb $0x67, %al 539 jle 1b 5402: cmpb $0xF0, %al 541 jl 3f 542 cmpb $0xF3, %al 543 jle 1b 544 5453: /* check if this code is out* or in* */ 546 547 /* ins? or outs? */ 548 cmpb $0x6C, %al 549 jl 4f 550 cmpb $0x6F, %al 551 jle 5f 552 5534: /* in? or out? (register operand version) */ 554 cmpb $0xEC, %al 555 jl 6f 556 cmpb $0xEF, %al 557 jle 5f 558 5596: /* in? or out? (immediate operand version) */ 560 cmpb $0xE4, %al 561 jl 8f 562 cmpb $0xE7, %al 563 jg 8f 564 5657: /* immediate has a port */ 566 lodsb (%si), %al 567 movzbw %al, %dx 568 5695: /* %dx has a port */ 570 571 /* set %ds to zero */ 572 xorw %ax, %ax 573 movw %ax, %ds 574 575 /* set %si to the io map */ 576 movw $ABS(EXT_C(io_map)), %si 577 578 5799: /* check if the io map already has the port */ 580 lodsw (%si), %ax 581 /* check if this is the end */ 582 testw %ax, %ax 583 jz 1f 584 /* check if this matches the port */ 585 cmpw %ax, %dx 586 jne 9b 587 /* if so, leave from this handler */ 588 jmp 8f 589 5901: /* check for the buffer overrun */ 591 cmpw $(ABS(EXT_C(io_map)) + (IO_MAP_SIZE + 1) * 2), %si 592 je 8f 593 /* add the port into the io map */ 594 movw %dx, -2(%si) 595 5968: /* restore registers */ 597 popw %dx 598 popw %si 599 popw %ax 600 popw %ds 601 popw %bp 602 603 iret 604 605 .code32 606 607ENTRY(io_map) 608 .space (IO_MAP_SIZE + 1) * 2 609 610 611/* 612 * set_int15_handler(void) 613 * 614 * Set up int15_handler. 615 */ 616ENTRY(set_int15_handler) 617 pushl %edi 618 619 /* save the original int15 handler */ 620 movl $0x54, %edi 621 movw (%edi), %ax 622 movw %ax, ABS(int15_offset) 623 movw 2(%edi), %ax 624 movw %ax, ABS(int15_segment) 625 626 /* save the new int15 handler */ 627 movw $ABS(int15_handler), %ax 628 movw %ax, (%edi) 629 xorw %ax, %ax 630 movw %ax, 2(%edi) 631 632 popl %edi 633 ret 634 635 636/* 637 * unset_int15_handler(void) 638 * 639 * Restore the original int15 handler 640 */ 641ENTRY(unset_int15_handler) 642 pushl %edi 643 644 /* check if int15_handler is set */ 645 movl $0x54, %edi 646 movw $ABS(int15_handler), %ax 647 cmpw %ax, (%edi) 648 jne 1f 649 xorw %ax, %ax 650 cmpw %ax, 2(%edi) 651 jne 1f 652 653 /* restore the original */ 654 movw ABS(int15_offset), %ax 655 movw %ax, (%edi) 656 movw ABS(int15_segment), %ax 657 movw %ax, 2(%edi) 658 6591: 660 popl %edi 661 ret 662 663 664/* 665 * Translate a key code to another. 666 * 667 * Note: This implementation cannot handle more than one length 668 * scancodes (such as Right Ctrl). 669 */ 670 .code16 671int15_handler: 672 /* if non-carrier, ignore it */ 673 jnc 1f 674 /* check if AH=4F */ 675 cmpb $0x4F, %ah 676 jne 1f 677 678 /* E0 and E1 are special */ 679 cmpb $0xE1, %al 680 je 4f 681 cmpb $0xE0, %al 682 /* this flag is actually the machine code (je or jmp) */ 683int15_skip_flag: 684 je 4f 685 686 pushw %bp 687 movw %sp, %bp 688 689 pushw %bx 690 pushw %dx 691 pushw %ds 692 pushw %si 693 694 /* save bits 0-6 of %al in %dl */ 695 movw %ax, %dx 696 andb $0x7f, %dl 697 /* save the highest bit in %bl */ 698 movb %al, %bl 699 xorb %dl, %bl 700 /* set %ds to 0 */ 701 xorw %ax, %ax 702 movw %ax, %ds 703 /* set %si to the key map */ 704 movw $ABS(EXT_C(bios_key_map)), %si 705 706 /* find the key code from the key map */ 7072: 708 lodsw 709 /* check if this is the end */ 710 testw %ax, %ax 711 jz 3f 712 /* check if this matches the key code */ 713 cmpb %al, %dl 714 jne 2b 715 /* if so, perform the mapping */ 716 movb %ah, %dl 7173: 718 /* restore %ax */ 719 movw %dx, %ax 720 orb %bl, %al 721 /* make sure that CF is set */ 722 orw $1, 6(%bp) 723 /* restore other registers */ 724 popw %si 725 popw %ds 726 popw %dx 727 popw %bx 728 popw %bp 729 iret 730 7314: 732 /* tricky: jmp (0x74) <-> je (0xeb) */ 733 xorb $(0x74 ^ 0xeb), ABS(int15_skip_flag) 7341: 735 /* just cascade to the original */ 736 /* ljmp */ 737 .byte 0xea 738int15_offset: .word 0 739int15_segment: .word 0 740 741 .code32 742 743 .align 4 744ENTRY(bios_key_map) 745 .space (KEY_MAP_SIZE + 1) * 2 746 747 748/* 749 * set_int13_handler(map) 750 * 751 * Copy MAP to the drive map and set up int13_handler. 752 */ 753ENTRY(set_int13_handler) 754 pushl %ebp 755 movl %esp, %ebp 756 757 pushl %edi 758 pushl %esi 759 760 /* copy MAP to the drive map */ 761 movl $(DRIVE_MAP_SIZE * 2), %ecx 762 movl $ABS(drive_map), %edi 763 movl 8(%ebp), %esi 764 cld 765 rep 766 movsb 767 768 /* save the original int13 handler */ 769 movl $0x4c, %edi 770 movw (%edi), %ax 771 movw %ax, ABS(int13_offset) 772 movw 2(%edi), %ax 773 movw %ax, ABS(int13_segment) 774 775 /* decrease the lower memory size and set it to the BIOS memory */ 776 movl $0x413, %edi 777 decw (%edi) 778 xorl %eax, %eax 779 movw (%edi), %ax 780 781 /* compute the segment */ 782 shll $6, %eax 783 784 /* save the new int13 handler */ 785 movl $0x4c, %edi 786 movw %ax, 2(%edi) 787 xorw %cx, %cx 788 movw %cx, (%edi) 789 790 /* copy int13_handler to the reserved area */ 791 shll $4, %eax 792 movl %eax, %edi 793 movl $ABS(int13_handler), %esi 794 movl $(int13_handler_end - int13_handler), %ecx 795 rep 796 movsb 797 798 popl %esi 799 popl %edi 800 popl %ebp 801 ret 802 803 804/* 805 * Map a drive to another drive. 806 */ 807 808 .code16 809 810int13_handler: 811 pushw %ax 812 pushw %bp 813 movw %sp, %bp 814 815 pushw %si 816 817 /* set %si to the drive map */ 818 movw $(drive_map - int13_handler), %si 819 /* find the drive number from the drive map */ 820 cld 8211: 822 lodsw %cs:(%si), %ax 823 /* check if this is the end */ 824 testw %ax, %ax 825 jz 2f 826 /* check if this matches the drive number */ 827 cmpb %al, %dl 828 jne 1b 829 /* if so, perform the mapping */ 830 movb %ah, %dl 8312: 832 /* restore %si */ 833 popw %si 834 /* save %ax in the stack */ 835 pushw %ax 836 /* simulate the interrupt call */ 837 pushw 8(%bp) 838 /* set %ax and %bp to the original values */ 839 movw 2(%bp), %ax 840 movw (%bp), %bp 841 /* lcall */ 842 .byte 0x9a 843int13_offset: .word 0 844int13_segment: .word 0 845 /* save flags */ 846 pushf 847 /* restore %bp */ 848 movw %sp, %bp 849 /* save %ax */ 850 pushw %ax 851 /* set the flags in the stack to the value returned by int13 */ 852 movw (%bp), %ax 853 movw %ax, 0xc(%bp) 854 /* check if should map the drive number */ 855 movw 6(%bp), %ax 856 cmpw $0x8, %ax 857 jne 3f 858 cmpw $0x15, %ax 859 jne 3f 860 /* check if the mapping was performed */ 861 movw 2(%bp), %ax 862 testw %ax, %ax 863 jz 3f 864 /* perform the mapping */ 865 movb %al, %dl 8663: 867 popw %ax 868 movw 4(%bp), %bp 869 addw $8, %sp 870 iret 871 872 .align 4 873drive_map: .space (DRIVE_MAP_SIZE + 1) * 2 874int13_handler_end: 875 876 .code32 877 878 879/* 880 * chain_stage1(segment, offset, part_table_addr) 881 * 882 * This starts another stage1 loader, at segment:offset. 883 */ 884 885ENTRY(chain_stage1) 886 /* no need to save anything, just use %esp */ 887 888 /* store %ESI, presuming %ES is 0 */ 889 movl 0xc(%esp), %esi 890 891 /* store new offset */ 892 movl 0x8(%esp), %eax 893 movl %eax, offset 894 895 /* store new segment */ 896 movw 0x4(%esp), %ax 897 movw %ax, segment 898 899 /* set up to pass boot drive */ 900 movb EXT_C(boot_drive), %dl 901 902 call EXT_C(prot_to_real) 903 .code16 904 905#ifdef ABSOLUTE_WITHOUT_ASTERISK 906 DATA32 ADDR32 ljmp (offset) 907#else 908 DATA32 ADDR32 ljmp *(offset) 909#endif 910 .code32 911#endif /* STAGE1_5 */ 912 913 914#ifdef STAGE1_5 915/* 916 * chain_stage2(segment, offset, second_sector) 917 * 918 * This starts another stage2 loader, at segment:offset. It presumes 919 * that the other one starts with this same "asm.S" file, and passes 920 * parameters by writing the embedded install variables. 921 */ 922 923ENTRY(chain_stage2) 924 /* no need to save anything, just use %esp */ 925 926 /* store new offset */ 927 movl 0x8(%esp), %eax 928 movl %eax, offset 929 movl %eax, %ebx 930 931 /* store new segment */ 932 movw 0x4(%esp), %ax 933 movw %ax, segment 934 shll $4, %eax 935 936 /* generate linear address */ 937 addl %eax, %ebx 938 939 /* set up to pass the partition where stage2 is located in */ 940 movl EXT_C(current_partition), %eax 941 movl %eax, (EXT_C(install_partition)-EXT_C(main))(%ebx) 942 943 /* set up to pass the drive where stage2 is located in */ 944 movb EXT_C(current_drive), %dl 945 946 /* set up to pass the second sector of stage2 */ 947 movl 0xc(%esp), %ecx 948 949 call EXT_C(prot_to_real) 950 .code16 951 952 movl %ecx, %ebp 953 954#ifdef ABSOLUTE_WITHOUT_ASTERISK 955 DATA32 ADDR32 ljmp (offset) 956#else 957 DATA32 ADDR32 ljmp *(offset) 958#endif 959 960 .code32 961#endif /* STAGE1_5 */ 962 963/* 964 * These next two routines, "real_to_prot" and "prot_to_real" are structured 965 * in a very specific way. Be very careful when changing them. 966 * 967 * NOTE: Use of either one messes up %eax and %ebp. 968 */ 969 970ENTRY(real_to_prot) 971 .code16 972 cli 973 974 /* load the GDT register */ 975 DATA32 ADDR32 lgdt gdtdesc 976 977 /* turn on protected mode */ 978 movl %cr0, %eax 979 orl $CR0_PE_ON, %eax 980 movl %eax, %cr0 981 982 /* jump to relocation, flush prefetch queue, and reload %cs */ 983 DATA32 ljmp $PROT_MODE_CSEG, $protcseg 984 985 /* 986 * The ".code32" directive only works in GAS, the GNU assembler! 987 * This gets out of "16-bit" mode. 988 */ 989 .code32 990 991protcseg: 992 /* reload other segment registers */ 993 movw $PROT_MODE_DSEG, %ax 994 movw %ax, %ds 995 movw %ax, %es 996 movw %ax, %fs 997 movw %ax, %gs 998 movw %ax, %ss 999 1000 /* put the return address in a known safe location */ 1001 movl (%esp), %eax 1002 movl %eax, STACKOFF 1003 1004 /* get protected mode stack */ 1005 movl protstack, %eax 1006 movl %eax, %esp 1007 movl %eax, %ebp 1008 1009 /* get return address onto the right stack */ 1010 movl STACKOFF, %eax 1011 movl %eax, (%esp) 1012 1013 /* zero %eax */ 1014 xorl %eax, %eax 1015 1016 /* return on the old (or initialized) stack! */ 1017 ret 1018 1019 1020ENTRY(prot_to_real) 1021 /* just in case, set GDT */ 1022 lgdt gdtdesc 1023 1024 /* save the protected mode stack */ 1025 movl %esp, %eax 1026 movl %eax, protstack 1027 1028 /* get the return address */ 1029 movl (%esp), %eax 1030 movl %eax, STACKOFF 1031 1032 /* set up new stack */ 1033 movl $STACKOFF, %eax 1034 movl %eax, %esp 1035 movl %eax, %ebp 1036 1037 /* set up segment limits */ 1038 movw $PSEUDO_RM_DSEG, %ax 1039 movw %ax, %ds 1040 movw %ax, %es 1041 movw %ax, %fs 1042 movw %ax, %gs 1043 movw %ax, %ss 1044 1045 /* this might be an extra step */ 1046 ljmp $PSEUDO_RM_CSEG, $tmpcseg /* jump to a 16 bit segment */ 1047 1048tmpcseg: 1049 .code16 1050 1051 /* clear the PE bit of CR0 */ 1052 movl %cr0, %eax 1053 andl $CR0_PE_OFF, %eax 1054 movl %eax, %cr0 1055 1056 /* flush prefetch queue, reload %cs */ 1057 DATA32 ljmp $0, $realcseg 1058 1059realcseg: 1060 /* we are in real mode now 1061 * set up the real mode segment registers : DS, SS, ES 1062 */ 1063 /* zero %eax */ 1064 xorl %eax, %eax 1065 1066 movw %ax, %ds 1067 movw %ax, %es 1068 movw %ax, %fs 1069 movw %ax, %gs 1070 movw %ax, %ss 1071 1072 /* restore interrupts */ 1073 sti 1074 1075 /* return on new stack! */ 1076 DATA32 ret 1077 1078 .code32 1079 1080 1081/* 1082 * int biosdisk_int13_extensions (int ax, int drive, void *dap) 1083 * 1084 * Call IBM/MS INT13 Extensions (int 13 %ax=AX) for DRIVE. DAP 1085 * is passed for disk address packet. If an error occurs, return 1086 * non-zero, otherwise zero. 1087 */ 1088 1089ENTRY(biosdisk_int13_extensions) 1090 pushl %ebp 1091 movl %esp, %ebp 1092 1093 pushl %esi 1094 pushl %ebx 1095 1096 /* compute the address of disk_address_packet */ 1097 movl 0x10(%ebp), %eax 1098 movw %ax, %si 1099 xorw %ax, %ax 1100 shrl $4, %eax 1101 movw %ax, %cx /* save the segment to cx */ 1102 1103 /* drive */ 1104 movb 0xc(%ebp), %dl 1105 /* ax */ 1106 movw 0x8(%ebp), %bx 1107 /* enter real mode */ 1108 call EXT_C(prot_to_real) 1109 1110 .code16 1111 movw %bx, %ax 1112 movw %cx, %ds 1113 int $0x13 /* do the operation */ 1114 movb %ah, %dl /* save return value */ 1115 /* clear the data segment */ 1116 xorw %ax, %ax 1117 movw %ax, %ds 1118 /* back to protected mode */ 1119 DATA32 call EXT_C(real_to_prot) 1120 .code32 1121 1122 movb %dl, %al /* return value in %eax */ 1123 1124 popl %ebx 1125 popl %esi 1126 popl %ebp 1127 1128 ret 1129 1130/* 1131 * int biosdisk_standard (int ah, int drive, int coff, int hoff, int soff, 1132 * int nsec, int segment) 1133 * 1134 * Call standard and old INT13 (int 13 %ah=AH) for DRIVE. Read/write 1135 * NSEC sectors from COFF/HOFF/SOFF into SEGMENT. If an error occurs, 1136 * return non-zero, otherwise zero. 1137 */ 1138 1139ENTRY(biosdisk_standard) 1140 pushl %ebp 1141 movl %esp, %ebp 1142 1143 pushl %ebx 1144 pushl %edi 1145 pushl %esi 1146 1147 /* set up CHS information */ 1148 movl 0x10(%ebp), %eax 1149 movb %al, %ch 1150 movb 0x18(%ebp), %al 1151 shlb $2, %al 1152 shrw $2, %ax 1153 movb %al, %cl 1154 movb 0x14(%ebp), %dh 1155 /* drive */ 1156 movb 0xc(%ebp), %dl 1157 /* segment */ 1158 movw 0x20(%ebp), %bx 1159 /* save nsec and ah to %di */ 1160 movb 0x8(%ebp), %ah 1161 movb 0x1c(%ebp), %al 1162 movw %ax, %di 1163 /* enter real mode */ 1164 call EXT_C(prot_to_real) 1165 1166 .code16 1167 movw %bx, %es 1168 xorw %bx, %bx 1169 movw $3, %si /* attempt at least three times */ 1170 11711: 1172 movw %di, %ax 1173 int $0x13 /* do the operation */ 1174 jnc 2f /* check if successful */ 1175 1176 movb %ah, %bl /* save return value */ 1177 /* if fail, reset the disk system */ 1178 xorw %ax, %ax 1179 int $0x13 1180 1181 decw %si 1182 cmpw $0, %si 1183 je 2f 1184 xorb %bl, %bl 1185 jmp 1b /* retry */ 11862: 1187 /* back to protected mode */ 1188 DATA32 call EXT_C(real_to_prot) 1189 .code32 1190 1191 movb %bl, %al /* return value in %eax */ 1192 1193 popl %esi 1194 popl %edi 1195 popl %ebx 1196 popl %ebp 1197 1198 ret 1199 1200 1201/* 1202 * int check_int13_extensions (int drive) 1203 * 1204 * Check if LBA is supported for DRIVE. If it is supported, then return 1205 * the major version of extensions, otherwise zero. 1206 */ 1207 1208ENTRY(check_int13_extensions) 1209 pushl %ebp 1210 movl %esp, %ebp 1211 1212 pushl %ebx 1213 1214 /* drive */ 1215 movb 0x8(%ebp), %dl 1216 /* enter real mode */ 1217 call EXT_C(prot_to_real) 1218 1219 .code16 1220 movb $0x41, %ah 1221 movw $0x55aa, %bx 1222 int $0x13 /* do the operation */ 1223 1224 /* check the result */ 1225 jc 1f 1226 cmpw $0xaa55, %bx 1227 jne 1f 1228 1229 movb %ah, %bl /* save the major version into %bl */ 1230 1231 /* check if AH=0x42 is supported if FORCE_LBA is zero */ 1232 movb EXT_C(force_lba), %al 1233 testb %al, %al 1234 jnz 2f 1235 andw $1, %cx 1236 jnz 2f 1237 12381: 1239 xorb %bl, %bl 12402: 1241 /* back to protected mode */ 1242 DATA32 call EXT_C(real_to_prot) 1243 .code32 1244 1245 movb %bl, %al /* return value in %eax */ 1246 1247 popl %ebx 1248 popl %ebp 1249 1250 ret 1251 1252 1253/* 1254 * int get_diskinfo_standard (int drive, unsigned long *cylinders, 1255 * unsigned long *heads, unsigned long *sectors) 1256 * 1257 * Return the geometry of DRIVE in CYLINDERS, HEADS and SECTORS. If an 1258 * error occurs, then return non-zero, otherwise zero. 1259 */ 1260 1261ENTRY(get_diskinfo_standard) 1262 pushl %ebp 1263 movl %esp, %ebp 1264 1265 pushl %ebx 1266 pushl %edi 1267 1268 /* drive */ 1269 movb 0x8(%ebp), %dl 1270 /* enter real mode */ 1271 call EXT_C(prot_to_real) 1272 1273 .code16 1274 movb $0x8, %ah 1275 int $0x13 /* do the operation */ 1276 /* check if successful */ 1277 testb %ah, %ah 1278 jnz 1f 1279 /* bogus BIOSes may not return an error number */ 1280 testb $0x3f, %cl /* 0 sectors means no disk */ 1281 jnz 1f /* if non-zero, then succeed */ 1282 /* XXX 0x60 is one of the unused error numbers */ 1283 movb $0x60, %ah 12841: 1285 movb %ah, %bl /* save return value in %bl */ 1286 /* back to protected mode */ 1287 DATA32 call EXT_C(real_to_prot) 1288 .code32 1289 1290 /* restore %ebp */ 1291 leal 0x8(%esp), %ebp 1292 1293 /* heads */ 1294 movb %dh, %al 1295 incl %eax /* the number of heads is counted from zero */ 1296 movl 0x10(%ebp), %edi 1297 movl %eax, (%edi) 1298 1299 /* sectors */ 1300 xorl %eax, %eax 1301 movb %cl, %al 1302 andb $0x3f, %al 1303 movl 0x14(%ebp), %edi 1304 movl %eax, (%edi) 1305 1306 /* cylinders */ 1307 shrb $6, %cl 1308 movb %cl, %ah 1309 movb %ch, %al 1310 incl %eax /* the number of cylinders is 1311 counted from zero */ 1312 movl 0xc(%ebp), %edi 1313 movl %eax, (%edi) 1314 1315 xorl %eax, %eax 1316 movb %bl, %al /* return value in %eax */ 1317 1318 popl %edi 1319 popl %ebx 1320 popl %ebp 1321 1322 ret 1323 1324 1325#if 0 1326/* 1327 * int get_diskinfo_floppy (int drive, unsigned long *cylinders, 1328 * unsigned long *heads, unsigned long *sectors) 1329 * 1330 * Return the geometry of DRIVE in CYLINDERS, HEADS and SECTORS. If an 1331 * error occurs, then return non-zero, otherwise zero. 1332 */ 1333 1334ENTRY(get_diskinfo_floppy) 1335 pushl %ebp 1336 movl %esp, %ebp 1337 1338 pushl %ebx 1339 pushl %esi 1340 1341 /* drive */ 1342 movb 0x8(%ebp), %dl 1343 /* enter real mode */ 1344 call EXT_C(prot_to_real) 1345 1346 .code16 1347 /* init probe value */ 1348 movl $probe_values-1, %esi 13491: 1350 xorw %ax, %ax 1351 int $0x13 /* reset floppy controller */ 1352 1353 incw %si 1354 movb (%si), %cl 1355 cmpb $0, %cl /* probe failed if zero */ 1356 je 2f 1357 1358 /* perform read */ 1359 movw $SCRATCHSEG, %ax 1360 movw %ax, %es 1361 xorw %bx, %bx 1362 movw $0x0201, %ax 1363 movb $0, %ch 1364 movb $0, %dh 1365 int $0x13 1366 1367 /* FIXME: Read from floppy may fail even if the geometry is correct. 1368 So should retry at least three times. */ 1369 jc 1b /* next value */ 1370 1371 /* succeed */ 1372 jmp 2f 1373 1374probe_values: 1375 .byte 36, 18, 15, 9, 0 1376 13772: 1378 /* back to protected mode */ 1379 DATA32 call EXT_C(real_to_prot) 1380 .code32 1381 1382 /* restore %ebp */ 1383 leal 0x8(%esp), %ebp 1384 1385 /* cylinders */ 1386 movl 0xc(%ebp), %eax 1387 movl $80, %ebx 1388 movl %ebx, (%eax) 1389 /* heads */ 1390 movl 0x10(%ebp), %eax 1391 movl $2, %ebx 1392 movl %ebx, (%eax) 1393 /* sectors */ 1394 movl 0x14(%ebp), %eax 1395 movzbl %cl, %ebx 1396 movl %ebx, (%eax) 1397 1398 /* return value in %eax */ 1399 xorl %eax, %eax 1400 cmpb $0, %cl 1401 jne 3f 1402 incl %eax /* %eax = 1 (non-zero) */ 14033: 1404 popl %esi 1405 popl %ebx 1406 popl %ebp 1407 1408 ret 1409#endif 1410 1411 1412/* Source files are splitted, as they have different copyrights. */ 1413#ifndef STAGE1_5 1414# include "setjmp.S" 1415# include "apm.S" 1416#endif /* ! STAGE1_5 */ 1417 1418 1419 1420#ifndef STAGE1_5 1421/* get_code_end() : return the address of the end of the code 1422 * This is here so that it can be replaced by asmstub.c. 1423 */ 1424ENTRY(get_code_end) 1425 /* will be the end of the bss */ 1426# if defined(HAVE_END_SYMBOL) 1427 movl $end, %eax 1428# elif defined(HAVE_USCORE_END_SYMBOL) 1429 movl $_end, %eax 1430# endif 1431 shrl $2, %eax /* Round up to the next word. */ 1432 incl %eax 1433 shll $2, %eax 1434 ret 1435#endif /* ! STAGE1_5 */ 1436 1437/* 1438 * 1439 * get_memsize(i) : return the memory size in KB. i == 0 for conventional 1440 * memory, i == 1 for extended memory 1441 * BIOS call "INT 12H" to get conventional memory size 1442 * BIOS call "INT 15H, AH=88H" to get extended memory size 1443 * Both have the return value in AX. 1444 * 1445 */ 1446 1447ENTRY(get_memsize) 1448 push %ebp 1449 push %ebx 1450 1451 mov 0xc(%esp), %ebx 1452 1453 call EXT_C(prot_to_real) /* enter real mode */ 1454 .code16 1455 1456 cmpb $0x1, %bl 1457 DATA32 je xext 1458 1459 int $0x12 1460 DATA32 jmp xdone 1461 1462xext: 1463 movb $0x88, %ah 1464 int $0x15 1465 1466xdone: 1467 movw %ax, %bx 1468 1469 DATA32 call EXT_C(real_to_prot) 1470 .code32 1471 1472 movw %bx, %ax 1473 pop %ebx 1474 pop %ebp 1475 ret 1476 1477 1478#ifndef STAGE1_5 1479 1480/* 1481 * 1482 * get_eisamemsize() : return packed EISA memory map, lower 16 bits is 1483 * memory between 1M and 16M in 1K parts, upper 16 bits is 1484 * memory above 16M in 64K parts. If error, return -1. 1485 * BIOS call "INT 15H, AH=E801H" to get EISA memory map, 1486 * AX = memory between 1M and 16M in 1K parts. 1487 * BX = memory above 16M in 64K parts. 1488 * 1489 */ 1490 1491ENTRY(get_eisamemsize) 1492 push %ebp 1493 push %ebx 1494 1495 call EXT_C(prot_to_real) /* enter real mode */ 1496 .code16 1497 1498 movw $0xe801, %ax 1499 int $0x15 1500 1501 shll $16, %ebx 1502 movw %ax, %bx 1503 1504 DATA32 call EXT_C(real_to_prot) 1505 .code32 1506 1507 movl $0xFFFFFFFF, %eax 1508 cmpb $0x86, %bh 1509 je xnoteisa 1510 1511 movl %ebx, %eax 1512 1513xnoteisa: 1514 pop %ebx 1515 pop %ebp 1516 ret 1517 1518/* 1519 * 1520 * get_mmap_entry(addr, cont) : address and old continuation value (zero to 1521 * start), for the Query System Address Map BIOS call. 1522 * 1523 * Sets the first 4-byte int value of "addr" to the size returned by 1524 * the call. If the call fails, sets it to zero. 1525 * 1526 * Returns: new (non-zero) continuation value, 0 if done. 1527 * 1528 * NOTE: Currently hard-coded for a maximum buffer length of 1024. 1529 */ 1530 1531ENTRY(get_mmap_entry) 1532 push %ebp 1533 push %ebx 1534 push %edi 1535 push %esi 1536 1537 /* place address (+4) in ES:DI */ 1538 movl 0x14(%esp), %eax 1539 addl $4, %eax 1540 movl %eax, %edi 1541 andl $0xf, %edi 1542 shrl $4, %eax 1543 movl %eax, %esi 1544 1545 /* set continuation value */ 1546 movl 0x18(%esp), %ebx 1547 1548 /* set default maximum buffer size */ 1549 movl $0x14, %ecx 1550 1551 /* set EDX to 'SMAP' */ 1552 movl $0x534d4150, %edx 1553 1554 call EXT_C(prot_to_real) /* enter real mode */ 1555 .code16 1556 1557 movw %si, %es 1558 movl $0xe820, %eax 1559 int $0x15 1560 1561 DATA32 jc xnosmap 1562 1563 cmpl $0x534d4150, %eax 1564 DATA32 jne xnosmap 1565 1566 cmpl $0x14, %ecx 1567 DATA32 jl xnosmap 1568 1569 cmpl $0x400, %ecx 1570 DATA32 jg xnosmap 1571 1572 DATA32 jmp xsmap 1573 1574xnosmap: 1575 movl $0, %ecx 1576 1577xsmap: 1578 DATA32 call EXT_C(real_to_prot) 1579 .code32 1580 1581 /* write length of buffer (zero if error) into "addr" */ 1582 movl 0x14(%esp), %eax 1583 movl %ecx, (%eax) 1584 1585 /* set return value to continuation */ 1586 movl %ebx, %eax 1587 1588 pop %esi 1589 pop %edi 1590 pop %ebx 1591 pop %ebp 1592 ret 1593 1594/* 1595 * get_rom_config_table() 1596 * 1597 * Get the linear address of a ROM configuration table. Return zero, 1598 * if fails. 1599 */ 1600 1601ENTRY(get_rom_config_table) 1602 pushl %ebp 1603 pushl %ebx 1604 1605 /* zero %ebx for simplicity */ 1606 xorl %ebx, %ebx 1607 1608 call EXT_C(prot_to_real) 1609 .code16 1610 1611 movw $0xc0, %ax 1612 int $0x15 1613 1614 jc no_rom_table 1615 testb %ah, %ah 1616 jnz no_rom_table 1617 1618 movw %es, %dx 1619 jmp found_rom_table 1620 1621no_rom_table: 1622 xorw %dx, %dx 1623 xorw %bx, %bx 1624 1625found_rom_table: 1626 DATA32 call EXT_C(real_to_prot) 1627 .code32 1628 1629 /* compute the linear address */ 1630 movw %dx, %ax 1631 shll $4, %eax 1632 addl %ebx, %eax 1633 1634 popl %ebx 1635 popl %ebp 1636 ret 1637 1638 1639/* 1640 * int get_vbe_controller_info (struct vbe_controller *controller_ptr) 1641 * 1642 * Get VBE controller information. 1643 */ 1644 1645ENTRY(get_vbe_controller_info) 1646 pushl %ebp 1647 movl %esp, %ebp 1648 1649 pushl %edi 1650 pushl %ebx 1651 1652 /* Convert the linear address to segment:offset */ 1653 movl 8(%ebp), %eax 1654 movl %eax, %edi 1655 andl $0x0000000f, %edi 1656 shrl $4, %eax 1657 movl %eax, %ebx 1658 1659 call EXT_C(prot_to_real) 1660 .code16 1661 1662 movw %bx, %es 1663 movw $0x4F00, %ax 1664 int $0x10 1665 1666 movw %ax, %bx 1667 DATA32 call EXT_C(real_to_prot) 1668 .code32 1669 1670 movzwl %bx, %eax 1671 1672 popl %ebx 1673 popl %edi 1674 popl %ebp 1675 ret 1676 1677 1678/* 1679 * int get_vbe_mode_info (int mode_number, struct vbe_mode *mode_ptr) 1680 * 1681 * Get VBE mode information. 1682 */ 1683 1684ENTRY(get_vbe_mode_info) 1685 pushl %ebp 1686 movl %esp, %ebp 1687 1688 pushl %edi 1689 pushl %ebx 1690 1691 /* Convert the linear address to segment:offset */ 1692 movl 0xc(%ebp), %eax 1693 movl %eax, %edi 1694 andl $0x0000000f, %edi 1695 shrl $4, %eax 1696 movl %eax, %ebx 1697 1698 /* Save the mode number in %cx */ 1699 movl 0x8(%ebp), %ecx 1700 1701 call EXT_C(prot_to_real) 1702 .code16 1703 1704 movw %bx, %es 1705 movw $0x4F01, %ax 1706 int $0x10 1707 1708 movw %ax, %bx 1709 DATA32 call EXT_C(real_to_prot) 1710 .code32 1711 1712 movzwl %bx, %eax 1713 1714 popl %ebx 1715 popl %edi 1716 popl %ebp 1717 ret 1718 1719 1720/* 1721 * int set_vbe_mode (int mode_number) 1722 * 1723 * Set VBE mode. Don't support user-specified CRTC information. 1724 */ 1725 1726ENTRY(set_vbe_mode) 1727 pushl %ebp 1728 movl %esp, %ebp 1729 1730 pushl %ebx 1731 1732 /* Save the mode number in %bx */ 1733 movl 0x8(%ebp), %ebx 1734 /* Clear bit D11 */ 1735 andl $0xF7FF, %ebx 1736 1737 call EXT_C(prot_to_real) 1738 .code16 1739 1740 movw $0x4F02, %ax 1741 int $0x10 1742 1743 movw %ax, %bx 1744 DATA32 call EXT_C(real_to_prot) 1745 .code32 1746 1747 movzwl %bx, %eax 1748 1749 popl %ebx 1750 popl %ebp 1751 ret 1752 1753 1754/* 1755 * gateA20(int linear) 1756 * 1757 * Gate address-line 20 for high memory. 1758 * 1759 * This routine is probably overconservative in what it does, but so what? 1760 * 1761 * It also eats any keystrokes in the keyboard buffer. :-( 1762 */ 1763 1764ENTRY(gateA20) 1765 /* first, try a BIOS call */ 1766 pushl %ebp 1767 movl 8(%esp), %edx 1768 1769 call EXT_C(prot_to_real) 1770 1771 .code16 1772 movw $0x2400, %ax 1773 testw %dx, %dx 1774 jz 1f 1775 incw %ax 17761: stc 1777 int $0x15 1778 jnc 2f 1779 1780 /* set non-zero if failed */ 1781 movb $1, %ah 1782 1783 /* save the status */ 17842: movb %ah, %dl 1785 1786 DATA32 call EXT_C(real_to_prot) 1787 .code32 1788 1789 popl %ebp 1790 testb %dl, %dl 1791 jnz 3f 1792 ret 1793 17943: /* 1795 * try to switch gateA20 using PORT92, the "Fast A20 and Init" 1796 * register 1797 */ 1798 mov $0x92, %dx 1799 inb %dx, %al 1800 /* skip the port92 code if it's unimplemented (read returns 0xff) */ 1801 cmpb $0xff, %al 1802 jz 6f 1803 1804 /* set or clear bit1, the ALT_A20_GATE bit */ 1805 movb 4(%esp), %ah 1806 testb %ah, %ah 1807 jz 4f 1808 orb $2, %al 1809 jmp 5f 18104: and $0xfd, %al 1811 1812 /* clear the INIT_NOW bit; don't accidently reset the machine */ 18135: and $0xfe, %al 1814 outb %al, %dx 1815 18166: /* use keyboard controller */ 1817 pushl %eax 1818 1819 call gloop1 1820 1821 movb $KC_CMD_WOUT, %al 1822 outb $K_CMD 1823 1824gloopint1: 1825 inb $K_STATUS 1826 cmpb $0xff, %al 1827 jz gloopint1_done 1828 andb $K_IBUF_FUL, %al 1829 jnz gloopint1 1830 1831gloopint1_done: 1832 movb $KB_OUTPUT_MASK, %al 1833 cmpb $0, 0x8(%esp) 1834 jz gdoit 1835 1836 orb $KB_A20_ENABLE, %al 1837gdoit: 1838 outb $K_RDWR 1839 1840 call gloop1 1841 1842 /* output a dummy command (USB keyboard hack) */ 1843 movb $0xff, %al 1844 outb $K_CMD 1845 call gloop1 1846 1847 popl %eax 1848 ret 1849 1850gloop1: 1851 inb $K_STATUS 1852 cmpb $0xff, %al 1853 jz gloop2ret 1854 andb $K_IBUF_FUL, %al 1855 jnz gloop1 1856 1857gloop2: 1858 inb $K_STATUS 1859 andb $K_OBUF_FUL, %al 1860 jz gloop2ret 1861 inb $K_RDWR 1862 jmp gloop2 1863 1864gloop2ret: 1865 ret 1866 1867 1868ENTRY(patch_code) /* labels start with "pc_" */ 1869 .code16 1870 1871 mov %cs, %ax 1872 mov %ax, %ds 1873 mov %ax, %es 1874 mov %ax, %fs 1875 mov %ax, %gs 1876 ADDR32 movl $0, 0 1877pc_stop: 1878 hlt 1879 DATA32 jmp pc_stop 1880ENTRY(patch_code_end) 1881 1882 .code32 1883 1884 1885/* 1886 * linux_boot() 1887 * 1888 * Does some funky things (including on the stack!), then jumps to the 1889 * entry point of the Linux setup code. 1890 */ 1891 1892VARIABLE(linux_text_len) 1893 .long 0 1894 1895VARIABLE(linux_data_tmp_addr) 1896 .long 0 1897 1898VARIABLE(linux_data_real_addr) 1899 .long 0 1900 1901ENTRY(linux_boot) 1902 /* don't worry about saving anything, we're committed at this point */ 1903 cld /* forward copying */ 1904 1905 /* copy kernel */ 1906 movl EXT_C(linux_text_len), %ecx 1907 addl $3, %ecx 1908 shrl $2, %ecx 1909 movl $LINUX_BZIMAGE_ADDR, %esi 1910 movl $LINUX_ZIMAGE_ADDR, %edi 1911 1912 rep 1913 movsl 1914 1915ENTRY(big_linux_boot) 1916 movl EXT_C(linux_data_real_addr), %ebx 1917 1918 /* copy the real mode part */ 1919 movl EXT_C(linux_data_tmp_addr), %esi 1920 movl %ebx, %edi 1921 movl $LINUX_SETUP_MOVE_SIZE, %ecx 1922 cld 1923 rep 1924 movsb 1925 1926 /* change %ebx to the segment address */ 1927 shrl $4, %ebx 1928 movl %ebx, %eax 1929 addl $0x20, %eax 1930 movl %eax, linux_setup_seg 1931 1932 /* XXX new stack pointer in safe area for calling functions */ 1933 movl $0x4000, %esp 1934 call EXT_C(stop_floppy) 1935 1936 /* final setup for linux boot */ 1937 1938 call EXT_C(prot_to_real) 1939 .code16 1940 1941 /* final setup for linux boot */ 1942 cli 1943 movw %bx, %ss 1944 movw $LINUX_SETUP_STACK, %sp 1945 1946 movw %bx, %ds 1947 movw %bx, %es 1948 movw %bx, %fs 1949 movw %bx, %gs 1950 1951 /* jump to start */ 1952 /* ljmp */ 1953 .byte 0xea 1954 .word 0 1955linux_setup_seg: 1956 .word 0 1957 .code32 1958 1959 1960/* 1961 * multi_boot(int start, int mb_info) 1962 * 1963 * This starts a kernel in the manner expected of the multiboot standard. 1964 */ 1965 1966ENTRY(multi_boot) 1967 /* no need to save anything */ 1968 call EXT_C(stop_floppy) 1969 1970 movl $0x2BADB002, %eax 1971 movl 0x8(%esp), %ebx 1972 1973 /* boot kernel here (absolute address call) */ 1974 call *0x4(%esp) 1975 1976 /* error */ 1977 call EXT_C(stop) 1978 1979#endif /* ! STAGE1_5 */ 1980 1981/* 1982 * void console_putchar (int c) 1983 * 1984 * Put the character C on the console. Because GRUB wants to write a 1985 * character with an attribute, this implementation is a bit tricky. 1986 * If C is a control character (CR, LF, BEL, BS), use INT 10, AH = 0Eh 1987 * (TELETYPE OUTPUT). Otherwise, save the original position, put a space, 1988 * save the current position, restore the original position, write the 1989 * character and the attribute, and restore the current position. 1990 * 1991 * The reason why this is so complicated is that there is no easy way to 1992 * get the height of the screen, and the TELETYPE OUPUT BIOS call doesn't 1993 * support setting a background attribute. 1994 */ 1995ENTRY(console_putchar) 1996 movl 0x4(%esp), %edx 1997 pusha 1998#ifdef STAGE1_5 1999 movb $0x07, %bl 2000#else 2001 movl EXT_C(console_current_color), %ebx 2002#endif 2003 2004 call EXT_C(prot_to_real) 2005 .code16 2006 movb %dl, %al 2007 xorb %bh, %bh 2008 2009#ifndef STAGE1_5 2010 /* use teletype output if control character */ 2011 cmpb $0x7, %al 2012 je 1f 2013 cmpb $0x8, %al 2014 je 1f 2015 cmpb $0xa, %al 2016 je 1f 2017 cmpb $0xd, %al 2018 je 1f 2019 2020 /* save the character and the attribute on the stack */ 2021 pushw %ax 2022 pushw %bx 2023 2024 /* get the current position */ 2025 movb $0x3, %ah 2026 int $0x10 2027 2028 /* check the column with the width */ 2029 cmpb $79, %dl 2030 jl 2f 2031 2032 /* print CR and LF, if next write will exceed the width */ 2033 movw $0x0e0d, %ax 2034 int $0x10 2035 movb $0x0a, %al 2036 int $0x10 2037 2038 /* get the current position */ 2039 movb $0x3, %ah 2040 int $0x10 2041 20422: 2043 /* restore the character and the attribute */ 2044 popw %bx 2045 popw %ax 2046 2047 /* write the character with the attribute */ 2048 movb $0x9, %ah 2049 movw $1, %cx 2050 int $0x10 2051 2052 /* move the cursor forward */ 2053 incb %dl 2054 movb $0x2, %ah 2055 int $0x10 2056 2057 jmp 3f 2058#endif /* ! STAGE1_5 */ 2059 20601: movb $0xe, %ah 2061 int $0x10 2062 20633: DATA32 call EXT_C(real_to_prot) 2064 .code32 2065 2066 popa 2067 ret 2068 2069 2070#ifndef STAGE1_5 2071 2072/* this table is used in translate_keycode below */ 2073translation_table: 2074 .word KEY_LEFT, 2 2075 .word KEY_RIGHT, 6 2076 .word KEY_UP, 16 2077 .word KEY_DOWN, 14 2078 .word KEY_HOME, 1 2079 .word KEY_END, 5 2080 .word KEY_DC, 4 2081 .word KEY_BACKSPACE, 8 2082 .word KEY_PPAGE, 7 2083 .word KEY_NPAGE, 3 2084 .word 0 2085 2086/* 2087 * translate_keycode translates the key code %dx to an ascii code. 2088 */ 2089 .code16 2090 2091translate_keycode: 2092 pushw %bx 2093 pushw %si 2094 2095 movw $ABS(translation_table), %si 2096 20971: lodsw 2098 /* check if this is the end */ 2099 testw %ax, %ax 2100 jz 2f 2101 /* load the ascii code into %ax */ 2102 movw %ax, %bx 2103 lodsw 2104 /* check if this matches the key code */ 2105 cmpw %bx, %dx 2106 jne 1b 2107 /* translate %dx, if successful */ 2108 movw %ax, %dx 2109 21102: popw %si 2111 popw %bx 2112 ret 2113 2114 .code32 2115 2116 2117/* 2118 * remap_ascii_char remaps the ascii code %dl to another if the code is 2119 * contained in ASCII_KEY_MAP. 2120 */ 2121 .code16 2122 2123remap_ascii_char: 2124 pushw %si 2125 2126 movw $ABS(EXT_C(ascii_key_map)), %si 21271: 2128 lodsw 2129 /* check if this is the end */ 2130 testw %ax, %ax 2131 jz 2f 2132 /* check if this matches the ascii code */ 2133 cmpb %al, %dl 2134 jne 1b 2135 /* if so, perform the mapping */ 2136 movb %ah, %dl 21372: 2138 /* restore %si */ 2139 popw %si 2140 2141 ret 2142 2143 .code32 2144 2145 .align 4 2146ENTRY(ascii_key_map) 2147 .space (KEY_MAP_SIZE + 1) * 2 2148 2149 2150/* 2151 * int console_getkey (void) 2152 * BIOS call "INT 16H Function 00H" to read character from keyboard 2153 * Call with %ah = 0x0 2154 * Return: %ah = keyboard scan code 2155 * %al = ASCII character 2156 */ 2157 2158ENTRY(console_getkey) 2159 push %ebp 2160 2161wait_for_key: 2162 call EXT_C(console_checkkey) 2163 incl %eax 2164 jz wait_for_key 2165 2166 call EXT_C(prot_to_real) 2167 .code16 2168 2169 int $0x16 2170 2171 movw %ax, %dx /* real_to_prot uses %eax */ 2172 call translate_keycode 2173 call remap_ascii_char 2174 2175 DATA32 call EXT_C(real_to_prot) 2176 .code32 2177 2178 movw %dx, %ax 2179 2180 pop %ebp 2181 ret 2182 2183 2184/* 2185 * int console_checkkey (void) 2186 * if there is a character pending, return it; otherwise return -1 2187 * BIOS call "INT 16H Function 01H" to check whether a character is pending 2188 * Call with %ah = 0x1 2189 * Return: 2190 * If key waiting to be input: 2191 * %ah = keyboard scan code 2192 * %al = ASCII character 2193 * Zero flag = clear 2194 * else 2195 * Zero flag = set 2196 */ 2197ENTRY(console_checkkey) 2198 push %ebp 2199 xorl %edx, %edx 2200 2201 call EXT_C(prot_to_real) /* enter real mode */ 2202 .code16 2203 2204 movb $0x1, %ah 2205 int $0x16 2206 2207 DATA32 jz notpending 2208 2209 movw %ax, %dx 2210 call translate_keycode 2211 call remap_ascii_char 2212 DATA32 jmp pending 2213 2214notpending: 2215 movl $0xFFFFFFFF, %edx 2216 2217pending: 2218 DATA32 call EXT_C(real_to_prot) 2219 .code32 2220 2221 mov %edx, %eax 2222 2223 pop %ebp 2224 ret 2225 2226 2227/* 2228 * int console_getxy (void) 2229 * BIOS call "INT 10H Function 03h" to get cursor position 2230 * Call with %ah = 0x03 2231 * %bh = page 2232 * Returns %ch = starting scan line 2233 * %cl = ending scan line 2234 * %dh = row (0 is top) 2235 * %dl = column (0 is left) 2236 */ 2237 2238 2239ENTRY(console_getxy) 2240 push %ebp 2241 push %ebx /* save EBX */ 2242 2243 call EXT_C(prot_to_real) 2244 .code16 2245 2246 xorb %bh, %bh /* set page to 0 */ 2247 movb $0x3, %ah 2248 int $0x10 /* get cursor position */ 2249 2250 DATA32 call EXT_C(real_to_prot) 2251 .code32 2252 2253 movb %dl, %ah 2254 movb %dh, %al 2255 2256 pop %ebx 2257 pop %ebp 2258 ret 2259 2260 2261/* 2262 * void console_gotoxy(int x, int y) 2263 * BIOS call "INT 10H Function 02h" to set cursor position 2264 * Call with %ah = 0x02 2265 * %bh = page 2266 * %dh = row (0 is top) 2267 * %dl = column (0 is left) 2268 */ 2269 2270 2271ENTRY(console_gotoxy) 2272 push %ebp 2273 push %ebx /* save EBX */ 2274 2275 movb 0xc(%esp), %dl /* %dl = x */ 2276 movb 0x10(%esp), %dh /* %dh = y */ 2277 2278 call EXT_C(prot_to_real) 2279 .code16 2280 2281 xorb %bh, %bh /* set page to 0 */ 2282 movb $0x2, %ah 2283 int $0x10 /* set cursor position */ 2284 2285 DATA32 call EXT_C(real_to_prot) 2286 .code32 2287 2288 pop %ebx 2289 pop %ebp 2290 ret 2291 2292 2293/* 2294 * void console_cls (void) 2295 * BIOS call "INT 10H Function 09h" to write character and attribute 2296 * Call with %ah = 0x09 2297 * %al = (character) 2298 * %bh = (page number) 2299 * %bl = (attribute) 2300 * %cx = (number of times) 2301 */ 2302 2303 2304ENTRY(console_cls) 2305 push %ebp 2306 push %ebx /* save EBX */ 2307 2308 call EXT_C(prot_to_real) 2309 .code16 2310 2311 /* move the cursor to the beginning */ 2312 movb $0x02, %ah 2313 xorb %bh, %bh 2314 xorw %dx, %dx 2315 int $0x10 2316 2317 /* write spaces to the entire screen */ 2318 movw $0x0920, %ax 2319 movw $0x07, %bx 2320 movw $(80 * 25), %cx 2321 int $0x10 2322 2323 /* move back the cursor */ 2324 movb $0x02, %ah 2325 int $0x10 2326 2327 DATA32 call EXT_C(real_to_prot) 2328 .code32 2329 2330 pop %ebx 2331 pop %ebp 2332 ret 2333 2334 2335/* 2336 * int console_setcursor (int on) 2337 * BIOS call "INT 10H Function 01h" to set cursor type 2338 * Call with %ah = 0x01 2339 * %ch = cursor starting scanline 2340 * %cl = cursor ending scanline 2341 */ 2342 2343console_cursor_state: 2344 .byte 1 2345console_cursor_shape: 2346 .word 0 2347 2348ENTRY(console_setcursor) 2349 push %ebp 2350 push %ebx 2351 2352 /* check if the standard cursor shape has already been saved */ 2353 movw console_cursor_shape, %ax 2354 testw %ax, %ax 2355 jne 1f 2356 2357 call EXT_C(prot_to_real) 2358 .code16 2359 2360 movb $0x03, %ah 2361 xorb %bh, %bh 2362 int $0x10 2363 2364 DATA32 call EXT_C(real_to_prot) 2365 .code32 2366 2367 movw %cx, console_cursor_shape 23681: 2369 /* set %cx to the designated cursor shape */ 2370 movw $0x2000, %cx 2371 movl 0xc(%esp), %ebx 2372 testl %ebx, %ebx 2373 jz 2f 2374 movw console_cursor_shape, %cx 23752: 2376 call EXT_C(prot_to_real) 2377 .code16 2378 2379 movb $0x1, %ah 2380 int $0x10 2381 2382 DATA32 call EXT_C(real_to_prot) 2383 .code32 2384 2385 movzbl console_cursor_state, %eax 2386 movb %bl, console_cursor_state 2387 2388 pop %ebx 2389 pop %ebp 2390 ret 2391 2392/* graphics mode functions */ 2393#ifdef SUPPORT_GRAPHICS 2394VARIABLE(cursorX) 2395.word 0 2396VARIABLE(cursorY) 2397.word 0 2398VARIABLE(cursorCount) 2399.word 0 2400VARIABLE(cursorBuf) 2401.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 2402 2403 2404/* 2405 * int set_videomode(mode) 2406 * BIOS call "INT 10H Function 0h" to set video mode 2407 * Call with %ah = 0x0 2408 * %al = video mode 2409 * Returns old videomode. 2410 */ 2411ENTRY(set_videomode) 2412 push %ebp 2413 push %ebx 2414 push %ecx 2415 2416 movb 0x10(%esp), %cl 2417 2418 call EXT_C(prot_to_real) 2419 .code16 2420 2421 xorw %bx, %bx 2422 movb $0xf, %ah 2423 int $0x10 /* Get Current Video mode */ 2424 movb %al, %ch 2425 xorb %ah, %ah 2426 movb %cl, %al 2427 int $0x10 /* Set Video mode */ 2428 2429 DATA32 call EXT_C(real_to_prot) 2430 .code32 2431 2432 xorb %ah, %ah 2433 movb %ch, %al 2434 2435 pop %ecx 2436 pop %ebx 2437 pop %ebp 2438 ret 2439 2440 2441/* 2442 * unsigned char * graphics_get_font() 2443 * BIOS call "INT 10H Function 11h" to set font 2444 * Call with %ah = 0x11 2445 */ 2446ENTRY(graphics_get_font) 2447 push %ebp 2448 push %ebx 2449 push %ecx 2450 push %edx 2451 2452 call EXT_C(prot_to_real) 2453 .code16 2454 2455 movw $0x1130, %ax 2456 movb $6, %bh /* font 8x16 */ 2457 int $0x10 2458 movw %bp, %dx 2459 movw %es, %cx 2460 2461 DATA32 call EXT_C(real_to_prot) 2462 .code32 2463 2464 xorl %eax, %eax 2465 movw %cx, %ax 2466 shll $4, %eax 2467 movw %dx, %ax 2468 2469 pop %edx 2470 pop %ecx 2471 pop %ebx 2472 pop %ebp 2473 ret 2474 2475 2476 2477/* 2478 * graphics_set_palette(index, red, green, blue) 2479 * BIOS call "INT 10H Function 10h" to set individual dac register 2480 * Call with %ah = 0x10 2481 * %bx = register number 2482 * %ch = new value for green (0-63) 2483 * %cl = new value for blue (0-63) 2484 * %dh = new value for red (0-63) 2485 */ 2486 2487ENTRY(graphics_set_palette) 2488 push %ebp 2489 push %eax 2490 push %ebx 2491 push %ecx 2492 push %edx 2493 2494 movw $0x3c8, %bx /* address write mode register */ 2495 2496 /* wait vertical retrace */ 2497 2498 movw $0x3da, %dx 2499l1b: inb %dx, %al /* wait vertical active display */ 2500 test $8, %al 2501 jnz l1b 2502 2503l2b: inb %dx, %al /* wait vertical retrace */ 2504 test $8, %al 2505 jnz l2b 2506 2507 mov %bx, %dx 2508 movb 0x18(%esp), %al /* index */ 2509 outb %al, %dx 2510 inc %dx 2511 2512 movb 0x1c(%esp), %al /* red */ 2513 outb %al, %dx 2514 2515 movb 0x20(%esp), %al /* green */ 2516 outb %al, %dx 2517 2518 movb 0x24(%esp), %al /* blue */ 2519 outb %al, %dx 2520 2521 movw 0x18(%esp), %bx 2522 2523 call EXT_C(prot_to_real) 2524 .code16 2525 2526 movb %bl, %bh 2527 movw $0x1000, %ax 2528 int $0x10 2529 2530 DATA32 call EXT_C(real_to_prot) 2531 .code32 2532 2533 pop %edx 2534 pop %ecx 2535 pop %ebx 2536 pop %eax 2537 pop %ebp 2538 ret 2539 2540#endif /* SUPPORT_GRAPHICS */ 2541 2542/* 2543 * getrtsecs() 2544 * if a seconds value can be read, read it and return it (BCD), 2545 * otherwise return 0xFF 2546 * BIOS call "INT 1AH Function 02H" to check whether a character is pending 2547 * Call with %ah = 0x2 2548 * Return: 2549 * If RT Clock can give correct values 2550 * %ch = hour (BCD) 2551 * %cl = minutes (BCD) 2552 * %dh = seconds (BCD) 2553 * %dl = daylight savings time (00h std, 01h daylight) 2554 * Carry flag = clear 2555 * else 2556 * Carry flag = set 2557 * (this indicates that the clock is updating, or 2558 * that it isn't running) 2559 */ 2560ENTRY(getrtsecs) 2561 push %ebp 2562 2563 call EXT_C(prot_to_real) /* enter real mode */ 2564 .code16 2565 2566 movb $0x2, %ah 2567 int $0x1a 2568 2569 DATA32 jnc gottime 2570 movb $0xff, %dh 2571 2572gottime: 2573 DATA32 call EXT_C(real_to_prot) 2574 .code32 2575 2576 movb %dh, %al 2577 2578 pop %ebp 2579 ret 2580 2581 2582/* 2583 * currticks() 2584 * return the real time in ticks, of which there are about 2585 * 18-20 per second 2586 */ 2587ENTRY(currticks) 2588 pushl %ebp 2589 2590 call EXT_C(prot_to_real) /* enter real mode */ 2591 .code16 2592 2593 /* %ax is already zero */ 2594 int $0x1a 2595 2596 DATA32 call EXT_C(real_to_prot) 2597 .code32 2598 2599 movl %ecx, %eax 2600 shll $16, %eax 2601 movw %dx, %ax 2602 2603 popl %ebp 2604 ret 2605 2606ENTRY(amd64_rdmsr) 2607 movl 4(%esp), %ecx 2608 rdmsr 2609 movl 8(%esp), %ecx 2610 movl %eax, (%ecx) 2611 movl %edx, 4(%ecx) 2612 ret 2613 2614ENTRY(amd64_wrmsr) 2615 movl 8(%esp), %ecx 2616 movl (%ecx), %eax 2617 movl 4(%ecx), %edx 2618 movl 4(%esp), %ecx 2619 wrmsr 2620 ret 2621 2622ENTRY(amd64_cpuid_insn) 2623 pushl %ebp 2624 movl %esp, %ebp 2625 pushl %ebx 2626 pushl %esi 2627 movl 0x8(%ebp), %eax 2628 movl 0xc(%ebp), %esi 2629 cpuid 2630 movl %eax, 0x0(%esi) 2631 movl %ebx, 0x4(%esi) 2632 movl %ecx, 0x8(%esi) 2633 movl %edx, 0xc(%esi) 2634 popl %esi 2635 popl %ebx 2636 popl %ebp 2637 ret 2638 2639 /* 2640 * Based on code from AMD64 Volume 3 2641 */ 2642ENTRY(amd64_cpuid_supported) 2643 pushf 2644 popl %eax 2645 mov %eax, %edx /* save %eax for later */ 2646 xorl %eax, 0x200000 /* toggle bit 21 */ 2647 pushl %eax 2648 popf /* save new %eax to EFLAGS */ 2649 pushf /* save new EFLAGS */ 2650 popl %ecx /* copy EFLAGS to %eax */ 2651 xorl %eax, %eax 2652 cmpl %ecx, %edx /* see if bit 21 has changes */ 2653 jne 1f 2654 incl %eax 26551: 2656 ret 2657 2658ENTRY(get_target_operating_mode) 2659 pusha 2660 2661 call EXT_C(prot_to_real) 2662 .code16 2663 2664 movw $0xec00, %ax 2665 movw $0x03, %bx 2666 int $0x15 2667 2668 setc %al 2669 movw %ax, %cx 2670 2671 DATA32 call EXT_C(real_to_prot) 2672 .code32 2673 2674 xorl %eax, %eax 2675 movw %cx, %ax 2676 movl %eax, 0x1c(%esp) 2677 2678 popa 2679 ret 2680 2681#endif /* ! STAGE1_5 */ 2682 2683/* 2684 * This is the area for all of the special variables. 2685 */ 2686 2687 .p2align 2 /* force 4-byte alignment */ 2688 2689protstack: 2690 .long PROTSTACKINIT 2691 2692VARIABLE(boot_drive) 2693#ifdef SUPPORT_DISKLESS 2694 .long NETWORK_DRIVE 2695#else 2696 .long 0 2697#endif 2698 2699VARIABLE(install_second_sector) 2700 .long 0 2701 2702 /* an address can only be long-jumped to if it is in memory, this 2703 is used by multiple routines */ 2704offset: 2705 .long 0x8000 2706segment: 2707 .word 0 2708 2709VARIABLE(apm_bios_info) 2710 .word 0 /* version */ 2711 .word 0 /* cseg */ 2712 .long 0 /* offset */ 2713 .word 0 /* cseg_16 */ 2714 .word 0 /* dseg_16 */ 2715 .word 0 /* cseg_len */ 2716 .word 0 /* cseg_16_len */ 2717 .word 0 /* dseg_16_len */ 2718 2719/* 2720 * This is the Global Descriptor Table 2721 * 2722 * An entry, a "Segment Descriptor", looks like this: 2723 * 2724 * 31 24 19 16 7 0 2725 * ------------------------------------------------------------ 2726 * | | |B| |A| | | |1|0|E|W|A| | 2727 * | BASE 31..24 |G|/|0|V| LIMIT |P|DPL| TYPE | BASE 23:16 | 2728 * | | |D| |L| 19..16| | |1|1|C|R|A| | 2729 * ------------------------------------------------------------ 2730 * | | | 2731 * | BASE 15..0 | LIMIT 15..0 | 2732 * | | | 2733 * ------------------------------------------------------------ 2734 * 2735 * Note the ordering of the data items is reversed from the above 2736 * description. 2737 */ 2738 2739 .p2align 2 /* force 4-byte alignment */ 2740gdt: 2741 .word 0, 0 2742 .byte 0, 0, 0, 0 2743 2744 /* code segment */ 2745 .word 0xFFFF, 0 2746 .byte 0, 0x9A, 0xCF, 0 2747 2748 /* data segment */ 2749 .word 0xFFFF, 0 2750 .byte 0, 0x92, 0xCF, 0 2751 2752 /* 16 bit real mode CS */ 2753 .word 0xFFFF, 0 2754 .byte 0, 0x9E, 0, 0 2755 2756 /* 16 bit real mode DS */ 2757 .word 0xFFFF, 0 2758 .byte 0, 0x92, 0, 0 2759 2760 2761/* this is the GDT descriptor */ 2762gdtdesc: 2763 .word 0x27 /* limit */ 2764 .long gdt /* addr */ 2765