[syslinux] [PATCH] memdisk varieties: Allow for multiple memdisk installable hooks

Miller, Shao Shao.Miller at yrdsb.edu.on.ca
Sun Mar 8 21:05:13 PDT 2009


>From c8d7f14a939c2abb7165eafa57521ae29fabe327 Mon Sep 17 00:00:00 2001
From: Shao Miller <shao.miller at yrdsb.edu.on.ca>
Date: Sun, 8 Mar 2009 23:54:43 -0400
Subject: [PATCH] memdisk varieties: Allow for multiple memdisk installable hooks

This patch "sets the stage" for the memdisk kernel to include different
"installables": versions of the memdisk hooks.

This patch splits the case of the EDD-compiled hook from the non-EDD-compiled
hook.  Both are available inside the kernel, and the kernel chooses which one
to install based on the command-line.

It's possible that other, slightly modified versions of the memdisk hook could
be useful to have...
---
 memdisk/Makefile        |    9 +-
 memdisk/memdisk.asm     |  988 +----------------------------------------------
 memdisk/memdisk.inc     |  987 ++++++++++++++++++++++++++++++++++++++++++++++
 memdisk/memdisk_edd.asm |    2 +
 memdisk/setup.c         |   28 +-
 5 files changed, 1014 insertions(+), 1000 deletions(-)
 create mode 100644 memdisk/memdisk.inc
 create mode 100644 memdisk/memdisk_edd.asm

diff --git a/memdisk/Makefile b/memdisk/Makefile
index 3776731..b8cb91a 100644
--- a/memdisk/Makefile
+++ b/memdisk/Makefile
@@ -20,7 +20,7 @@ LDFLAGS  = $(GCCOPT) -g
 INCLUDE  = -I$(topdir)/com32/include
 NASM     = nasm
 NASMOPT  = -O9999
-NFLAGS   = -dDATE='"$(DATE)"' -dWITH_EDD
+NFLAGS   = -dDATE='"$(DATE)"'
 NINCLUDE =
 
 SRCS	 = $(wildcard *.asm *.c *.h)
@@ -38,11 +38,11 @@ endif
 # Important: init.o16 must be first!!
 OBJS16   = init.o16 init32.o
 OBJS32   = start32.o setup.o msetup.o e820func.o conio.o memcpy.o memset.o \
-           unzip.o memdisk.o
+           unzip.o memdisk.o memdisk_edd.o
 
 CSRC     = setup.c msetup.c e820func.c conio.c unzip.c
 SSRC     = start32.S memcpy.S memset.S
-NASMSRC  = memdisk.asm memdisk16.asm
+NASMSRC  = memdisk.asm memdisk_edd.asm memdisk16.asm
 
 all: memdisk # e820test
 
@@ -110,6 +110,9 @@ e820test: e820test.c e820func.c msetup.c
 memdisk.o: memdisk.bin
 	$(LD) -r -b binary -o $@ $<
 
+memdisk_edd.o: memdisk_edd.bin
+	$(LD) -r -b binary -o $@ $<
+
 .depend:
 	rm -f .depend
 	for csrc in *.c ; do $(CC) $(INCLUDE) $(CFLAGS) -MM $$csrc >> .depend ; done
