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, parmW hExe parmW entno cBegin if KDEBUG mov cx,1 cCall EntProcAddress, else cCall EntProcAddress, 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, parmW hExe parmW entno cBegin xor cx,cx ;Force RIPs on this one cCall EntProcAddress, cEnd endif ; KDEBUG externNP FindOrdinal cProc FarFindOrdinal, parmW hExe parmD lpname parmW fh cBegin cCall FindOrdinal, cEnd externNP LoadSegment cProc FarLoadSegment, parmW hExe parmW segno parmW fh parmW isfh cBegin cCall LoadSegment, cEnd externNP AllocSeg cProc FarAllocSeg, parmD pSegInfo cBegin cCall AllocSeg, cEnd externNP DeleteTask cProc FarDeleteTask, parmW taskID cBegin cCall DeleteTask, cEnd externNP UnlinkObject cProc FarUnlinkObject, cBegin cCall UnlinkObject cEnd externNP MyLower cProc FarMyLower, cBegin cCall MyLower cEnd externNP MyUpper cProc FarMyUpper, cBegin cCall MyUpper cEnd externNP MyAlloc cProc FarMyAlloc, parmW aflags parmW nsize parmW nelem cBegin cCall MyAlloc, cEnd externNP MyAllocLinear cProc FarMyAllocLinear, parmW aflags parmD dwBytes cBegin cCall MyAllocLinear, cEnd externNP MyLock cProc FarMyLock, parmW h1 cBegin cCall MyLock,

cEnd externNP MyFree cProc FarMyFree, parmW h2 cBegin cCall MyFree,

cEnd externNP genter cProc Far_genter, cBegin cCall genter cEnd externNP gleave cProc Far_gleave, cBegin cCall gleave cEnd externNP lalign cProc Far_lalign, cBegin cCall lalign cEnd externNP lrepsetup cProc Far_lrepsetup, cBegin cCall lrepsetup cEnd if KDEBUG externNP lfillCC cProc Far_lfillCC, 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,, 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, push ax cCall IGlobalLock, pop ax push dx cCall IGlobalUnlock, 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, mov ax,es reexit: cEnd ife ROM ;---------------------------------------------------------------- cProc LKAllocSegs,, 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, 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, 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, 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, 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, mov ax,di ; Return offset to NR segment lkallocfail: cEnd endif ;ROM --------------------------------------------------------- nop ; Stop linker from padding segment sEnd INITCODE end