;
; GRDB
;
; Copyright(c) LADsoft
;
; David Lindauer, camille@bluegrass.net
;
;
; mtrap.asm
;
; Function: handle the all traps.  Int 3 and Int 1 are debug traps and
; are handled specially
	;MASM MODE
	.model small
	.386

	.stack 1024

include iversion.inc
include  eprints.inc 
include  eregs.inc 
include  einput.inc 
include  ebreaks.inc 
include	 eenv.inc
include  eloader.inc
include  elogging.inc
include  edos.inc
include  eMemory.inc
include  eints.inc
include  eexec.inc
include eoptions.inc
include eloader.inc
include ehistory.inc
include eswift.inc
include efp.inc
include ehbreak.inc

	public  entry3,indos,entry1
	PUBLIC	RegdumpFLAGS,RegdumpEAX,RegdumpEBX,RegdumpECX,RegdumpEDX
	PUBLIC	RegdumpESI,RegdumpEDI,RegdumpEBP
	PUBLIC	RegdumpESP,RegdumpEIP
	PUBLIC	RegdumpCS,RegdumpES,RegdumpDS,RegdumpSS,RegdumpFS,RegdumpGS
	PUBLIC	TrapHandler, _exit, psp
	PUBLIC  reentry, grdbname, veclist, entry1
	PUBLIC	stackseg,stackofs, dosver

	extrn checkcpu : PROC, FileLoadErr : PROC, trapcount : dword
        extrn ReTrap : PROC
	EXTRN	initflatreal:PROC, rundownflatreal : PROC
;
; CPU instruction trap enable flag
;
TRAPFLAG = 100h

	.data
stackofs	dw	0	;to restore out stack in INT1
stackseg	dw	0
;
; Register image
;
veclist	db	00h
	dw	entry0
	db	1
	dw	entry1
	db	3
	dw	entry3
	db	1bh
	dw	int1bh
	db	20h
	dw	int20handle
	db	21h
	dw	int21handle
	db	0ffh	; trailer
RegdumpFLAGS	dd	0
RegdumpEAX	dd	0
RegdumpEBX	dd	0
RegdumpECX	dd	0
RegdumpEDX	dd	0
RegdumpESI	dd	0
RegdumpEDI	dd	0
RegdumpEBP	dd	0
RegdumpESP	dd	0
RegdumpEIP	dd	0
RegdumpCS	dw	0
RegdumpES	dw	0
RegdumpDS	dw	0
RegdumpSS	dw	0
RegdumpFS	dw	0
RegdumpGS	dw	0
;
dosver	dw	0
haserr	dw	0	; If there is an error# on stack
errnum	dw	0	; The error#
trapnum	dw	0	; The trap#
indos	dd	0	; pointer to indos flag
grdbname	db	'********',0
psp	dw	0	;debugger PSP
neederr	db	0	;flag for file load result from command line

trappop	dd	6790h	;traps that need to pop a value

	.code
cpuerr	db	"GRDB requires a 386 or better processor",0
memerr	db	"not enough memory/corrupt arena",0
vererr	db	"GRDB requires MSDOS 4.0 or better"
nomsg	db	0

;This macro generates a front end for the interrupt handlers installed for
;int 0, 1 and 3.

entry	macro	num
	local	est
entry&num:
if num EQ 1
	call	hdwechk
	jc	est
	call	swiftrace
ENDIF
IF num EQ 3
	call	swiftrace
ENDIF
est:
	push	gs
	push	fs
	push	es
	push	ds
	pushad
	mov	al,num
	jmp	traphandler
endm

	entry	0
	entry	1
	entry	3
	
;
; Save an image of the regs
; This MUST BE the first thing the trap handler calls; it assumes
; there is ONE PUSH (return address) followed by the DS at the time
; of interrupt followed by the interrupt data
;
saveregs	PROC
	pop	cx	
	pop	[RegdumpEDI]
	pop	[RegdumpESI]
	pop	[RegdumpEBP]
	pop	eax
	pop	[RegdumpEBX]
	pop	[RegdumpEDX]
	pop	[RegdumpECX]
	pop	[RegdumpEAX]
	pop	[RegdumpDS]
	pop	[RegdumpES]
	pop	[RegdumpFS]
	pop	[RegdumpGS]
	bt	[haserr],0	; See if an error
	jnc	short noerr	;
	pop	eax		; Get the error #
	mov	[errnum],ax	;
noerr:
	pop	word ptr [RegdumpEIP]
	pop	[RegdumpCS]
	pop	word ptr [RegdumpFLAGS]
	mov	ax,ss		; Otherwise just save the current
	mov	[RegdumpSS],ax	; stack pointer before we started pushing
	mov	[RegdumpESP],esp	;
	jmp	cx
saveregs	ENDP	
;
; Adjust EIP to the trap if it's not int 3
;
adjusteip	PROC	
	cmp	[trapnum],3	; See if int 3
	jnz	short noadj	; No, get out
	mov	ebx,[RegdumpEIP]	;
	mov	fs,[RegdumpCS]	;
	cmp	BYTE PTR fs:[bx-1],0cch ; See if is an INT 3
	jz	short nodecrement ; Get out if so
	dec	word ptr [RegdumpEIP]		; Else point at trap
