📄 memdisk.asm
字号:
; -*- fundamental -*- (asm-mode sucks); $Id$; ****************************************************************************;; memdisk.asm;; A program to emulate an INT 13h disk BIOS from a "disk" in extended; memory.;; Copyright (C) 2001-2005 H. Peter Anvin;; 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.; ; ****************************************************************************%ifndef DEPEND%include "../version.gen"%endif; %define DEBUG_TRACERS ; Uncomment to get debugging tracers%ifdef WITH_EDD%define EDD 1%else%define EDD 0%endif%ifdef DEBUG_TRACERS%macro TRACER 1 call debug_tracer db %1%endmacro%else ; DEBUG_TRACERS%macro TRACER 1%endmacro%endif ; DEBUG_TRACERS%define CONFIG_READONLY 0x01%define CONFIG_RAW 0x02%define CONFIG_BIGRAW 0x08 ; MUST be 8! org 0h%define SECTORSIZE_LG2 9 ; log2(sector size)%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 binaryPointers: dw Int13Start dw Int15Start dw PatchArea dw TotalSizeInt13Start: ; Swap stack mov [cs:Stack],esp mov [cs:SavedAX],ax mov ax,ss mov [cs:Stack+4],ax mov ax,cs mov ss,ax mov sp,[cs:MyStack] ; 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 jz .our_drive ; If ZF=1, we have an exact match cmp dl,[cs:DriveNo] jb .nomatch ; Drive < Our drive dec dl ; Drive > Our drive, adjust drive #.nomatch: mov ax,[cs:SavedAX] pushf call far [cs:OldInt13] pushf push bp mov bp,sp cmp byte [cs:SavedAX+1],08h je .norestoredl cmp byte [cs:SavedAX+1],15h jne .restoredl test byte [bp+4],80h ; Hard disk? jnz .norestoredl.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 ; Arithmetric flags pop ds pop ebx pop ax pop bp lss esp,[cs:Stack] iret.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' ; Note: AH == P_AH here cmp ah,Int13FuncsMax jae Invalid_jump 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,axDoneWeird: 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 arithmetric 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] iretReset: ; 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 far [cs:OldInt13]Invalid: pop dx ; Drop return addressInvalid_jump: TRACER 'I' mov ah,01h ; Unsupported function jmp short DoneGetDriveType: test byte [DriveNo],80h mov bl,02h ; Type 02h = floppy with changeline jz .floppy ; Hard disks only... 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_AXGetStatus: xor ax,ax mov es,ax mov bx,[StatusPtr] mov ah,[bx] ; Copy last status retReadMult: TRACER 'm'Read: TRACER 'R' call setup_regsdo_copy: TRACER '<' call bcopy TRACER '>' movzx ax,P_AL ; AH = 0, AL = transfer count retWriteMult: 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-checkSeek:Verify: call setup_regs ; Returns error if appropriate ; And fall through to successCheckIfReady: ; These are always-successful noop functionsRecalibrate:InitWithParms:DetectChange:SetMode:success: xor ax,ax ; Always successful retGetParms: 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 EDDEDDPresence: TRACER 'E' TRACER 'c' cmp P_BX,55AAh jne Invalid mov P_BX,0AA55h ; EDD signature mov P_AX,02100h ; EDD 1.1 mov P_CX,0001h ; Fixed disk access 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 retEDDWrite: TRACER 'E' TRACER 'w' call edd_setup_regs xchg esi,edi call bcopy xor ax,ax retEDDVerify:EDDSeek: call edd_setup_regs ; Just bounds checking xor ax,ax retEDDGetParms: TRACER 'E' TRACER 'p' mov es,P_DS mov di,P_SI mov cx,30 ; Length of our DPT cmp [es:di],cx jae .oksize mov cx,26 cmp [es:di],cx jb .overrun.oksize: mov [si],cx ; This should be done by the installer... mov eax,[DiskSize] mov [si+16],eax mov si,EDD_DPT 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 EDDedd_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 esi,word [es:si+4] ; Offset
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -