	TITLE	GMOREMEM - More Global Memory Manager procedures

.xlist
include kernel.inc
include tdb.inc
include newexe.inc
include protect.inc
.list

	.286

DataBegin

externB Kernel_Flags
;externW hGlobalHeap
externW pGlobalHeap
externW curTDB
externW headTDB
externW cur_dos_PDB
externW Win_PDB
externW MaxCodeSwapArea

DataEnd

externFP CalcMaxNRSeg

sBegin	CODE
assumes CS,CODE
assumes DS,NOTHING
assumes ES,NOTHING

;externW MyCSDS

if SDEBUG
externNP DebugMovedSegment
endif

;if SWAPPRO
;externNP WriteDiscardRecord
;endif

externNP real_dos
externNP gcompact
externNP get_physical_address
externNP get_arena_pointer
externNP GetAccessWord
externFP CVWBreak
externNP GrowHeap

if LDCHKSUM
externNP ZeroSegmentChksum
endif


;-----------------------------------------------------------------------;
; genter                                                                ;
; 									;
; Enters a critical region for the global heap.				;
; 									;
; Arguments:								;
;	none								;
; 									;
; Returns:								;
;	DS:DI = address of GlobalInfo for global heap			;
; 									;
; Error Returns:							;
; 									;
; Registers Preserved:							;
;	All								;
;									;
; Registers Destroyed:							;
; 									;
; Calls:								;
; 									;
; History:								;
; 									;
;  Mon Sep 29, 1986 03:05:33p  -by-  David N. Weise   [davidw]          ;
; Added this nifty comment block.					;
;-----------------------------------------------------------------------;

cProc	genter,<PUBLIC,NEAR>
cBegin nogen
	SetKernelDS
	mov	ds,pGlobalHeap
	UnSetKernelDS
	xor	di,di
	inc	[di].gi_lrulock
	ret
cEnd nogen


;-----------------------------------------------------------------------;
; gleave                                                                ;
; 									;
; Leaves a critical region for the global heap.				;
; 									;
; Arguments:								;
;	DS:DI = address of GlobalInfo for global heap			;
; 									;
; Returns:								;
; 									;
; Error Returns:							;
; 									;
; Registers Preserved:							;
; 									;
; Registers Destroyed:							;
; 									;
; Calls:								;
; 									;
; History:								;
; 									;
;  Mon Sep 29, 1986 03:07:53p  -by-  David N. Weise   [davidw]          ;
; Added this nifty comment block.					;
;-----------------------------------------------------------------------;

cProc	gleave,<PUBLIC,NEAR>

cBegin nogen
	dec	ds:[gi_lrulock]
	jnz	gl_ret
	test	ds:[gi_flags],GIF_INT2
	jz	gl_ret
	and	ds:[gi_flags],NOT GIF_INT2
	pushf
	call	CVWBreak
gl_ret: ret

cEnd nogen


;-----------------------------------------------------------------------;
; gavail                                                                ;
; 									;
; Gets the available memory.						;
; 									;
; Arguments:								;
;	DX    = number of paragraphs wanted				;
;	DS:DI = master object						;
; Returns:								;
;	AX = #paragraphs available for the biggest block		;
;	DX = 0 								;
;									;
; Error Returns:							;
;	none								;
; 									;
; Registers Preserved:							;
;	DI,DS 								;
; Registers Destroyed:							;
;	BX,CX,SI,ES							;
; Calls:								;
;	gcompact							;
; 									;
; History:								;
;  Thu Apr 06, 1988 08:00:00a  -by-  Tim Halvorsen    [iris]		;
; Fix bug in computation of space available when GA_NOT_THERE object	;
; resides above discard fence.						;
;									;
;  Wed Oct 15, 1986 05:09:27p  -by-  David N. Weise   [davidw]          ;
; Moved he_count to ga_count.						;
; 									;
;  Sat Sep 27, 1986 09:37:27a  -by-  David N. Weise   [davidw]          ;
; Reworked it.								;
;-----------------------------------------------------------------------;

