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