1; -*- fundamental -*- (asm-mode sucks) 2; **************************************************************************** 3; 4; memdisk.inc 5; 6; A program to emulate an INT 13h disk BIOS from a "disk" in extended 7; memory. 8; 9; Copyright 2001-2009 H. Peter Anvin - All Rights Reserved 10; Copyright 2009 Intel Corporation; author: H. Peter Anvin 11; Portions copyright 2009 Shao Miller [El Torito code, mBFT, safe hook] 12; 13; This program is free software; you can redistribute it and/or modify 14; it under the terms of the GNU General Public License as published by 15; the Free Software Foundation, Inc., 53 Temple Place Ste 330, 16; Boston MA 02111-1307, USA; either version 2 of the License, or 17; (at your option) any later version; incorporated herein by reference. 18; 19; **************************************************************************** 20 21%include "../version.gen" 22 23; %define DEBUG_TRACERS ; Uncomment to get debugging tracers 24 25%ifdef DEBUG_TRACERS 26 27%macro TRACER 1 28 call debug_tracer 29 db %1 30%endmacro 31%macro WRITEHEX2 0-1 al 32%ifnidni %1,al 33 push ax 34 mov al,%1 35 call writehex2 36 pop ax 37%else 38 call writehex2 39%endif 40%endmacro 41%macro WRITEHEX4 0-1 ax 42%ifnidni %1,ax 43 push ax 44 mov ax,%1 45 call writehex4 46 pop ax 47%else 48 call writehex4 49%endif 50%endmacro 51%macro WRITEHEX8 0-1 eax 52%ifnidni %1,eax 53 push eax 54 mov eax,%1 55 call writehex8 56 pop eax 57%else 58 call writehex8 59%endif 60%endmacro 61 62%else ; DEBUG_TRACERS 63 64%macro TRACER 1 65%endmacro 66%macro WRITEHEX2 0-1 67%endmacro 68%macro WRITEHEX4 0-1 69%endmacro 70%macro WRITEHEX8 0-1 71%endmacro 72 73%endif ; DEBUG_TRACERS 74 75; Flags we test our configuration against 76%define CONFIG_READONLY 0x01 77%define CONFIG_RAW 0x02 78%define CONFIG_SAFEINT 0x04 79%define CONFIG_BIGRAW 0x08 ; MUST be 8! 80 81 org 0h 82 83%define SECTORSIZE (1 << SECTORSIZE_LG2) 84 85 ; Parameter registers definition; this is the definition 86 ; of the stack frame. 87%define P_DS word [bp+34] 88%define P_ES word [bp+32] 89%define P_EAX dword [bp+28] 90%define P_HAX word [bp+30] 91%define P_AX word [bp+28] 92%define P_AL byte [bp+28] 93%define P_AH byte [bp+29] 94%define P_ECX dword [bp+24] 95%define P_HCX word [bp+26] 96%define P_CX word [bp+24] 97%define P_CL byte [bp+24] 98%define P_CH byte [bp+25] 99%define P_EDX dword [bp+20] 100%define P_HDX word [bp+22] 101%define P_DX word [bp+20] 102%define P_DL byte [bp+20] 103%define P_DH byte [bp+21] 104%define P_EBX dword [bp+16] 105%define P_HBX word [bp+18] 106%define P_HBXL byte [bp+18] 107%define P_BX word [bp+16] 108%define P_BL byte [bp+16] 109%define P_BH byte [bp+17] 110%define P_EBP dword [bp+8] 111%define P_BP word [bp+8] 112%define P_ESI dword [bp+4] 113%define P_SI word [bp+4] 114%define P_EDI dword [bp] 115%define P_DI word [bp] 116 117 section .text 118 ; These pointers are used by the installer and 119 ; must be first in the binary 120Pointers: dw Int13Start 121 dw Int15Start 122 dw MemDisk_Info ; Portions are patched by installer 123 dw TotalSize 124 dw IretPtr 125 126IretPtr equ Int13Start.iret 127Int13Start: 128 jmp strict near .SafeHookEnd ; 3-byte jump 129 db '$INT13SF' ; Signature for "safe hook" 130 db 'MEMDISK ' ; Vendor ID 131 dd 0 ; SEG:OFF of previous INT 13h hook 132 ; Must be filled in by installer 133 dd 0 ; "Safe hook" flags 134; ---- "Safe hook" structure ends here --- 135 136; This next field should be guaranteed at this position after the 137; "safe hook" structure. This allows for a MEMDISK OS driver to 138; immediately find out the particular parameters using the mBFT 139; and MDI structures. This binary will have the offset to the mBFT 140; in this field to begin with, so the installer knows where the mBFT 141; is. This is akin to the "Pointers" section above. The installer 142; will refill this field with the physical address of the mBFT for 143; future consumers, such as OS drivers. 144 dd mBFT ; Offset from hook to the mBFT 145 146.SafeHookEnd: 147 cmp word [cs:Recursive],0 148 jne recursive 149 150 ; Swap stack 151 mov [cs:Stack],esp 152 mov [cs:Stack+4],ss 153 mov [cs:SavedAX],ax 154 mov ax,cs 155 mov ss,ax 156 mov sp,[cs:MyStack] 157 158%if ELTORITO 159 cmp word [cs:SavedAX],4a00h ; El Torito function? 160 jae our_drive ; We grab it 161%endif 162 ; See if DL points to our class of device (FD, HD) 163 push dx 164 push dx 165 xor dl,[cs:DriveNo] 166 pop dx 167 js .nomatch ; If SF=0, we have a class match here 168 ; 0x00 the sign bit for FD 169 ; 0x80 the sign bit for HD 170 jz our_drive ; If ZF=1, we have an exact match 171 cmp dl,[cs:DriveNo] 172 jb .nomatch ; Drive < Our drive 173 cmp dl,[cs:DriveShiftLimit] 174 jae .nomatch ; Drive > The maximum drive 175 ; number that we will shift for. 176 ; This leaves any higher-up BIOS 177 ; drives alone, such as an optical 178 ; disc drive 0xA0 or 0xE0 179 dec dl ; Drive > Our drive, adjust drive # 180.nomatch: 181 TRACER '!' 182 WRITEHEX2 dl 183 TRACER ',' 184 mov ax,[cs:SavedAX] 185 WRITEHEX4 186 inc word [cs:Recursive] 187 pushf 188 call far [cs:OldInt13] 189 pushf 190 dec word [cs:Recursive] 191 push bp 192 mov bp,sp 193 cmp byte [cs:SavedAX+1],08h ; Get drive params function? 194 je .norestoredl ; DL = number of drives 195 cmp byte [cs:SavedAX+1],15h ; Get disk type function? 196 jne .restoredl 197 test byte [bp+4],80h ; Hard disk? 198 jnz .norestoredl ; CX:DX = size of device 199.restoredl: 200 mov dl,[bp+4] 201.norestoredl: 202 push ax 203 push ebx 204 push ds 205 mov ax,[bp+2] ; Flags 206 lds ebx,[cs:Stack] 207 mov [bx+4],al ; Arithmetic flags 208 pop ds 209 pop ebx 210 pop ax 211 pop bp 212 lss esp,[cs:Stack] 213.iret: iret 214 215recursive: 216 TRACER '@' 217jmp_oldint13: 218 jmp far [cs:OldInt13] 219 220our_drive: 221 ; Set up standard entry frame 222 push ds 223 push es 224 mov ds,ax 225 mov es,ax 226 mov ax,[SavedAX] 227 pushad 228 mov bp,sp ; Point BP to the entry stack frame 229 TRACER 'F' 230 WRITEHEX4 231 ; Note: AX == P_AX here 232 cmp ah,Int13FuncsCnt-1 233 ja Invalid_jump 234%if ELTORITO 235 mov al,[CD_PKT.type] ; Check if we are in 236 cmp al,0 ; El Torito no emulation mode 237 ja .emulation ; No. We support the function 238 cmp ah,3fh ; Yes. We must not support functions 239 jbe Invalid_jump ; 0 through 3Fh. Check and decide 240.emulation: 241%endif 242 xor al,al ; AL = 0 is standard entry condition 243 mov di,ax 244 shr di,7 ; Convert AH to an offset in DI 245 call [Int13Funcs+di] 246 247Done: ; Standard routine for return 248 mov P_AX,ax 249DoneWeird: 250 TRACER 'D' 251 xor bx,bx 252 mov es,bx 253 mov bx,[StatusPtr] 254 mov [es:bx],ah ; Save status 255 and ah,ah 256 257 lds ebx,[Stack] 258 ; This sets the low byte (the arithmetic flags) of the 259 ; FLAGS on stack to either 00h (no flags) or 01h (CF) 260 ; depending on if AH was zero or not. 261 setnz [bx+4] ; Set CF iff error 262 popad 263 pop es 264 pop ds 265 lss esp,[cs:Stack] 266 iret 267 268Reset: 269 ; Reset affects multiple drives, so we need to pass it on 270 TRACER 'R' 271 xor ax,ax ; Bottom of memory 272 mov es,ax 273 test dl,dl ; Always pass it on if we are 274 ; resetting HD 275 js .hard_disk ; Bit 7 set 276 ; Some BIOSes get very unhappy if we pass a reset floppy 277 ; command to them and don't actually have any floppies. 278 ; This is a bug, but we have to deal with it nontheless. 279 ; Therefore, if we are the *ONLY* floppy drive, and the 280 ; user didn't request HD reset, then just drop the command. 281 ; BIOS equipment byte, top two bits + 1 == total # of floppies 282 test byte [es:0x410],0C0h 283 jz success 284 jmp .pass_on ; ... otherwise pass it to the BIOS 285.hard_disk: 286 ; ... same thing for hard disks, sigh ... 287 cmp byte [es:0x475],1 ; BIOS variable for number of hard 288 ; disks 289 jbe success 290 291.pass_on: 292 pop ax ; Drop return address 293 popad ; Restore all registers 294 pop es 295 pop ds 296 lss esp,[cs:Stack] ; Restore the stack 297 and dl,80h ; Clear all but the type bit 298 jmp jmp_oldint13 299 300 301Invalid: 302 pop dx ; Drop return address 303Invalid_jump: 304 TRACER 'I' 305 mov ah,01h ; Unsupported function 306 jmp short Done 307 308GetDriveType: 309 test byte [DriveNo],80h 310 mov bl,02h ; Type 02h = floppy with changeline 311 jz .floppy 312 ; Hard disks only! DO NOT set CX:DX for floppies... 313 ; it apparently causes Win98SE DOS to go into an loop 314 ; resetting the drive over and over. Sigh. 315 inc bx ; Type = 03h 316 mov dx,[DiskSize] ; Return the disk size in sectors 317 mov P_DX,dx 318 mov cx,[DiskSize+2] 319 mov P_CX,cx 320.floppy: 321 mov P_AH,bl ; 02h floppy, 03h hard disk 322 pop ax ; Drop return address 323 xor ax,ax ; Success... 324 jmp DoneWeird ; But don't stick it into P_AX 325 326GetStatus: 327 xor ax,ax 328 mov es,ax 329 mov bx,[StatusPtr] 330 mov ah,[bx] ; Copy last status 331 ret 332 333ReadMult: 334 TRACER 'm' 335Read: 336 TRACER 'R' 337 call setup_regs 338do_copy: 339 TRACER '<' 340 call bcopy 341 TRACER '>' 342 movzx ax,P_AL ; AH = 0, AL = transfer count 343 ret 344 345WriteMult: 346 TRACER 'M' 347Write: 348 TRACER 'W' 349 test byte [ConfigFlags],CONFIG_READONLY 350 jnz .readonly 351 call setup_regs 352 xchg esi,edi ; Opposite direction of a Read! 353 jmp short do_copy 354.readonly: mov ah,03h ; Write protected medium 355 ret 356 357 ; Verify integrity; just bounds-check 358Seek: 359Verify: 360 call setup_regs ; Returns error if appropriate 361 ; And fall through to success 362 363CheckIfReady: ; These are always-successful noop functions 364Recalibrate: 365InitWithParms: 366DetectChange: 367EDDDetectChange: 368EDDLock: 369SetMode: 370success: 371 xor ax,ax ; Always successful 372 ret 373 374GetParms: 375 TRACER 'G' 376 mov dl,[DriveCnt] ; Cached data 377 mov P_DL,dl 378 test byte [DriveNo],80h 379 jnz .hd 380 mov P_DI,DPT 381 mov P_ES,cs 382 mov bl,[DriveType] 383 mov P_BL,bl 384.hd: 385 mov ax,[Cylinders] 386 dec ax ; We report the highest #, not the count 387 xchg al,ah 388 shl al,6 389 or al,[Sectors] 390 mov P_CX,ax 391 mov ax,[Heads] 392 dec ax 393 mov P_DH,al 394 395 ; 396 ; Is this MEMDISK installation check? 397 ; 398 cmp P_HAX,'ME' 399 jne .notic 400 cmp P_HCX,'MD' 401 jne .notic 402 cmp P_HDX,'IS' 403 jne .notic 404 cmp P_HBX,'K?' 405 jne .notic 406 407 ; MEMDISK installation check... 408 mov P_HAX,'!M' 409 mov P_HCX,'EM' 410 mov P_HDX,'DI' 411 mov P_HBX,'SK' 412 mov P_ES,cs 413 mov P_DI,MemDisk_Info 414 415.notic: 416 xor ax,ax 417 ret 418; 419; EDD functions -- only if enabled 420; 421%if EDD 422EDDPresence: 423 TRACER 'E' 424 TRACER 'c' 425 426 cmp P_BX,55AAh 427 jne Invalid 428 mov P_BX,0AA55h ; EDD signature 429 mov P_AX,03000h ; EDD 3.0 430 mov P_CX,0007h ; Bit 0 - Fixed disk access subset 431 ; Bit 1 - Locking and ejecting subset 432 ; Bit 2 - EDD subset 433 pop ax ; Drop return address 434 xor ax,ax ; Success 435 jmp DoneWeird ; Success, but AH != 0, sigh... 436 437EDDRead: 438 TRACER 'E' 439 TRACER 'r' 440 441 call edd_setup_regs 442 call bcopy 443 xor ax,ax 444 ret 445 446EDDWrite: 447 TRACER 'E' 448 TRACER 'w' 449 450 call edd_setup_regs 451 xchg esi,edi ; Opposite direction of a Read! 452 call bcopy 453 xor ax,ax 454 ret 455 456EDDVerify: 457EDDSeek: 458 call edd_setup_regs ; Just bounds checking 459 xor ax,ax 460 ret 461 462EDDGetParms: 463 TRACER 'E' 464 TRACER 'p' 465 466 mov es,P_DS 467 mov di,P_SI 468 mov si,EDD_DPT 469 470 lodsw ; Length of our DPT 471 mov cx,[es:di] 472 cmp cx,26 ; Minimum size 473 jb .overrun 474 475 cmp cx,ax 476 jb .oksize 477 mov cx,ax 478 479.oksize: 480 mov ax,cx 481 stosw 482 dec cx 483 dec cx 484 rep movsb 485 486 xor ax,ax 487 ret 488 489.overrun: 490 mov ax,0100h 491 ret 492%endif ; EDD 493 494 ; Set up registers as for a "Read", and compares against disk 495 ; size. 496 ; WARNING: This fails immediately, even if we can transfer some 497 ; sectors. This isn't really the correct behaviour. 498setup_regs: 499 500 ; Convert a CHS address in P_CX/P_DH into an LBA in eax 501 ; CH = cyl[7:0] 502 ; CL[0:5] = sector (1-based) CL[7:6] = cyl[9:8] 503 ; DH = head 504 movzx ecx,P_CX 505 movzx ebx,cl ; Sector number 506 and bl,3Fh 507 dec ebx ; Sector number is 1-based 508 cmp bx,[Sectors] 509 jae .overrun 510 movzx edi,P_DH ; Head number 511 movzx eax,word [Heads] 512 cmp di,ax 513 jae .overrun 514 shr cl,6 515 xchg cl,ch ; Now (E)CX <- cylinder number 516 mul ecx ; eax <- Heads*cyl# (edx <- 0) 517 add eax,edi 518 mul dword [Sectors] 519 add eax,ebx 520 ; Now eax = LBA, edx = 0 521 522 ; 523 ; setup_regs continues... 524 ; 525 ; Note: edi[31:16] and ecx[31:16] = 0 already 526 mov di,P_BX ; Get linear address of target buffer 527 mov cx,P_ES 528 shl ecx,4 529 add edi,ecx ; EDI = address to fetch to 530 movzx ecx,P_AL ; Sector count 531 mov esi,eax 532 add eax,ecx ; LBA of final sector + 1 533 shl esi,SECTORSIZE_LG2 ; LBA -> byte offset 534 add esi,[DiskBuf] ; Get address in high memory 535 cmp eax,[DiskSize] ; Check the high mark against limit 536 ja .overrun 537 shl ecx,SECTORSIZE_LG2-2 ; Convert count to dwords 538 ret 539 540.overrun: pop ax ; Drop setup_regs return address 541 mov ax,0200h ; Missing address mark 542 ret ; Return to Done 543 544 ; Set up registers as for an EDD Read, and compares against disk size. 545%if EDD 546edd_setup_regs: 547 push es 548 mov si,P_SI ; DS:SI -> DAPA 549 mov es,P_DS 550 551 mov dx,[es:si] 552 cmp dx,16 553 jb .baddapa 554 555 cmp dword [es:si+4],-1 556 je .linear_address 557 558 movzx ebx,word [es:si+4] ; Offset 559 movzx edi,word [es:si+6] ; Segment 560 shl edi,4 561 add ebx,edi 562 jmp .got_address 563 564.linear_address: 565 cmp dx,24 ; Must be large enough to hold 566 ; linear address 567 jb .baddapa 568 569 cmp dword [es:si+20],0 ; > 4 GB addresses not supported 570 mov ax,0900h ; "Data boundary error" - bogus, but 571 ; no really better code available 572 jne .error 573 574 mov ebx,[es:si+16] 575 576.got_address: 577 cmp dword [es:si+12],0 ; LBA too large? 578 jne .overrun 579 580 movzx ecx, word [es:si+2] ; Sectors to transfer 581 mov esi,[es:si+8] ; Starting sector 582 mov eax,esi 583 add eax,ecx 584 jc .overrun 585 cmp eax,[DiskSize] 586 ja .overrun 587 588 shl ecx,SECTORSIZE_LG2-2 ; Convert to dwords 589 shl esi,SECTORSIZE_LG2 ; Convert to an offset 590 add esi,[DiskBuf] 591 mov edi,ebx 592 pop es 593 ret 594 595.baddapa: 596 mov ax,0100h ; Invalid command 597 pop es 598 pop ax ; Drop setup_regs return address 599 ret 600 601.overrun: 602 mov ax,0200h ; "Address mark not found" = 603 ; LBA beyond end of disk 604.error: 605 and word [es:si+2],0 ; No sectors transferred 606 pop es 607 pop ax 608 ret 609 610EDDEject: 611 mov ax,0B200h ; Volume Not Removable 612 ret 613%if ELTORITO 614ElToritoTerminate: 615 TRACER 'T' 616 mov ax,[cs:SavedAX] 617 cmp al,1 ; We only support query, not terminate 618 jne ElToritoErr ; Fail 619 cmp dl,7fh ; Terminate all? 620 je .doit 621 cmp dl,[cs:DriveNo] ; Terminate our drive? 622 je .doit 623 jmp ElToritoErr ; Fail 624.doit: mov es,P_DS ; Caller's DS:SI pointed to packet 625 mov di,P_SI ; We'll use ES:DI 626 mov si,CD_PKT.size ; First byte is packet size 627 xor cx,0 ; Empty our count 628 ;mov cl,[ds:si] ; We'll copy that many bytes 629 mov cl,13h 630 rep movsb ; Copy until CX is zero 631 mov ax,0 ; Success 632 ret 633ElToritoEmulate: 634ElToritoBoot: 635ElToritoCatalog: 636ElToritoErr: 637 TRACER '!' 638 mov ax,100h ; Invalid parameter 639 ret 640%endif ; ELTORITO 641%endif ; EDD 642 643; 644; INT 15h intercept routines 645; 646int15_e820: 647 cmp edx,534D4150h ; "SMAP" 648 jne oldint15 649 cmp ecx,20 ; Need 20 bytes 650 jb err86 651 push ds 652 push cs 653 pop ds 654 push edx ; "SMAP" 655 and ebx,ebx 656 jne .renew 657 mov ebx,E820Table 658.renew: 659 add bx,12 ; Advance to next 660 mov eax,[bx-4] ; Type 661 and eax,eax ; Null type? 662 jz .renew ; If so advance to next 663 mov [es:di+16],eax 664 mov eax,[bx-12] ; Start addr (low) 665 mov edx,[bx-8] ; Start addr (high) 666 mov [es:di],eax 667 mov [es:di+4],edx 668 mov eax,[bx] ; End addr (low) 669 mov edx,[bx+4] ; End addr (high) 670 sub eax,[bx-12] ; Derive the length 671 sbb edx,[bx-8] 672 mov [es:di+8],eax ; Length (low) 673 mov [es:di+12],edx ; Length (high) 674 cmp dword [bx+8],-1 ; Type of next = end? 675 jne .notdone 676 xor ebx,ebx ; Done with table 677.notdone: 678 pop eax ; "SMAP" 679 mov edx,eax ; Some systems expect eax = edx = SMAP 680 mov ecx,20 ; Bytes loaded 681 pop ds 682int15_success: 683 mov byte [bp+6], 02h ; Clear CF 684 pop bp 685 iret 686 687err86: 688 mov byte [bp+6], 03h ; Set CF 689 mov ah,86h 690 pop bp 691 iret 692 693Int15Start: 694 push bp 695 mov bp,sp 696 cmp ax,0E820h 697 je near int15_e820 698 cmp ax,0E801h 699 je int15_e801 700 cmp ax,0E881h 701 je int15_e881 702 cmp ah,88h 703 je int15_88 704oldint15: pop bp 705 jmp far [cs:OldInt15] 706 707int15_e801: ; Get mem size for > 64 MB config 708 mov ax,[cs:Mem1MB] 709 mov cx,ax 710 mov bx,[cs:Mem16MB] 711 mov dx,bx 712 jmp short int15_success 713 714int15_e881: ; Get mem size for > 64 MB config 715 ; 32-bit code 716 mov eax,[cs:Mem1MB] 717 mov ecx,eax 718 mov ebx,[cs:Mem16MB] 719 mov edx,ebx 720 jmp short int15_success 721 722int15_88: ; Get extended mem size 723 mov ax,[cs:MemInt1588] 724 jmp short int15_success 725 726; 727; Routine to copy in/out of high memory 728; esi = linear source address 729; edi = linear target address 730; ecx = 32-bit word count 731; 732; Assumes cs = ds = es 733; 734bcopy: 735 push eax 736 push ebx 737 push edx 738 push ebp 739 740 mov bx, real_int15_stub 741 742 test byte [ConfigFlags], CONFIG_RAW|CONFIG_SAFEINT 743 jz .anymode ; Always do the real INT 15h 744 745 smsw ax ; Unprivileged! 746 test al,01h 747 jnz .protmode ; Protmode -> do real INT 15h 748 749.realmode: 750 ; Raw or Safeint mode, and we're in real mode... 751 752 test byte [ConfigFlags], CONFIG_SAFEINT 753 jnz .fakeint15 754 755.raw: 756 TRACER 'r' 757 ; We're in real mode, do it outselves 758 759 pushfd ; <A> 760 push ds ; <B> 761 push es ; <C> 762 763 cli 764 cld 765 766 xor ebx,ebx 767 mov bx,cs 768 shl ebx,4 769 lea edx,[Shaker+ebx] 770 mov [Shaker+2],edx 771 772 ; Test to see if A20 is enabled or not 773 xor ax,ax 774 mov ds,ax 775 dec ax 776 mov es,ax 777 778 mov ax,[0] 779 mov bx,ax 780 xor bx,[es:10h] 781 not ax 782 mov [0],ax 783 mov dx,ax 784 xor dx,[es:10h] 785 not ax 786 mov [0],ax 787 788 or dx,bx 789 push dx ; <D> Save A20 status 790 jnz .skip_a20e 791 792 mov ax,2401h ; Enable A20 793 int 15h 794.skip_a20e: 795 mov dl,[ConfigFlags] 796 and dx,CONFIG_BIGRAW 797 add dx,8 798 ; DX = 16 for BIGRAW, 8 for RAW 799 ; 8 is selector for a 64K flat segment, 800 ; 16 is selector for a 4GB flat segment. 801 802 lgdt [cs:Shaker] 803 mov eax,cr0 804 or al,01h 805 mov cr0,eax 806 807 mov bx,16 ; Large flat segment 808 mov ds,bx 809 mov es,bx 810 811 a32 rep movsd 812 813 ; DX has the appropriate value to put in 814 ; the registers on return 815 mov ds,dx 816 mov es,dx 817 818 and al,~01h 819 mov cr0,eax 820 821 pop dx ; <D> A20 status 822 pop es ; <C> 823 pop ds ; <B> 824 825 and dx,dx 826 jnz .skip_a20d 827 mov ax,2400h ; Disable A20 828 int 15h 829.skip_a20d: 830 popfd ; <A> 831 jmp .done 832 833.fakeint15: 834 ; We're in real mode with CONFIG_SAFEINT, invoke the 835 ; original INT 15h vector. We used to test for the 836 ; INT 15h vector being unchanged here, but that is 837 ; *us*; however, the test was wrong for years (always 838 ; negative) so instead of fixing the test do what we 839 ; tested and don't bother probing. 840 mov bx, fake_int15_stub 841 842.protmode: 843 TRACER 'p' 844.anymode: 845 846.copy_loop: 847 push esi 848 push edi 849 push ecx 850 cmp ecx,4000h 851 jna .safe_size 852 mov ecx,4000h 853.safe_size: 854 push ecx ; Transfer size this cycle 855 mov eax, esi 856 mov [Mover_src1], si 857 shr eax, 16 858 mov [Mover_src1+2], al 859 mov [Mover_src2], ah 860 mov eax, edi 861 mov [Mover_dst1], di 862 shr eax, 16 863 mov [Mover_dst1+2], al 864 mov [Mover_dst2], ah 865 mov si,Mover 866 mov ah, 87h 867 shl cx,1 ; Convert to 16-bit words 868 call bx ; INT 15h stub 869 pop eax ; Transfer size this cycle 870 pop ecx 871 pop edi 872 pop esi 873 jc .error 874 lea esi,[esi+4*eax] 875 lea edi,[edi+4*eax] 876 sub ecx, eax 877 jnz .copy_loop 878 ; CF = 0 879.error: 880.done: 881 pop ebp 882 pop edx 883 pop ebx 884 pop eax 885 ret 886 887real_int15_stub: 888 int 15h 889 cli ; Some BIOSes enable interrupts on INT 15h 890 ret 891 892fake_int15_stub: 893 pushf 894 call far [OldInt15] 895 cli 896 ret 897 898%ifdef DEBUG_TRACERS 899debug_tracer: pushad 900 pushfd 901 mov bp,sp 902 mov bx,[bp+9*4] 903 mov al,[cs:bx] 904 inc word [bp+9*4] 905 mov ah,0Eh 906 mov bx,7 907 int 10h 908 popfd 909 popad 910 ret 911 912writehex2: pushad 913 pushfd 914 mov cx,2 915 ror eax,4 916 jmp writehex_common 917writehex4: pushad 918 pushfd 919 mov cx,4 920 ror eax,12 921 jmp writehex_common 922writehex8: pushad 923 pushfd 924 mov cx,8 925 ror eax,28 926writehex_common: 927.loop: push cx 928 push eax 929 and al,0Fh 930 cmp al,10 931 jb .isdec 932 add al,'a'-'0'-10 933.isdec: add al,'0' 934 mov ah,0Eh 935 mov bx,7 936 int 10h 937 pop eax 938 rol eax,4 939 pop cx 940 loop .loop 941 popfd 942 popad 943 ret 944%endif 945 946 section .data align=16 947 alignb 2 948Int13Funcs dw Reset ; 00h - RESET 949 dw GetStatus ; 01h - GET STATUS 950 dw Read ; 02h - READ 951 dw Write ; 03h - WRITE 952 dw Verify ; 04h - VERIFY 953 dw Invalid ; 05h - FORMAT TRACK 954 dw Invalid ; 06h - FORMAT TRACK AND SET BAD FLAGS 955 dw Invalid ; 07h - FORMAT DRIVE AT TRACK 956 dw GetParms ; 08h - GET PARAMETERS 957 dw InitWithParms ; 09h - INITIALIZE CONTROLLER WITH 958 ; DRIVE PARAMETERS 959 dw Invalid ; 0Ah 960 dw Invalid ; 0Bh 961 dw Seek ; 0Ch - SEEK TO CYLINDER 962 dw Reset ; 0Dh - RESET HARD DISKS 963 dw Invalid ; 0Eh 964 dw Invalid ; 0Fh 965 dw CheckIfReady ; 10h - CHECK IF READY 966 dw Recalibrate ; 11h - RECALIBRATE 967 dw Invalid ; 12h 968 dw Invalid ; 13h 969 dw Invalid ; 14h 970 dw GetDriveType ; 15h - GET DRIVE TYPE 971 dw DetectChange ; 16h - DETECT DRIVE CHANGE 972%if EDD 973 dw Invalid ; 17h 974 dw Invalid ; 18h 975 dw Invalid ; 19h 976 dw Invalid ; 1Ah 977 dw Invalid ; 1Bh 978 dw Invalid ; 1Ch 979 dw Invalid ; 1Dh 980 dw Invalid ; 1Eh 981 dw Invalid ; 1Fh 982 dw Invalid ; 20h 983 dw ReadMult ; 21h - READ MULTIPLE 984 dw WriteMult ; 22h - WRITE MULTIPLE 985 dw SetMode ; 23h - SET CONTROLLER FEATURES 986 dw SetMode ; 24h - SET MULTIPLE MODE 987 dw Invalid ; 25h - IDENTIFY DRIVE 988 dw Invalid ; 26h 989 dw Invalid ; 27h 990 dw Invalid ; 28h 991 dw Invalid ; 29h 992 dw Invalid ; 2Ah 993 dw Invalid ; 2Bh 994 dw Invalid ; 2Ch 995 dw Invalid ; 2Dh 996 dw Invalid ; 2Eh 997 dw Invalid ; 2Fh 998 dw Invalid ; 30h 999 dw Invalid ; 31h 1000 dw Invalid ; 32h 1001 dw Invalid ; 33h 1002 dw Invalid ; 34h 1003 dw Invalid ; 35h 1004 dw Invalid ; 36h 1005 dw Invalid ; 37h 1006 dw Invalid ; 38h 1007 dw Invalid ; 39h 1008 dw Invalid ; 3Ah 1009 dw Invalid ; 3Bh 1010 dw Invalid ; 3Ch 1011 dw Invalid ; 3Dh 1012 dw Invalid ; 3Eh 1013 dw Invalid ; 3Fh 1014 dw Invalid ; 40h 1015 dw EDDPresence ; 41h - EDD PRESENCE DETECT 1016 dw EDDRead ; 42h - EDD READ 1017 dw EDDWrite ; 43h - EDD WRITE 1018 dw EDDVerify ; 44h - EDD VERIFY 1019 dw EDDLock ; 45h - EDD LOCK/UNLOCK MEDIA 1020 dw EDDEject ; 46h - EDD EJECT 1021 dw EDDSeek ; 47h - EDD SEEK 1022 dw EDDGetParms ; 48h - EDD GET PARAMETERS 1023 dw EDDDetectChange ; 49h - EDD MEDIA CHANGE STATUS 1024%if ELTORITO ; EDD El Torito Functions 1025 ; ELTORITO _must_ also have EDD 1026 dw ElToritoEmulate ; 4Ah - Initiate Disk Emulation 1027 dw ElToritoTerminate ; 4Bh - Terminate Disk Emulation 1028 dw ElToritoBoot ; 4Ch - Initiate Disk Emu. and Reboot 1029 dw ElToritoCatalog ; 4Dh - Return Boot Catalog 1030%endif ; ELTORITO 1031%endif ; EDD 1032 1033Int13FuncsEnd equ $ 1034Int13FuncsCnt equ (Int13FuncsEnd-Int13Funcs) >> 1 1035 1036 1037 alignb 8, db 0 1038Shaker dw ShakerEnd-$-1 ; Descriptor table limit 1039 dd 0 ; Pointer to self 1040 dw 0 1041 1042Shaker_RMDS: dd 0x0000ffff ; 64K data segment 1043 dd 0x00009300 1044 1045Shaker_DS: dd 0x0000ffff ; 4GB data segment 1046 dd 0x008f9300 1047 1048ShakerEnd equ $ 1049 1050 alignb 8, db 0 1051 1052Mover dd 0, 0, 0, 0 ; Must be zero 1053 dw 0ffffh ; 64 K segment size 1054Mover_src1: db 0, 0, 0 ; Low 24 bits of source addy 1055 db 93h ; Access rights 1056 db 00h ; Extended access rights 1057Mover_src2: db 0 ; High 8 bits of source addy 1058 dw 0ffffh ; 64 K segment size 1059Mover_dst1: db 0, 0, 0 ; Low 24 bits of target addy 1060 db 93h ; Access rights 1061 db 00h ; Extended access rights 1062Mover_dst2: db 0 ; High 8 bits of source addy 1063Mover_dummy2: dd 0, 0, 0, 0 ; More space for the BIOS 1064 1065 alignb 16, db 0 1066mBFT: 1067; Fields common to all ACPI tables 1068 dd ' ' ; ACPI signature ("mBFT") 1069 ; This is filled-in by the installer 1070 ; to avoid an accidentally valid mBFT 1071 dd mBFT_Len ; ACPI table length 1072 db 1 ; ACPI revision 1073 db 0 ; ACPI table checksum 1074 db 'MEMDSK' ; ACPI OEM ID 1075 db 'Syslinux' ; ACPI OEM table ID 1076 dd 0 ; ACPI OEM revision 1077 dd 0 ; ACPI ASL compiler vendor ID 1078 dd 0 ; ACPI ASL compiler revision 1079; The next field is mBFT-specific and filled-in by the installer 1080 dd 0 ; "Safe hook" physical address 1081 1082; Note that the above ends on a DWORD boundary. 1083; The MDI has always started at such a boundary. 1084; Portions of the MDI are patched by the installer 1085MemDisk_Info equ $ ; Pointed to by installation check 1086MDI_Bytes dw MDI_Len ; Total bytes in MDI structure 1087MDI_Version db VERSION_MINOR, VERSION_MAJOR ; MEMDISK version 1088 1089DiskBuf dd 0 ; Linear address of high memory disk 1090DiskSize dd 0 ; Size of disk in blocks 1091CommandLine dw 0, 0 ; Far pointer to saved command line 1092 1093OldInt13 dd 0 ; INT 13h in chain 1094OldInt15 dd 0 ; INT 15h in chain 1095 1096OldDosMem dw 0 ; Old position of DOS mem end 1097BootLoaderID db 0 ; Boot loader ID from header 1098 db 0 ; pad 1099 1100DPT_ptr dw 0 ; If nonzero, pointer to DPT 1101 ; Original DPT pointer follows 1102 1103MDI_Len equ $-MemDisk_Info 1104mBFT_Len equ $-mBFT ; mBFT includes the MDI 1105 1106; ---- MDI structure ends here --- 1107DriveShiftLimit db 0ffh ; Installer will probe for 1108 ; a range of contiguous drives. 1109 ; Any BIOS drives above this region 1110 ; shall not be impacted by our 1111 ; shifting behaviour 1112 db 0 ; pad to a DWORD 1113 dw 0 ; pad to a QWORD 1114MemInt1588 dw 0 ; 1MB-65MB memory amount (1K) 1115 1116Cylinders dw 0 ; Cylinder count 1117Heads dw 0 ; Head count 1118Sectors dd 0 ; Sector count (zero-extended) 1119 1120Mem1MB dd 0 ; 1MB-16MB memory amount (1K) 1121Mem16MB dd 0 ; 16MB-4G memory amount (64K) 1122 1123DriveNo db 0 ; Our drive number 1124DriveType db 0 ; Our drive type (floppies) 1125DriveCnt db 0 ; Drive count (from the BIOS) 1126 1127ConfigFlags db 0 ; Bit 0 - readonly 1128 1129MyStack dw 0 ; Offset of stack 1130StatusPtr dw 0 ; Where to save status (zeroseg ptr) 1131 1132DPT times 16 db 0 ; BIOS parameter table pointer (floppies) 1133OldInt1E dd 0 ; Previous INT 1E pointer (DPT) 1134 1135%if EDD 1136EDD_DPT: 1137.length dw 30 1138.info dw 0029h 1139 ; Bit 0 - DMA boundaries handled transparently 1140 ; Bit 3 - Device supports write verify 1141 ; Bit 5 - Media is lockable 1142.cylinders dd 0 ; Filled in by installer 1143.heads dd 0 ; Filled in by installer 1144.sectors dd 0 ; Filled in by installer 1145.totalsize dd 0, 0 ; Filled in by installer 1146.bytespersec dw SECTORSIZE 1147.eddtable dw -1, -1 ; Invalid DPTE pointer 1148.dpikey dw 0BEDDh ; Device Path Info magic 1149.dpilen db 2ch ; DPI len 1150.res1 db 0 ; Reserved 1151.res2 dw 0 ; Reserved 1152.bustype dd 'MEM ' ; Host bus type (4 bytes, space padded) 1153.inttype dd 'MEMORY ' ; Interface type (8 bytes, spc. padded) 1154.intpath dd 0, 0 ; Interface path 1155.devpath dd 0, 0, 0, 0 ; Device path 1156.res3 db 0 ; Reserved 1157.chksum db 0 ; DPI checksum 1158 1159%if ELTORITO 1160; El Torito CD Specification Packet - mostly filled in by installer 1161CD_PKT: 1162.size db 13h ; Packet size (19 bytes) 1163.type db 0 ; Boot media type (flags) 1164.driveno db 0E0h ; INT 13h drive number 1165.controller db 0 ; Controller index 1166.start dd 0 ; Starting LBA of image 1167.devno dw 0 ; Device number 1168.user_buf dw 0 ; User buffer segment 1169.load_seg dw 0 ; Load segment 1170.sect_count dw 0 ; Emulated sectors to load 1171.geom1 db 0 ; Cylinders bits 0 thru 7 1172.geom2 db 0 ; Sects/track 0 thru 5, cyls 8, 9 1173.geom3 db 0 ; Heads 1174%endif ; ELTORITO 1175 1176%endif ; EDD 1177 1178; End patch area 1179 1180 alignb 4, db 0 1181Stack dd 0 ; Saved SS:ESP on invocation 1182 dw 0 1183SavedAX dw 0 ; AX saved on invocation 1184Recursive dw 0 ; Recursion counter 1185 1186 alignb 4, db 0 ; We *MUST* end on a dword boundary 1187 1188E820Table equ $ ; The installer loads the E820 table here 1189TotalSize equ $ ; End pointer 1190