TITLE	LDSELF - BootStrap procedure for KERNEL.EXE

.xlist
?NODATA=1
?TF=1
include kernel.inc
include newexe.inc
include tdb.inc
.list

externFP IGlobalAlloc
externFP IGlobalLock
externFP IGlobalUnlock
	       
DataBegin

externW winVer
;externW pGlobalHeap

DataEnd

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

;externW MyCSDS

externNP SetOwner

externFP set_discarded_sel_owner

; extra debugging parameter for EntProcAddress to avoid RIPing if all 
; we are doing is a GetProcAddress to something that isn't there.
externNP EntProcAddress
cProc	FarEntProcAddress,<PUBLIC,FAR,NODATA>
    parmW   hExe
    parmW   entno
cBegin
if KDEBUG
	mov	cx,1
	cCall	EntProcAddress,<hExe,entno,cx>
else
	cCall	EntProcAddress,<hExe,entno>
endif
cEnd

if KDEBUG

;  AppLoaderEntProcAddress
;       This call added for the app loader.  The above call (FarEntProcAddress)
;       forces no RIPs.  When we're using the app loader, we really want
;       RIPs, so in debug we add this entry point.
;       This call ONLY exists in debug.

cProc	AppLoaderEntProcAddress,<PUBLIC,FAR,NODATA>
    parmW   hExe
    parmW   entno
cBegin
        xor     cx,cx           ;Force RIPs on this one
	cCall	EntProcAddress,<hExe,entno,cx>
cEnd

endif ; KDEBUG


externNP FindOrdinal
cProc	FarFindOrdinal,<PUBLIC,FAR,NODATA>
    parmW   hExe
    parmD   lpname
    parmW   fh
cBegin
	cCall	FindOrdinal,<hExe,lpName,fh>
cEnd


externNP LoadSegment
cProc	FarLoadSegment,<PUBLIC,FAR,NODATA>
    parmW   hExe
    parmW   segno
    parmW   fh
    parmW   isfh
cBegin
	cCall	LoadSegment,<hExe,segno,fh,isfh>
cEnd


externNP AllocSeg
cProc	FarAllocSeg,<PUBLIC,FAR,NODATA>
    parmD   pSegInfo
cBegin
	cCall	AllocSeg,<pSegInfo>
cEnd


externNP DeleteTask
cProc	FarDeleteTask,<PUBLIC,FAR,NODATA,ATOMIC>
    parmW taskID
cBegin
	cCall	DeleteTask,<taskID>
cEnd


externNP UnlinkObject
cProc	FarUnlinkObject,<PUBLIC,FAR,NODATA,ATOMIC>
cBegin
	cCall	UnlinkObject
cEnd


externNP MyLower
cProc	FarMyLower,<PUBLIC,FAR,NODATA,ATOMIC>
cBegin
	cCall	MyLower
cEnd


externNP MyUpper
cProc	FarMyUpper,<PUBLIC,FAR,NODATA,ATOMIC>
cBegin
	cCall	 MyUpper
cEnd


externNP MyAlloc
cProc	FarMyAlloc,<PUBLIC,FAR,NODATA>
    parmW   aflags
    parmW   nsize
    parmW   nelem
cBegin
	cCall	MyAlloc,<aflags,nsize,nelem>
cEnd


externNP MyAllocLinear
cProc	FarMyAllocLinear,<PUBLIC,FAR,NODATA>
    parmW   aflags
    parmD   dwBytes
cBegin
	cCall	MyAllocLinear,<aflags,dwBytes>
cEnd


externNP MyLock
cProc	FarMyLock,<PUBLIC,FAR,NODATA>
    parmW   h1
cBegin
	cCall	MyLock,<h1>
cEnd


externNP MyFree
cProc	FarMyFree,<PUBLIC,FAR,NODATA>
    parmW   h2
cBegin
	cCall	MyFree,<h2>
cEnd

externNP genter
cProc	Far_genter,<PUBLIC,FAR,NODATA,ATOMIC>
cBegin
	cCall	genter
