;======================================================================
; 
; Reverse-Engineered Disassembly of SoftRAM 95 - Windows 95 version
;
; By Mark Russinovich.
;
; This file was created by first passing SoftRAM 95 through Sourcer,
; a disassembler from V Communications. Then an instruction-by-instruction
; comparison was made with the Windows 95 DDK version of Dynapage and
; all identical code was removed. Finally, the code was reverse-engineered
; to determine the purpose and functionality of the variables and 
; sub-routines. Note that this code will not assemble since it is missing
; the rest of the dynapage code.
;
;----------------------------------------------------------------------

PAGE  59,132

;==========================================================================
;==					                                 ==
;==				DYNAPAGE                                 ==
;==					                                 ==
;==      Created:   9-Aug-95		                                 ==
;==      Code type: Windows VxD		                                 ==
;==      Passes:    5          Analysis	Options on: AU                   ==
;==					                                 ==
;==========================================================================

target		EQU   'M6'                      ; Target assembler: MASM-6.1

include  srmacros.inc

.486p

.387


;------------------------------------------------------------  seg_a   ----

seg_a		segment	byte public use32
		assume cs:seg_a  , ds:seg_a

;======================================================================
;
; Constants
;
;======================================================================
#define PAGESIZE  400h
#define PAGESHIFT 0Ch

#define UNCOMP  80000000h
#define FAKECOMP   40000000h

;======================================================================
;
; Structures
;
;======================================================================

; this structure is used to manage the cache. The flag field indicates
; if the buffer is present (flag != 0), if the buffer is a plain copy
; (flag &= UNCOMP), and if the buffer is fake-compressed (flag &= FAKECOMP).
; The nextoff field has the pageoffset of the page in the buffer written
; after the current one (bad attempt at LRU?). The last field is unused.

header  STRUCT
	flag	: DWORD		; flags and base address in cache
	nextoff	: WORD		; next offset in list
	field2	: WORD		; this field is unused
header	ENDS

;======================================================================
;
; Softram variables as I've determined them
;
;======================================================================

softramenabled	dd	?	; this is not used
bufferbase	dd	?	; start of our grabbed paging cache buffer
buffertail	dd	?	; head of list of pages in buffer
bufferhead	dd	?	; tail of list of pages in buffer
maxpfileoffset	dd	?	; max pagefile offset that is cached
pagebase	dd	?	; base of page area
headersize	dd	8	; size of header structure 
headerbase	dd	?	; base of header structure area
headerlen	dd	?	; number pages for header structures
headerarealen	dd	?	; len in bytes of header structure area
pagesgrabbed	dd	?	; number of pages in initial grab
heapclear	dd	?	; number of pages to keep free
pageaddress	dd	?	; address of current page 
fileoffset	dd	?	; file offset of current page 
lastoffset	dd	?	; last offset written to
writeoffset 	dd	?	; used to store write offset
tmp		dd	?	; used for tmp storage 
tmp1		dd	?	; another temporary 
curhead		dd	?	; tmp used to store cur head pointer

cmdstruct	struct pagecmd	; structure used for internal commands 

fkcompresshead	dd	?	; head of compressed list 
fkcompresstail	dd	?	; tail of compressed list 

tmppfoffset	dd	?	; temporarily store target pagefile offset

nopurpose1	dd	?	; not used for anything real 

neverused1	dd	?	; written, but never read
neverused2	dd	?	; written, but never read
neverused3	dd	?	; written, but never read
neverused4	dd	?	; written, but never read
neverused5	dd	?	; written, but never read

tmpbuf		db	4096 DUP(0) ; temporary buffer for compression


;======================================================================
;
; FreeCompressed
;
; Takes a buffer that was marked as fake-compressed and frees the header
; for it. Then it calls the buffer free routine and removes the buffer
; from the fake-compressed buffer list.
;
;======================================================================

FreeCompressed:
		push	eax
		push	ebx
		push	ecx
		push	edx
		mov	eax, fkcompresstail
		mov	ebx, fkcompresshead
		cmp	eax,ebx			; fcomptail > fcomphead?
		jb	short loc_0002
		xor	eax,eax			; no
		mov	ax,word ptr [ebx+1]	; always 3 (size of header)
		add	ebx,eax
		mov	fkcompresshead, ebx	; remove header of first page
		jmp	short loc_0004		;  on fake compress list
loc_0002::
		xor	eax,eax
		mov	ax,word ptr [ebx+1]	; always 3 (size of header)
		add	ebx,eax
		mov	eax, pagesgrabbed
		shl	eax, PAGESHIFT
		add	eax, pagebase
		cmp	ebx,eax			; addr of mem header: are we
		jb	short loc_0003		;   off the end of grabbed mem
		mov	eax, pagebase		; yes, reset fcomp list
		mov	fkcompresshead, eax
		jmp	short loc_0004
loc_0003::
		mov	fkcompresshead, ebx	; no, just remove page
loc_0004::
		call	FreeCompBuf
		pop	edx
		pop	ecx
		pop	ebx
		pop	eax
		retn