nodecrement:
noadj:
	ret
adjusteip	ENDP	
;
; Generic trap handler
;
traphandler	PROC
	cld
	sti
	mov	bx,dgroup
	mov	ds,bx
	mov	es,bx
	mov	[CtrlBrkPressedInDOS],0
	movzx	eax,al
	mov	[trapnum],ax
	bt	[trappop],eax
	jnc	noerr2
	inc	[haserr]	; Set the error flag
noerr2:
	mov	si,offset veclist
	call	ReleaseRMInts
	call	saveregs	; Save Regs
	and	[RegdumpFLAGS],NOT TRAPFLAG ; reset trap flag in flags image
	mov	ss,[stackseg]	; load our stack
	movzx	esp,[stackofs]	; clear top of ESP just in case...
	call	disableBreaks	; Disable breakpoints if not
	call	adjusteip	; Adjust the EIP to point to the breakpoint
	call	SetDebugPSP
	call	crlf
	cmp     [trapnum],3	; No stats if it is int 3
	jz	short reentry	;
	cmp	[trapnum],1	; Or int 1
	jz	short reentry	;
	PRINT_MESSAGE	<'Trap: '>
	mov	ax,[trapnum]	; Say which one
	call	printbyte	;
	call	crlf
	btr	[haserr],0	; If has error 
	jnc	reentry		;
	PRINT_MESSAGE	<'Error: '>
	mov	ax,[errnum]	; Say which one
	call	printword
	call	crlf
; fall through
traphandler ENDP
reentry	PROC
	call	DisplayRegisters; Display registers
	test	[trapcount],-1
	jz	noretrace
	dec	[trapcount]
	jmp	ReTrap
noretrace:
	call	initflatreal
	test	[neederr],-1
	jz	InputHandler
	mov	ah,[neederr]
	mov	[neederr],0
	sahf
	call	FileLoadErr
	jmp	InputHandler	; Go do input

reentry	ENDP	
;
; Monitor init routine, point all traps to point to the monitor handler
;

start:
	mov	bx,dgroup	; setup
	mov	ds,bx
	mov	[psp],es	; our PSP
	mov	es,bx		;set ES to DX
	mov	ax,ss		; have to adjust stack to be DS-relative
	sub	ax,bx		; the disassembler requires it
	shl	ax,4		;to segment
	add	ax,sp		;add in the stack pointer
	mov	ss,bx		;set SS to DS
	mov	sp,ax		;and new stack based on DS
	mov	[stackseg],ss
	mov	[stackofs],sp
	PRINT_MESSAGE	<"GRDB version ",30h +VERID/10,'.',30h + VERID MOD 10, " Copyright (c) LADsoft",13,10>
	mov	ah,30h				; dos version check
	int	21h
	cmp	al,4
	mov	dx,offset cs:vererr
	jc	errx
	xchg	ah,al
	mov	[dosver],ax
	push	es    				; get indos flag
	mov	ah,34h	
	int	21h
	mov	word ptr [indos],bx
	mov	word ptr [indos+2],es
	pop	es
	call	checkcpu			; validate CPU
	mov	dx,offset cs:cpuerr
	jc	errx
IFNDEF TEST1
	call	ResizeMem			; cut mem back
	mov	dx,offset cs:memerr
	jc	errx
	call	IntSnapshot			; grab the ints so we can
						; restoire context later
	mov	dx,offset cs:memerr
	jc	errx2
	mov	si,offset grdbname	; create data spaces for
	call	MakeEmptyProg			; empty prog
	mov	dx,offset cs:memerr
	jc	errx2
	call	ReadOptions			; read the options disk file
	call	FloatCheck			; check for an FP coprocessor

	push	ds				; parse command line params
	mov	ds,[psp]
	mov	si,81h
	call	ParseProgName
	pop	ds
	test	[loadfile],-1			; load program
	jz	dohist
	sub	ax,ax
	call	LoadProgram			; load the program
	lahf
	mov	[neederr],ah
dohist:
	test	[opthist],0ffh			; init history
	jz	reentry
	call	LoadHistory
ENDIF
	jmp	reentry				; get us started
;
; program exit
;
_exit:
IFNDEF TEST1
	call	KillFiles			; close files they opened
	call	CloseLogFile			; close our log file
	call	rundownflatreal			; no more flat real mode
	mov	dx,offset cs:nomsg
ENDIF
errx2:
IFNDEF TEST1
	push	dx
	call	UnLoadInts			; unload int vects
	call	ReleaseMemory			; release any memory tagged
						; to them
	call	ReleaseDebugMem			; release any memory tagged
						; to us
	call	WriteOptions			; write options file
	pop	dx
ENDIF
errx:
	mov	bx,dx
	call	olMessage
	mov	bx,0				; close the input file
	mov	ah,3eh
	int	21h
	mov	ax,4c00h
	int	21h

	END	start