cEnd

externNP gleave
cProc   Far_gleave,<PUBLIC,FAR,NODATA,ATOMIC>
cBegin
    cCall   gleave
cEnd

externNP lalign
cProc	Far_lalign,<PUBLIC,FAR,NODATA,ATOMIC>
cBegin
	cCall	lalign
cEnd


externNP lrepsetup
cProc	Far_lrepsetup,<PUBLIC,FAR,NODATA,ATOMIC>
cBegin
	cCall	lrepsetup
cEnd


if KDEBUG

externNP lfillCC
cProc	Far_lfillCC,<PUBLIC,FAR,NODATA,ATOMIC>
cBegin
	cCall	 lfillCC
cEnd
endif

sEnd	CODE




sBegin	INITCODE

;-----------------------------------------------------------------------;
; LKExeHeader								;
; 									;
; Copy of LoadExeHeader (from LDHEADER.ASM) that has been stripped	;
; down to the minimum needed to load the new format .EXE header for	;
; KERNEL.EXE.								;
; 									;
; Arguments:								;
;	parmW	pMem							;
;	parmD	pfilename						;
; 									;
; Returns:								;
;	AX = segment of exe header					;
; 									;
; Error Returns:							;
;	AX = 0								;
; 									;
; Registers Preserved:							;
;	DI,SI,DS							;
; 									;
; Registers Destroyed:							;
;	AX,BX,CX,DX,ES							;
; Calls:								;
; 									;
; History:								;
; 									;
;  Thu Mar 19, 1987 08:35:32p  -by-  David N. Weise   [davidw]		;
; Added this nifty comment block.					;
;-----------------------------------------------------------------------;

cProc	LKExeHeader,<PUBLIC,NEAR>,<si,di,ds>
	parmW	pMem
	parmD   pfilename
	localW	nchars
cBegin
	lds	si,pfilename
	xor	ax,ax
	mov	al,ds:[si].opLen
	inc	ax			; include null byte
	mov	nchars,ax

	mov	ds,pMem
	xor	si,si
	mov	di,ds:[si].ne_enttab	; Compute size of resident new header
	add	di, 6			; Room for one block of entries
	push	si
	mov	si, ds:[si].ne_enttab	; Scan current entry table

calc_next_block:
	lodsw
	xor	cx, cx
	mov	cl, al
	jcxz	calc_ent_sized

	cmp	ah, ENT_UNUSED		; 6 bytes per unused block
	jne	calc_used_block
	add	di, 6
	jmps	calc_next_block

calc_used_block:
	errnz	<5-SIZE PENT>
	mov	bx, cx
	shl	bx, 1
	add	di, bx
	add	di, bx			; 5 bytes per entry
	add	di, cx

	add	si, bx
	add	si, cx			; Skip the block
	cmp	ah, ENT_MOVEABLE
	jne	calc_next_block

calc_moveable_block:
	add	si, bx
	add	si, cx			; Skip the block
	jmps	calc_next_block

calc_ent_sized:
	pop	si
	mov	cx,ds:[si].ne_cseg	; + 3 * #segments

; Reserve space for segment reference bytes

	add	di,cx
	shl	cx,1

; Reserve space for ns_handle field in segment table

	add	di,cx
	errnz	<10-SIZE NEW_SEG1>

if LDCHKSUM

; Reserve space for segment chksum table (2 words per segment)

	add	di,cx
	add	di,cx
endif


; Reserve space for file info block at end

	add	di,16			; 16 bytes of slop
	add	di,nchars		; + size of file info block

	xor	ax,ax			; Allocate a block for header
	cCall	IGlobalAlloc,<GA_MOVEABLE,ax,di>
	push	ax
	cCall	IGlobalLock,<ax>
	pop	ax
	push	dx
	cCall	IGlobalUnlock,<ax>
	pop	ax
	mov	es,ax			; ES:DI -> new header location
	xor	di,di
	cld				; DS:SI -> old header
	mov	cx,SIZE NEW_EXE		; Copy fixed portion of header
	cld
	rep	movsb
	mov	cx,es:[ne_cseg] 	; Copy segment table
	mov	es:[ne_segtab],di