FreeCompressed	endp


;==========================================================================
;
; FreeUncompressed
; 
; During Idle callback this routine is called to free the uncompressed
; buffer when a fake-compressed buffer is created for the data.
;
;==========================================================================

FreeUncompressed proc	near
		push	eax
		push	ebx
		push	ecx
		push	edx
		mov	eax, buffertail
		mov	ebx, bufferhead
		cmp	eax,ebx			; buffertail > bufferhead?
		jb	short loc_0005
		add	ebx,1000h		; yes, add 1 page to buffer
		mov	bufferhead,ebx
		jmp	short loc_0007		; return
loc_0005::
		add	ebx,1000h		; add 1 page to buffer anyway
		mov	eax, pagesgrabbed
		shl	eax, PAGESHIFT
		add	eax, bufferbase
		cmp	ebx,eax			; are we falling of end of 
		ja	short loc_0006		;   grabbed mem? 
		mov	bufferhead, ebx		; no, update buffer
		jmp	short loc_0007		; return
loc_0006::
		mov	eax, bufferbase		; reset bufferhead to base
		mov	bufferhead, eax
loc_0007::
		pop	edx
		pop	ecx
		pop	ebx
		pop	eax
		retn
FreeUncompressed endp


;==========================================================================
;              
; StoreCompressed
;
; Called when a new fake-compressed page has been created and needs
; to be stored in the fake-compressed part of the cache.
;
; on entry:
;	ecx = length of fake-compressed buffer
;	edx = address of fake-compressed buffer (always points at tmpbuf)
;
; on exit:
;	edx = -1 if error
; 
;==========================================================================

StoreCompressed	proc	near
		push	eax
		push	ebx
		mov	eax, buffertail
		mov	ebx, bufferhead
		cmp	eax,ebx		
		ja	short loc_0008		; is buftail > bufhead?
		mov	fileoffset, eax		; use buftail
		jmp	short loc_0009
loc_0008::
		mov	fileoffset, ebx		; use bufhead
loc_0009::
		mov	eax, fkcompresstail
		add	eax,ecx			; get tail of compress buffers
		mov	ebx, pagesgrabbed
		shl	ebx, PAGESHIFT
		add	ebx, pagebase		; get base of grabbed memory
		cmp	eax,ebx			; is comptail < bufbase?
		jb	short loc_0013		; yes
		sub	ebx, fkcompresstail	; no, subtract bufbase
		push	ecx
		mov	ecx,ebx			; store address in ecx
		mov	ebx, fkcompresstail
		mov	al,-1			; reset all data up to point

resetloop:
		mov	[ecx][ebx],al		; reset loop (-1 means invalid)
		loopd	resetloop		

		pop	ecx			; restore ecx (fakecomp len)
		mov	eax, pagebase
		add	eax,ecx			; add to pagebase
		cmp	eax, fileoffset		; is it > bufhead?
		ja	short loc_0011		; yes
		mov	edx,-1			; nope
		jmp	short loc_0016		; signal error
loc_0011::
		mov	eax, buffertail		
		mov	ebx, bufferhead
		cmp	eax,ebx			; is buftail > bufhead?
		ja	short loc_0012		; yep
		mov	edx,-1			; nope, bail-out!
		jmp	short loc_0016
loc_0012::
		mov	eax, pagebase		; set fakecomptail to pagebase
		mov	fkcompresstail, eax
loc_0013::
		mov	eax, fkcompresstail
		mov	ebx, bufferhead
		cmp	eax, ebx		; is comptail > bufhead?
		ja	short loc_0014		; yep
		add	eax, ecx		; no, add the length
		cmp	eax, ebx		; is it still < bufhead?
		jb	short loc_0014		; nope 
		mov	edx, -1			; yep, we went over the end
		jmp	short loc_0016		; return error
loc_0014::
		push	ecx			; save ecx
		mov	eax, fkcompresstail

locloop_0015::
		mov	bl,[edx]		; copy original buf to compress
		mov	[eax],bl
		inc	edx
		inc	eax
		loopd	locloop_0015		; again, really, really loop

		pop	ecx
		mov	edx, fkcompresstail	; 
		add	edx,ecx
		mov	fkcompresstail, edx
		sub	edx,ecx
		sub	edx, pagebase
loc_0016::
		pop	ebx
		pop	eax
		retn
StoreCompressed	endp


;==========================================================================
;
; CreateIfRoom
;
; Called from pagefile wrie. Only creates a new buffer if there is room
; in the fakebuffer area.
;
; on entry:
;	edx == address of page to add
;
; on exit:
;	edx == address of buffer if room, -1 if not
;
;==========================================================================

CreateIfRoom	proc	near
		push	eax
		push	ebx
		push	ecx
		mov	eax, buffertail
		add	eax, 1000h		; add 1 page to buff tail
		mov	ebx, pagesgrabbed
		shl	ebx, PAGESHIFT
		add	ebx, pagebase
		cmp	eax,ebx			; see if we are within grabbed
		jbe	short loc_0020		; nope
		mov	ecx, buffertail		; yes
		sub	ebx,ecx			; get difference from end of
		mov	ecx,ebx			;  grabbed mem and store in ecx
		mov	al,-1
		mov	ebx, buffertail		; is distance non-null? 
		test	ecx,ecx			; this is always true
		jz	short loc_0018