diff --git a/memdisk/memdisk.asm b/memdisk/memdisk.asm
index 0d48961..daa5c0a 100644
--- a/memdisk/memdisk.asm
+++ b/memdisk/memdisk.asm
@@ -1,987 +1 @@
-; -*- fundamental -*- (asm-mode sucks)
-; ****************************************************************************
-;
-;  memdisk.asm
-;
-;  A program to emulate an INT 13h disk BIOS from a "disk" in extended
-;  memory.
-;
-;   Copyright 2001-2008 H. Peter Anvin - All Rights Reserved
-;
-;  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_SAFEINT	0x04
-%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 binary
-Pointers:	dw Int13Start
-		dw Int15Start
-		dw PatchArea
-		dw TotalSize
-		dw IretPtr
-
-IretPtr		equ Int13Start.iret
-Int13Start:
-		; 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:		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,[Int13MaxFunc]
-		ja 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,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 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]
-		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 far [cs: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...
-		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,0003h		; Bit 0 - Fixed disk access subset
-					; Bit 1 - Locking and ejecting 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
-		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
-
-%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,16		; Advance to next
-		mov eax,[bx-8]		; Type
-		and eax,eax		; Null type?
-		jz .renew		; If so advance to next
-		mov [es:di+16],eax
-		and cl,~3
-		cmp ecx,24
-		jb .no_extattr
-		mov eax,[bx-4]		; Extended attributes
-		mov [es:di+20],eax
-		mov ecx,24		; Bytes loaded
-.no_extattr:
-		mov eax,[bx-16]		; Start addr (low)
-		mov edx,[bx-12]		; 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-16]		; Derive the length
-		sbb edx,[bx-12]
-		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
-		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:
-		mov ax,[cs:Mem1MB]
-		mov cx,ax
-		mov bx,[cs:Mem16MB]
-		mov dx,bx
-		jmp short int15_success
-
-int15_e881:
-		mov eax,[cs:Mem1MB]
-		mov ecx,eax
-		mov ebx,[cs:Mem16MB]
-		mov edx,ebx
-		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 = 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			; <A>
-		push ds			; <B>
-		push es			; <C>
-
-		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			; <D> 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			; <D> A20 status
-		pop es			; <C>
-		pop ds			; <B>
-
-		and dx,dx
-		jnz .skip_a20d
-		mov ax,2400h		; Disable A20
-		int 15h
-.skip_a20d:
-		popfd			; <A>
-		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
-%endif
-
-		section .data
-		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
-%endif
-
-Int13FuncsEnd	equ $
-Int13FuncsCnt	equ (Int13FuncsEnd-Int13Funcs) >> 1
-
-
-		alignb 8, db 0
-Shaker		dw ShakerEnd-$
-		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 4, db 0
-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
-
-PatchArea	equ $			; This gets filled in by the installer
-
-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
-
-; ---- MDI structure ends here ---
-Int13MaxFunc	db Int13FuncsCnt-1	; Max INT 13h function (to disable EDD)
-		db 0			; pad
-
-		dw 0			; pad
-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
-
-%endif
-
-		; End patch area
-Stack		dd 0			; Saved SS:ESP on invocation
-		dw 0
-SavedAX		dw 0			; AX saved on invocation
-
-		alignb 4, db 0		; We *MUST* end on a dword boundary
-
-E820Table	equ $			; The installer loads the E820 table here
-TotalSize	equ $			; End pointer
+%include "memdisk.inc"
diff --git a/memdisk/memdisk.inc b/memdisk/memdisk.inc
new file mode 100644
index 0000000..2b5b4e0
--- /dev/null
+++ b/memdisk/memdisk.inc
@@ -0,0 +1,987 @@
+; -*- fundamental -*- (asm-mode sucks)
+; ****************************************************************************
+;
+;  memdisk.inc
+;
+;  A program to emulate an INT 13h disk BIOS from a "disk" in extended
+;  memory.
+;
+;   Copyright 2001-2008 H. Peter Anvin - All Rights Reserved
+;
+;  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_SAFEINT	0x04
+%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 binary
+Pointers:	dw Int13Start
+		dw Int15Start
+		dw PatchArea
+		dw TotalSize
+		dw IretPtr
+
+IretPtr		equ Int13Start.iret
+Int13Start:
+		; 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:		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,[Int13MaxFunc]
+		ja 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,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 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]
+		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 far [cs: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...
+		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,0003h		; Bit 0 - Fixed disk access subset
+					; Bit 1 - Locking and ejecting 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
+		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
+
+%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,16		; Advance to next
+		mov eax,[bx-8]		; Type
+		and eax,eax		; Null type?
+		jz .renew		; If so advance to next
+		mov [es:di+16],eax
+		and cl,~3
+		cmp ecx,24
+		jb .no_extattr
+		mov eax,[bx-4]		; Extended attributes
+		mov [es:di+20],eax
+		mov ecx,24		; Bytes loaded
+.no_extattr:
+		mov eax,[bx-16]		; Start addr (low)
+		mov edx,[bx-12]		; 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-16]		; Derive the length
+		sbb edx,[bx-12]
+		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
+		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:
+		mov ax,[cs:Mem1MB]
+		mov cx,ax
+		mov bx,[cs:Mem16MB]
+		mov dx,bx
+		jmp short int15_success
+
+int15_e881:
+		mov eax,[cs:Mem1MB]
+		mov ecx,eax
+		mov ebx,[cs:Mem16MB]
+		mov edx,ebx
+		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 = 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			; <A>
+		push ds			; <B>
+		push es			; <C>
+
+		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			; <D> 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			; <D> A20 status
+		pop es			; <C>
+		pop ds			; <B>
+
+		and dx,dx
+		jnz .skip_a20d
+		mov ax,2400h		; Disable A20
+		int 15h
+.skip_a20d:
+		popfd			; <A>
+		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
+%endif
+
+		section .data
+		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
+%endif
+
+Int13FuncsEnd	equ $
+Int13FuncsCnt	equ (Int13FuncsEnd-Int13Funcs) >> 1
+
+
+		alignb 8, db 0
+Shaker		dw ShakerEnd-$
+		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 4, db 0
+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
+
+PatchArea	equ $			; This gets filled in by the installer
+
+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
+
+; ---- MDI structure ends here ---
+Int13MaxFunc	db Int13FuncsCnt-1	; Max INT 13h function (to disable EDD)
+		db 0			; pad
+
+		dw 0			; pad
+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
+
+%endif
+
+		; End patch area
+Stack		dd 0			; Saved SS:ESP on invocation
+		dw 0
+SavedAX		dw 0			; AX saved on invocation
+
+		alignb 4, db 0		; We *MUST* end on a dword boundary
+
+E820Table	equ $			; The installer loads the E820 table here
+TotalSize	equ $			; End pointer
diff --git a/memdisk/memdisk_edd.asm b/memdisk/memdisk_edd.asm
new file mode 100644
index 0000000..97d3fe9
--- /dev/null
+++ b/memdisk/memdisk_edd.asm
@@ -0,0 +1,2 @@
+%define WITH_EDD
+%include "memdisk.inc"
diff --git a/memdisk/setup.c b/memdisk/setup.c
index 7b1f456..ed08d57 100644
--- a/memdisk/setup.c
+++ b/memdisk/setup.c
@@ -24,6 +24,9 @@ const char copyright[] =
 
 extern const char _binary_memdisk_bin_start[], _binary_memdisk_bin_end[];
 extern const char _binary_memdisk_bin_size[]; /* Weird, I know */
