windows-nt/Source/XPSP1/NT/base/mvdm/wow16/kernel31/ldself.asm
2020-09-26 16:20:57 +08:00

567 lines
11 KiB
NASM

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