locloop_0017::
		mov	[ecx][ebx],al		; fill space to end of grabbed
		loopd	locloop_0017		;   mem with -1

loc_0018::
		mov	eax, pagebase
		add	eax,5000h
		cmp	eax, fkcompresshead	; is fcompresshead < pagebase +
		jbe	short loc_0019		;  5 pages? yes.
		mov	edx,-1			; no, exit out
		jmp	noroom
loc_0019::
		mov	eax, pagebase		; set buffertail to page base
		mov	buffertail, eax
		jmp	copypage
loc_0020::
		mov	eax, buffertail		; is fcompresshead <buffertail?
		mov	ebx, fkcompresshead
		cmp	eax,ebx
		ja	copypage		; no, its greater
		add	eax,1000h		; yes, so add 1 page to tail
		cmp	eax,ebx			; test again
		jbe	copypage		; if it fits, go copy
		mov	edx,-1			; no room
		jmp	noroom		
copypage:
		mov	eax, buffertail
		mov	ecx, PAGESIZE

copyloop:
		mov	ebx,[edx]		; just copy thge page to the
		mov	[eax],ebx		;   uncompressed cache
		inc	edx			; unbelievably bad loop!!
		inc	edx
		inc	edx
		inc	edx
		inc	eax
		inc	eax
		inc	eax
		inc	eax
		loopd	copyloop

		mov	edx, buffertail		; increment buffertail
		add	edx,1000h		; return in edx offset of the
		mov	buffertail,edx		;   start of pagebase of new
		sub	edx,1000h		;   entry
		sub	edx, pagebase
		jmp	noroom			; no need for this!
noroom:
		pop	ecx
		pop	ebx
		pop	eax
		retn
CreateIfRoom	endp


;==========================================================================
;          
; FreeCompBuf
;
; Looks through the fake-compressed buffer list for buffers that are no
; longer valid and removes them from the list.
;
;==========================================================================

FreeCompBuf	proc	near
		push	eax
		push	ebx
		push	ecx
		push	edx
loc_0024::
		mov	eax, fkcompresstail
		mov	ebx, fkcompresshead	; is comptail < comphead
		cmp	eax,ebx
		jb	short loc_0025		; yes

		mov	eax, fkcompresshead	; use comphead
		xor	ebx,ebx
		mov	bl,[eax]		; always 0 (first byte of 
		cmp	bl,-1			;  fake compress header)
		jne	short loc_0028		; if not -1, return

		mov	bx,word ptr [eax+1]	; calculate address of data
		add	ebx, fkcompresshead	;   (always 3 bytes) using
		mov	fkcompresshead, ebx	;   offset in header
		jmp	short loc_0024
loc_0025::
		mov	eax, pagesgrabbed	
		shl	eax, PAGESHIFT
		add	eax, pagebase		; get base of grabbed memory
		add	ebx,4			; add 4 bytes to buff addr
		cmp	ebx,eax			; is it > pagebase?
		jb	short loc_0026		; yes

		mov	eax, pagebase		
		mov	tmp1, eax		; tmp store pagebase
		jmp	short loc_0024		; look again
loc_0026::
		mov	eax, tmp1		; pagebase
		xor	ebx,ebx			; zero ebx
		mov	bl,[eax]		; is the header valid?
		cmp	bl,-1		
		jne	short loc_0028		; yep, its valid

		mov	bx,word ptr [eax+1]	; nope, is next byte valid?
		cmp	bx,-1		
		jne	short loc_0027		; yep, its valid

		mov	eax, pagebase		; start looking at beginning
		mov	fkcompresshead, eax	;  of the compress buffer
		jmp	short loc_0024
loc_0027::
		add	ebx, fkcompresshead	; skip header
		mov	fkcompresshead, ebx	; store
		jmp	loc_0024		; keep looking
loc_0028::
		pop	edx
		pop	ecx
		pop	ebx
		pop	eax
		retn
FreeCompBuf	endp


;==========================================================================
; 
; CreateNewHeader
;
; on entry:
;	eax == flag for new page
;	ebx == pagefileoffset
;
; Called from pagefile write. Creates a new cache buffer header and links
; it onto the "least recently created" list (a poor approximation of LRU).
;
;==========================================================================

CreateNewHeader proc	near
		push	ecx
		mov	fileoffset, edx
		mov	tmp, eax

		mov	ecx, headerbase
		mov	eax, headersize
		mul	ebx			; index into header structs
		add	eax,ecx
		mov	ecx,[eax]		; get existing flag
		test	ecx, FAKECOMP		; do we already have this page
						;   fake compressed?
		jz	short loc_0029		; no, create it

		and	ecx,0FFFFFFFh		; yes, get the buffer addr
		add	ecx, pagebase		;   for it
		mov	dl,-1
		mov	[ecx],dl		; mark buffer with -1

