%include "util.mac"
%include "icedump.inc"
%include "vxdn.inc"
%include "wiat.inc"


global Parse_Dump
global Service_Dump
global Parse_Dump.EmodeFileName
global Parse_Dump.EmodeExtPtr


extern sdata
extern Parser.error
extern Parser.errorMsg
extern OD_TOGGLE_EXPERT_MODE.Emode
extern EmodeSub.IncDumpNum
extern SetCB
extern IsPageCommitted
extern ParseAddress
extern ParseExpression


bits 32


;-------------------------------------------------------------------------------
; DUMP <address> [<length> <file name>]
;-------------------------------------------------------------------------------
segment _LTEXT
Parse_Dump:
	mov	edi,.Error_BadAddress
	call	ParseAddress		; parse <address>
	jb	near Parser.errorMsg

	mov	ebx,eax			; ebx = start address of block

	call	[pSkipWhiteSpace]	; skip to <length>
	setnz	cl			; cl = new behaviour
	jz	@F			; length was not specified

	mov	edi,.Error_BadLength
	call	ParseExpression		; parse <length>
	jb	near Parser.errorMsg

@@
	mov	ebp,[dClient_EDI]	; store start address of block
	mov	[ebp],ebx

	test	cl,cl
	jz	.emulate		; let's emulate the old behaviour

	mov	dl,byte [OD_TOGGLE_EXPERT_MODE.Emode]
	cmp	dl,'E'			; see if in expert mode	
	jne	.modeD

	mov	ebp,[dClient_ECX]	; store length of block
	mov	[ebp],eax

	mov	ebp,[dClient_ESI]	; store ptr to filename
	mov	dword [ebp],.EmodeFileName
	add	edi,[.EmodeExtPtr]	; get offset of the extension
	call	EmodeSub.IncDumpNum
	jmp	.setCB

.modeD:
	call	[pSkipWhiteSpace]	; skip to <file name>
	jnz	@F

.emulate:
	xor	eax,eax			; zero length, old PAGEIN is emulated
	xor	esi,esi			; no filename, old PAGEIN is emulated

@@
	mov	ebp,[dClient_ESI]	; store pointer to file name
	mov	[ebp],esi

	mov	ebp,[dClient_ECX]	; store length of block
	mov	[ebp],eax

.setCB:
	push	byte SERVICE_DUMP
	mov	ebp,[dClient_EAX]
	pop	dword [ebp]

	call	SetCB

	mov	ebp,[fExecuteMoreCommands]	; set internal Winice flag to 0
	mov	byte [ebp],0

	popad
	retn


segment _LDATA
.Error_BadAddress	db 'invalid address.',0
.Error_BadLength	db 'invalid length.',0

.EmodeViewFilename:	db 'Current auto-dump filename: '
.EmodeFileName:		db 'C:\MEMDUMP.00/',0		; watch out for .EmodeExtPtr

; this should padd up to OPT_EMODE_FILENAMELEN and leave extra space
; for dump-number
TIMES OPT_EMODE_FILENAMELEN-($-.EmodeFileName)+1+OPT_EMODE_NUMLEN	db 0

.EmodeExtPtr:	dd 11


;-------------------------------------------------------------------------------
; this is the actual dumper code that's executed in ring-0.
;-------------------------------------------------------------------------------
segment _LTEXT
Service_Dump:
	mov	esi,[ebp+CRS.ESI]	; get pointer to file name
	test	esi,esi			; emulate old PAGEIN?
	jz	.emulate

	mov	eax,R0_OPENCREAT_IN_CONTEXT
	mov	ebx,0x2012		; read/write|share:deny all|no INT24
;	mov	ecx,0x20		; archive
	movzx	ecx,bh
;	mov	edx,0x12		; replace/open|create
	movzx	edx,bl
	VxDCall	IFSMgr_Ring0_FileIO
	jb	.return

	mov	ebx,eax			; store file handle

.emulate:
	mov	esi,[ebp+CRS.EDI]	; get start address of block

.loop:
	mov	edi,esi
	shr	edi,12			; get current page number
	mov	eax,edi			; save page number for later use
	inc	edi			; get next page number
	shl	edi,12			; get linear start address of next page
	sub	edi,esi			; get length of block on current page
	mov	ecx,[ebp+CRS.ECX]	; get remaining length
	cmp	edi,ecx			; EDI: bytes to dump from current page
	ja	@F

	mov	ecx,edi			; dump from one page at a time

@@
	call	IsPageCommitted
	jz	.skipPage

	mov	al,[esi]		; PAGEIN!

	jecxz	.return			; emulate old PAGEIN?

	mov	eax,R0_WRITEFILE_IN_CONTEXT
	push	ebx			; save file handle
	mov	edx,esi
	sub	edx,[ebp+CRS.EDI]	; EDX: absolute file pointer
	VxDCall	IFSMgr_Ring0_FileIO
	pop	ebx			; restore file handle
	jb	.close

	mov	ecx,eax			; never seen them being different...

	debug_start debugflags, ICEDUMP_DEBUG_FILEIO
	Trace_Out "ICEDUMP: R0_WRITE eax:#eax ecx:#ecx"
	debug_end

.skipPage:
	jecxz	.return			; emulate old PAGEIN?

	add	esi,ecx
	sub	[ebp+CRS.ECX],ecx	; are we done?
	jnz	.loop

.close:
	mov	eax,R0_CLOSEFILE
	VxDCall	IFSMgr_Ring0_FileIO

.return:
	popfd
	popad
	retn				; client will return to an INT3
