;    File              : $STACKS.ASM$
;
;    Description       :
;
;    Original Author   : DIGITAL RESEARCH
;
;    Last Edited By    : $CALDERA$
;
;-----------------------------------------------------------------------;
;    Copyright Work of Caldera, Inc. All Rights Reserved.
;      
;    THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL,
;    PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC.
;    ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES
;    WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
;    THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO
;    HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE
;    AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE
;    AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED,
;    COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED,
;    CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST,
;    TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF
;    CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT
;    AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND
;    CIVIL LIABILITY.
;-----------------------------------------------------------------------;
;
;    *** Current Edit History ***
;    *** End of Current Edit History ***
;
;    $Log$
;    STACKS.ASM 1.6 93/10/26 19:08:13
;    Fix bug when we run out of stacks
;    STACKS.ASM 1.4 93/09/02 22:36:47
;    Add header to system allocations
;    ENDLOG

CGROUP	group	INITCODE, STACKS

STACKS		segment	public para 'STACKS'

	Assume	CS:STACKS, DS:Nothing, ES:Nothing, SS:Nothing

StackCode:

;************
; FIXED DATA
;************

        dw  0       
NumOfStacks	dw	0		; we have this many stacks
StackCB		dw	0		; NumOfStacks*8 = size of control array
StackSize       dw	0		; size of an individual stack
StackPtr	label dword		; pointer to stack data		
StackOff	dw	offset STACKS:StackHeap
StackSeg	dw	0
FirstStack	dw	offset STACKS:StackHeap
LastStack	dw	offset STACKS:StackHeap-STACK_CB_SIZE
NextStack	dw	offset STACKS:StackHeap-STACK_CB_SIZE

;************
; FIXED DATA
;************

STACK_CB_FLAGS	equ	word ptr 0	; stack flags
STACK_CB_SP	equ	word ptr 2	; old stack saved here
STACK_CB_SS	equ	word ptr 4
STACK_CB_TOP	equ	word ptr 6	; stack top lives here
STACK_CB_SIZE	equ	8

STACK_FREE	equ	0		; stack is available to allocate
STACK_INUSE	equ	1		; stack is in use
STACK_OVERFLOW	equ	2		; stack has overflowed

;
; Our hardware interrupt handlers which are of the form
;
;	call	SwapStack
;	db	0EAh			; JMPF opcode
;	dd	oldIntHandler
;
; By looking at the near return address we can find the address of the old
; interrupt handler.
; We try to allocate a stack from our pool of stacks, working downward to
; reduce the problems of stack overflow.
;
; We check the top of the stack contains a pointer to our control block and
; if this is invalid we assume the stack has overflowed, and try the next one.
; We have no way of recovering a stack that has overflowed (eg. by zapping
; everything below us on exit).
;
; If we run out of stacks we just continue on the callers stack, rather than
; halting the system.
;

Int02:
	call	SwapStack
	db	0EAh		; JMPF
i02Off	dw	4*02h,0

Int08:
	call	SwapStack
	db	0EAh		; JMPF
i08Off	dw	4*08h,0

Int09:
	call	SwapStack
	db	0EAh
i09Off	dw	4*09h,0

Int0A:
	call	SwapStack
	db	0EAh		; JMPF
i0AOff	dw	4*0Ah,0

Int0B:
	call	SwapStack
	db	0EAh		; JMPF
i0BOff	dw	4*0Bh,0

Int0C:
	call	SwapStack
	db	0EAh		; JMPF
i0COff	dw	4*0Ch,0

Int0D:
	call	SwapStack
	db	0EAh		; JMPF
i0DOff	dw	4*0Dh,0

Int0E:
	call	SwapStack
	db	0EAh		; JMPF
i0EOff	dw	4*0Eh,0

Int70:
	call	SwapStack
	db	0EAh		; JMPF
i70Off	dw	4*70h,0

Int72:
	call	SwapStack
	db	0EAh		; JMPF
i72Off	dw	4*72h,0

Int73:
	call	SwapStack
	db	0EAh		; JMPF
