pxe.asm (13797B)
1 bits 16 2 3 _start: 4 mov bp, sp 5 6 call .1 7 .1: 8 pop di 9 10 mov cs:[di + pxenv_ptr - .1], bx 11 mov cs:[di + pxenv_ptr - .1 + 2], es 12 13 mov eax, ss:[bp + 4] 14 mov cs:[di + pxe_ptr - .1], eax 15 16 push booting_msg 17 call puts 18 pop ax 19 20 call enable_a20 21 test ax, ax 22 jnz .no_a20 23 24 call detect_mem 25 test ax, ax 26 jnz .no_mem 27 28 call enter_unreal 29 test ax, ax 30 jnz .no_unreal 31 32 call check_unreal 33 test ax, ax 34 jnz .no_unreal 35 36 call find_pxe 37 test ax, ax 38 jnz .no_pxe 39 40 push dot 41 call puts 42 pop ax 43 44 call download 45 test ax, ax 46 jnz .no_download 47 48 push dot 49 call puts 50 pop ax 51 52 call parse_mb 53 test ax, ax 54 jnz .no_mb 55 56 call boot 57 58 push fail_errmsg 59 call puts 60 pop ax 61 jmp hang 62 .no_a20: 63 push a20_errmsg 64 call puts 65 pop ax 66 jmp hang 67 .no_mem: 68 push mem_errmsg 69 call puts 70 pop ax 71 jmp hang 72 .no_unreal: 73 push unreal_errmsg 74 call puts 75 pop ax 76 jmp hang 77 .no_pxe: 78 push pxe_errmsg 79 call puts 80 pop ax 81 jmp hang 82 .no_download: 83 push download_errmsg 84 call puts 85 pop ax 86 jmp hang 87 .no_mb: 88 push mb_errmsg 89 call puts 90 pop ax 91 jmp hang 92 93 dot: 94 db `.`, 0 95 booting_msg: 96 db `Booting.`, 0 97 fail_errmsg: 98 db `\r\nBoot failed!`, 0 99 a20_errmsg: 100 db `\r\nFailed to enable A20!`, 0 101 mem_errmsg: 102 db `\r\nFailed to detect memory!`, 0 103 unreal_errmsg: 104 db `\r\nFailed to enter unreal mode!`, 0 105 pxe_errmsg: 106 db `\r\nNo pxe!`, 0 107 download_errmsg: 108 db `\r\nFailed to download!`, 0 109 mb_errmsg: 110 db `\r\nFailed to find a.out multiboot header!`, 0 111 112 hang: 113 cli 114 hlt 115 jmp hang 116 117 enable_a20: 118 pusha 119 ; Check if we need to do anything 120 call test_a20 121 test ax, ax 122 jz .a20_ok 123 ; BIOS - Query A20 Gate Support 124 mov ax, 0x2403 125 clc 126 int 0x15 127 jc .a20_bios 128 test ah, ah 129 jnz .a20_bios 130 test bx, 2 131 jz .a20_bios 132 .a20_fast: 133 ; Fast A20 134 in al, 0x92 135 or al, 2 136 out 0x92, al 137 ; Check if that worked 138 call test_a20 139 test ax, ax 140 jz .a20_ok 141 .a20_bios: 142 ; BIOS - Enable A20 Gate 143 mov ax, 0x2401 144 clc 145 int 0x15 146 jc .a20_slow 147 test ah, ah 148 jnz .a20_slow 149 ; Double check the bios 150 call test_a20 151 test ax, ax 152 jz .a20_ok 153 .a20_slow: 154 ; Give up 155 popa 156 mov ax, 1 157 ret 158 .a20_ok: 159 popa 160 mov ax, 0 161 ret 162 163 ; Result ax=0 if A20 is enabled 164 test_a20: 165 push es 166 push ds 167 push si 168 push di 169 ; ds:[di] es:[si] are aliases if A20=0 170 mov ax, 0 171 mov ds, ax 172 mov di, 0x0500 173 mov ax, -1 174 mov es, ax 175 mov si, 0x1500 176 ; Write different values to ds:[di] to es:[si] 177 mov ax, 0 178 mov ds:[di], ax 179 mov ax, -1 180 mov es:[si], ax 181 ; Compare the values 182 mov ax, ds:[di] 183 xor ax, es:[si] 184 not ax 185 pop di 186 pop si 187 pop ds 188 pop es 189 ret 190 191 detect_mem: 192 pusha 193 push ds 194 push es 195 call .1 196 .1: 197 pop bp 198 sub bp, .1 199 push cs 200 pop es 201 ; BIOS - Get memory size 202 clc 203 int 0x12 204 jc .no_mem 205 push ax 206 xor eax, eax 207 pop ax 208 shl eax, 10 209 mov es:[bp + low_mem_size], eax 210 ; BIOS - Get high memory size 211 mov ah, 0x88 212 clc 213 int 0x15 214 jc .no_mem 215 push ax 216 xor eax, eax 217 pop ax 218 shl eax, 10 219 mov es:[bp + high_mem_size], eax 220 ; Zero kernel size 221 mov dword es:[bp + kernel_size], 0 222 mov di, bp 223 add di, mmap + 4 224 mov ebx, 0 225 mov word es:[bp + mmap_size], 0 226 .loop: 227 ; BIOS - Get system memory map 228 mov edx, 0x534D4150 229 mov eax, 0xe820 230 mov ecx, 20 231 clc 232 int 0x15 233 jc .no_mem 234 mov edx, 0x534d4150 235 cmp eax, edx 236 jnz .no_mem 237 cmp ecx, 20 238 jnz .no_mem 239 mov es:[di - 4], ecx 240 add word es:[bp + mmap_size], 24 241 cmp word es:[bp + mmap_size], (mmap_end - mmap) 242 jz .no_mem 243 add di, 24 244 test ebx, ebx 245 jnz .loop 246 pop es 247 pop ds 248 popa 249 mov ax, 0 250 ret 251 .no_mem: 252 pop es 253 pop ds 254 popa 255 mov ax, 1 256 ret 257 258 enter_unreal: 259 pop ax 260 push cs 261 push ax 262 pusha 263 push ds 264 push es 265 push fs 266 push gs 267 pushf 268 cli 269 call .1 270 .1: 271 xor ebx, ebx 272 pop bx 273 ; Load the gdt 274 sub sp, 6 275 mov bp, sp 276 mov word ss:[bp], 39 277 xor eax, eax 278 mov ax, cs 279 shl eax, 4 280 add eax, ebx 281 add eax, (gdt - .1) 282 mov ss:[bp + 2], eax 283 lgdt ss:[bp] 284 add sp, 6 285 286 mov bx, sp 287 mov dx, ss 288 289 xor ebp, ebp 290 mov bp, sp 291 xor eax, eax 292 mov ax, ss 293 shl eax, 4 294 add ebp, eax 295 296 mov ecx, cr0 297 or ecx, 1 298 mov cr0, ecx 299 300 push 24 301 call .retf 302 303 mov ax, 32 304 mov ds, ax 305 mov es, ax 306 mov fs, ax 307 mov gs, ax 308 mov ss, ax 309 mov esp, ebp 310 311 mov ecx, cr0 312 and ecx, -2 313 mov cr0, ecx 314 315 mov ss, dx 316 mov sp, bx 317 318 popf 319 pop gs 320 pop fs 321 pop es 322 pop ds 323 popa 324 mov ax, 0 325 .retf: 326 retf 327 328 gdt: 329 ; 0 = null 330 dq 0x0000000000000000 331 ; 8 = 32 code 332 dq 0x00cf9b000000ffff 333 ; 16 = 32 data 334 dq 0x00cf93000000ffff 335 ; 24 = 16 code 336 dq 0x008f9b000000ffff 337 ; 32 = 16 data 338 dq 0x008f93000000ffff 339 340 check_unreal: 341 push ds 342 push es 343 344 mov ax, 0 345 mov ds, ax 346 mov ax, -1 347 mov es, ax 348 349 mov word ds:[0x500], 0 350 mov eax, 0x100500 351 mov word ds:[eax], 44 352 mov ax, ds:[0x500] 353 cmp ax, 0 354 jnz .fail 355 356 mov ax, es:[0x510] 357 cmp ax, 44 358 jnz .fail 359 360 mov ax, 0 361 pop es 362 pop ds 363 ret 364 .fail: 365 mov ax, 1 366 pop es 367 pop ds 368 ret 369 370 getframe: 371 call .1 372 .1: 373 pop di 374 add di, (frame - .1) 375 push cs 376 pop ds 377 push cs 378 pop es 379 ret 380 381 download: 382 push ds 383 push es 384 pusha 385 pushf 386 387 call getframe 388 389 mov word [di], 0 ; status 390 mov word [di + 2], 2 ; PXENV_PACKET_TYPE_DHCP_ACK 391 mov word [di + 4], 0 ; buffer size 392 mov word [di + 6], 0 ; buffer base 393 mov word [di + 8], 0 ; buffer segment 394 mov word [di + 10], 0 ; buffer limit 395 push ds 396 push di 397 mov bx, 0x71 398 push bx ; PXENV_GET_CACHED_INFO = 0x71 399 call far word [di + (pxe_entry - frame)] 400 add sp, 6 401 test ax, ax 402 jnz .fail 403 404 call getframe 405 406 mov si, di 407 add si, (filename - frame) 408 add di, 10 409 mov cx, 128 410 rep movsb 411 412 call getframe 413 414 mov word [di], 0 ; status 415 mov byte [di + 2], 192 ; server ip 416 mov byte [di + 3], 168 417 mov byte [di + 4], 30 418 mov byte [di + 5], 1 419 mov dword [di + 6], 0 ; gateway ip 420 mov word [di + 138], 69 ; port 421 mov word [di + 140], 512 ; packet size 422 push ds 423 push di 424 mov bx, 0x20 425 push bx ; PXENV_TFTP_OPEN = 0x0020 426 call far [di + (pxe_entry - frame)] 427 add sp, 6 428 test ax, ax 429 jnz .fail 430 431 call getframe 432 mov eax, 0x100000 433 mov cs:[di + (download_ptr - frame)], eax 434 435 .loop: 436 437 call getframe 438 439 mov ax, di 440 add ax, (page - frame) 441 mov word [di], 0 ; status 442 mov word [di + 2], 0 ; packet number 443 mov word [di + 4], 0 ; buffer size 444 mov word [di + 6], ax ; buffer 445 mov word [di + 8], ds 446 push ds 447 push di 448 mov bx, 0x22 449 push bx ; PXENV_TFTP_READ = 0x0022 450 call far [di + (pxe_entry - frame)] 451 add sp, 6 452 test ax, ax 453 jnz .fail 454 455 call getframe 456 457 ; Push the kernel pointer 458 xor ecx, ecx 459 mov cx, cs:[di + 4] 460 mov ebx, cs:[di + (kernel_size - frame)] 461 mov eax, ebx 462 add eax, ecx 463 mov cs:[di + (kernel_size - frame)], eax 464 add ebx, cs:[di + (download_ptr - frame)] 465 466 cmp cs:[di + (high_mem_size - frame)], eax 467 jb .fail 468 469 xor esi, esi 470 mov si, di 471 add si, (page - frame) 472 473 mov ax, 0 474 mov es, ax 475 mov edi, ebx 476 477 cld 478 rep a32 movsb 479 480 call getframe 481 482 ; Keep reading blocks until we get a small one 483 cmp word cs:[di + 4], 512 484 jz .loop 485 486 call getframe 487 488 mov word cs:[di], 0 ; status 489 push ds 490 push di 491 mov bx, 0x21 492 push bx ; PXENV_TFTP_CLOSE = 0x0021 493 call far [di + (pxe_entry - frame)] 494 add sp, 6 495 test ax, ax 496 jnz .fail 497 498 popf 499 popa 500 pop es 501 pop ds 502 mov ax, 0 503 ret 504 .fail: 505 popf 506 popa 507 pop es 508 pop ds 509 mov ax, 1 510 ret 511 512 find_pxe: 513 pusha 514 push ds 515 push es 516 517 mov ax, cs 518 mov es, ax 519 520 call .1 521 .1: 522 pop bx 523 524 mov ax, es:[bx + (pxenv_ptr - .1 + 2)] 525 mov ds, ax 526 mov si, es:[bx + (pxenv_ptr - .1)] 527 528 ; PXENV+ 529 cmp word [si], 0x5850 530 jnz .fail 531 cmp word [si + 2], 0x4e45 532 jnz .fail 533 cmp word [si + 4], 0x2b56 534 jnz .fail 535 cmp word [si + 6], 0x0201 536 jb .fail 537 cmp byte [si + 8], 44 538 jb .fail 539 mov ch, 0 540 mov cl, [si + 8] 541 call bsum 542 test ax, ax 543 jnz .fail 544 545 mov ax, [si + 40] 546 mov es:[bx + (pxe_ptr - .1)], ax 547 mov ax, [si + 42] 548 mov es:[bx + (pxe_ptr - .1 + 2)], ax 549 mov ds, ax 550 mov si, es:[bx + (pxe_ptr - .1)] 551 552 ; !PXE 553 cmp word [si], 0x5021 554 jnz .fail 555 cmp word [si + 2], 0x4558 556 jnz .fail 557 cmp byte [si + 4], 20 558 jb .fail 559 mov ch, 0 560 mov cl, [si + 4] 561 call bsum 562 test ax, ax 563 jnz .fail 564 565 ; Save pxe entry point 566 mov ax, [si + 16] 567 mov es:[bx + pxe_entry - .1], ax 568 mov ax, [si + 18] 569 mov es:[bx + pxe_entry - .1 + 2], ax 570 571 pop es 572 pop ds 573 popa 574 mov ax, 0 575 ret 576 .fail: 577 pop es 578 pop ds 579 popa 580 mov ax, 1 581 ret 582 583 bsum: 584 push si 585 push cx 586 xor ax, ax 587 test cx, cx 588 jz .out 589 .loop: 590 add al, ds:[si] 591 inc si 592 dec cx 593 jnz .loop 594 .out: 595 pop cx 596 pop si 597 ret 598 599 bzero32: 600 push edi 601 push ecx 602 test ecx, ecx 603 jz .out 604 .loop: 605 mov byte ds:[edi], 0 606 inc edi 607 dec ecx 608 jz .out 609 jmp .loop 610 .out: 611 pop ecx 612 pop edi 613 ret 614 615 bcopy32: 616 push edi 617 push esi 618 push ecx 619 test ecx, ecx 620 jz .out 621 cmp edi, esi 622 je .out 623 jb .loop_forward 624 add esi, ecx 625 add edi, ecx 626 .loop_backward: 627 dec edi 628 dec esi 629 mov al, ds:[esi] 630 mov ds:[edi], al 631 dec ecx 632 jz .out 633 jmp .loop_backward 634 .loop_forward: 635 mov al, ds:[esi] 636 mov ds:[edi], al 637 inc esi 638 inc edi 639 dec ecx 640 jz .out 641 jmp .loop_forward 642 .out: 643 pop ecx 644 pop esi 645 pop edi 646 ret 647 648 parse_mb: 649 pusha 650 push ds 651 push es 652 pushf 653 cld 654 mov ax, 0 655 mov ds, ax 656 mov es, ax 657 call .1 658 .1: 659 xor ebx, ebx 660 pop bx 661 ; Bound the search to the first 8k (2k dwords) 662 mov ecx, 2048 663 664 sub ecx, 7 665 jbe .fail 666 ; Find the multiboot header 667 mov edi, cs:[bx + (download_ptr - .1)] 668 .loop: 669 mov eax, ds:[edi] 670 cmp eax, 0x1badb002 671 jnz .next 672 add eax, ds:[edi + 4] 673 add eax, ds:[edi + 8] 674 jz .found 675 .next: 676 add edi, 4 677 dec ecx 678 jz .fail 679 jmp .loop 680 .found: 681 test dword ds:[edi + 4], 0x10000 682 jz .fail 683 684 mov cs:[bx + (mb_ptr - .1)], edi 685 686 mov eax, ds:[edi + 12] 687 mov cs:[bx + (mb_header_addr - .1)], eax 688 689 mov eax, ds:[edi + 16] 690 mov cs:[bx + (mb_load_addr - .1)], eax 691 692 mov eax, ds:[edi + 20] 693 test eax, eax 694 jnz .endok 695 mov eax, cs:[bx + (mb_load_addr - .1)] 696 add eax, cs:[bx + (kernel_size - .1)] 697 .endok: 698 mov cs:[bx + (mb_load_end_addr - .1)], eax 699 700 mov eax, ds:[edi + 24] 701 test eax, eax 702 jnz .bssok 703 mov eax, cs:[bx + (mb_load_end_addr - .1)] 704 .bssok: 705 mov cs:[bx + (mb_bss_end_addr - .1)], eax 706 707 mov eax, ds:[edi + 28] 708 mov cs:[bx + (mb_entry_addr - .1)], eax 709 710 ; sanity checks 711 712 ; 0x100000 <= load_addr 713 cmp dword cs:[bx + (mb_load_addr - .1)], 0x100000 714 jb .fail 715 716 ; load_addr <= header_addr 717 mov eax, cs:[bx + (mb_load_addr - .1)] 718 cmp eax, cs:[bx + (mb_header_addr - .1)] 719 ja .fail 720 721 ; header_addr <= load_end_addr 722 mov eax, cs:[bx + (mb_header_addr - .1)] 723 cmp eax, cs:[bx + (mb_load_end_addr - .1)] 724 ja .fail 725 726 ; load_addr <= entry_addr 727 mov eax, cs:[bx + (mb_load_addr - .1)] 728 cmp eax, cs:[bx + (mb_entry_addr - .1)] 729 ja .fail 730 731 ; entry_addr <= load_end_addr 732 mov eax, cs:[bx + (mb_entry_addr - .1)] 733 cmp eax, cs:[bx + (mb_load_end_addr - .1)] 734 ja .fail 735 736 ; load_end_addr <= bss_end_addr 737 mov eax, cs:[bx + (mb_load_end_addr - .1)] 738 cmp eax, cs:[bx + (mb_bss_end_addr - .1)] 739 ja .fail 740 741 ; load_end_addr - load_addr <= kernel_size 742 mov ecx, cs:[bx + (mb_load_end_addr - .1)] 743 sub ecx, cs:[bx + (mb_load_addr - .1)] 744 cmp ecx, cs:[bx + (kernel_size - .1)] 745 ja .fail 746 747 ; bss_end_addr - load_addr <= high_mem_size 748 mov ecx, cs:[bx + (mb_bss_end_addr - .1)] 749 sub ecx, cs:[bx + (mb_load_addr - .1)] 750 cmp ecx, cs:[bx + (high_mem_size - .1)] 751 ja .fail 752 753 ; header_addr - load_addr <= mb_ptr - download_ptr 754 mov eax, cs:[bx + (mb_header_addr - .1)] 755 sub eax, cs:[bx + (mb_load_addr - .1)] 756 mov ecx, cs:[bx + (mb_ptr - .1)] 757 sub ecx, cs:[bx + (download_ptr - .1)] 758 cmp eax, ecx 759 ja .fail 760 761 ; copy to load_addr 762 ; from mb_ptr - header_addr + load_addr 763 mov edi, cs:[bx + (mb_load_addr - .1)] 764 mov esi, cs:[bx + (mb_ptr - .1)] 765 sub esi, cs:[bx + (mb_header_addr - .1)] 766 add esi, edi 767 mov ecx, cs:[bx + (mb_load_end_addr - .1)] 768 sub ecx, edi 769 call bcopy32 770 771 ; zero bss 772 mov edi, cs:[bx + (mb_load_end_addr - .1)] 773 mov ecx, cs:[bx + (mb_bss_end_addr - .1)] 774 sub ecx, edi 775 call bzero32 776 777 ; Align to dword 778 xor edi, edi 779 mov di, cs 780 shl edi, 4 781 add edi, ebx 782 add edi, (frame - .1 + 3) 783 and edi, -4 784 785 mov cs:[bx + (mb_info_ptr - .1)], edi 786 787 ; Write multiboot info 788 mov dword ds:[edi], ((1 << 0) + (1 << 6)) 789 790 ; Save mem_lower 791 mov eax, cs:[bx + low_mem_size - .1] 792 shr eax, 10 793 mov dword ds:[edi + 4], eax 794 795 ; Save mem_upper 796 mov eax, cs:[bx + high_mem_size - .1] 797 shr eax, 10 798 mov dword ds:[edi + 8], eax 799 800 ; Save mmap_len 801 xor eax, eax 802 mov ax, cs:[bx + mmap_size - .1] 803 mov dword ds:[edi + 44], eax 804 805 ; Save mmap_addr 806 xor eax, eax 807 mov ax, cs 808 shl eax, 4 809 add eax, ebx 810 add eax, (mmap - .1) 811 mov dword ds:[edi + 48], eax 812 813 popf 814 pop es 815 pop ds 816 popa 817 mov ax, 0 818 ret 819 .fail: 820 popf 821 pop es 822 pop ds 823 popa 824 mov ax, 1 825 ret 826 827 boot: 828 mov ax, 0 829 mov ds, ax 830 mov es, ax 831 call .1 832 .1: 833 xor ebx, ebx 834 pop bx 835 836 mov esi, cs:[bx + mb_info_ptr - .1] 837 mov edi, cs:[bx + mb_entry_addr - .1] 838 839 cli 840 841 ; Load the gdt 842 sub sp, 6 843 mov bp, sp 844 mov word ss:[bp], 39 845 xor eax, eax 846 mov ax, cs 847 shl eax, 4 848 add eax, ebx 849 add eax, (gdt - .1) 850 mov ss:[bp + 2], eax 851 lgdt ss:[bp] 852 add sp, 6 853 854 mov ecx, cr0 855 or ecx, 1 856 mov cr0, ecx 857 858 859 xor ebp, ebp 860 mov bp, sp 861 xor eax, eax 862 mov ax, ss 863 shl eax, 4 864 add ebp, eax 865 866 push 8 867 call .retf 868 869 bits 32 870 871 .3: 872 873 mov ax, 16 874 mov ds, ax 875 mov es, ax 876 mov fs, ax 877 mov gs, ax 878 mov ss, ax 879 mov esp, ebp 880 881 mov eax, 0x2badb002 882 mov ebx, esi 883 jmp edi 884 885 bits 16 886 887 .retf: 888 retf 889 890 puts: 891 push bp 892 mov bp, sp 893 pusha 894 push ds 895 push es 896 push fs 897 push gs 898 pushf 899 call .1 900 .1: 901 pop ax 902 sub ax, .1 903 mov si, ss:[bp + 4] 904 add si, ax 905 cld 906 .loop: 907 mov ah, 0x0e 908 mov al, cs:[si] 909 test al, al 910 jz .out 911 mov bx, 0x0001 912 int 0x10 913 inc si 914 jmp .loop 915 .out: 916 popf 917 pop gs 918 pop fs 919 pop es 920 pop ds 921 popa 922 pop bp 923 ret 924 925 puth: 926 push bp 927 mov bp, sp 928 pusha 929 push ds 930 push es 931 push fs 932 push gs 933 pushf 934 mov cx, 32 935 .loop: 936 sub cx, 4 937 mov eax, [bp + 4] 938 shr eax, cl 939 and eax, 15 940 cmp eax, 10 941 jb .a 942 add eax, 'a' - '0' - 10 943 .a: 944 add eax, 0x0e00 + '0' 945 mov bx, 0x0001 946 int 0x10 947 test cx, cx 948 jnz .loop 949 .out: 950 popf 951 pop gs 952 pop fs 953 pop es 954 pop ds 955 popa 956 pop bp 957 ret 958 959 low_mem_size: 960 dd 0 961 high_mem_size: 962 dd 0 963 kernel_size: 964 dd 0 965 mmap_size: 966 dw 0 967 pxenv_ptr: 968 dd 0 969 pxe_ptr: 970 dd 0 971 pxe_entry: 972 dd 0 973 download_ptr: 974 dd 0 975 mb_ptr: 976 dd 0 977 mb_header_addr: 978 dd 0 979 mb_load_addr: 980 dd 0 981 mb_load_end_addr: 982 dd 0 983 mb_bss_end_addr: 984 dd 0 985 mb_entry_addr: 986 dd 0 987 mb_info_ptr: 988 dd 0 989 align 16, db 0 990 filename: 991 db `/kernel`, 0 992 times 128 - ($ - filename) db 0 993 frame equ $ 994 ;times 256 db 0 995 page equ frame + 256 996 ;times 512 db 0 997 mmap equ page + 512 998 ;times (8192 + 8192) db 0 999 mmap_end equ mmap + (8192 + 8192)