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