i73Off	dw	4*73h,0

Int74:
	call	SwapStack
	db	0EAh		; JMPF
i74Off	dw	4*74h,0

Int76:
	call	SwapStack
	db	0EAh		; JMPF
i76Off	dw	4*76h,0

Int77:
	call	SwapStack
	db	0EAh		; JMPF
i77Off	dw	4*77h,0

SwapStack proc near
; On Entry:
;	As per INT except word on stack from near call, which gives old vector
; On Exit:
;	None
;
	cli				; just in case
	push	bp
	push	si			; save work registers
	mov	si,cs:NextStack		; start looking here for a stack
SwapStack10:
	cmp	cs:STACK_CB_FLAGS[si],STACK_FREE
	 jne	SwapStack20		; use this stack if possible
	mov	bp,cs:STACK_CB_TOP[si]	; get the top of this stack
	cmp	si,cs:word ptr [bp]	; does the check match ?
	 jne	SwapStack20		; no, try the next one
	mov	cs:NextStack,si		; remember where we are
	mov	cs:STACK_CB_FLAGS[si],STACK_INUSE
	mov	cs:STACK_CB_SS[si],ss	; save old stack
	mov	cs:STACK_CB_SP[si],sp

	mov	bp,sp
	xchg	bx,ss:word ptr 4[bp]	; BX = return address, BX saved

	mov	bp,cs
	mov	ss,bp
	mov	sp,cs:STACK_CB_TOP[si]	; switch stacks
	pushf
	call	cs:dword ptr 1[bx]	; fake an INT to old handler
	mov	ss,cs:STACK_CB_SS[si]
	mov	sp,cs:STACK_CB_SP[si]	; swap back to the original stack
	mov	cs:STACK_CB_FLAGS[si],STACK_FREE
	mov	cs:NextStack,si		; update in case we were nested
	pop	si			; restore registers
	pop	bp
	pop	bx			; (was return address, now saved BX)
	iret				; exit interrupt handler

SwapStack20:
	sub	si,STACK_CB_SIZE	; it's not, so try the next
	cmp	si,cs:FirstStack	;  if there is one
	 jae	SwapStack10
	pop	si			; restore registers
	pop	bp
	ret				; back to JMPF as we can't swap stacks

SwapStack endp

i19Table dw	4*02H, offset STACKS:i02Off
	dw	4*08H, offset STACKS:i08Off
	dw	4*09H, offset STACKS:i09Off
	dw	4*0AH, offset STACKS:i0AOff
	dw	4*0BH, offset STACKS:i0BOff
	dw	4*0CH, offset STACKS:i0COff
	dw	4*0DH, offset STACKS:i0DOff
	dw	4*0EH, offset STACKS:i0EOff
	dw	4*70H, offset STACKS:i70Off
	dw	4*72H, offset STACKS:i72Off
	dw	4*73H, offset STACKS:i73Off
	dw	4*74H, offset STACKS:i74Off
	dw	4*76H, offset STACKS:i76Off
	dw	4*77H, offset STACKS:i77Off
	dw	0

Int19:
; Trap the Int 19 reboot and restore any hardware vectors we have hooked
	cli
	cld
	xor	ax,ax
	mov	es,ax		; ES = interrupt vectors
	push	cs
	pop	ds
	lea	si,i19Table	; DS:SI -> table to restore
Int1910:
	lodsw
	xchg	ax,di		; ES:DI -> address to restore to
	lodsw
	xchg	ax,si		; CS:SI -> value to restore
	movsw
	movsw
	xchg	ax,si		; restore position in table
	cmp	ds:word ptr [si],0
	 jne	Int1910
	db	0EAh		; JMPF
i19Off	dw	4*19h,0

	even				; word align our stacks

StackHeap label	word			; dynamically build stack CB's here

RELOCATE_SIZE	equ	($ - StackCode)

STACKS		ends

INITCODE	segment public para 'INITCODE'

	Assume	CS:CGROUP, DS:CGROUP, ES:Nothing, SS:Nothing

	extrn	alloc_hiseg:near

	Public	InitStacks