loc_0029::
		mov	ecx, fileoffset
		or	ecx, tmp
		mov	[eax],ecx		; store flag for new page
		mov	tmp, eax
		mov	edx, lastoffset		; link with previous on chain
		mov	nopurpose1, edx
		cmp	edx,-1
		jne	short loc_0030
		mov	dx,-1
		mov	word ptr [eax+4],dx	
		mov	word ptr [eax+6],dx	; mark the buffer end of chain

		; set up other variables

		mov	lastoffset, ebx		; update last offset
		mov	writeoffset, ebx
		mov	neverused1, ebx
		mov	neverused2, ebx
		jmp	short loc_0031

		; this code is called once when the first page is added to
		; the buffer

initchain:
		mov	eax, headersize	
		mul	edx
		add	eax, headerbase
		mov	word ptr [eax+4],bx	; store next offset 
		mov	lastoffset, ebx		; set last offset
		mov	eax, lastoffset		; this is always 0 since 
						;   Windows writes to start of
						;   file first
		mul	writeoffset		; this too!
		add	eax, headerbase
		mov	dx,-1
		mov	word ptr [eax+4],dx	; mark page as end of chain
		mov	eax, tmp			
		mov	edx, nopurpose1
		mov	word ptr [eax+6],dx
		mov	neverused1, ebx
loc_0031::
		xor	edx,edx
		pop	ecx
		retn
CreateNewHeader	endp


;==========================================================================
;
; MakeRoom
;
; Called from pagefile write. This routine is called when there is not
; any free room in the cache. It follows the "least recently created" chain
; sending out the number of pages needed to make room for the current write.
; Always makes room for at least one page. 
;
; on entry:
;	dl = # of pages to send out.
;
;==========================================================================
MakeRoom	proc	near
		push	eax
		push	ebx
		push	ecx
		push	esi
		push	edi
		mov	ecx,edx
		test	edx,edx			; any pages to send out?
		jnz	loc_0033		; yep.

		mov	eax, buffertail		; nope.
		mov	ebx, fkcompresshead
		cmp	eax,ebx			; is buffertail > bufferhead?
		ja	short loc_0032		; yes

		sub	ebx,eax			; no, ebx = difference
		mov	eax,ebx
		cmp	eax, heapclear		; if tail - fcomphead > heapclr
		ja	loc_0037		; then return

		mov	ebx, heapclear
		sub	ebx,eax			; ebx = heapclr-(tail-comphead)
		jz	loc_0037		; if 0, then return

		mov	eax,ebx		
		mov	ebx, PAGESIZE
		push	edx
		xor	edx,edx			; how many pages left before 
						;   runs out of heap-clear
		div	ebx			; heapclear
		inc	eax			; increment by 1
		pop	edx
		mov	ecx,eax
		jmp	short loc_0033		; go make room
loc_0032::
		mov	eax, fkcompresshead	; get difference between 
						;  fkcompressed and pagebase
		sub	eax, pagebase		; pagebase
		mov	fileoffset, eax
		mov	eax, pagesgrabbed
		shl	eax, PAGESHIFT
		add	eax, pagebase
		sub	eax buffertail		; memgrabbed - buffertail
		add	eax, fileoffset		;  + offset
		cmp	eax, heapclear		; is that >= heapclear
		jae	loc_0037		; if yes, then return - need to
						;   to leave things be
		mov	ebx,800h		; nope
		push	edx			; get # of pages/2 that fit
		xor	edx,edx
		div	ebx
		inc	eax
		pop	edx
		mov	ecx,eax
loc_0033::					; at this point, ecx=# pages 
						;  that can be sent out
		mov	eax, writeoffset
		cmp	eax,-1
		je	loc_0037
loc_0034::
		mov	tmppfoffset,eax		; get file pagefileoffset
		mul	headersize
		add	eax, headerbase		; calc where header struct is
		mov	edx,[eax]		; get the header
		test	edx, FAKECOMP		; is it fake-compressed?
		jz	notcompressed		; nope

		and	edx,0FFFFFFFh		; yes
		add	edx, pagebase		; get the position in the buf
		mov	esi,edx
		mov	edi, offset32 tmpbuf
		push	eax
		call	FakeDecompress		; fake-decompress it
		mov	ebx, offset32 cmdstruct
		mov	byte ptr [ebx+4],1	; get ready to write out page
						;   being replaced
		mov	byte ptr [ebx+7],1	; 1 page
		mov	edx, offset32 tmpbuf
		mov	dword ptr [ebx+8],edx	; address of page
		mov	eax, tmppfoffset
		mov	dword ptr [ebx+0Ch],eax	; pagefile page offset
;****
;**** 
;
; Race condition can occur here. If a page is being written out and
; another request comes into SoftRAM, global variables will be made
; inconsistent. This case is rare, but can be triggered by running a 
; compile in one window, and then switching to the start-up of WordPad,
; for example. By rapidly switching between the two, SoftRAM will start
; to cause problems.
;
		call	ddkpagefile_read_or_write ; do the write-out
