;
; EXCEP32.ASM (c) Rainer Schnitker 92,93
;

; contains:
;
; Exception handler entry
; Ints that came from real-mode
; Other utils
;

	INCLUDE REGS386.INC

	.386P


DGROUP	group _DATA

IFDEF	__WASM__
	MYEXCEP13	  equ myexcep13_
	SWAPPER 	  equ swapper_
	extrn myexcep13_:near		; C-func:exception hander
	extrn swapper_:near
ELSE
	MYEXCEP13	  equ _myexcep13
	BACK_FROM_SYSCALL equ _back_from_syscall
	SWAPPER 	  equ _swapper
	extrn _myexcep13:near		; C-func:exception hander
	extrn _swapper:near
ENDIF
	extrn _back_from_syscall:near

_DATA	segment word public 'DATA' use16

	extrn _code16sel:word		;  16 bit selectors
	extrn _data16sel:word		;
	extrn _stack16sel:word		;
	extrn _stackp16:dword		;  16 bit stackpointer

	extrn _npz:PROCESS		;  current process
	extrn _regf:REG386		;  regs for exceptions
	extrn _reg_info:REGEXCEPT10	;  ext. exception info

	public _time_tic
	public _cbrkcall
	_time_tic		dd	0
	_cbrkcall		dw	0

	dpmiss			dw	?
	dpmiesp 		dd	?

_DATA	ends

_TEXT segment dword public 'CODE' use16
	assume	cs:_TEXT,ds:DGROUP


	public _extender_ds
	_extender_ds		dw	?
	fill_ds 		dw	?


	public _load_ds
_load_ds proc near		; load our extender ds
	push	cs:[_extender_ds]
	pop	ds
	ret
_load_ds endp

	public _clearregs
_clearregs proc near				; clear high bits
	and	eax, dword ptr 0ffffH		; for 16 bit code
	and	ebx, dword ptr 0ffffH
	and	ecx, dword ptr 0ffffH
	and	edx, dword ptr 0ffffH
	and	esi, dword ptr 0ffffH
	and	edi, dword ptr 0ffffH
	and	ebp, dword ptr 0ffffH
	ret
_clearregs endp

; this proc is called after exception handler return from DPMI-server
; cs:eip and ss:esp set
exception_after_return proc near	; called after FAR-RET from exception
	mov	ax, ss			; get extender ds
	mov	ds, ax
	mov	es, ax			; ds = es = ss

	call	_clearregs
	call	MYEXCEP13

	jmp	_back_from_syscall
exception_after_return endp