;==========
InitStacks:
;==========
; On Entry:
;	CX = number of stacks
;	DX = size of stack
;	Values are checked
; On Exit:
;	None
;
	push	ds
	push	es
	inc	dx			; let's ensure stacks are WORD
	and	dx,0FFFEh		;  aligned...
	mov	NumOfStacks,cx
	mov	StackSize,dx
	mov	ax,STACK_CB_SIZE
	mul	cx			; AX = bytes in control area
	mov	StackCB,ax
	add	LastStack,ax
	add	NextStack,ax
	add	StackOff,ax		; adjust our pointers
	xchg	ax,cx			; AX = NumOfStacks
	mul	StackSize		; AX bytes are required for stacks
	add	ax,StackOff		; add to start of stacks
	push	ax			; save length in bytes
	add	ax,15			; allow for rounding
	mov	cl,4
	shr	ax,cl			; convert it to para's
	mov	dl,'S'			; allocation signature is Stacks
	call	alloc_hiseg		; allocate some memory
	pop	cx			; CX = length in bytes
	mov	StackSeg,ax		; remember where
	mov	es,ax
			Assume ES:STACKS
	xor	di,di
	mov	al,0CCh			; fill stacks with CC for debug
	rep	stosb
	xor	di,di
	mov	si,offset CGROUP:StackCode
	mov	cx,RELOCATE_SIZE
	rep	movsb			; relocate the code

	mov	bx,FirstStack		; lets start building the CB's
	mov	cx,NumOfStacks
	lds	si,StackPtr		; SI = bottom of stack area
			Assume DS:STACKS
	sub	si,WORD			; we want the word below top of stack
InitStacks10:
	add	si,StackSize		; SI = top of stack
	mov	ds:STACK_CB_FLAGS[bx],STACK_FREE
	mov	ds:STACK_CB_TOP[bx],si	; set top of stack
	mov	ds:word ptr [si],bx	; set backlink
	add	bx,STACK_CB_SIZE	; onto next control block
	loop	InitStacks10
			
	xor	ax,ax
	mov	ds,ax
			Assume DS:Nothing
	cli
	mov	si,offset CGROUP:iTable	; now we fixup the vectors
InitStacks20:
	mov	ax,cs:word ptr 0[si]	; ES:AX = entry point
	mov	di,cs:word ptr 2[si]	; ES:DI = fixup location
	mov	bx,es:word ptr [di]	; get the vector to fixup
	xchg	ax,ds:word ptr [bx]	; set entry offset while saving
	stosw				;  previous handler offset
	mov	ax,es
	xchg	ax,ds:word ptr 2[bx]	; now the segment
	stosw
	add	si,2*WORD		; onto next entry
	cmp	cs:word ptr 0[si],0	; (zero terminated)
	 jnz	InitStacks20
	sti
InitStacks30:
	pop	es
	pop	ds
	ret

iTable	dw	offset STACKS:Int02, offset STACKS:i02Off
	dw	offset STACKS:Int08, offset STACKS:i08Off
	dw	offset STACKS:Int09, offset STACKS:i09Off
	dw	offset STACKS:Int0A, offset STACKS:i0AOff
	dw	offset STACKS:Int0B, offset STACKS:i0BOff
	dw	offset STACKS:Int0C, offset STACKS:i0COff
	dw	offset STACKS:Int0D, offset STACKS:i0DOff
	dw	offset STACKS:Int0E, offset STACKS:i0EOff
	dw	offset STACKS:Int70, offset STACKS:i70Off
	dw	offset STACKS:Int72, offset STACKS:i72Off
	dw	offset STACKS:Int73, offset STACKS:i73Off
	dw	offset STACKS:Int74, offset STACKS:i74Off
	dw	offset STACKS:Int76, offset STACKS:i76Off
	dw	offset STACKS:Int77, offset STACKS:i77Off
	dw	offset STACKS:Int19, offset STACKS:i19Off
	dw	0

INITCODE	ends

	end