;****
;****
		call	FreeCompressed		; free the original buffer
		xor	edx,edx
		pop	eax
		mov	[eax],edx		; mark page as not present
		mov	dx,word ptr [eax+4]	; get next offset
		cmp	dx,-1			; have we hit the end of list?
		jne	doneyet			; no, go send more out
		mov	ecx,1			; yes, set ecx so we'll exit
		jmp	doneyet
notcompressed:
		xor	edx,edx
		mov	dx,word ptr [eax+4]	; get next offset
		mov	eax,edx
		cmp	ax,-1			; end of list?
		jne	loc_0034		; if not, make room for more
		mov	ecx,1			; yes, so exit
doneyet:
		dec	ecx			; this should be a loopz!
		test	ecx,ecx			
		jnz	loc_0033		; any more pages to make room?
		xor	edx,edx			; nope, exit
loc_0037::
		pop	edi
		pop	esi
		pop	ecx
		pop	ebx
		pop	eax
		retn
MakeRoom	endp


;==========================================================================
;           
; FakeCompress
;
; Just takes a buffer, copies it to a new buffer and prefixes it with a 
; 3 byte fake-compress header (0,3,16).
;
;==========================================================================

FakeCompress	proc	near
		pushad
		mov	al,0			; store the following bytes at
		mov	[edi],al		;   at the head of the fake 
		inc	edi			;   fake compress buffer
		mov	al,3
		mov	[edi],al		; 0, 3, 16, the copy the data
		inc	edi			;   and return 0x1003 (bytes)
		mov	al,10h
		mov	[edi],al
		inc	edi
		cld
		mov	ecx,1000h		; another inefficient copy
		rep	movsb
		popad
		mov	eax,1003h		; signal success with size
						;  of new buffer
		retn
FakeCompress	endp


;==========================================================================
;
; FakeDecompress
;
; This routine assumes that there are 3 bytes of header in the cache
; buffer which is skipped over before the copy.
;
;==========================================================================

FakeDecompress	proc	near
		pushad
		inc	esi
		inc	esi
		inc	esi
		cld
		mov	ecx,1000h
		rep	movsb			; use inefficient byte copy
		popad
		mov	eax,1000h
		retn
FakeDecompress	endp

;======================================================================
;
; Idle_Callback
;
; Starts at page most recently stored in the cache and looks for one
; that is not fake-compressed. It compresses at most 1 page per call.
; It only does this if there is room in the buffer to take the new
; page (nobody has to be forced out).
;
;======================================================================
BeginProc IdleProc

		push	eax
		push	ebx
		push	ecx
		push	edx
		push	esi
		push	edi
		mov	ecx,7
		VMMcall	Begin_Critical_Section	

		xor	edx,edx
		call	MakeRoom		; make room for 
		call	FreeCompBuf		; free aged fake-compressed 
						;   bufs
		mov	eax, bufferhead
		mov	ebx, buffertail
		cmp	eax,ebx			; are bufhead and buftail equal
		je	loc_0040	
		mov	eax, writeoffset	; nope, so get last page added
		mov	ebx, headersize		; calc its position in the buf
		mul	ebx
		add	eax, headerbase
loc_0038::
		mov	ecx,[eax]		; get the header address
		mov	curhead, eax		; update current variable
		test	ecx, FAKECOMP		; is it fake-compressed?
		jnz	checknext		; yep, 
		test	ecx, UNCOMP		; is it valid uncompressed?
		jz	checknext		; nope
		and	ecx,0FFFFFFFh		; get the page address
		add	ecx, pagebase		; add to pagebase
		mov	edi, offset32 tmpbuf
		mov	esi,ecx
		call	FakeCompress		; fake-compress it into tmpbuf
		test	eax,eax			; success?
		jz	idledone		; nope
		mov	ecx,eax			; success, move length into ecx
		mov	edx, offset32 tmpbuf
		call	StoreCompressed
		cmp	edx,-1			; if failure, return
		je	idledone

		; mark page as in buffer with 3 byte header

		or	edx, FAKECOMP		; its fake-compressed
		or	edx, UNCOMP		; its valid
		mov	eax, curhead		; put header pointer in struct
		mov	[eax],edx		; store in header
		call	FreeUncompressed	; free uncompressed buffer
		jmp	idledone		; do 1 page per idle
checknext:
		xor	ecx,ecx
		mov	cx,word ptr [eax+4]	; get next offset
		mov	eax,ecx
		cmp	ax,-1			; end of list
		je	idledone
		mul	headersize
		add	eax, headerbase
		jmp	short loc_0038
idledone:
		VMMcall	End_Critical_Section	; Win-VMM function   fn=10020h
		or	word ptr [ebp+2Ch],1
		pop	edi
		pop	esi
		pop	edx
		pop	ecx
		pop	ebx
		pop	eax
		retn

EndProc IdleProc