cProc	gavail,<PUBLIC,NEAR>
cBegin nogen
	mov	byte ptr [di].gi_cmpflags,0
	call	gcompact
	mov	es,[di].hi_first
	xor	dx,dx
loop_for_beginning:
	xor	ax,ax
	mov	es,es:[di].ga_next		; Next block
	cmp	es:[di].ga_sig,GA_ENDSIG	; End of arena?
	jnz	blecher
	jmp	all_done
blecher:
	cmp	es:[di].ga_owner,di		; Free?
	jz	how_big_is_it			; Yes
	mov	si,es:[di].ga_handle
	or	si,si				; Fixed?
	jz	loop_for_beginning		; Yes, next block
	cmp	es:[di].ga_count,0		; Locked?
	jne	loop_for_beginning		; Yes, next block
	push	ax
	cCall	GetAccessWord,<si>
	test	ah, DSC_DISCARDABLE
	pop	ax
	jz	loop_for_beginning		; No, next block

how_big_is_it:
	mov	ax,es:[di].ga_size		; Use this size
loop_for_bigness:
	mov	es,es:[di].ga_next		; Next block
	cmp	es:[di].ga_owner,di		; Free?
	jz	include_his_size		; Yes, include size

	cmp	es:[di].ga_sig,GA_ENDSIG	; End of arena?
	jz	all_done
	mov	si,es:[di].ga_handle
	or	si,si				; Fixed?
	jz	end_of_bigness			; Yes, stop looking
	cmp	es:[di].ga_count,0		; Locked?
	jne	end_of_bigness			; Yes, stop looking
	push	ax
	cCall	GetAccessWord,<si>
	test	ah, DSC_DISCARDABLE
	pop	ax
	jz	dont_include_him	; No, dont include in count then
include_his_size:			; Free or Discardable
	add	ax,es:[di].ga_size	; Increase availabe space
	inc	ax			; by size of this block
dont_include_him:			; Moveable
	jmp	loop_for_bigness

end_of_bigness:
	mov	si,es
	cmp	es:[di].ga_owner,GA_NOT_THERE
	jnz	nothing_not_there
	push	ax
	push	dx
	cCall	get_physical_address,<si>
	sub	ax,word ptr [di].gi_disfence_lo
	sbb	dx,word ptr [di].gi_disfence_hi
	jae	fence_lower
	pop	dx
	pop	ax
	jmps	nothing_not_there

fence_lower:
	REPT	4
	shr	dx,1
	rcr	ax,1
	ENDM
	mov	si,ax
	pop	dx
	pop	ax
	sub	ax,si
	jmps	all_done_1

nothing_not_there:
	cmp	ax,dx			; Did we find a bigger block?
	jbe	blech_o_rama		; No, then look again
	mov	dx,ax			; Yes, remember size
blech_o_rama:
	jmp	loop_for_beginning

all_done:
	sub	ax,[di].gi_reserve	; In case lower_land has little free.
	jb	all_done_2
all_done_1:
	cmp	ax,dx			; Did we find a bigger block?
	ja	gcsize
all_done_2:
	mov	ax,dx
gcsize:
	inc	ax			; Cheap bug fix
	or	ax,ax			; zero mem available?
	jz	gcfinal			; yes, return 0
	dec	ax			; Dont be too exact
	jz	gcfinal
	dec	ax
	jz	gcfinal
	dec	ax
gcfinal:
	and	al,GA_MASK		; round down to nearest alignment
	xor	dx,dx
	ret
cEnd nogen