recopyseg:

if ROM

; This code assumes kernel segments will not need to be reloaded from ROM
; and so doesn't set the ns_sector field like LoadExeHeader().

	lodsw				; ns_sector has segment selector in ROM
	mov	bx,ax
	stosw
else
	movsw				; ns_sector
endif
	movsw				; ns_cbseg
	lodsw				; ns_flags
	errnz	<4-ns_flags>
	and	ax,not NS286DOS 	; Clear 286DOS bits
if ROM
	or	ax,NENOTP+4000h+NSINROM+NSLOADED  ; library code in ROM
else
	or	ax,NENOTP+4000h 	; Mark library code segments
endif
	stosw
	movsw				; ns_minalloc
	errnz	<8-SIZE NEW_SEG>
if ROM
	mov	ax,bx
else
	xor	ax,ax
endif
	stosw				; one word for ns_handle field
	errnz	<10-SIZE NEW_SEG1>
	loop	recopyseg

recopysegx:
	mov	cx,es:[ne_restab]	; Copy resource table
	sub	cx,es:[ne_rsrctab]
	mov	es:[ne_rsrctab],di
	rep	movsb
rerestab:
	mov	cx,es:[ne_modtab]	; Copy resident name table
	sub	cx,es:[ne_restab]
	mov	es:[ne_restab],di
	rep	movsb

	mov	cx,es:[ne_imptab]	; Copy module xref table
	sub	cx,es:[ne_modtab]
	mov	es:[ne_modtab],di
	rep	movsb

	mov	es:[ne_psegrefbytes],di ; Insert segment reference byte table
	mov	cx,es:[ne_cseg]
	mov	al,0FFh
	rep	stosb			; initialize to not-loaded condition

	mov	es:[ne_pretthunks],di	; Setup return thunks

if LDCHKSUM
	mov	es:[ne_psegcsum],di	; Setup segment chksum table
	mov	cx,es:[ne_cseg]
	jcxz	resetsegcsumexit
	xor	ax,ax
	shl	cx,1			; Two words per segment
	rep	stosw
resetsegcsumexit:
endif
	mov	cx,es:[ne_enttab]	; Copy imported name table
	sub	cx,es:[ne_imptab]
	mov	es:[ne_imptab],di
	jcxz	reenttab
	rep	movsb

reenttab:
	mov	es:[ne_enttab],di
					; Scan current entry table
	xor	ax, ax			; First entry in block
	mov	bx, di			; Pointer to info for this block
	stosw				; Starts at 0
	stosw				; Ends at 0
	stosw				; And is not even here!

copy_next_block:
	lodsw				; Get # entries and type
	xor	cx, cx
	mov	cl, al
	jcxz	copy_ent_done

	mov	al, ah
	cmp	al, ENT_UNUSED
	jne	copy_used_block

	mov	ax, es:[bx].PM_EntEnd	; Last entry in current block
	cmp	ax, es:[bx].PM_EntStart	; No current block?
	jne	end_used_block

int 3
	add	es:[bx].PM_EntStart, cx
	add	es:[bx].PM_EntEnd, cx
	jmps	copy_next_block

end_used_block:
	mov	es:[bx].PM_EntNext, di	; Pointer to next block
	mov	bx, di
	add	ax, cx			; Skip unused entries
	stosw				; First in new block
	stosw				; Last in new block
	xor	ax, ax
	stosw				; End of list
	jmps	copy_next_block

copy_used_block:
	add	es:[bx].PM_EntEnd, cx	; Add entries in this block
	cmp	al, ENT_MOVEABLE
	je	copy_moveable_block

copy_fixed_block:
	stosb				; Segno
	movsb				; Flag byte
	stosb				; segno again to match structure
	movsw				; Offset
	loop	copy_fixed_block
	jmps	copy_next_block

