;
; ADOSX32.ASM (c) Rainer Schnitker 92,93
;
; Entry point for protected mode int 0x21
;

	INCLUDE REGS386.INC
	INCLUDE TRANS.INC

	.386p

DGROUP group _DATA

IFDEF	__WASM__
	INT21		equ int21_
	CHECK_SIGNALS	equ check_signals_
	MYEXCEP13	equ myexcep13_
	extrn int21_:near		; C-function int21 handler
	extrn check_signals_:near	; C-func:check if signals raised
	extrn myexcep13_:near		; C-func:exception hander
ELSE
	INT21		equ _int21
	CHECK_SIGNALS	equ _check_signals
	MYEXCEP13	equ _myexcep13
	extrn _int21:near		; C-function int21 handler
	extrn _check_signals:near	; C-func:check if signals raised
	extrn _myexcep13:near		; C-func:exception hander
ENDIF

	extrn _load_ds:near		; load 16bit extender ds
	extrn _clearregs:near		; clear high bits from 32bit regs

_DATA segment word public 'DATA' use16
	extrn _npz:PROCESS		; pointer to running process
	extrn _regf:REG386		; regs for exceptions
	extrn _cs16real: word		; RM cs segment
	extrn _ds16real: word		; RM ds segment
	extrn _real_mode_stack: word	; RM stack pointer
	td TRANS  <>			; translation struct for dos
_DATA ends

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


; ***************************************

; Entry point for int 0x10

public _bioscall
_bioscall proc far			; INT 0x10 handler entry

not_vesa:
					; jmp to orginal handler (DPMI-host)
	db 066h 	; 32bit
	db 0EAh 	; JMP
public _int10voff			; label for writing in code
_int10voff:
	dd 2		; offset
public _int10vsel			; label for writing in code
_int10vsel:
	dd 1		; selector

_bioscall endp


; **************************************

public _mousecall
_mousecall proc far			 ; INT 0x33 handler entry
	iret
_mousecall endp

; **************************************
; Entry point for int 0x21
; - test default bit from code segment ( 32 or 16 bit )
; - we handle only 32bit-calls
; - all 16bit calls (from our extender) passed to real mode
;   only segment registers are changed
;

public _doscall
_doscall proc far			; INT 0x21 handler entry
	push	eax
	mov	ax, cs			; KERNEL_CS == CS ?
	cmp	[esp+8], ax		; 0:eax,4:eip,8:cs,12:eflags
	pop	eax

	je	short int16bit		; 16bit DOS call from extender

	cmp	ah, 04Ch		; exit call ?
	jne	int32bit		; no, must 32bit user int

	; ah=4Ch: recursive extender instance or 32bit user call ?
	; next instance reset interrupt handler and do int21/0x4c00

	push	eax
	push	si
	push	ds
	call	_load_ds			; load 16 bit extender ds
	mov	si, word ptr _npz		; load process ptr
	mov	eax, [esp+12]			; 0:eax,4:si,ds,8:eip,12:cs
	cmp	ax, word ptr [si].r_cs
	pop	ds
	pop	si
	pop	eax
	je	short int32bit

					; jmp to orginal handler (DPMI-host)
	db 066h 	; 32bit
	db 0EAh 	; JMP
public _int21voff			; label for writing in code
_int21voff:
	dd 2		; offset
public _int21vsel			; label for writing in code
_int21vsel:
	dd 1		; selector



; **************************************
; all 16bit calls assume that this call is equal to a real mode call
; where the segment registers are equal to programs segments
;
; stack: 0=eip 4=cs 8=eflags

int16bit:
	mov	word ptr td.T_EAX, ax	       ; save registers
	mov	word ptr td.T_EBX, bx
	mov	word ptr td.T_ECX, cx
	mov	word ptr td.T_EDX, dx
	mov	word ptr td.T_ESI, si
	mov	word ptr td.T_EDI, di
	mov	word ptr td.T_EBP, bp
	mov	ax, _cs16real			; set RM segments
	mov	word ptr td.T_CS, ax
	mov	ax, _ds16real
	mov	word ptr td.T_DS, ax
	mov	word ptr td.T_ES, ax
	mov	word ptr td.T_SS, ax
	mov	ax, _real_mode_stack		; stack for int
	mov	word ptr td.T_sp, ax

	push	ds				; DPMI call now
	pop	es
	mov	cx, 0				; no stack words
	mov	bh, 0				; flags
	mov	bl, 21h 			; interrupt no
	xor	edi, edi			;
	mov	di, offset DGROUP:td		; es:edi translation
	mov	ax, 0300h
	int	31h				; simulate real-mode int

	movzx	ebp, sp
	mov	ax, word ptr td.T_FLAGS 	; trans -> registers
	mov	word ptr [bp+8], ax
	mov	ax, word ptr td.T_EAX
	mov	bx, word ptr td.T_EBX
	mov	cx, word ptr td.T_ECX
	mov	dx, word ptr td.T_EDX
	mov	si, word ptr td.T_ESI
	mov	di, word ptr td.T_EDI
	mov	bp, word ptr td.T_EBP
	iretd


; **************************************
; here is the 32bit handler
; save all registers, check signals, restore all registers