;======================================================================
;
; PageFile_Read_Or_Write
;
;======================================================================
BeginProc PageFile_Read_Or_Write

		push	eax
		push	ebx
		push	ecx
		push	edx
		push	esi
		push	edi
		mov	eax, neverused3		; no-op: next inst. overrides
		mov	eax, buffertail		; do we have any pages?
		mov	ecx, bufferhead
		cmp	eax,ecx
		jne	short loc_0043		; empty cache

		mov	eax, fkcompresstail	; another check - any pages?
		mov	ecx, fkcompresshead
		cmp	eax,ecx
		jb	short loc_0042

		mov	ecx, pagesgrabbed	; see if any room for non-comp
		shl	ecx, PAGESHIFT		;   page?
		add	ecx, pagebase		; i.e. this is basically a test
		add	eax,5000h		;   to see if enough mem 
		cmp	eax,ecx			;   allocated?
		jb	short loc_0041		; or, see if compresstail in 
						;   legal part of memory
		mov	eax, pagebase		; see if compresshead is in 
		add	eax,5000h		;   front 5 pages of grabbed
						;   mem
		cmp	eax, fkcompresshead
		ja	short loc_0043

		mov	eax, pagebase
		mov	buffertail, eax
		mov	bufferhead, eax
		jmp	short loc_0043
loc_0041::
		mov	eax, fkcompresstail	; reset buffer pointers
		add	eax,5000h
		mov	buffertail, eax
		mov	bufferhead, eax
		jmp	short loc_0043
loc_0042::
		mov	eax, fkcompresstail	; is tail+5 pages> head?
		add	eax,5000h
		cmp	eax, fkcompresshead
		ja	short loc_0043

		mov	buffertail, eax		; no, set buffer pointers to
		mov	bufferhead, eax		;   tail+5 pages
loc_0043::
		xor	eax,eax			
		mov	tmp, eax		; tmp=0
		mov	al,byte ptr [ebx+4]	; command
		cmp	al, 1			; is it a write?
		jne	pageread		; no, go handle read

		; Pagefile write

		mov	edx,dword ptr [ebx+0Ch]	; is offset too high?
		cmp	edx, maxpfoffset
		ja	diskreadwrite		; yes, just do a disk I/O

		xor	eax,eax
		mov	al, byte ptr [ebx+7]	; is offset of last page too
		add	edx, eax		;    high?
		cmp	edx, maxpfoffset
		ja	diskreadwrite		; yes, just do a disk I/O

writeloop:
		xor	edx,edx
		mov	dl, byte ptr [ebx+7]	; number of pages
		shl	edx, PAGESHIFT
		mov	eax, buffertail
		mov	ecx, fcompresshead	; is buffertail > compresshead?
		cmp	eax, ecx
		ja	short loc_0045

		sub	ecx, eax		; no, ecx=difference
		mov	eax, ecx
		jmp	short loc_0046
loc_0045::
		mov	eax, fkcompresshead	; here buffertail>compresshead
		sub	eax, bufferbase
		mov	fileoffset, eax
		mov	eax, pagesgrabbed
		shl	eax, PAGESHIFT
		add	eax, bufferbase
		sub	eax, buffertail
		add	eax, fileoffset
loc_0046::
		cmp	edx,eax
		jb	initwriteloop

		mov	ecx, tmp		; have we already tried to free
		cmp	ecx,1			;  space, and there isn't 
		je	loc_0053		;  enough?

		xor	edx,edx
		mov	dl,byte ptr [ebx+7]	; number of pages
		call	MakeRoom
		inc	tmp			; tmp=tmp+1
		jmp	writeloop

initwriteloop:
		xor	ecx,ecx
		mov	cl,byte ptr [ebx+7]	; number of pages
		mov	edx,dword ptr [ebx+8]	; linear address of buf
		mov	pageaddress, edx
		mov	eax,dword ptr [ebx+0Ch]	; pagefile offset
loc_0048::
		push	eax
		push	edx
		mul	headersize
		add	eax, headerbase
		mov	edx,[eax]
		mov	dword ptr B3340,edx
		mov	neverused5, eax
		test	edx, UNCOMP
		jz	neworcompressed		; is buffer valid uncompressed?
		test	edx, FAKECOMP		; is buffer fake-compressed?
		jnz	neworcompressed		; yep, skip this
		push	ecx			; nope, buffer is already there
		push	edi
		push	esi
		mov	esi, pageaddress	; copy the new version info
		mov	edx,dword ptr B3340	;  into the existing buffer
		and	edx,0FFFFFFFh
		add	edx, bufferbase
		mov	edi,edx
		mov	ecx, PAGESIZE
		cld
		rep	movsd			; one good copy routine!
		pop	esi
		pop	edi
		pop	ecx
		pop	edx
		pop	eax
		jmp	short loc_0052
neworcompressed:				; come here if page exists and
		pop	edx			; is fake-compressed
		pop	eax			; or if it doesn't exist yet
		call	CreateIfRoom
		test	edx,-1			; was there room?
		jz	diskwritepage
		jmp	newheader

locloop_0050::
		jmp	short loc_0048		; trampoline for short jump