;-----------------------------------------------------------------------;
; greserve                                                              ;
; 									;
; Sets the size of the discardable code reserve area.			;
; If the new size is larger than the old size, it checks to see		;
; if there is enough room to support the new size.			;
; 									;
; Arguments:								;
;	AX = new greserve size						;
; 									;
; Returns:								;
;	CX = the largest greserve we can get				;
;	AX != 0  success						;
;	AX  = 0  failure						;
; 									;
; Error Returns:							;
; 									;
; Registers Preserved:							;
;	DI,SI,DS							;
; 									;
; Registers Destroyed:							;
;	BX,DX,ES							;
; 									;
; Calls:								;
;	genter								;
;	gcompact							;
;	will_gi_reserve_fit						;
;	gleave								;
; 									;
; History:								;
; 									;
;  Sun 14-Jan-1990 13:42:59  -by-  David N. Weise  [davidw]		;
; The greserve must be twice as big as the largest non-resident 	;
; segment, because restarting a NP fault requires both caller and	;
; callee to be in memory.						;
;									;
;  Tue May 19, 1987 00:03:08p  -by-  David N. Weise   [davidw]		;
; Made it far.								;
;									;
;  Sat Sep 27, 1986 01:03:08p  -by-  David N. Weise   [davidw]          ;
; Made it perform according to spec and added this nifty comment block.	;
;-----------------------------------------------------------------------;

	assumes ds,nothing
	assumes es,nothing

cProc	greserve,<PUBLIC,FAR>,<si,di>	; FAR because of the gcompact below
	localW	new_size
cBegin
	call	genter
	add	ax, ax			; Double required so caller & callee
	add	ax,GA_ALIGN		;   both fit in memory
	and	al,GA_MASK
	mov	new_size,ax
	mov	si, ax

	mov	cx,[di].gi_reserve	; Get old size.
	jcxz	first_time		; Old size equal to zero?
	call	will_gi_reserve_fit
	jnc	new_okay
 
        call    GrowHeap
        call    will_gi_reserve_fit
        jnc     new_okay
        
try_compacting:
	mov	dx,new_size
	call	gcompact		; Try compacting to get new reserve
	call	will_gi_reserve_fit
	jnc	new_okay
	
will_not_fit:
	xor	ax,ax
	jmps	gr_exit

first_time:				; Things are strange at first
	mov	bx, ax
	xor	cx, cx
REPT 4
	shl	bx, 1
	rcl	cx, 1
ENDM
	cCall	get_physical_address,<[di].hi_last>
	sub	ax, bx
	sbb	dx, cx			; Address of gi_reserve

new_okay:
	mov	word ptr [di].gi_disfence_lo,ax
	mov	word ptr [di].gi_disfence_hi,dx
	mov	dx,new_size
	mov	[di].gi_reserve,dx
gr_exit:
	call	gleave
cEnd


;-----------------------------------------------------------------------;
; will_gi_reserve_fit                                                   ;
; 									;
; See if new size okay by scanning arena backwards.			;
; 									;
; Arguments:								;
;	SI = new greserve size						;
;	DS:DI = master object						;
;									;
; Returns:								;
;	DX:AX = gi_disfence						;
;	BX = amount of NOT THERE memory, such as EGA			;
;	CX = the largest greserve we can get				;
;	CF = 0  new size ok						;
;	CF = 1  new size NOT ok						;
;	ES:DI => arena below CODE segments				;
; 									;
; Error Returns:							;
; 									;
; Registers Preserved:							;
;	SI,DI,DS							;
; 									;
; Registers Destroyed:							;
;									;
; 									;
; Calls:								;
;	nothing								;
; 									;
; History:								;
; 									;
;  Sun Jul 12, 1987 08:13:23p  -by-  David N. Weise      [davidw]	;
; Added EMS support.							;
; 									;
;  Sat Sep 27, 1986 01:03:57p  -by-  David N. Weise   [davidw]          ;
; Rewrote it.								;
;-----------------------------------------------------------------------;

cProc	will_gi_reserve_fit,<PUBLIC,NEAR>
	localB	got_half
	localW	second_block
	localW	largest_block
	localW	fence_block
	localW	fence_offset