+extern const char _binary_memdisk_edd_bin_start[],
+       _binary_memdisk_edd_end[];
+extern const char _binary_memdisk_edd_bin_size[];
 
 struct memdisk_header {
   uint16_t int13_offs;
@@ -93,7 +96,6 @@ struct patch_area {
   uint16_t dpt_ptr;
   /* End of the official MemDisk_Info */
   uint8_t  maxint13func;
-#define MAXINT13_NOEDD	0x16
   uint8_t  _pad2;
 
   uint16_t _pad3;
@@ -598,7 +600,8 @@ void *sys_bounce;
 
 __cdecl void setup(__cdecl syscall_t cs_syscall, void *cs_bounce)
 {
-  unsigned int bin_size = (int) &_binary_memdisk_bin_size;
+  unsigned int bin_size;
+  char *memdisk_hook;
   struct memdisk_header *hptr;
   struct patch_area *pptr;
   uint16_t driverseg;
@@ -610,7 +613,7 @@ __cdecl void setup(__cdecl syscall_t cs_syscall, void *cs_bounce)
   com32sys_t regs;
   uint32_t ramdisk_image, ramdisk_size;
   int bios_drives;
-  int do_edd = -1;		/* -1 = default, 0 = no, 1 = yes */
+  int do_edd = 1;		/* 0 = no, 1 = yes, default is yes */
   int no_bpt;			/* No valid BPT presented */
 
   /* Set up global variables */
@@ -649,13 +652,22 @@ __cdecl void setup(__cdecl syscall_t cs_syscall, void *cs_bounce)
   else
     do_edd = (geometry->driveno & 0x80) ? 1 : 0;
 
+  /* Choose the appropriate installable memdisk hook */
+  if (do_edd) {
+    bin_size = (int) &_binary_memdisk_edd_bin_size;
+    memdisk_hook = (char *) &_binary_memdisk_edd_bin_start;
+  } else {
+    bin_size = (int) &_binary_memdisk_bin_size;
+    memdisk_hook = (char *) &_binary_memdisk_bin_start;
+  }
+
   /* Reserve the ramdisk memory */
   insertrange(ramdisk_image, ramdisk_size, 2, 1);
   parse_mem();			/* Recompute variables */
 
   /* Figure out where it needs to go */
-  hptr = (struct memdisk_header *) &_binary_memdisk_bin_start;
-  pptr = (struct patch_area *)(_binary_memdisk_bin_start + hptr->patch_offs);
+  hptr = (struct memdisk_header *) memdisk_hook;
+  pptr = (struct patch_area *)(memdisk_hook + hptr->patch_offs);
 
   dosmem_k = rdz_16(BIOS_BASEMEM);
   pptr->olddosmem = dosmem_k;
@@ -726,10 +738,6 @@ __cdecl void setup(__cdecl syscall_t cs_syscall, void *cs_bounce)
   }
   puts(" access to high memory\n");
 
-  /* pptr->maxint13func defaults to EDD enabled, if compiled in */
-  if (!do_edd)
-    pptr->maxint13func = MAXINT13_NOEDD;
-
   /* Set up a drive parameter table */
   if ( geometry->driveno & 0x80 ) {
     /* Hard disk */
@@ -898,7 +906,7 @@ __cdecl void setup(__cdecl syscall_t cs_syscall, void *cs_bounce)
     hptr = (struct memdisk_header *)dpp;
 
     /* Actually copy to low memory */
-    dpp = mempcpy(dpp, &_binary_memdisk_bin_start, bin_size);
+    dpp = mempcpy(dpp, memdisk_hook, bin_size);
     dpp = mempcpy(dpp, ranges, (nranges+1)*sizeof(ranges[0]));
     dpp = mempcpy(dpp, shdr->cmdline, cmdlinelen+1);
   }
-- 
1.5.3.4


-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-memdisk-varieties-Allow-for-multiple-memdisk-instal.patch
Type: application/octet-stream
Size: 49072 bytes
Desc: 0001-memdisk-varieties-Allow-for-multiple-memdisk-instal.patch
URL: <http://www.zytor.com/pipermail/syslinux/attachments/20090309/2175bab4/attachment.obj>


More information about the Syslinux mailing list