newheader:
		push	eax			; want to create a new page
		push	ebx
		mov	ebx,eax			; pagefile offset
		mov	eax, UNCOMP		; flag for new page
		call	CreateNewHeader
		pop	ebx
		pop	eax
loc_0052::
		mov	edx, pageaddress	; move to next page
		add	edx,1000h
		mov	pageaddress, edx
		inc	eax
		loopd	locloop_0050		; process next page

		jmp	finish			; all done
diskwritepage:
		xor	ecx,ecx			; if no room, have to send
		push	ebx			; the page to disk
		mov	cl,byte ptr [ebx+7]	; number of pages
		xor	edx,edx
		xor	eax,eax			; flag for new page
		mov	ebx, dword ptr [ebx+0Ch]; pagefile offset

makeheaders:
		call	CreateNewHeader		; new header's marked as 0!
		inc	ebx
		xor	edx,edx
		xor	eax,eax
		loopd	makeheaders

		pop	ebx			; restore the page cmd block
		jmp	diskreadwrite		; go write all pages to disk

		; pagefile read code

pageread:
		mov	edx,dword ptr [ebx+0Ch]	; is offset of first page too
		cmp	edx, maxpfoffset	;   high
		ja	diskreadwrite		; yes, just do disk I/O

		xor	eax,eax
		mov	al,byte ptr [ebx+7]	; is offset of last page too
		add	edx,eax			;    high
		cmp	edx, maxpfoffset
		ja	diskreadwrite		; yes, just do disk I/O

		; set up globals for easy access

		mov	ecx,eax
		mov	eax,dword ptr [ebx+0Ch]	; pagefile offset
		mov	fileoffset, eax
		mov	eax,dword ptr [ebx+8]	; linear address
		mov	pageaddress, eax

readloop:
		mov	eax, fileoffset		; get address of header
		mul	headersize
		mov	edx, headerbase
		add	edx, eax

		mov	eax, [edx]		; get header flag
		test	eax, UNCOMP	
		jnz	short loc_0057

		; page isn't in the cache, read from disk

		mov	tmp, ebx
		mov	ebx, cmdstruct
		mov	byte ptr [ebx+4], 0	; make a read command
		mov	byte ptr [ebx+7], 1	; 1 page
		mov	eax, tmp
		mov	edx, dword ptr [eax+8]	; get linear address
		mov	dword ptr [ebx+8], edx	; store it in new command
		mov	eax, fileoffset
		mov	dword ptr [ebx+0Ch], eax; store pagefile offset
		call	ddkpagefile_read_or_write
		mov	ebx, tmp
		jmp	increadpage

loc_0057::
		test	eax, FAKECOMP		; is it fake-compressed?
		jz	readfrombuffer		; nope, just read it out

		; in cache, fake-compressed

		mov	tmp, ebx
		mov	ebx, pageaddress
		and	eax, 0FFFFFFFh
		add	eax, bufferbase
		push	ecx
		mov	edi, ebx		; address to read to
		mov	esi, eax		; address to read from
		call	FakeDecompress
		pop	ecx
		mov	ebx, tmp
		jmp	increadpage

readnext:
		jmp	readloop		; go do another page

		; page is in cache, not fake-compressed

readfrombuffer:
		push	ecx
		mov	ecx, PAGESIZE
		mov	tmp, ebx		; save off command struct
		mov	edx, pageaddress
		and	eax, 0FFFFFFFh
		add	eax, bufferbase

readcopyloop:
		mov	ebx,[eax]		; really, really bad copy loop!
		mov	[edx],ebx
		inc	edx
		inc	edx
		inc	edx
		inc	edx
		inc	eax
		inc	eax
		inc	eax
		inc	eax
		loopd	readcopyloop

		pop	ecx
		mov	ebx, tmp		; restore command struct
increadpage:
		inc	fileoffset		; move to next page
		mov	eax, pageaddress
		add	eax, 1000h
		mov	pageaddress, eax
		loopd	readnext

finish:
		mov	byte ptr [ebx+6], 0	; indicate success
		pop	edi
		pop	esi
		pop	edx
		pop	ecx
		pop	ebx
		pop	eax
		retn

diskreadwrite:
		pop	edi
		pop	esi
		pop	edx
		pop	ecx
		pop	ebx
		pop	eax

; Real PageFile_Read_Or_Write goes here

ddkpagefile_read_or_write:



;==========================================================================
;
; PageFile_Get_Version
;
;==========================================================================
BeginProc PageFile_Get_Version, Service, RARE

; in real dynapage this is 
;		mov	eax, 400h

		mov	eax,410h		; version number
		clc
		ret

EndProc PageFile_Get_Version