; EXCEPTIONS
;
;  DPMI-rules:
; - return with far return , org SS:ESP,CS:EIP,EFLAGS(i-flag!) will restored
;   (note: iret doesn't restore i-flag, because IOPL < DPL )
; - all fault have error code (only valid for 08,0A-0E)
; - handler must preserve and restore all registers
; - handler will be called on a locked stack with interrupts disabled
; - handler must return or jump to the next handler
; - handler can modify exception stack, but not return cs,eip
;   it must return to the orginal handler
; - called only for protected mode exceptions
;
;	 exception STACK
;	   0 : ebp  (our,not default)
;	   4 : return eip (to host)
;	   8 : return cs  (to host)
;	  12 : error
;	  16 : EIP (orginal)
;	  20 : CS (orginal)
;	  24 : Eflags
;	  28 : ESP
;	  32 : SS

align 4
	public _excep13_386
_excep13_386 proc far
	push	word ptr 13
	jmp	short exceptionhandler

public _excep14_386
_excep14_386:
	push	word ptr 14
	jmp	short exceptionhandler

public _excep0_386
_excep0_386:
	push	word ptr 0
	jmp	short exceptionhandler

public _excep1_386
_excep1_386:
	push	word ptr 1
	jmp	short exceptionhandler

public _excep2_386
_excep2_386:
	push	word ptr 2
	jmp	short exceptionhandler

public _excep3_386
_excep3_386:
	push	word ptr 3
	jmp	short exceptionhandler

public _excep4_386
_excep4_386:
	push	word ptr 4
	jmp	short exceptionhandler

public _excep5_386
_excep5_386:
	push	word ptr 5
	jmp	short exceptionhandler

public _excep6_386
_excep6_386:
	push	word ptr 6
	jmp	short exceptionhandler

public _excep7_386
_excep7_386:
	push	word ptr 7
	jmp	short exceptionhandler

public _excep8_386
_excep8_386:
	push	word ptr 8
	jmp	short exceptionhandler

public _excep9_386
_excep9_386:
	push	word ptr 9
	jmp	short exceptionhandler

public _excep10_386
_excep10_386:
	push	word ptr 10
	jmp	short exceptionhandler

public _excep11_386
_excep11_386:
	push	word ptr 11
	jmp	short exceptionhandler

public _excep12_386
_excep12_386:
	push	word ptr 12
	jmp	short exceptionhandler

public _excep15_386
_excep15_386:
	push	word ptr 15
	jmp	short exceptionhandler

public _excep16_386
_excep16_386:
	push	word ptr 16
	jmp	short exceptionhandler

public _excep17_386
_excep17_386:
	push	word ptr 17
	jmp	short exceptionhandler

align 4
exceptionhandler:
	push	ds				; save user ds
	call	_load_ds			; we need our extender ds

	mov	dword ptr DGROUP:_regf.REG_EAX, eax
	mov	dword ptr DGROUP:_regf.REG_EBX, ebx
	mov	dword ptr DGROUP:_regf.REG_ECX, ecx
	mov	dword ptr DGROUP:_regf.REG_EDX, edx
	mov	dword ptr DGROUP:_regf.REG_EBP, ebp
	mov	dword ptr DGROUP:_regf.REG_EDI, edi
	mov	dword ptr DGROUP:_regf.REG_ESI, esi
	mov	word ptr DGROUP:_regf.REG_ES , es
	mov	word ptr DGROUP:_regf.REG_FS , fs
	mov	word ptr DGROUP:_regf.REG_GS , gs

	pop	ax
	mov	word ptr DGROUP:_regf.REG_DS, ax
	pop	ax
	mov	word ptr DGROUP:_regf.REG_FAULTNO, ax

	; the rest regs are on stack
	push	ebp
	mov	ebp, esp

	; get error code from stack
	mov	eax,dword ptr [ebp+12]
	mov	dword ptr DGROUP:_regf.REG_ERR, eax

	; get eip from stack
	mov	eax,dword ptr [ebp+16]
	mov	dword ptr DGROUP:_regf.REG_EIP, eax

	; get cs from stack
	mov	eax,dword ptr [ebp+20]
	mov	dword ptr DGROUP:_regf.REG_CS, eax

	; get eflags from stack
	mov	eax, dword ptr [ebp+24]
	and	ax,0FEFFh				; clear trace flag
	or	ax, 0200h				; set iret flag
	mov	dword ptr DGROUP:_regf.REG_EFLAGS, eax	; else trap after fret
	mov	dword ptr [ebp+24],eax			; back on dpmi-stack

	; get esp from stack
	mov	eax, dword ptr [ebp+28]
	mov	dword ptr DGROUP:_regf.REG_ESP, eax
	mov	dword ptr DGROUP:_regf.REG_ESPORG, eax

	; get ss from stack
	mov	ax,word ptr [ebp+32]
	mov	word ptr DGROUP:_regf.REG_SS, ax

	; set new return address cs:eip
	; to exception_after_return

	xor	eax,eax
	mov	ax,offset exception_after_return
	mov	dword ptr [ebp+16], eax 		; set new eip

	mov	ax,cs					; bzw _code16sel
	mov	word ptr [ebp+20],ax			; set cs


	; set new ss:esp
	; to our C gp_fault handler

	mov	si, word ptr DGROUP:_npz	; load process ptr
	mov	eax, dword ptr [si].kstack
	mov	dword ptr [ebp+28],eax		; set esp

	mov	ax,ds				; bzw _stack16sel
	mov	word ptr [ebp+32],ax		; set ss

	pop ebp

	; restore changed regs
	mov	esi, dword ptr DGROUP:_regf.REG_ESI
	mov	eax, dword ptr DGROUP:_regf.REG_EAX
	push	word ptr _regf.REG_DS
	pop	ds

	db 066H 				; we need 16:32 bit return
	retf
_excep13_386 endp

;
; EXCEPTIONS DPMI 1.0
;
; extended info at esp + 32
;	  32 : ebp  (our,not default)
;	  36 : return eip (to host)
;	  40 : return cs  (to host)
;	  44 : error code
;	  48 : EIP (orginal)
;	  52 : CS (orginal)
;	  56 : EFLAGS
;	  60 : ESP
;	  64 : SS
;	  68 : DS
;	  72 : ES
;	  76 : FS
;	  80 : GS
;	  84 : CR2
;	  88 : PTE

;
; only page fault (exception 14) use this
;
public _page_fault
_page_fault	proc  far
	push	ebp
	mov	ebp, esp
	push	ds
	push	es
	pushad

	call	_load_ds				; get:
	mov	eax, dword ptr [ebp+44] 		; error code
	mov	dword ptr DGROUP:_reg_info.RE_ERR, eax
	mov	eax, dword ptr [ebp+48] 		; EIP
	mov	dword ptr DGROUP:_reg_info.RE_EIP, eax
	movzx	eax, word ptr [ebp+52]			; CS
	mov	dword ptr DGROUP:_reg_info.RE_CS, eax
	mov	eax, dword ptr [ebp+84] 		; CR2
	mov	dword ptr DGROUP:_reg_info.RE_CR2, eax	;
	mov	eax, dword ptr [ebp+88] 		; PTE
	mov	dword ptr DGROUP:_reg_info.RE_PTE, eax

	mov	dpmiss, ss
	mov	dpmiesp, esp
	mov	ax, ds
	mov	es, ax
	mov	ss, ax
	mov	esp, _stackp16
	mov	ax, 0901h				; enable ints
	int	031h

	call	SWAPPER 				; call swapper
	or	ax, ax					; uncommit fault?
	jz	short @@swapper_return			; yes, return

	mov	ss, dpmiss
	mov	esp, dpmiesp
	popad
	nop
	pop	es
	pop	ds
	pop	ebp
	push	word ptr 14				; no, generic fault
	jmp	exceptionhandler

@@swapper_return:
	mov	ss, dpmiss
	mov	esp, dpmiesp
	popad
	nop
	pop	es
	pop	ds
	pop	ebp

	db 066H 				; we need 16:32 bit return
	retf
_page_fault endp


;
; INTs that came form real mode (timer 0x1C,^C 0x23,crit error 0x24)
;
;  DPMI-rules:
; - handler must return ( don't terminate )
; - interrupts are disabled (?)
; - stack: locked protected mode stack from host (4 KB)
;

; Control-C handler
	public _prot_cbrk
_prot_cbrk   proc    far
	push	ds
	push	si
	call	_load_ds
	mov	word ptr DGROUP:_cbrkcall,1
	mov	si,word ptr DGROUP:_npz     ; load process ptr
	bts	[si].sig_raised,1
	pop	si
	pop	ds

	; iret doesn't restore I-flag
	push	ax
	mov	ax,0901h
	int	031h
	pop	ax

	iretd
	; retfar caused error by qemm/qdpmi
_prot_cbrk   endp


; Timer handler
	public _timer_handler
_timer_handler proc far
	push	ds
	call	_load_ds
	add	dword ptr _time_tic ,1
	pop	ds

	; iret doesn't restore I-flag
	push	ax
	mov	ax,0901h
	int	031h
	pop	ax

	iretd
_timer_handler endp

_TEXT	ends
	end
