	.386p
;************************************************************************/
;*	Copyright (C) 1986-1990 Phar Lap Software, Inc.			*/
;*	Unpublished - rights reserved under the Copyright Laws of the	*/
;*	United States.  Use, duplication, or disclosure by the 		*/
;*	Government is subject to restrictions as set forth in 		*/
;*	subparagraph (c)(1)(ii) of the Rights in Technical Data and 	*/
;*	Computer Software clause at 252.227-7013.			*/
;*	Phar Lap Software, Inc., 60 Aberdeen Ave., Cambridge, MA 02138	*/
;************************************************************************/

;
; This program demonstrates how to call high level language code from 
; within an interrupt handler.  It installs a CTRL-C interrupt handler
; that calls the C library printf() routine to print a string.
;

;
; Constants and data structures
;
include	dosx.ah

;
; Segment definitions and ordering.  No stack segment in this program,
; because the stack is set up by the C initializer before it calls us.
;
_codeseg	segment	byte public use32 'code'
_codeseg	ends
_data		segment	dword public use32 'data'
_data		ends

;
; Global data
;
_data	segment	

	public	pm_ccsel,pm_ccoff,rm_ccvec
rm_ccvec	dd	?	; original real mode CTRL-C vector
pm_ccoff	dd	?	; original protected mode CTRL-C vector
pm_ccsel	dw	?		; 
	align	4

	public	pgm_ss
pgm_ss	dw	?		; program's SS value (including RPL bits;
				; you can't blindly load 0014h into SS if
				; you're running at privilege level 3
	align	4

	public	cc_flag
cc_flag	dd	FALSE		; set TRUE when CTRL-C occurs

	public	cc_tos
	db	4096 dup (?)	; Temp. stack space for CTRL-C handler
cc_tos	label	byte		; Initial top of temp. stack

typecc_msg db	'Please type CTRL-C',0Dh,0Ah,'$'
cc_msg	db	'CTRL-C was typed',0Ah,0	; C-style string
_data	ends

;****************************************************************************
; asm_main() routine called by C main() function
;****************************************************************************

	assume	cs:_codeseg,ds:_data
_codeseg	segment	

	public	asm_main,_asm_main,asm_main_
_asm_main label	near
asm_main_ label	near
asm_main proc	near

	push	ebx			; save non-volatile C regs we modify
	push	es				;
	mov	ax,ss			; save program's SS value (gets correct
	mov	pgm_ss,ax			; RPL bits in selector)

;
; Save current real and protected mode CTRL-C vectors, and install our
; CTRL-C handler so it always gets control in protected mode.  We use
; the 2506h system call to do this, because the CTRL-C interrupt is
; always issued in real mode by DOS.
;
	mov	cl, 23h			; save real mode CTRL-C vector
	mov	ax, 2503h			; 
	int	21h				;
	mov	rm_ccvec, ebx			; 
	mov	ax, 2502h		; save prot mode CTRL-C vector
	mov	cl,23h				;
	int	21h				; 
	mov	pm_ccsel, es			;
	mov	pm_ccoff, ebx			; 
	push	ds			; install our CTRL-C handler to 
	lea	edx, cc_hndlr			; always get control in
	mov	ax, cs				; protected mode
	mov	ds, ax				;
	mov	cl,23h				;
	mov	ax, 2506h			; 
	int	21h				;
	pop	ds				; 

;
; Wait for a CTRL-C to be typed
;
	mov	cc_flag,FALSE		; no CTRL-C yet
	mov	ah, 09h			; print "please type CTRL-C" message
	lea	edx, typecc_msg			;
	int	21h				;
#loop:
	cmp	cc_flag,TRUE		; branch if CTRL-C has been typed
	je	short #done			;
	mov	ah,0Bh			; get input status, to allow DOS to
	int	21h				; generate CTRL-C interrupt
	jmp	#loop			; continue loop

#done:
;
; Restore the original interrupt vectors and exit
;
	mov	cl, 23h			; restore original real mode vector
	mov	ebx, rm_ccvec			; 
	mov	ax, 2505h			;
	int	21h				; 
	push	ds			; restore original prot mode vector
	mov	edx, pm_ccoff			; 
	mov	ax, pm_ccsel			;
	mov	ds, ax				; 
	mov	cl,23h				;
	mov	ax, 2504h			;
	int	21h				; 
	pop	ds				;

	pop	es			; restore registers
	pop	ebx				;
	xor	eax,eax			; return success to caller
	ret					;

asm_main endp

;****************************************************************************
; CC_HNDLR - Protected Mode CTRL-C Handler
;	This handler calls through to the C printf() routine to print 
;	a string saying that CTRL-C occurred, and sets a global flag so
;	the main loop knows that CTRL-C has occurred.
;
;	In order to call a C routine, we must first set up a stack that
;	is in segment 0014h, and also set DS and ES to segment 0014h.
;****************************************************************************

ifdef __MSC32__
c_printf equ	_printf
endif
ifdef __HIGHC__
c_printf equ	printf
endif
ifdef __WATCOMC__
c_printf equ	printf_
endif
	extrn	c_printf:near		; C library routine

	public	cc_hndlr
cc_hndlr	proc	near
;
; This is an interrupt handler, so we must preserve all registers that
; may get modified by us or the C routine we will call.  Also re-enable
; interrupts so hardware interrupts aren't blocked.
;
	sti				; re-enable interrupts
	pushad				; save all registers
	push	ds				;
	push	es				;
	push	fs				;
	push	gs				;

;
; Set up a C environment, including a stack in our data segment, and call
; the C printf() library routine to print a string.
;
; Note the SS selector must have its RPL bits set to the current privilege
; level (unlike DS and ES, where we can just use a hardwired RPL of zero).
;
	mov	ax,SS_DATA		; set DS and ES to our data seg
	mov	ds,ax				;
	mov	es,ax				;
	mov	ecx,esp			; get current stack pointer
	mov	dx,ss				;
	mov	ax,pgm_ss		; switch to stack in data segment
	mov	ss,ax				;
	lea	esp,cc_tos			;
	push	edx			; save old stack pointer on new stack
	push	ecx				;
	lea	eax,cc_msg		; call printf to print string
	push	eax				;
	call	c_printf			;
	add	esp,4				;
	lss	esp,pword ptr [esp]	; switch back to old stack

;
; Set a flag so the main loop knows the CTRL-C occurred, restore registers,
; and return to caller
;
	mov	cc_flag,TRUE		; CTRL-C has been processed
	pop	gs			; restore regs
	pop	fs				;
	pop	es				;
	pop	ds				;
	popad					;
	iretd				; return from interrupt
cc_hndlr	endp

_codeseg	ends

	end