copy_moveable_block:
	stosb				; ENT_MOVEABLE
	movsb				; Flag byte
	add	si, 2			; Toss int 3Fh
	movsb				; Copy segment #
	movsw				; and offset
	loop	copy_moveable_block
	jmps	copy_next_block

copy_ent_done:


	xor	bx,bx
	mov	es:[bx].ne_usage,1
	mov	es:[bx].ne_pnextexe,bx
	mov	es:[bx].ne_pautodata,bx

	mov	cx,nchars
	mov	es:[bx].ne_pfileinfo,di
	lds	si,pfilename
	rep	movsb

	SetKernelDS
	mov	ax,winVer
	mov	es:[bx].ne_expver,ax
if ROM
	or	es:[bx].ne_flags,NENONRES OR NEMODINROM ;have disc code & in ROM
else
	or	es:[bx].ne_flags,NENONRES ; Remember that we have
						; discardable code
endif
	UnSetKernelDS
	cCall	SetOwner,<es,es>
	mov	ax,es
reexit:
cEnd

ife ROM ;----------------------------------------------------------------

cProc	LKAllocSegs,<PUBLIC,NEAR>,<si,di,ds>
	parmW	hExe

	localW	fixed_seg
	localW	SegCount
cBegin
	mov	ds,hExe
	mov	si,ds:[ne_segtab]
	mov	di,ds:[si].ns_minalloc
	xor	ax,ax
	mov	bx,(GA_ALLOC_LOW or GA_CODE_DATA) shl 8
	cCall	IGlobalAlloc,<bx,ax,di>
	or	ax,ax
	jz	lkallocfail
	mov	fixed_seg,ax
	mov	ds:[si].ns_handle,ax
	and	byte ptr ds:[si].ns_flags,not NSLOADED
	or	byte ptr ds:[si].ns_flags,NSALLOCED

	cCall	SetOwner,<ax,ds>

	add	si,SIZE NEW_SEG1	; NRES segment
	mov	di,ds:[si].ns_sector
	mov	SegCount, 0		; NRES and MISC segments

;;	  SetKernelDS	  es
;;	  cmp	  fWinX,0
;;	  UnSetKernelDS   es
;;	  je	  lk1
;;	  mov	  di,ds:[si].ns_cbseg
;;	  xchg	  ds:[si].ns_minalloc,di
;;	  xchg	  ds:[si].ns_sector,di
;;lk1:

SegLoop:
	inc	SegCount
	xor	ax,ax
	mov	bh,GA_DISCARDABLE + GA_SHAREABLE + GA_CODE_DATA
	mov	bl,GA_MOVEABLE + GA_DISCCODE
	cCall	IGlobalAlloc,<bx,ax,ax>
	or	ax,ax
	jz	lkallocfail
	mov	ds:[si].ns_handle,ax	; Handle into seg table
	and	byte ptr ds:[si].ns_flags,not NSLOADED
	or	byte ptr ds:[si].ns_flags,NSALLOCED
	mov	bx,ax			; put handle into base register
	smov	es,ds
	call	set_discarded_sel_owner
	smov	es,0
	mov	bx,ds:[si].ns_sector	; Save MiscCode sector
	add	si,SIZE NEW_SEG1	; Next segment
	cmp	SegCount, 2
	jnz	SegLoop


; Allocate fixed block for kernel's data segment

	push	bx			; Save MisCode sector
	mov	bx,ds:[si].ns_minalloc
	xor	ax,ax
	cCall	IGlobalAlloc,<ax,ax,bx>
	pop	bx
	or	ax,ax
	jz	lkallocfail
	mov	ds:[ne_pautodata], si
	mov	ds:[si].ns_handle,ax
	and	byte ptr ds:[si].ns_flags,not NSLOADED
	or	byte ptr ds:[si].ns_flags,NSALLOCED

	cCall	SetOwner,<ax,ds>

	mov	ax,di			; Return offset to NR segment
lkallocfail:
cEnd

endif ;ROM	---------------------------------------------------------

	nop				; Stop linker from padding segment

sEnd	INITCODE

end