int32bit:	  ; stack: 0=eip 4=cs 8=eflags

	push	esi
	call	_load_ds			; load 16 bit extender ds
	xor	esi, esi
	mov	si, word ptr DGROUP:_npz	; load process ptr
	pop	dword ptr [si].r_esi		; save ESI

	mov	[si].r_eax, eax 		; EAX
	mov	[si].r_ebx, ebx 		; EBX
	mov	[si].r_ecx, ecx 		; ECX
	mov	[si].r_edx, edx 		; EDX
	mov	[si].r_edi, edi 		; EDI
	mov	[si].r_ebp, ebp 		; EBP
	mov	word ptr [si].r_ds, es		; DS
	mov	word ptr [si].r_es, es		; ES	!assume(es=ds)
	mov	word ptr [si].r_ss, ss		; SS
	mov	word ptr [si].r_fs, fs		; FS
	mov	word ptr [si].r_gs, gs		; GS
	mov	[si].r_esp, esp 		; ESP
	mov	[si].r_esporg, esp		; ESP before int
	add	[si].r_esporg, dword ptr 12	;

	mov	ebp, esp			; others regs are on user stack
	mov	eax, [ebp]			; EIP
	mov	[si].r_eip, eax
	mov	eax, [ebp+4]			; CS
	mov	[si].r_cs, eax
	mov	eax, [ebp+8]			; EFLAGS
	mov	[si].r_eflags, eax

	mov	ax, ds				; make ss=ds=es
	mov	es, ax				; load 16bit es
	mov	ss, ax				; load 16bit ss
	mov	esp, [si].kstack		; load 16bit sp

	call	_clearregs	; clear high bits for our 16bit prg

	call	INT21		; call C-prg handler for int21h

public _back_from_syscall
_back_from_syscall:
	call	CHECK_SIGNALS

	mov	si, word ptr DGROUP:_npz	; load process ptr
	mov	ebx, [si].r_ebx 		; restore old regs
	mov	ecx, [si].r_ecx
	mov	edx, [si].r_edx
	mov	edi, [si].r_edi
	mov	ebp, [si].r_ebp
	mov	ss , word ptr [si].r_ss 	; change ss first
	mov	esp, [si].r_esp 		; restore ss:esp
	mov	es , word ptr [si].r_es
	mov	fs , word ptr [si].r_fs
	mov	gs , word ptr [si].r_gs

	mov	eax, [si].r_eflags		; other regs are on user stack
	mov	[esp+8], eax
	mov	eax, [si].r_cs
	mov	[esp+4], eax
	mov	eax, [si].r_eip
	mov	[esp], eax
	mov	eax, [si].r_eax 		; eax

	push	dword ptr [si].r_esi		; restore esi
	pop	esi

	push	es
	pop	ds				; last segment restore
	iretd
_doscall endp


public _debug_entry
_debug_entry proc far
	push	ds
	call	_load_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_SS , ss
	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

	mov	dword ptr DGROUP:_regf.REG_ESP, esp
	add	dword ptr DGROUP:_regf.REG_ESP, 12
	mov	dword ptr DGROUP:_regf.REG_ESPORG, esp
	add	dword ptr DGROUP:_regf.REG_ESPORG, 12
	mov	word ptr DGROUP:_regf.REG_FAULTNO, 3

	mov	ebp, esp			; others regs are on user stack
	mov	eax, [ebp]			; EIP
	mov	dword ptr DGROUP:_regf.REG_EIP, eax
	mov	eax, [ebp+4]			; CS
	mov	dword ptr DGROUP:_regf.REG_CS, eax
	mov	eax, [ebp+8]			; EFLAGS
	mov	dword ptr DGROUP:_regf.REG_EFLAGS, eax

	mov	si, word ptr DGROUP:_npz	; load process ptr
	mov	edx, [si].kstack
	mov	ax, ds				; make ss=ds=es
	mov	es, ax				; load 16bit es
	mov	ss, ax				; load 16bit ss
	mov	esp, edx			; load 16bit sp

	call	_clearregs
	call	MYEXCEP13

	jmp	_back_from_syscall
_debug_entry endp


public _execute_dpmi_function
_execute_dpmi_function proc near
	pushad
	push	ds
	push	es

	mov	si, word ptr DGROUP:_npz	; load process ptr
	mov	eax, [si].r_eax
	mov	ebx, [si].r_ebx
	mov	ecx, [si].r_ecx
	mov	edx, [si].r_edx
	mov	ebp, [si].r_ebp
	mov	edi, [si].r_edi
	push	word ptr [si].r_ds
	push	word ptr [si].r_es
	mov	esi, [si].r_esi
	pop	es
	pop	ds
	int	031h

	pop	es
	pop	ds
	popad
	nop

	pushf					; save carry
	pop	ax
	and	ax, 1
	ret
_execute_dpmi_function endp


public _save_all
_save_all proc near
	push	bp
	mov	bp, sp
	mov	bx, word ptr [bp+4]
	pusha
	mov	[bx], sp
	leave
	ret
_save_all endp

public _restore_all
_restore_all proc near
	push	bp
	mov	bp, sp
	mov	bx, word ptr [bp+4]
	mov	sp, [bx]
	popa
	leave
	ret
_restore_all endp

public _new_stack_return
_new_stack_return proc near
	mov	bp, sp
	mov	bx, word ptr [bp+2]
	mov	sp, [bx]
	jmp	_back_from_syscall
_new_stack_return endp

_TEXT	ends

	end