cBegin

	xor	ax,ax
	xor	bx,bx
	mov	got_half, al
	mov	fence_block, ax
	mov	largest_block, ax
	mov	second_block, ax

	mov	es,[di].hi_last
	mov	cx,[di].hi_count

how_much_space_loop:
	mov	es,es:[di].ga_prev
how_much_space_loop1:
	cmp	di,es:[di].ga_owner		; If free then include.
	jz	include_this_one
	test	es:[di].ga_flags,GA_DISCCODE	; If disccode then include.
	jz	end_block
include_this_one:
	add	ax, es:[di].ga_size	; Total the size of this block
	inc	ax			; include arena header
	loop	how_much_space_loop

end_block:
	cmp	ax, largest_block	; Track two largest blocks
	jbe	not_largest
	push	largest_block
	mov	largest_block, ax
	pop	second_block
	jmps	not_second
not_largest:
	cmp	ax, second_block
	jbe	not_second
	mov	second_block, ax
not_second:
	cmp	fence_block, di
	jne	skip_not_there
	cmp	si, ax			; This block big enough?
	jbe	set_fence
	cmp	got_half, 0
	jne	skip_not_there		; Already split requirement
	shr	si, 1
	cmp	si, ax			; Half fits?
	ja	no_good
	mov	got_half, 1		;  yes, will use this block
	jmps	skip_not_there
set_fence:
	sub	ax, si
	mov	fence_offset, ax	; Offset from next arena
	mov	ax, es:[di].ga_next
	mov	fence_block, ax
	jmps	skip_not_there
no_good:
	shl	si, 1			;  no, keep trying for full amount
skip_not_there:
	xor	ax, ax				; zero count
	cmp	es:[di].ga_owner,GA_NOT_THERE
	jne	thats_all_folks
skip_not_there_loop:
	add	bx,es:[di].ga_size
	dec	cx
	mov	es, es:[di].ga_prev
	cmp	es:[di].ga_owner, GA_NOT_THERE	; skip all not there blocks
	je	skip_not_there_loop
	jmps	how_much_space_loop1

thats_all_folks:
	mov	cx, second_block		; Return max of twice second
	shl	cx, 1				; largest block and the largest
	jnc	not_monstrously_huge		; block
	mov	cx, 0FFFDh
	jmps	time_to_go
not_monstrously_huge:
	cmp	cx, largest_block
	jae	time_to_go
	mov	cx, largest_block
time_to_go:
	cmp	got_half, 1
	jne	si_ok
	shl	si, 1
si_ok:
	cmp	cx, si				; Set CARRY for failure
	jc	failed
	push	bx
	push	cx
	cCall	get_physical_address,<fence_block>
	mov	bx, fence_offset
	xor	cx, cx
REPT 4
	shl	bx, 1
	rcl	cx, 1
ENDM
	add	ax, bx
	adc	dx, cx				; DX:AX is new fence
	pop	cx
	pop	bx
	clc					; Success
failed:
cEnd


