; -*- fundamental -*- (asm-mode sucks) ; **************************************************************************** ; ; memdisk.inc ; ; A program to emulate an INT 13h disk BIOS from a "disk" in extended ; memory. ; ; Copyright 2001-2009 H. Peter Anvin - All Rights Reserved ; Copyright 2009 Intel Corporation; author: H. Peter Anvin ; Portions copyright 2009 Shao Miller [El Torito code, mBFT, safe hook] ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation, Inc., 53 Temple Place Ste 330, ; Boston MA 02111-1307, USA; either version 2 of the License, or ; (at your option) any later version; incorporated herein by reference. ; ; **************************************************************************** %include "../version.gen" ; %define DEBUG_TRACERS ; Uncomment to get debugging tracers %ifdef DEBUG_TRACERS %macro TRACER 1 call debug_tracer db %1 %endmacro %macro WRITEHEX2 0-1 al %ifnidni %1,al push ax mov al,%1 call writehex2 pop ax %else call writehex2 %endif %endmacro %macro WRITEHEX4 0-1 ax %ifnidni %1,ax push ax mov ax,%1 call writehex4 pop ax %else call writehex4 %endif %endmacro %macro WRITEHEX8 0-1 eax %ifnidni %1,eax push eax mov eax,%1 call writehex8 pop eax %else call writehex8 %endif %endmacro %else ; DEBUG_TRACERS %macro TRACER 1 %endmacro %macro WRITEHEX2 0-1 %endmacro %macro WRITEHEX4 0-1 %endmacro %macro WRITEHEX8 0-1 %endmacro %endif ; DEBUG_TRACERS ; Flags we test our configuration against %define CONFIG_READONLY 0x01 %define CONFIG_RAW 0x02 %define CONFIG_SAFEINT 0x04 %define CONFIG_BIGRAW 0x08 ; MUST be 8! org 0h %define SECTORSIZE (1 << SECTORSIZE_LG2) ; Parameter registers definition; this is the definition ; of the stack frame. %define P_DS word [bp+34] %define P_ES word [bp+32] %define P_EAX dword [bp+28] %define P_HAX word [bp+30] %define P_AX word [bp+28] %define P_AL byte [bp+28] %define P_AH byte [bp+29] %define P_ECX dword [bp+24] %define P_HCX word [bp+26] %define P_CX word [bp+24] %define P_CL byte [bp+24] %define P_CH byte [bp+25] %define P_EDX dword [bp+20] %define P_HDX word [bp+22] %define P_DX word [bp+20] %define P_DL byte [bp+20] %define P_DH byte [bp+21] %define P_EBX dword [bp+16] %define P_HBX word [bp+18] %define P_HBXL byte [bp+18] %define P_BX word [bp+16] %define P_BL byte [bp+16] %define P_BH byte [bp+17] %define P_EBP dword [bp+8] %define P_BP word [bp+8] %define P_ESI dword [bp+4] %define P_SI word [bp+4] %define P_EDI dword [bp] %define P_DI word [bp] section .text ; These pointers are used by the installer and ; must be first in the binary Pointers: dw Int13Start dw Int15Start dw MemDisk_Info ; Portions are patched by installer dw TotalSize dw IretPtr IretPtr equ Int13Start.iret Int13Start: jmp strict near .SafeHookEnd ; 3-byte jump db '$INT13SF' ; Signature for "safe hook" db 'MEMDISK ' ; Vendor ID dd 0 ; SEG:OFF of previous INT 13h hook ; Must be filled in by installer dd 0 ; "Safe hook" flags ; ---- "Safe hook" structure ends here --- ; This next field should be guaranteed at this position after the ; "safe hook" structure. This allows for a MEMDISK OS driver to ; immediately find out the particular parameters using the mBFT ; and MDI structures. This binary will have the offset to the mBFT ; in this field to begin with, so the installer knows where the mBFT ; is. This is akin to the "Pointers" section above. The installer ; will refill this field with the physical address of the mBFT for ; future consumers, such as OS drivers. dd mBFT ; Offset from hook to the mBFT .SafeHookEnd: cmp word [cs:Recursive],0 jne recursive ; Swap stack mov [cs:Stack],esp mov [cs:Stack+4],ss mov [cs:SavedAX],ax mov ax,cs mov ss,ax mov sp,[cs:MyStack] %if ELTORITO cmp word [cs:SavedAX],4a00h ; El Torito function? jae our_drive ; We grab it %endif ; See if DL points to our class of device (FD, HD) push dx push dx xor dl,[cs:DriveNo] pop dx js .nomatch ; If SF=0, we have a class match here ; 0x00 the sign bit for FD ; 0x80 the sign bit for HD jz our_drive ; If ZF=1, we have an exact match cmp dl,[cs:DriveNo] jb .nomatch ; Drive < Our drive cmp dl,[cs:DriveShiftLimit] jae .nomatch ; Drive > The maximum drive ; number that we will shift for. ; This leaves any higher-up BIOS ; drives alone, such as an optical ; disc drive 0xA0 or 0xE0 dec dl ; Drive > Our drive, adjust drive # .nomatch: TRACER '!' WRITEHEX2 dl TRACER ',' mov ax,[cs:SavedAX] WRITEHEX4 inc word [cs:Recursive] pushf call far [cs:OldInt13] pushf dec word [cs:Recursive] push bp mov bp,sp cmp byte [cs:SavedAX+1],08h ; Get drive params function? je .norestoredl ; DL = number of drives cmp byte [cs:SavedAX+1],15h ; Get disk type function? jne .restoredl test byte [bp+4],80h ; Hard disk? jnz .norestoredl ; CX:DX = size of device .restoredl: mov dl,[bp+4] .norestoredl: push ax push ebx push ds mov ax,[bp+2] ; Flags lds ebx,[cs:Stack] mov [bx+4],al ; Arithmetic flags pop ds pop ebx pop ax pop bp lss esp,[cs:Stack] .iret: iret recursive: TRACER '@' jmp_oldint13: jmp far [cs:OldInt13] our_drive: ; Set up standard entry frame push ds push es mov ds,ax mov es,ax mov ax,[SavedAX] pushad mov bp,sp ; Point BP to the entry stack frame TRACER 'F' WRITEHEX4 ; Note: AX == P_AX here cmp ah,Int13FuncsCnt-1 ja Invalid_jump %if ELTORITO mov al,[CD_PKT.type] ; Check if we are in cmp al,0 ; El Torito no emulation mode ja .emulation ; No. We support the function cmp ah,3fh ; Yes. We must not support functions jbe Invalid_jump ; 0 through 3Fh. Check and decide .emulation: %endif xor al,al ; AL = 0 is standard entry condition mov di,ax shr di,7 ; Convert AH to an offset in DI call [Int13Funcs+di] Done: ; Standard routine for return mov P_AX,ax DoneWeird: TRACER 'D' xor bx,bx mov es,bx mov bx,[StatusPtr] mov [es:bx],ah ; Save status and ah,ah lds ebx,[Stack] ; This sets the low byte (the arithmetic flags) of the ; FLAGS on stack to either 00h (no flags) or 01h (CF) ; depending on if AH was zero or not. setnz [bx+4] ; Set CF iff error popad pop es pop ds lss esp,[cs:Stack] iret Reset: ; Reset affects multiple drives, so we need to pass it on TRACER 'R' xor ax,ax ; Bottom of memory mov es,ax test dl,dl ; Always pass it on if we are ; resetting HD js .hard_disk ; Bit 7 set ; Some BIOSes get very unhappy if we pass a reset floppy ; command to them and don't actually have any floppies. ; This is a bug, but we have to deal with it nontheless. ; Therefore, if we are the *ONLY* floppy drive, and the ; user didn't request HD reset, then just drop the command. ; BIOS equipment byte, top two bits + 1 == total # of floppies test byte [es:0x410],0C0h jz success jmp .pass_on ; ... otherwise pass it to the BIOS .hard_disk: ; ... same thing for hard disks, sigh ... cmp byte [es:0x475],1 ; BIOS variable for number of hard ; disks jbe success .pass_on: pop ax ; Drop return address popad ; Restore all registers pop es pop ds lss esp,[cs:Stack] ; Restore the stack and dl,80h ; Clear all but the type bit jmp jmp_oldint13 Invalid: pop dx ; Drop return address Invalid_jump: TRACER 'I' mov ah,01h ; Unsupported function jmp short Done GetDriveType: test byte [DriveNo],80h mov bl,02h ; Type 02h = floppy with changeline jz .floppy ; Hard disks only! DO NOT set CX:DX for floppies... ; it apparently causes Win98SE DOS to go into an loop ; resetting the drive over and over. Sigh. inc bx ; Type = 03h mov dx,[DiskSize] ; Return the disk size in sectors mov P_DX,dx mov cx,[DiskSize+2] mov P_CX,cx .floppy: mov P_AH,bl ; 02h floppy, 03h hard disk pop ax ; Drop return address xor ax,ax ; Success... jmp DoneWeird ; But don't stick it into P_AX GetStatus: xor ax,ax mov es,ax mov bx,[StatusPtr] mov ah,[bx] ; Copy last status ret ReadMult: TRACER 'm' Read: TRACER 'R' call setup_regs do_copy: TRACER '<' call bcopy TRACER '>' movzx ax,P_AL ; AH = 0, AL = transfer count ret WriteMult: TRACER 'M' Write: TRACER 'W' test byte [ConfigFlags],CONFIG_READONLY jnz .readonly call setup_regs xchg esi,edi ; Opposite direction of a Read! jmp short do_copy .readonly: mov ah,03h ; Write protected medium ret ; Verify integrity; just bounds-check Seek: Verify: call setup_regs ; Returns error if appropriate ; And fall through to success CheckIfReady: ; These are always-successful noop functions Recalibrate: InitWithParms: DetectChange: EDDDetectChange: EDDLock: SetMode: success: xor ax,ax ; Always successful ret GetParms: TRACER 'G' mov dl,[DriveCnt] ; Cached data mov P_DL,dl test byte [DriveNo],80h jnz .hd mov P_DI,DPT mov P_ES,cs mov bl,[DriveType] mov P_BL,bl .hd: mov ax,[Cylinders] dec ax ; We report the highest #, not the count xchg al,ah shl al,6 or al,[Sectors] mov P_CX,ax mov ax,[Heads] dec ax mov P_DH,al ; ; Is this MEMDISK installation check? ; cmp P_HAX,'ME' jne .notic cmp P_HCX,'MD' jne .notic cmp P_HDX,'IS' jne .notic cmp P_HBX,'K?' jne .notic ; MEMDISK installation check... mov P_HAX,'!M' mov P_HCX,'EM' mov P_HDX,'DI' mov P_HBX,'SK' mov P_ES,cs mov P_DI,MemDisk_Info .notic: xor ax,ax ret ; ; EDD functions -- only if enabled ; %if EDD EDDPresence: TRACER 'E' TRACER 'c' cmp P_BX,55AAh jne Invalid mov P_BX,0AA55h ; EDD signature mov P_AX,03000h ; EDD 3.0 mov P_CX,0007h ; Bit 0 - Fixed disk access subset ; Bit 1 - Locking and ejecting subset ; Bit 2 - EDD subset pop ax ; Drop return address xor ax,ax ; Success jmp DoneWeird ; Success, but AH != 0, sigh... EDDRead: TRACER 'E' TRACER 'r' call edd_setup_regs call bcopy xor ax,ax ret EDDWrite: TRACER 'E' TRACER 'w' call edd_setup_regs xchg esi,edi ; Opposite direction of a Read! call bcopy xor ax,ax ret EDDVerify: EDDSeek: call edd_setup_regs ; Just bounds checking xor ax,ax ret EDDGetParms: TRACER 'E' TRACER 'p' mov es,P_DS mov di,P_SI mov si,EDD_DPT lodsw ; Length of our DPT mov cx,[es:di] cmp cx,26 ; Minimum size jb .overrun cmp cx,ax jb .oksize mov cx,ax .oksize: mov ax,cx stosw dec cx dec cx rep movsb xor ax,ax ret .overrun: mov ax,0100h ret %endif ; EDD ; Set up registers as for a "Read", and compares against disk ; size. ; WARNING: This fails immediately, even if we can transfer some ; sectors. This isn't really the correct behaviour. setup_regs: ; Convert a CHS address in P_CX/P_DH into an LBA in eax ; CH = cyl[7:0] ; CL[0:5] = sector (1-based) CL[7:6] = cyl[9:8] ; DH = head movzx ecx,P_CX movzx ebx,cl ; Sector number and bl,3Fh dec ebx ; Sector number is 1-based cmp bx,[Sectors] jae .overrun movzx edi,P_DH ; Head number movzx eax,word [Heads] cmp di,ax jae .overrun shr cl,6 xchg cl,ch ; Now (E)CX <- cylinder number mul ecx ; eax <- Heads*cyl# (edx <- 0) add eax,edi mul dword [Sectors] add eax,ebx ; Now eax = LBA, edx = 0 ; ; setup_regs continues... ; ; Note: edi[31:16] and ecx[31:16] = 0 already mov di,P_BX ; Get linear address of target buffer mov cx,P_ES shl ecx,4 add edi,ecx ; EDI = address to fetch to movzx ecx,P_AL ; Sector count mov esi,eax add eax,ecx ; LBA of final sector + 1 shl esi,SECTORSIZE_LG2 ; LBA -> byte offset add esi,[DiskBuf] ; Get address in high memory cmp eax,[DiskSize] ; Check the high mark against limit ja .overrun shl ecx,SECTORSIZE_LG2-2 ; Convert count to dwords ret .overrun: pop ax ; Drop setup_regs return address mov ax,0200h ; Missing address mark ret ; Return to Done ; Set up registers as for an EDD Read, and compares against disk size. %if EDD edd_setup_regs: push es mov si,P_SI ; DS:SI -> DAPA mov es,P_DS mov dx,[es:si] cmp dx,16 jb .baddapa cmp dword [es:si+4],-1 je .linear_address movzx ebx,word [es:si+4] ; Offset movzx edi,word [es:si+6] ; Segment shl edi,4 add ebx,edi jmp .got_address .linear_address: cmp dx,24 ; Must be large enough to hold ; linear address jb .baddapa cmp dword [es:si+20],0 ; > 4 GB addresses not supported mov ax,0900h ; "Data boundary error" - bogus, but ; no really better code available jne .error mov ebx,[es:si+16] .got_address: cmp dword [es:si+12],0 ; LBA too large? jne .overrun movzx ecx, word [es:si+2] ; Sectors to transfer mov esi,[es:si+8] ; Starting sector mov eax,esi add eax,ecx jc .overrun cmp eax,[DiskSize] ja .overrun shl ecx,SECTORSIZE_LG2-2 ; Convert to dwords shl esi,SECTORSIZE_LG2 ; Convert to an offset add esi,[DiskBuf] mov edi,ebx pop es ret .baddapa: mov ax,0100h ; Invalid command pop es pop ax ; Drop setup_regs return address ret .overrun: mov ax,0200h ; "Address mark not found" = ; LBA beyond end of disk .error: and word [es:si+2],0 ; No sectors transferred pop es pop ax ret EDDEject: mov ax,0B200h ; Volume Not Removable ret %if ELTORITO ElToritoTerminate: TRACER 'T' mov ax,[cs:SavedAX] cmp al,1 ; We only support query, not terminate jne ElToritoErr ; Fail cmp dl,7fh ; Terminate all? je .doit cmp dl,[cs:DriveNo] ; Terminate our drive? je .doit jmp ElToritoErr ; Fail .doit: mov es,P_DS ; Caller's DS:SI pointed to packet mov di,P_SI ; We'll use ES:DI mov si,CD_PKT.size ; First byte is packet size xor cx,0 ; Empty our count ;mov cl,[ds:si] ; We'll copy that many bytes mov cl,13h rep movsb ; Copy until CX is zero mov ax,0 ; Success ret ElToritoEmulate: ElToritoBoot: ElToritoCatalog: ElToritoErr: TRACER '!' mov ax,100h ; Invalid parameter ret %endif ; ELTORITO %endif ; EDD ; ; INT 15h intercept routines ; int15_e820: cmp edx,534D4150h ; "SMAP" jne oldint15 cmp ecx,20 ; Need 20 bytes jb err86 push ds push cs pop ds push edx ; "SMAP" and ebx,ebx jne .renew mov ebx,E820Table .renew: add bx,12 ; Advance to next mov eax,[bx-4] ; Type and eax,eax ; Null type? jz .renew ; If so advance to next mov [es:di+16],eax mov eax,[bx-12] ; Start addr (low) mov edx,[bx-8] ; Start addr (high) mov [es:di],eax mov [es:di+4],edx mov eax,[bx] ; End addr (low) mov edx,[bx+4] ; End addr (high) sub eax,[bx-12] ; Derive the length sbb edx,[bx-8] mov [es:di+8],eax ; Length (low) mov [es:di+12],edx ; Length (high) cmp dword [bx+8],-1 ; Type of next = end? jne .notdone xor ebx,ebx ; Done with table .notdone: pop eax ; "SMAP" mov edx,eax ; Some systems expect eax = edx = SMAP mov ecx,20 ; Bytes loaded pop ds int15_success: mov byte [bp+6], 02h ; Clear CF pop bp iret err86: mov byte [bp+6], 03h ; Set CF mov ah,86h pop bp iret Int15Start: push bp mov bp,sp cmp ax,0E820h je near int15_e820 cmp ax,0E801h je int15_e801 cmp ax,0E881h je int15_e881 cmp ah,88h je int15_88 oldint15: pop bp jmp far [cs:OldInt15] int15_e801: ; Get mem size for > 64 MB config mov ax,[cs:Mem1MB] mov cx,ax mov bx,[cs:Mem16MB] mov dx,bx jmp short int15_success int15_e881: ; Get mem size for > 64 MB config ; 32-bit code mov eax,[cs:Mem1MB] mov ecx,eax mov ebx,[cs:Mem16MB] mov edx,ebx jmp short int15_success int15_88: ; Get extended mem size mov ax,[cs:MemInt1588] jmp short int15_success ; ; Routine to copy in/out of high memory ; esi = linear source address ; edi = linear target address ; ecx = 32-bit word count ; ; Assumes cs = ds = es ; bcopy: push eax push ebx push edx push ebp mov bx, real_int15_stub test byte [ConfigFlags], CONFIG_RAW|CONFIG_SAFEINT jz .anymode ; Always do the real INT 15h smsw ax ; Unprivileged! test al,01h jnz .protmode ; Protmode -> do real INT 15h .realmode: ; Raw or Safeint mode, and we're in real mode... test byte [ConfigFlags], CONFIG_SAFEINT jnz .fakeint15 .raw: TRACER 'r' ; We're in real mode, do it outselves pushfd ; push ds ; push es ; cli cld xor ebx,ebx mov bx,cs shl ebx,4 lea edx,[Shaker+ebx] mov [Shaker+2],edx ; Test to see if A20 is enabled or not xor ax,ax mov ds,ax dec ax mov es,ax mov ax,[0] mov bx,ax xor bx,[es:10h] not ax mov [0],ax mov dx,ax xor dx,[es:10h] not ax mov [0],ax or dx,bx push dx ; Save A20 status jnz .skip_a20e mov ax,2401h ; Enable A20 int 15h .skip_a20e: mov dl,[ConfigFlags] and dx,CONFIG_BIGRAW add dx,8 ; DX = 16 for BIGRAW, 8 for RAW ; 8 is selector for a 64K flat segment, ; 16 is selector for a 4GB flat segment. lgdt [cs:Shaker] mov eax,cr0 or al,01h mov cr0,eax mov bx,16 ; Large flat segment mov ds,bx mov es,bx a32 rep movsd ; DX has the appropriate value to put in ; the registers on return mov ds,dx mov es,dx and al,~01h mov cr0,eax pop dx ; A20 status pop es ; pop ds ; and dx,dx jnz .skip_a20d mov ax,2400h ; Disable A20 int 15h .skip_a20d: popfd ; jmp .done .fakeint15: ; We're in real mode with CONFIG_SAFEINT, invoke the ; original INT 15h vector. We used to test for the ; INT 15h vector being unchanged here, but that is ; *us*; however, the test was wrong for years (always ; negative) so instead of fixing the test do what we ; tested and don't bother probing. mov bx, fake_int15_stub .protmode: TRACER 'p' .anymode: .copy_loop: push esi push edi push ecx cmp ecx,4000h jna .safe_size mov ecx,4000h .safe_size: push ecx ; Transfer size this cycle mov eax, esi mov [Mover_src1], si shr eax, 16 mov [Mover_src1+2], al mov [Mover_src2], ah mov eax, edi mov [Mover_dst1], di shr eax, 16 mov [Mover_dst1+2], al mov [Mover_dst2], ah mov si,Mover mov ah, 87h shl cx,1 ; Convert to 16-bit words call bx ; INT 15h stub pop eax ; Transfer size this cycle pop ecx pop edi pop esi jc .error lea esi,[esi+4*eax] lea edi,[edi+4*eax] sub ecx, eax jnz .copy_loop ; CF = 0 .error: .done: pop ebp pop edx pop ebx pop eax ret real_int15_stub: int 15h cli ; Some BIOSes enable interrupts on INT 15h ret fake_int15_stub: pushf call far [OldInt15] cli ret %ifdef DEBUG_TRACERS debug_tracer: pushad pushfd mov bp,sp mov bx,[bp+9*4] mov al,[cs:bx] inc word [bp+9*4] mov ah,0Eh mov bx,7 int 10h popfd popad ret writehex2: pushad pushfd mov cx,2 ror eax,4 jmp writehex_common writehex4: pushad pushfd mov cx,4 ror eax,12 jmp writehex_common writehex8: pushad pushfd mov cx,8 ror eax,28 writehex_common: .loop: push cx push eax and al,0Fh cmp al,10 jb .isdec add al,'a'-'0'-10 .isdec: add al,'0' mov ah,0Eh mov bx,7 int 10h pop eax rol eax,4 pop cx loop .loop popfd popad ret %endif section .data align=16 alignb 2 Int13Funcs dw Reset ; 00h - RESET dw GetStatus ; 01h - GET STATUS dw Read ; 02h - READ dw Write ; 03h - WRITE dw Verify ; 04h - VERIFY dw Invalid ; 05h - FORMAT TRACK dw Invalid ; 06h - FORMAT TRACK AND SET BAD FLAGS dw Invalid ; 07h - FORMAT DRIVE AT TRACK dw GetParms ; 08h - GET PARAMETERS dw InitWithParms ; 09h - INITIALIZE CONTROLLER WITH ; DRIVE PARAMETERS dw Invalid ; 0Ah dw Invalid ; 0Bh dw Seek ; 0Ch - SEEK TO CYLINDER dw Reset ; 0Dh - RESET HARD DISKS dw Invalid ; 0Eh dw Invalid ; 0Fh dw CheckIfReady ; 10h - CHECK IF READY dw Recalibrate ; 11h - RECALIBRATE dw Invalid ; 12h dw Invalid ; 13h dw Invalid ; 14h dw GetDriveType ; 15h - GET DRIVE TYPE dw DetectChange ; 16h - DETECT DRIVE CHANGE %if EDD dw Invalid ; 17h dw Invalid ; 18h dw Invalid ; 19h dw Invalid ; 1Ah dw Invalid ; 1Bh dw Invalid ; 1Ch dw Invalid ; 1Dh dw Invalid ; 1Eh dw Invalid ; 1Fh dw Invalid ; 20h dw ReadMult ; 21h - READ MULTIPLE dw WriteMult ; 22h - WRITE MULTIPLE dw SetMode ; 23h - SET CONTROLLER FEATURES dw SetMode ; 24h - SET MULTIPLE MODE dw Invalid ; 25h - IDENTIFY DRIVE dw Invalid ; 26h dw Invalid ; 27h dw Invalid ; 28h dw Invalid ; 29h dw Invalid ; 2Ah dw Invalid ; 2Bh dw Invalid ; 2Ch dw Invalid ; 2Dh dw Invalid ; 2Eh dw Invalid ; 2Fh dw Invalid ; 30h dw Invalid ; 31h dw Invalid ; 32h dw Invalid ; 33h dw Invalid ; 34h dw Invalid ; 35h dw Invalid ; 36h dw Invalid ; 37h dw Invalid ; 38h dw Invalid ; 39h dw Invalid ; 3Ah dw Invalid ; 3Bh dw Invalid ; 3Ch dw Invalid ; 3Dh dw Invalid ; 3Eh dw Invalid ; 3Fh dw Invalid ; 40h dw EDDPresence ; 41h - EDD PRESENCE DETECT dw EDDRead ; 42h - EDD READ dw EDDWrite ; 43h - EDD WRITE dw EDDVerify ; 44h - EDD VERIFY dw EDDLock ; 45h - EDD LOCK/UNLOCK MEDIA dw EDDEject ; 46h - EDD EJECT dw EDDSeek ; 47h - EDD SEEK dw EDDGetParms ; 48h - EDD GET PARAMETERS dw EDDDetectChange ; 49h - EDD MEDIA CHANGE STATUS %if ELTORITO ; EDD El Torito Functions ; ELTORITO _must_ also have EDD dw ElToritoEmulate ; 4Ah - Initiate Disk Emulation dw ElToritoTerminate ; 4Bh - Terminate Disk Emulation dw ElToritoBoot ; 4Ch - Initiate Disk Emu. and Reboot dw ElToritoCatalog ; 4Dh - Return Boot Catalog %endif ; ELTORITO %endif ; EDD Int13FuncsEnd equ $ Int13FuncsCnt equ (Int13FuncsEnd-Int13Funcs) >> 1 alignb 8, db 0 Shaker dw ShakerEnd-$-1 ; Descriptor table limit dd 0 ; Pointer to self dw 0 Shaker_RMDS: dd 0x0000ffff ; 64K data segment dd 0x00009300 Shaker_DS: dd 0x0000ffff ; 4GB data segment dd 0x008f9300 ShakerEnd equ $ alignb 8, db 0 Mover dd 0, 0, 0, 0 ; Must be zero dw 0ffffh ; 64 K segment size Mover_src1: db 0, 0, 0 ; Low 24 bits of source addy db 93h ; Access rights db 00h ; Extended access rights Mover_src2: db 0 ; High 8 bits of source addy dw 0ffffh ; 64 K segment size Mover_dst1: db 0, 0, 0 ; Low 24 bits of target addy db 93h ; Access rights db 00h ; Extended access rights Mover_dst2: db 0 ; High 8 bits of source addy Mover_dummy2: dd 0, 0, 0, 0 ; More space for the BIOS alignb 16, db 0 mBFT: ; Fields common to all ACPI tables dd ' ' ; ACPI signature ("mBFT") ; This is filled-in by the installer ; to avoid an accidentally valid mBFT dd mBFT_Len ; ACPI table length db 1 ; ACPI revision db 0 ; ACPI table checksum db 'MEMDSK' ; ACPI OEM ID db 'Syslinux' ; ACPI OEM table ID dd 0 ; ACPI OEM revision dd 0 ; ACPI ASL compiler vendor ID dd 0 ; ACPI ASL compiler revision ; The next field is mBFT-specific and filled-in by the installer dd 0 ; "Safe hook" physical address ; Note that the above ends on a DWORD boundary. ; The MDI has always started at such a boundary. ; Portions of the MDI are patched by the installer MemDisk_Info equ $ ; Pointed to by installation check MDI_Bytes dw MDI_Len ; Total bytes in MDI structure MDI_Version db VERSION_MINOR, VERSION_MAJOR ; MEMDISK version DiskBuf dd 0 ; Linear address of high memory disk DiskSize dd 0 ; Size of disk in blocks CommandLine dw 0, 0 ; Far pointer to saved command line OldInt13 dd 0 ; INT 13h in chain OldInt15 dd 0 ; INT 15h in chain OldDosMem dw 0 ; Old position of DOS mem end BootLoaderID db 0 ; Boot loader ID from header db 0 ; pad DPT_ptr dw 0 ; If nonzero, pointer to DPT ; Original DPT pointer follows MDI_Len equ $-MemDisk_Info mBFT_Len equ $-mBFT ; mBFT includes the MDI ; ---- MDI structure ends here --- DriveShiftLimit db 0ffh ; Installer will probe for ; a range of contiguous drives. ; Any BIOS drives above this region ; shall not be impacted by our ; shifting behaviour db 0 ; pad to a DWORD dw 0 ; pad to a QWORD MemInt1588 dw 0 ; 1MB-65MB memory amount (1K) Cylinders dw 0 ; Cylinder count Heads dw 0 ; Head count Sectors dd 0 ; Sector count (zero-extended) Mem1MB dd 0 ; 1MB-16MB memory amount (1K) Mem16MB dd 0 ; 16MB-4G memory amount (64K) DriveNo db 0 ; Our drive number DriveType db 0 ; Our drive type (floppies) DriveCnt db 0 ; Drive count (from the BIOS) ConfigFlags db 0 ; Bit 0 - readonly MyStack dw 0 ; Offset of stack StatusPtr dw 0 ; Where to save status (zeroseg ptr) DPT times 16 db 0 ; BIOS parameter table pointer (floppies) OldInt1E dd 0 ; Previous INT 1E pointer (DPT) %if EDD EDD_DPT: .length dw 30 .info dw 0029h ; Bit 0 - DMA boundaries handled transparently ; Bit 3 - Device supports write verify ; Bit 5 - Media is lockable .cylinders dd 0 ; Filled in by installer .heads dd 0 ; Filled in by installer .sectors dd 0 ; Filled in by installer .totalsize dd 0, 0 ; Filled in by installer .bytespersec dw SECTORSIZE .eddtable dw -1, -1 ; Invalid DPTE pointer .dpikey dw 0BEDDh ; Device Path Info magic .dpilen db 2ch ; DPI len .res1 db 0 ; Reserved .res2 dw 0 ; Reserved .bustype dd 'MEM ' ; Host bus type (4 bytes, space padded) .inttype dd 'MEMORY ' ; Interface type (8 bytes, spc. padded) .intpath dd 0, 0 ; Interface path .devpath dd 0, 0, 0, 0 ; Device path .res3 db 0 ; Reserved .chksum db 0 ; DPI checksum %if ELTORITO ; El Torito CD Specification Packet - mostly filled in by installer CD_PKT: .size db 13h ; Packet size (19 bytes) .type db 0 ; Boot media type (flags) .driveno db 0E0h ; INT 13h drive number .controller db 0 ; Controller index .start dd 0 ; Starting LBA of image .devno dw 0 ; Device number .user_buf dw 0 ; User buffer segment .load_seg dw 0 ; Load segment .sect_count dw 0 ; Emulated sectors to load .geom1 db 0 ; Cylinders bits 0 thru 7 .geom2 db 0 ; Sects/track 0 thru 5, cyls 8, 9 .geom3 db 0 ; Heads %endif ; ELTORITO %endif ; EDD ; End patch area alignb 4, db 0 Stack dd 0 ; Saved SS:ESP on invocation dw 0 SavedAX dw 0 ; AX saved on invocation Recursive dw 0 ; Recursion counter alignb 4, db 0 ; We *MUST* end on a dword boundary E820Table equ $ ; The installer loads the E820 table here TotalSize equ $ ; End pointer