diff options
| author | hpa <hpa> | 2001-12-09 06:01:51 +0000 |
|---|---|---|
| committer | hpa <hpa> | 2001-12-09 06:01:51 +0000 |
| commit | 4a19e6aff7dcc8ff4db9d0ef350a681404dff93a (patch) | |
| tree | fc50403855eaded1c31daa88ec24ee91ba37dd7d /memdisk/memdisk.asm | |
| parent | 37da809d9804562200305901864019763c88d13d (diff) | |
| download | syslinux-4a19e6aff7dcc8ff4db9d0ef350a681404dff93a.tar.gz | |
Reinstate memdisk.asm
Diffstat (limited to 'memdisk/memdisk.asm')
| -rw-r--r-- | memdisk/memdisk.asm | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/memdisk/memdisk.asm b/memdisk/memdisk.asm new file mode 100644 index 00000000..b175d711 --- /dev/null +++ b/memdisk/memdisk.asm @@ -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 |