;-----------------------------------------------------------------------;
; gnotify                                                               ;
; 									;
; This is where the hard job of updating the stacks and thunks happens.	;
; We only walk stacks and thunks for code and data (defined by being	;
; LocalInit'ed), not for resources or task allocated segments.		;
; 									;
; Arguments:								;
;	AL = message code						;
;	BX = handle							;
;	CX = optional argument						;
;	ES = address of arena header					;
; 									;
; Returns:								;
;	AX = return value from notify proc or AL			;
;	DS = current DS (i.e. if DATA SEG was moved then DS is updated.	;
;	ZF = 1 if AX = 0						;
; 									;
; Error Returns:							;
; 									;
; Registers Preserved:							;
;	DI,SI								;
; 									;
; Registers Destroyed:							;
;	BX,CX,DX,ES							;
; 									;
; Calls:								;
; 									;
; History:								;
; 									;
;  Wed Jun 24, 1987 03:08:39a  -by-  David N. Weise   [davidw]		;
; Adding support for Global Notify.					;
; 									;
;  Wed Dec 03, 1986 01:59:27p  -by-  David N. Weise   [davidw]          ;
; Added this nifty comment block.					;
;-----------------------------------------------------------------------;

cProc	gnotify,<PUBLIC,NEAR>
cBegin nogen
	push	si
	push	di
	xor	ah,ah
	mov	di,cx
	mov	cx,ax
	mov	si,bx
	loop	notify_discard
	errnz	<GN_MOVE - 1>

;-----------------------------------------------------------------------;
;  Here for a segment that moved.					;
;-----------------------------------------------------------------------;

why_bother:

	mov	cx,ds
	cmp	cx,si			; Did we move DS?
	jne	notify_exit_0		; No, continue
notify_exit_0:
	jmp	notify_exit

notify_discard:
;;;;;;	loop	notify_exit
	loop	notify_exit_0
	errnz	<GN_DISCARD - 2>

;-----------------------------------------------------------------------;
;  Here for a segment discarded.					;
;-----------------------------------------------------------------------;

	xor	ax,ax
	test	bl,1
	jnz	notify_exit_0		; SDK is wrong, can't free fixed.
	push	ax
	cCall	GetAccessWord,<bx>
	test	ah, DSC_DISCARDABLE
	pop	ax
	jz	notify_exit_0

	test	es:[ga_flags],GAH_NOTIFY
	jnz	@F
	jmp	dont_bother_asking
@@:

	push	bx
	push	cx
	push	dx
	mov	ax,1
	mov	es,es:[ga_owner]
	cmp	es:[ne_magic],NEMAGIC
	jz	dont_ask		; doesn't belong to a particular task
	mov	ax,es
	SetKernelDS es
	push	HeadTDB 		; Look for TDB that owns this block.
find_TDB:
	pop	cx
	jcxz	dont_ask
	mov	es,cx
	UnSetKernelDS es
	push	es:[TDB_next]
	cmp	ax,es:[TDB_PDB]
	jnz	find_TDB
	pop	cx			; clear stack in 1 byte
	mov	cx,word ptr es:[TDB_GNotifyProc][0]	; paranoia
	cmp	cx,word ptr es:[TDB_GNotifyProc][2]
	jz	dont_ask
	push	ds
	SetKernelDS

;;;	xor	cx, cx			; Hack from hell for Legend
;;;	cmp	ax, cur_dos_PDB		; Are we on task's PDB
;;;	je	nothing_to_hack		;   Yes, fine
;;;	mov	cx, cur_dos_PDB		; No, save the PDB to restore
;;;	push	ax
;;;	push	bx
;;;	mov	bx, ax
;;;	mov	cur_dos_PDB, bx		; And point us to the task's
;;;	mov	Win_PDB, bx
;;;	mov	ah, 50h
;;;	call	real_dos
;;;	pop	bx
;;;	pop	ax
;;;nothing_to_hack:
;;;	push	cx			; Save old PDB (if any)

	push	Win_PDB			; Save current PDB
	mov	Win_PDB, ax		; Ensure it is the task's

	or	Kernel_Flags[1],kf1_GLOBALNOTIFY

	push	es:[TDB_GNotifyProc]+2	; push addr of func to call onto stack
	push	es:[TDB_GNotifyProc]

	push	bx			; push arg for notify proc

	mov	ax,ss			; Zap segment regs so DS
	mov	ds,ax			; doesn't get diddled by callee
	mov	es,ax

	mov	bx,sp
	call	dword ptr ss:[bx]+2
	add	sp,4			; clean up stack.

	SetKernelDS
	and	Kernel_Flags[1],not kf1_GLOBALNOTIFY

	pop	Win_PDB			; Restore PDB

;;;	pop	bx			; Saved PDB
;;;	or	bx, bx			; Was there one?
;;;	jz	@F			;   Nope.
;;;	push	ax
;;;	mov	ah, 50h			; Set it back...
;;;	mov	cur_dos_PDB, bx
;;;	mov	Win_PDB, bx
;;;	call	real_dos
;;;	pop	ax
;;;@@:
	
	pop	ds
	UnSetKernelDS

dont_ask:
	pop	dx
	pop	cx
	pop	bx
	or	ax,ax			; Well, can we?
	jz	notify_exit
dont_bother_asking:

	cCall	get_arena_pointer,<si>
	mov	es,ax
	mov	es,es:[ga_owner]
	cmp	es:[ne_magic],NEMAGIC
	jnz	not_in_exe
	mov	di,es:[ne_segtab]
	mov	cx,es:[ne_cseg]
	jcxz	not_in_exe
;	 test	 es:[ne_flags],NENOTP
;	 jnz	 pt0a
;	 inc	 bx
pt0a:
	cmp	bx,es:[di].ns_handle
	jz	pt0b
	add	di,SIZE NEW_SEG1
	loop	pt0a
	jmps	not_in_exe
pt0b:
	and	byte ptr es:[di].ns_flags,not NSLOADED	 ; Mark as not loaded.
not_in_exe:

why_bother_again:
	xor	di,di
if SDEBUG
	cCall	DebugMovedSegment,<si,di>
endif
if LDCHKSUM
	call	ZeroSegmentChksum	; SI points to segment
endif
	mov	ax,1
notify_exit:
	or	ax,ax
	pop	di
	pop	si
	ret

gn_error:
	kerror	0FFh,<gnotify - cant discard segment>,si,si
	xor	ax,ax
	jmp	notify_exit

cEnd nogen

;-----------------------------------------------------------------------;
; MemoryFreed								;
;									;
; This call is apps that have a GlobalNotify procedure.  Some apps	;
; may shrink the segment instead of allowing it to be discarded, or	;
; they may free other blocks.  This call tells the memory manager	;
; that some memory was freed somewhere. 				;
;									;
; Arguments:								;
;	WORD = # paragraphs freed					;
;									;
; Returns:								;
;	DX:AX = amount of memory that still needs freeing		;
; 									;
; Error Returns:							;
; 									;
; Registers Preserved:							;
; 									;
; Registers Destroyed:							;
; 									;
; Calls:								;
; 									;
; History:								;
;									;
;  Fri 08-Apr-1988 10:25:55  -by-  David N. Weise  [davidw]		;
; Wrote it!								;
;-----------------------------------------------------------------------;

cProc	MemoryFreed,<PUBLIC,FAR>

	parmW	memory_freed
cBegin
	xor	ax,ax
	SetKernelDS
	test	Kernel_Flags[1],kf1_GLOBALNOTIFY
	jz	mf_done
	mov	ds,pGlobalHeap
	UnSetKernelDS
	mov	ax,memory_freed
	or	ax,ax
	jz	mf_inquire
	or	ds:[hi_ncompact],1	; Remember we discarded something
	sub	ds:[hi_distotal],ax	; Have we discarded enough yet?
	ja	mf_inquire
	or	ds:[hi_ncompact],10h	; To tell gdiscard that we're done.
mf_inquire:
	mov	ax,ds:[hi_distotal]	; Have we discarded enough yet?
mf_done:
	xor	dx,dx

cEnd


;-----------------------------------------------------------------------;
; SetSwapAreaSize							;
; 									;
; Sets the current task's code swap area size.				;
; 									;
; Arguments:								;
;	WORD	== 0 then current size is just returned			;
; 		!= 0 number paragraphs wanted for swap area		;
; Returns:								;
;	AX = Size actually set						;
;	DX = Max size you can get					;
; 									;
; Error Returns:							;
; 									;
; Registers Preserved:							;
; 									;
; Registers Destroyed:							;
; 									;
; Calls:								;
; 									;
; History:								;
; 									;
;  Thu Apr 18, 1988 08:00:00a  -by-  T.H. SpeedWagon  [-????-]		;
; Move routine into CODE segment, so applications can query the		;
; code working set value without paging in the NRESCODE segment.	;
; 									;
;  Thu Apr 23, 1987 09:36:00p  -by-  R.E.O. SpeedWagon [-???-]		;
; Added ability to get size without setting it.				;
; 									;
;  Wed Dec 03, 1986 10:52:16p  -by-  David N. Weise   [davidw]          ;
; Rewrote it.								;
;-----------------------------------------------------------------------;


cProc   SetSwapAreaSize,<PUBLIC,FAR>
	parmW	nParas
	localW	MxCodeSwapArea
cBegin
	SetKernelDS
	mov	ax,nParas
	xor	bx,bx
	mov	cx,MaxCodeSwapArea
	mov	MxCodeSwapArea,cx	; avoid a segment load later
	cmp	ax,cx
	jbe	requested_size_OK
	mov	ax,cx
requested_size_OK:
	mov	ds,CurTDB
	UnSetKernelDS
	mov	ds,ds:[bx].TDB_pModule	; Get exe header address
	or	ax,ax			; just a query request?
	jz	got_it			; yes
	cmp	ax,ds:[bx].ne_swaparea
	jz	got_it			; just want what we have?
	ja	calc_it

; To restart a NP fault both caller and callee must be in memory.
;  So we cheat here, and set the minimum to be twice the rmode number.
; We have to prevent the app from setting the swap area too
;  small.  So we recalculate the minimum needed.  We should
;  do this is rmode as well, but the chance of screw up is
;  much larger in pmode, where new app writers are apt to
;  be very cavalier with lots of memory.
; We should keep another NE variable instead of always
;  recalculating the largest ne_seg BUT at this late
;  date this is simpler!

	push	ax
	xor	ax,ax				; No max yet.
	mov	cx,ds:[bx].ne_cseg
	mov	bx,ds:[bx].ne_segtab
	jcxz	no_NR_segments
get_largest_loop:
	test	ds:[bx].ns_flags,NSDATA 	; Code segment?
	jnz	not_disc_code
	.errnz	NSCODE
	test	ds:[bx].ns_flags,NSDISCARD	; Discardable?
	jz	not_disc_code			; No, ignore.
	mov	dx,ds:[bx].ns_minalloc		; Yes, get size
	add	dx,0Fh				; in paragraphs
	shr	dx,4
	cmp	ax,dx			; Biggest NR Seg?
	jae	not_disc_code
	mov	ax,dx
not_disc_code:
	add	bx,SIZE NEW_SEG1
	loop	get_largest_loop
no_NR_segments:
	shl	ax,1
	mov	cx,ax
	pop	ax
	cmp	ax,cx
	ja	calc_it
	mov	ax,cx

calc_it:
	xchg	ds:[ne_swaparea],ax
	push	ax
	call	CalcMaxNRSeg
	pop	dx
	or	ax,ax
	jnz	got_it
	mov	ds:[ne_swaparea],dx
got_it:
	mov	ax,ds:[ne_swaparea]
	mov	dx,MxCodeSwapArea
	cmp	cx,dx
	ja	cant_get_that_much
	mov	dx,cx
cant_get_that_much:
cEnd

;
; SetReserve	- Sets gi_reserve to the given number of paragraphs
;
; Registers Destroyed:
;	AX, BX, DX
;

cProc	SetReserve,<PUBLIC,FAR>,<di>
	parmW	paras
cBegin
	SetKernelDS
	mov	ds, pGlobalHeap
	UnSetKernelDS
	xor	di,di
	mov	bx, paras
	mov	ds:[di].gi_reserve, bx
	shl	bx, 4
	cCall	get_physical_address,<ds:[di].hi_last>
	sub	ax, bx
	sbb	dx, di
	mov	ds:[di].gi_disfence_lo, ax
	mov	ds:[di].gi_disfence_hi, dx
cEnd


sEnd	CODE

end
