Reinstate memdisk.asm
authorhpa <hpa>
Sun, 9 Dec 2001 06:01:51 +0000 (06:01 +0000)
committerhpa <hpa>
Sun, 9 Dec 2001 06:01:51 +0000 (06:01 +0000)
memdisk/memdisk.asm [new file with mode: 0644]

diff --git a/memdisk/memdisk.asm b/memdisk/memdisk.asm
new file mode 100644 (file)
index 0000000..b175d71
--- /dev/null
@@ -0,0 +1,418 @@
+; -*- 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  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., 675 Mass Ave, Cambridge MA 02139,
+;  USA; either version 2 of the License, or (at your option) any later
+;  version; incorporated herein by reference.
+; 
+; ****************************************************************************
+
+               org 0h
+
+%define SECTORSIZE_LG2 9               ; log2(sector size)
+%define        SECTORSIZE      (1 << SECTORSIZE_LG2)
+
+MyStack                equ 1024
+
+               ; 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_AX            word [bp+28]
+%define                P_AL            byte [bp+28]
+%define                P_AH            byte [bp+29]
+%define                P_ECX           dword [bp+24]
+%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_DX            word [bp+20]
+%define                P_DL            byte [bp+20]
+%define                P_DH            byte [bp+21]
+%define                P_EBX           dword [bp+16]
+%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
+Int13Start:
+               ; See if DL points to our class of device (FD, HD)
+               push dx
+               xor dl,[cs:DriveNo]
+               pop dx
+               js .nomatch             ; If SF=0, we have a match here
+               cmp dl,[cs:DriveNo]
+               je .our_drive
+               jb .nomatch             ; Drive < Our drive
+               dec dl                  ; Drive > Our drive, adjust drive #
+.nomatch:
+               jmp far [OldInt13]
+
+.our_drive:
+               mov [cs:Stack],sp
+               mov [cs:SavedAX],ax
+               mov ax,ss
+               mov [cs:Stack+2],ax
+               mov ax,cs
+               mov ss,ax
+               mov sp,MyStack
+               push ds
+               push es
+               mov ds,ax
+               mov es,ax
+               mov ax,[SavedAX]
+               pushad
+               mov bp,sp
+               cmp ah,Int13FuncsMax
+               jae Invalid
+               xor al,al               ; AL = 0 is standard entry condition
+               mov di,ax
+               shr di,7
+               call [Int13Funcs+di]
+
+Done:          ; Standard routine for return
+               mov [LastStatus],ah
+               mov P_AX,ax
+               cmp ah,1
+DoneWeird:
+               setnb al                ; AL <- (AH > 0) ? 1 : 0 (CF)
+               lds bx,[Stack]          ; DS:BX <- Old stack pointer
+               mov [bx+4],al           ; Low byte of old FLAGS -> arithmetric flags
+               popad
+               pop es
+               pop ds
+               lss sp,[cs:Stack]
+               iret
+
+Reset:
+               ; Reset affects multiple drives, so we need to pass it on
+               pop ax                  ; Drop return address
+               mov [LastStatus], byte 0
+               popad
+               pop es
+               pop ds
+               lss sp,[cs:Stack]
+               and dl,80h              ; Clear all but the type bit
+               jmp far [OldInt13]
+
+Invalid:
+               mov ax,0100h            ; Unsupported function
+               ret
+
+GetDriveType:
+               pop ax                  ; Drop return address
+               mov ah,[DriveNo]
+               shr ah,7
+               or ah,02h               ; CF = 0
+               mov P_AH,ah
+               mov [LastStatus],byte 0 ; Success, but AH returns a value
+               jmp short DoneWeird
+
+GetStatus:
+               mov ah,[LastStatus]     ; Copy last status
+               ret
+
+CheckIfReady:                          ; These are always-successful noop functions
+Recalibrate:
+InitWithParms:
+DetectChange:
+success:
+               xor ax,ax               ; Always successful
+               ret
+
+Read:
+               call setup_regs
+do_copy:
+               call bcopy
+               movzx ax,P_AL           ; AH = 0, AL = transfer count
+               ret
+
+Write:
+               call setup_regs
+               xchg esi,edi
+               jmp short do_copy
+
+               ; These verify one sector only
+Seek:
+               mov P_AL,1
+
+               ; Verify integrity; just bounds-check
+Verify:
+               call setup_regs         ; Returns error if appropriate
+               jmp short success       
+
+GetParms:
+               ; We need to get the "number of drives" from the BIOS
+               mov dl,P_DL
+               inc dl                  ; The drive whose number we're stealing
+               mov ah,08h
+               int 13h
+               inc dl                  ; Add ourselves to the count
+               mov P_DL,dl             ; Drive count
+               mov P_DI,di             ; Steal the diskette parameter table if applicable
+               mov ax,es
+               mov P_ES,ax
+               mov bl,[DriveType]
+               mov P_BL,bl
+               mov ax,[Cylinders]
+               dec ax                  ; We report the highest #, not the count
+               or ah,[Sectors]
+               xchg al,ah
+               mov P_CX,ax
+               mov al,[Heads]
+               dec al
+               mov P_DH,al
+               xor ax,ax
+               ret
+
+               ; Convert a CHS address in CX/DH into an LBA in EAX
+chstolba:
+               xor ebx,ebx
+               mov bl,cl               ; Sector number
+               and bl,3Fh
+               dec bx
+               mov si,dx
+               mov ax,[Heads]
+               shr cl,6
+               xchg cl,ch              ; Now CX <- cylinder number
+               mul cx                  ; DX:AX <- AX*CX
+               shr si,8                ; SI <- head number
+               add ax,si
+               adc dx,byte 0
+               shl edx,16
+               or eax,edx
+               mul dword [Sectors]
+               add eax,ebx
+               ret
+
+               ; Set up registers as for a "Read", and compares against disk size
+setup_regs:
+               call chstolba
+               movzx edi,P_BX          ; Get linear address of target buffer
+               movzx ecx,P_ES
+               shr ecx,4
+               add edi,ecx
+               movzx ecx,P_AL
+               lea ebx,[eax+ecx]
+               mov esi,eax
+               shr esi,SECTORSIZE_LG2
+               add esi,[DiskBuf]
+               cmp ebx,[DiskSize]
+               jae .overrun
+               shr ecx,SECTORSIZE_LG2-1
+               ret
+
+.overrun:      pop ax                  ; Drop return address
+               mov ax,0400h            ; Sector not found
+               ret
+
+int15_e820:
+               cmp edx,534D4150h
+               jne near oldint15
+               cmp ecx,20              ; Need 20 bytes
+               jb err86
+               push edx                ; "SMAP"
+               push esi
+               push edi
+               and ebx,ebx
+               jne .renew
+               mov ebx,[E820Table]
+.renew:                mov esi,ebx
+               xor edi,edi
+               mov di,cs
+               shr di,4
+               add edi,E820Buf
+               mov ecx,24/2
+               call bcopy
+               add ebx, byte 12
+               pop edi
+               pop esi
+               mov eax,[cs:E820Buf]
+               mov [es:di],eax
+               mov eax,[cs:E820Buf+4]
+               mov [es:di+4],eax
+               mov eax,[cs:E820Buf+12]
+               mov [es:di+8],eax
+               mov eax,[cs:E820Buf+16]
+               mov [es:di+12],eax
+               mov eax,[cs:E820Buf+8]
+               mov [es:di+16],eax
+               cmp dword [cs:E820Buf+20], byte -1
+               jne .notdone
+               xor ebx,ebx             ; Done with table
+.notdone:
+               pop eax                 ; "SMAP"
+               mov ecx,20              ; Bytes loaded
+int15_success:
+               mov byte [bp+12], 02h   ; Clear CF
+               pop bp
+               iret
+
+err86:
+               mov byte [bp+12], 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:
+               mov ax,[cs:Mem1MB]
+               mov cx,ax
+               mov bx,[cs:Mem16MB]
+               mov dx,ax
+               jmp short int15_success
+
+int15_e881:
+               mov eax,[cs:Mem1MB]
+               mov ecx,eax
+               mov ebx,[cs:Mem16MB]
+               mov edx,eax
+               jmp short int15_success
+
+int15_88:
+               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 = 16-bit word count 
+;
+; Assumes cs = ds = es
+;
+bcopy:
+               push eax
+               push ebx
+               push edx
+               push ebp
+               push esi
+               push edi
+.copy_loop:
+               push ecx
+               cmp ecx,8000h
+               jna .safe_size
+               mov ecx,8000h
+.safe_size:
+               push ecx
+               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
+               int 15h
+               pop eax
+               pop ecx
+               pop edi
+               pop esi
+               jc .error
+               lea esi,[esi+2*eax]
+               lea edi,[edi+2*eax]
+               sub ecx, eax
+               jnz .copy_loop
+               ; CF = 0
+.error:
+               pop ebp
+               pop edx
+               pop ebx
+               pop eax
+               ret
+
+               section .data
+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
+Int13FuncsEnd  equ $
+Int13FuncsMax  equ (Int13FuncsEnd-Int13Funcs) >> 1
+
+DriveNo                db 0                    ; Our drive number
+DriveType      db 0                    ; Our drive type (floppies)
+LastStatus     db 0                    ; Last return status
+
+               alignb 4, db 0
+Cylinders      dw 0                    ; Cylinder count
+Heads          dw 0                    ; Head count
+Sectors                dd 0                    ; Sector count (zero-extended)
+DiskSize       dd 0                    ; Size of disk in blocks
+DiskBuf                dd 0                    ; Linear address of high memory disk
+
+E820Table      dd 0                    ; E820 table in high memory
+Mem1MB         dd 0                    ; 1MB-16MB memory amount (1K)
+Mem16MB                dd 0                    ; 16MB-4G memory amount (64K)
+MemInt1588     dw 0                    ; 1MB-65MB memory amount (1K)
+
+               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
+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
+
+               section .bss
+OldInt13       resd 1                  ; INT 13h in chain
+OldInt15       resd 1                  ; INT 15h in chain
+Stack          resd 1                  ; Saved SS:SP on invocation
+E820Buf                resd 6                  ; E820 fetch buffer
+SavedAX                resw 1                  ; AX saved during initialization