;======================================================================
;
; PageFile_Init_File
;
;======================================================================
BeginProc PageFile_Init_File, Service

		pushad
		mov     eax,FFFFFFFF
		xor     esi,esi
		mov     edi, "Paging"
		int     20 vxdcall get_profile_boolean
		test    eax,eax
		jz      pagingoff

		call    DDKPageFile_Init_File	; call real init file

		; softram init file

		mov     ebx,ddkpagfilevar	; did init go okay?
		test    ebx,ebx			
		jz      pagingoff		; nope, exit

		; everything is go for softram

		push    00			; see how much memory is avail
		int     20 vxdcall _pagegetallocinfo
		pop     ecx

		xor     esi,esi
		mov     edi, "SoftRAMMaxPhys"	; what percent of mem to grab?
		mov     eax, 25			; default of 25% if not listed
						; in system.ini
		int     20 vxdcall get_profile_decimal_int
		mul     edx			; multiply by available memory
		mov     ebx, 100		 
		div     ebx			; divide by 100
		
		; grab a buffer - note that by default SoftRAMMaxPhys is
		; 100 in system.ini so this next allocate tries to grab
		; all memory available and will therefore fail

		push    00000081
		push    00
		push    FF
		push    00
		push    00
		push    00
		push    01
		push    eax			; amount to grab
		int     20 vxdcall _pageallocate
		add     esp,20
		test    eax,eax			; success?
		jz      c038478b		; nope, exit

		; memory grab succeeded - initialize variables

		mov     pagebase, eax
		mov     fkcopresstail, eax
		mov     fkcompresshead, eax

		; start a seperate region 5 pages into the buffer

		add     eax, 5000h
		mov     buffertail, eax
		mov     bufferhead, eax
		mov     bufferbase, edx

		; make sure we got the memory we asked for

		push    00
		push    bufferbase
		int     20 vxdcall _pagegetsizeaddr
		pop     ecx
		pop     ecx

		; because of bug, only zero first 1/4 of buffer 

		mov     pagesgrabbed, eax	; number of pages we grabbed
		mov     ecx, pagesgrabbed
		shl     ecx, 10			; this should be 12!
		mov     eax, bufferbase
		xor     edx, edx

locloop_0096::
		mov	[eax], edx		; look how horribly coded
		inc	eax			; this zero loop is!
		inc	eax
		inc	eax
		inc	eax
		loopd	locloop_0096

		; allocate 17 pages for header data structures

		mov	eax,2000h		; take 8092 bytes
		mov	maxpfileoffset, eax
		mov	ebx,8			; multiply by size of header
		mov	headerarea, ebx		; never referenced again
		mul	ebx
		shr	eax, PAGESHIFT			; get number of pages 
		inc	eax			; add one (we've got 17 now)
						; this increment is a bug
		mov	ebx,eax
		push	81h
		push	0
		push	-1
		push	0
		push	0
		push	0
		push	1
		push	eax
		VMMcall	_PageAllocate	
		add	esp,20h
		test	eax,eax			; did the allocate succeed?
		jz	softraminitfail		; no, so exit
		mov	headerbase, eax

		; make sure we got the memory we asked for

		push	0
		push	headerbase
		VMMcall	_PageGetSizeAddr
		pop	ecx
		pop	ecx
		cmp	eax,ebx			; any memory?
		jb	softraminitfail		; nope, exit

		; initialize variables

		mov	headerlen, eax
		mov	eax,-1
		mov	lastoffset, eax
		mov	writeoffset, eax
		mov	neverused1, eax
		mov	neverused2, eax

		; again, only zero the first 1/4 of the buffer

		mov	ecx, headerlen
		shl	ecx,0Ah
		mov	eax, headerbase
		xor	edx,edx

locloop_0097::
		mov	[eax],edx
		inc	eax
		inc	eax
		inc	eax
		inc	eax
		loopd	locloop_0097

		; set-up idle callback

		mov	esi, offset IdleProc
		VMMcall	Call_When_Idle		
		jc	softraminitfail		; disable if failure

		; get final parameter from system.ini
		; heapclear is a percentage value of total pages grabbed

		xor	esi,esi
		mov	edi, "SoftRAMHeapClear"
		mov	eax, 10			; default value
		VMMcall	Get_Profile_Decimal_Int	
		mov	edx, pagesgrabbed
		shl	edx, PAGESHIFT
		mul	edx
		mov	ebx, 100
		div	ebx
		mov	heapclear, eax

		; success - now initialize variables we'll never use!

		mov	ecx, neverused4
		add	ecx, pagesgrabbed
		mov	neverused4, ecx		; this is never referenced
		mov	softramenabled, 1	; this is never referenced
		jmp	softraminisucc		; everything went fine

		; init failed - zero everything

softraminitfail:
		mov	neverused3, 0	
		mov	pagesgrabbed, 0
		mov	bufferbase, 0
		mov	neverused4, 0
		mov	headerbase, 0
		mov	lastoffset, 0
		mov	writeoffset, 0
		mov	neverused1, 0
		mov	neverused2, 0
		mov	buffertail, 0
		mov	bufferhead, 0
		mov	fkcompresstail, 0
		mov	fcompresshead, 0
		mov	headerlen, 0
		mov	maxpfoffset, 0
		mov	softramenabled, 0

		; init succeeded

softraminitsucc:
		popad
		mov	eax, DDKVar
		mov	ebx, DDKVar
		clc
		retn

pageingoff:
		mov	DDKVar,0
		mov	byte ptr B32EC,1
		jmp	softraminitsucc


