760 lines
16 KiB
Plaintext
760 lines
16 KiB
Plaintext
; -*- fundamental -*- (asm-mode sucks)
|
|
; $Id: memdisk.asm,v 1.29 2005/04/29 06:08:03 hpa Exp $
|
|
; ****************************************************************************
|
|
;
|
|
; memdisk.asm
|
|
;
|
|
; A program to emulate an INT 13h disk BIOS from a "disk" in extended
|
|
; memory.
|
|
;
|
|
; Copyright (C) 2001-2004 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 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 binary
|
|
Pointers: dw Int13Start
|
|
dw Int15Start
|
|
dw PatchArea
|
|
dw TotalSize
|
|
|
|
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
|
|
|
|
.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,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'
|
|
test dl,dl ; Always pass it on if we are resetting HD
|
|
js .pass_on ; 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.
|
|
xor ax,ax ; Bottom of memory
|
|
mov es,ax
|
|
; BIOS equipment byte, top two bits + 1 == total # of floppies
|
|
test byte [es:0x410],0C0h
|
|
jz success
|
|
; ... otherwise pass it to the BIOS
|
|
.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 short 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:
|
|
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
|
|
|
|
; Set up registers as for a "Read", and compares against disk size
|
|
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 32-bit words
|
|
ret
|
|
|
|
.overrun: pop ax ; Drop setup_regs return address
|
|
mov ax,0200h ; Missing address mark
|
|
ret ; Return to Done
|
|
|
|
int15_e820:
|
|
cmp edx,534D4150h ; "SMAP"
|
|
jne near oldint15
|
|
cmp ecx,20 ; Need 20 bytes
|
|
jb err86
|
|
push ds
|
|
push cs
|
|
pop ds
|
|
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 [es:di],eax
|
|
mov ecx,[bx-8] ; Start addr (high)
|
|
mov [es:di+4],ecx
|
|
mov eax,[bx] ; End addr (low)
|
|
mov ecx,[bx+4] ; End addr (high)
|
|
sub eax,[bx-12] ; Derive the length
|
|
sbb ecx,[bx-8]
|
|
mov [es:di+8],eax ; Length (low)
|
|
mov [es:di+12],ecx ; Length (high)
|
|
cmp dword [bx+8],-1 ; Type of next = end?
|
|
jne .notdone
|
|
xor ebx,ebx ; Done with table
|
|
.notdone:
|
|
mov eax,edx ; "SMAP"
|
|
pop ds
|
|
mov ecx,20 ; Bytes loaded
|
|
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
|
|
|
|
test byte [ConfigFlags],CONFIG_RAW
|
|
jz .anymode
|
|
|
|
smsw ax ; Unprivileged!
|
|
test al,01h
|
|
jnz .protmode
|
|
|
|
.realmode:
|
|
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 es
|
|
pop ds
|
|
|
|
pop dx ; A20 status
|
|
and dx,dx
|
|
jnz .skip_a20d
|
|
mov ax,2400h ; Disable A20
|
|
int 15h
|
|
.skip_a20d:
|
|
popfd
|
|
jmp .done
|
|
|
|
.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
|
|
int 15h
|
|
cli ; Some BIOSes enable interrupts on INT 15h
|
|
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
|
|
|
|
%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 0
|
|
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 Invalid ; 45h - EDD LOCK/UNLOCK MEDIA
|
|
dw Invalid ; 46h - EDD EJECT
|
|
dw EDDSeek ; 47h - EDD SEEK
|
|
dw EDDGetParms ; 48h - EDD GET PARAMETERS
|
|
%endif
|
|
|
|
Int13FuncsEnd equ $
|
|
Int13FuncsMax 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 27 ; Total bytes in MDI structure
|
|
MDI_Version db VER_MINOR, VER_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
|
|
; ---- MDI structure ends here ---
|
|
db 0, 0, 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)
|
|
|
|
; 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
|