TITLE LDSEG - SegAlloc procedure .xlist include kernel.inc include newexe.inc include tdb.inc include protect.inc ; Handle_To_Sel .list NSHUGESEG = NSKCACHED ; not first seg of huge segment ; A huge segment (data object larger than 64K) requires more than one ; selector, but is part of a single memory allocation block. The first ; selector is a handle, like any other segment. Subsequent selectors of ; the huge memory block are _not_ handles, so we can't call MyLock() on ; them, as the consistency check will fail. We mark these selectors with ; the NSHUGESEG bit in the flags word. TonyG suggested this. ; Note that data segments are already loaded, locked, etc, so the call to ; MyLock is redundant anyway. ; Thu Feb 28, 1991 01:39:00p -by- Don A. Corbitt [donc] ; externFP IGlobalFree externFP IGlobalAlloc externFP IGlobalReAlloc externFP IGlobalLock externFP MyOpenFile externFP FlushCachedFileHandle externFP Int21Handler externFP set_discarded_sel_owner externFP GetPatchAppRegKey externFP PatchAppSeg if KDEBUG externFP OutputDebugString endif if ROM ;externNP SetROMOwner externFP FarSetROMOwner externFP ChangeROMHandle externFP AllocSelector externFP IFreeSelector externNP CloneROMSelector externFP LZDecode endif DataBegin externB Kernel_flags ;externB fBooting externB fPadCode ;externW pGlobalHeap ;externW MyCSDS externW Win_PDB if KDEBUG externB fLoadTrace externB fPreloadSeg endif if PMODE32 externD FreeArenaCount extrn CountFreeSel:WORD endif DataEnd sBegin CODE assumes CS,CODE assumes DS,NOTHING assumes ES,NOTHING ;externNP MyFree externNP SegReloc externNP MyAlloc externNP MyAllocLinear ; MyAlloc with useful parameters externNP MyLock externNP GetCachedFileHandle externNP CloseCachedFileHandle externNP GetOwner externNP SetOwner externNP get_selector_length16 externNP get_rover_2 externNP DiscardTheWorld IFNDEF NO_APPLOADER externNP LoadApplSegment endif ;!NO_APPLOADER if LDCHKSUM ;externNP GetChksumAddr externNP CheckSegChksum externNP ZeroSegmentChksum endif if SDEBUG externNP DebugDefineSegment endif ifdef WOW_x86 externNP get_physical_address endif ;-----------------------------------------------------------------------; ; AllocSeg ; ; ; ; Allocates memory for a segment. Does not load the segment. Puts ; ; the handle of the segment into the segment descriptor structure ; ; in the module database, and updates the flags there to mark the ; ; segment as allocated but not loaded. Put the segment number into ; ; the BurgerMaster handle entry. It also changes the .ga_owner to be ; ; the module database. ; ; ; ; Arguments: ; ; parmD pSegInfo ; ; ; ; Returns: ; ; AX = handle for segment ; ; ; ; Error Returns: ; ; AX = 0 ; ; ZF = 1 ; ; ; ; Registers Preserved: ; ; SI,DS,ES ; ; ; ; Registers Destroyed: ; ; BX,CX,DX ; ; ; ; Calls: ; ; MyAlloc ; ; ; ; History: ; ; Thu Feb 28, 1991 01:39:00p -by- Don A. Corbitt [donc] ; ; Handle 64K (big/huge) data segments ; ; ; ; ; Mon Feb 09, 1987 10:29:16p -by- David N. Weise [davidw] ; ; Added this nifty comment block. ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc AllocSeg,, parmD pSegInfo cBegin SetKernelDS les si,pSegInfo ; Get size into AX (max of file size and minimum allocation). mov bx,es:[si].ns_flags test bl,NSALLOCED ; Already allocated? jz as0 ; No, allocate it jmp SHORT as3 as0: mov ax,es:[si].ns_minalloc xor dx, dx ; if AX == 0 cmp ax, 1 ; then it is really 64K adc dx, dx add ax, 2 ; We may have a 1 byte entry point at the adc dx, 0 ; very end of a segment. PatchCodeHandle ; will GP trying to decipher the prolog. ; Also allow space for reading relocation word cmp si,es:[ne_pautodata] jne as1 add ax,es:[ne_stack] ; Include stack and heap for data. jc asfail ; Don't need to handle big auto segs add ax,es:[ne_heap] jnc as1 asfail: krDebugOut DEB_ERROR, "%es2 Automatic Data Segment larger than 64K." xor ax,ax asxj: jmp SHORT asx as1: ; Allocate space for segment push bx push es cCall MyAllocLinear, pop es pop bx or ax,ax jz asxj as2: if ROM ; If this segment gets loaded from ROM, change the segment handle ; to be the one that was used to fix-up the ROM code segments. This ; is the value of ns_sector in the segment table. test byte ptr es:[si].ns_flags+1,(NSINROM SHR 8) jz as_not_a_rom_seg mov bx,es:[si].ns_sector test dl,GA_FIXED jnz as_fixed StoH bx as_fixed: cCall ChangeROMHandle, mov dx,bx as_not_a_rom_seg: endif mov es:[si].ns_handle,dx ; Handle into seg table and byte ptr es:[si].ns_flags,not NSLOADED or byte ptr es:[si].ns_flags,NSALLOCED mov bx,dx cCall SetOwner, as3: mov ax,es:[si].ns_handle asx: or ax,ax cEnd ;-----------------------------------------------------------------------; ; LoadSegment ; ; ; ; Loads a segment and performs any necessary relocations. ; ; ; ; Arguments: ; ; parmW hExe ; ; parmW segno ; ; parmW fh ; ; parmW isfh ; ; ; ; Returns: ; ; AX = handle of segment ; ; CX = handle of segment ; ; DX = handle of segment ; ; ; ; Error Returns: ; ; AX = 0 ; ; CX = 0 ; ; ; ; Registers Preserved: ; ; DI,SI,DS ; ; ; ; Registers Destroyed: ; ; BX,ES ; ; ; ; Calls: ; ; LoadSegment ; ; AllocSeg ; ; LoadApplSegment ; ; MyOpenFile ; ; SegLoad ; ; GlobalAlloc ; ; MyLock ; ; SegReloc ; ; GlobalFree ; ; ZeroSegmentChksum ; ; CheckSegChksum ; ; ; ; History: ; ; Thu Feb 28, 1991 01:39:00p -by- Don A. Corbitt [donc] ; ; ; ; Tue Oct 27, 1987 06:10:31p -by- David N. Weise [davidw] ; ; Wrote it. ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc LoadSegment,, parmW hExe parmW segno parmW fh parmW isfh localW myfh localW hrleseg localD pseginfo localW creloc localW hseg localW fdataseg localW retries localW SavePDB localB fReload if ROM localW selROMrle endif localW pleaseNoLock ; 1 if shouldn't lock seg cBegin mov retries, 2 xor ax,ax mov hrleseg,ax mov hseg,ax mov SavePDB, ax mov pleaseNoLock, ax mov fReload, al if ROM mov selROMrle,ax endif not ax mov myfh,ax mov es,hexe mov si,segno dec si cmp es:[ne_cseg],si jg ls_not_done ; wish we had auto jump sizing... jmp lsdone ls_not_done: shl si,1 mov bx,si shl si,1 shl si,1 add si,bx .errnz 10 - SIZE NEW_SEG1 add si,es:[ne_segtab] mov SEG_pseginfo, es ; Save segment info pointer mov OFF_pseginfo, si IFNDEF NO_APPLOADER test es:[ne_flags],NEAPPLOADER jnz ls_special_load ls_not_special_load: ENDIF ;!NO_APPLOADER mov bx,es:[si].ns_flags mov ax, bx and ax, NSHUGESEG mov pleaseNoLock, ax if ROM test bh,(NSINROM SHR 8) ; Segment in ROM? jz ls0b ; no, go load it normally test bl,NSLOADED ; Alread 'loaded' in ROM? jnz chk_rom_seg push es cCall AllocSelector,<0> pop es cCall CloneROMSelector, mov selROMrle,ax mov fh,ax ; Fake parmas to indicate loading mov isfh,-1 ; from memory and go load it jmps ls1b chk_rom_seg: test bl,NSALLOCED ; ROM seg allocated & loaded into RAM? jnz ls0b ; yes, treat normally mov ax,es:[si].ns_handle ; later code expects this jmp DefineSeg ; define seg to debugger (maybe) ls0b: endif ;ROM test bl,NSALLOCED jnz ls1 push bx cCall AllocSeg, ; No, so try allocating the segment pop bx or ax,ax jnz ls1b ls1: mov ax,es:[si].ns_handle mov hseg,ax test bl,NSLOADED jz ls1b mov fReload,1 jmp lsexit ; so MyLock at lsexit can swap them in IFNDEF NO_APPLOADER ls_special_load: mov ax,segno cmp ax,1 je ls_not_special_load ;* first segment normal load test es:[si].ns_flags,NSLOADED jnz ls_already_loaded cCall LoadApplSegment, jmp lsx ls_already_loaded: mov ax,es:[si].ns_handle mov hseg,ax mov fReload,1 jmp lsexit endif ;!NO_APPLOADER ls1b: mov ax,fh inc ax ; Already have file handle? jz ls2 ; No, then get one and load segment dec ax cmp isfh,ax ; Yes, loading from memory? jne lsdoit ; Yes, load it now jmps ls2b ; No, load it now ls2: SetKernelDS mov ax, Win_PDB ; Save what PDB is supposed to be mov SavePDB, ax ; since we will set it to kernel's PDB mov ax,-1 cCall GetCachedFileHandle, ; Get file handle from cache ls2b: mov myfh,ax mov isfh,ax inc ax jnz lsdoit0 cmp SavePDB, ax ; If we saved the PDB, (ax=0) je @F push SavePDB ; better restore it! pop Win_PDB @@: jmp lsdone lsdoit0: dec ax lsdoit: push es cCall SegLoad, pop es mov hseg,0 or ax,ax jz lsexit1 inc ax ; Did we get a file error? jnz lsloaded mov bx, myfh inc bx ; Reading from memory? jz lsexit1 ; no, fail dec bx cmp bx, fh ; We opened the file? je lsexit1 ; no, fail ;;; cCall CloseCachedFileHandle, mov bx, SavePDB mov Win_PDB, bx cCall FlushCachedFileHandle, ; Close it dec retries jz lsbadfile jmps ls2 ; and try to re-open it. UnSetKernelDS lsbadfile: krDebugOut DEB_ERROR, "%ES2 I/O error reading segment" lsexit1: jmp lsexit lsloaded: mov hseg,bx mov bx,es:[si].ns_flags test bx,NSRELOC jnz lm1x jmp lschksum lm1x: and bx,NSDATA mov fdataseg,bx mov bx,myfh ; Loading from memory? inc bx jnz lm1 ; No, continue mov es,dx ; Yes, point to relocation info mov si,cx cld lods word ptr es:[si] mov creloc,ax jmps lm2 lm1: dec bx mov creloc,cx shl cx,1 shl cx,1 shl cx,1 .errnz 8 - SIZE new_rlc push bx push cx mov ax,GA_MOVEABLE+GA_NODISCARD ; DO NOT WANT FIXED!! xor bx,bx regptr xsize,bx,cx if PMODE32 .386 ; We don't really want to cause an attempt to grow the global arena ; table or the LDT here! push ds SetKernelDS cmp FreeArenaCount,0 ; free arena? jz NoFreeArenas ; No cmp CountFreeSel,0 ; free selector? NoFreeArenas: pop ds UnsetKernelDS jz lm1a ; No, then read one at a time .286 endif cCall IGlobalAlloc, mov hrleseg,ax ; Save handle or ax,ax ; Did we get the memory jz lm1a ; No, then read one at a time cCall IGlobalLock, ; Get the address of the relocation info mov si, ax mov es, dx pop cx ; Restore byte count pop bx ; Restore file handle push ds mov ds,dx assumes ds,nothing xor dx,dx mov ah,3Fh ; Read in relocation information DOSCALL pop ds assumes ds,nothing jc lserr2 cmp ax,cx jne lserr2 jmps lm2 lm1a: pop cx ; Restore byte count pop bx ; Restore file handle xor si,si mov es,si ; Signal no records read lm2: ; Pass pseginfo, not hseg cCall SegReloc, lm2a: mov cx,hrleseg jcxz no_hrleseg push ax cCall IGlobalFree, pop ax no_hrleseg: les si,pseginfo or ax,ax jnz lschksum lsdone2: jmps lsdone lserr2: krDebugOut DEB_ERROR, "Error reading relocation records from %es2" xor ax,ax jmp lm2a lschksum: mov ax, hseg ; in case we aren't locking Handle_To_Sel al cmp pleaseNoLock, 0 jnz lschksum1 cCall MyLock, lschksum1: if LDCHKSUM push ax push si mov si,ax cCall ZeroSegmentChksum pop si cCall CheckSegChksum ; destroys ax, bx, cx, dx, es pop ax endif les si, pseginfo if ROM DefineSeg: if SDEBUG push ax ; save segment selector endif endif if SDEBUG ; Tell debugger about new segment cmp pleaseNoLock, 0 jnz keep_secrets mov bx,es:[ne_restab] inc bx mov dx,es:[si].ns_flags mov si, ax xor ax, ax test dx,NSDATA ; test to pass NSKCACHED too jz sa8 test byte ptr es:[ne_flags],NEINST jz sa8 mov ax,es:[ne_usage] dec ax sa8: mov cx,segno dec cx cCall DebugDefineSegment, keep_secrets: endif if ROM if SDEBUG pop ax ; recover segment selector endif mov dx,ax ; in case this is a ROM code seg, ; MyLock doesn't get called, but we ; want to return AX & DX = selector endif lsexit: mov cx,hseg jcxz lsdone mov ax, cx ; in case we don't lock mov dx, ax Handle_To_Sel al cmp pleaseNoLock, 0 jnz lsdone cCall MyLock, lsdone: if ROM mov cx,selROMrle ; If a segment was loaded from ROM, jcxz @f ; an extra selector was allocated push ax ; to point to reloc info--free that cCall IFreeSelector, ; now. pop ax @@: endif mov cx,myfh inc cx jz lsx dec cx cmp fh,cx je lsx push ax SetKernelDS ;;; cCall CloseCachedFileHandle, mov ax, SavePDB if KDEBUG or ax, ax jnz @F int 3 @@: endif mov Win_PDB, ax UnSetKernelDS pop ax public lsx lsx: mov es, hExe test es:[ne_flagsothers], NEHASPATCH jz ls_exeunt cmp fReload, 0 jne ls_exeunt push dx push ax cCall GetPatchAppRegKey, mov cx, dx or cx, ax jnz @F ; MCF_MODPATCH is set, but there are no patches ; in the registry for this module. Turn off the patch flag. and es:[ne_flagsothers], not NEHASPATCH jmp short ls_after_patch @@: ; reg key in dx:ax cCall PatchAppSeg, test ax, ax jz ls_after_patch ; One or more patches applied, so mark the segment not discardable. ; PatchAppSeg already cleared GA_DISCARDABLE or GA_DISCCODE in the ; global arena record. mov si, pseginfo.off and es:[si].ns_flags, not NSDISCARD ; mark not discardable ls_after_patch: pop ax pop dx ls_exeunt: mov cx,ax cEnd GETSEGLEN macro segval local not_huge_386 if PMODE32 .386p xor eax, eax ; since we now have huge segments, mov ax, segval ; we need to be able to handle limit lsl eax, eax ; values > 64K. On a 386 we just inc eax ; execute the lsl instruction. test eax, 0ffff0000h .286 jz not_huge_386 mov ax, 0 ; 0 == 64K not_huge_386: else cCall get_selector_length16, ; Get size of segment endif endm ;-----------------------------------------------------------------------; ; SegLoad ; ; ; ; Reads in the data portion of a code or data segment. ; ; ; ; It can be confusing decoding how various values of ns_cbseg, ; ; ns_minalloc, and ns_sector define the size of disk files. I hope ; ; this table is accurate for all combinations.... ; ; ; ; sector cbseg minalloc- Sector in memory is ... ; ; 0 0 0 - 64K segment, all 0's ; ; 0 0 m - 'm' bytes, all 0's ; ; 0 c 0 - illegal (sector = 0 when cbseg != 0) ; ; 0 c m - illegal (sector = 0 when cbseg != 0) ; ; s 0 0 - 64K segment on disk at given sector ; ; s 0 m - illegal (cbseg > minalloc) ; ; s c 0 - 64K, 'c' from file, 64K-'c' 0's ; ; s c m - 'm' bytes, 'c' from file, 'm-c' 0's ; ; ; ; In other words, cbseg == 0 means 64K when a sector value is given, ; ; else it means 0 bytes from the file ; ; ; ; Arguments: ; ; parmD pseginfo ; ; parmW segno ; ; parmW psegsrc ; ; parmW isfh ; ; ; ; Returns: ; ; ; ; Error Returns: ; ; ; ; Registers Preserved: ; ; ; ; Registers Destroyed: ; ; ; ; Calls: ; ; ; ; History: ; ; Thu Feb 28, 1991 01:39:00p -by- Don A. Corbitt [donc] ; ; Add support for big/huge segments ; ; ; ; Tue Oct 27, 1987 06:17:07p -by- David N. Weise [davidw] ; ; Added this nifty comment block. ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc SegLoad,, parmD pseginfo parmW segno parmW psegsrc parmW isfh localW hseg localW pseg localW psegdest localD prleinfo localW retry localW segoffset localW pleaseNoLock ;1 if segment is 64K localW allocTwice ;if first alloc fails, FreeTheWorld ifdef WOW_x86 localD rover_2 endif cBegin mov retry,1 mov segoffset, 0 mov allocTwice, 1 les si,pseginfo mov ax,es:[si].ns_handle mov hseg,ax Handle_To_Sel al ; in case we don't lock mov pleaseNoLock, 1 test es:[si].ns_flags, NSHUGESEG jnz dont_touch ;big segs are always locked and present mov pleaseNoLock, 0 push es cCall MyLock, pop es or ax,ax jz try_alloc ; wish I could "jnz saalloced" dont_touch: jmps saalloced try_alloc: push es xor ax,ax mov bx, es:[si].ns_minalloc xor dx, dx cmp bx, 1 adc dx, dx add bx, 2 ; We may have a 1 byte entry point at the adc dx, 0 ; very end of a segment. PatchCodeHandle ; will GP trying to decipher the prolog. ; Allow room to read relocation word ife PMODE32 push ds SetKernelDS cmp fPadCode, 0 je @F add bx, 14 adc dx, 0 @@: pop ds UnSetKernelDS endif cCall IGlobalReAlloc, pop es cmp hseg,ax jz sarealloced saerr2: test es:[si].ns_flags,NSDISCARD jz dont_scream push es cCall DiscardTheWorld ; Maybe if we try again pop es dec allocTwice jz try_alloc krDebugOut DEB_ERROR, "Out of mem loading seg %es2" dont_scream: jmp saerr1 sarealloced: ; ax == handle Handle_To_Sel al cmp pleaseNoLock, 0 jnz saalloced push es cCall MyLock, pop es or ax,ax jz saerr2 saalloced: mov pseg,ax mov psegdest,ax sareread: push es push si push ds ; We are going to trash this cld cmp es:[si].ns_sector,0 ; if sector == 0, then just init jnz sa_read_from_disk ; segment to all 0's ; mov cx, es:[si].ns_minalloc ; convert minalloc == 0 to 64K GETSEGLEN pseg mov cx, ax ifdef WOW_x86 ; .386 ;; WOW we can use the magic flat selector 23h to write to any segment ;; This saves us calling get_rover_2 which makes an NT system call to set ;; a temp selector cCall get_physical_address, shl edx,16 mov dx,ax mov ax,FLAT_SEL mov es,ax xor eax, eax mov edi,edx ; es:edi -> pseg:0 cmp cx, 1 ; Need to handle case where CX == 0 mov dx, cx rcr cx, 1 shr cx, 1 movzx ecx,cx rep stos dword ptr [edi] mov cx, dx and cx, 3 rep stos byte ptr [edi] jmp sa_after_read else ; 286 cmp cx, 1 ; set CF if 0000 rcr cx, 1 ; this sets CF for odd byte of size xor ax, ax xor di, di mov es, pseg ; start at pseg:0000 call get_rover_2 rep stosw adc cx, cx rep stosb ; this case now handled jmp sa_after_read endif; sa_read_from_disk: mov di,es:[si].ns_cbseg ; #bytes in segment to read ; If source segment address given then copy segment contents mov bx,psegsrc ; Get source handle cmp isfh,bx ; Is source a file handle? je sa_read_file ; Yes, go read segment from file ; We are reading from preload buffer, bx == src seg address, di == len push di ; No, set up for fast copy mov OFF_prleinfo,di mov SEG_prleinfo,bx pop cx if ROM mov al,byte ptr es:[si].ns_flags+1 ; Compressed seg in ROM? and al,(NSINROM OR NSCOMPR) SHR 8 cmp al,(NSINROM OR NSCOMPR) SHR 8 ; Both NSINROM & NSCOMPR must jnz @f ; be set jmp sa_exp_seg @@: endif mov ds,bx ifdef WOW_x86 ; .386 ;; For WOW on NT we don't want to set the selector unesssarily cCall get_physical_address, shl edx,16 mov dx,ax mov rover_2,edx mov ax,FLAT_SEL mov es,ax mov edi,edx ; es:edi -> pseg:0 xor esi,esi cmp cx, 1 ; set carry if 0 for big/huge segs mov ax, cx rcr cx, 1 shr cx, 1 movzx ecx,cx rep movs dword ptr [edi], dword ptr [esi] mov cx, ax and cx, 3 rep movs byte ptr [edi], dword ptr [esi] sub edi,edx ; make di correct for rest of code else mov es,pseg ; Writing to pseg call get_rover_2 xor si,si xor di,di IF ROM clc ; HACK: 64K segs not allowed in ROM ; because ns_sector always != 0 ELSE ; need to handle case where seg size is 64K (cx == 0) cmp cx, 1 ; set carry if 0 for big/huge segs ENDIF ife PMODE32 rcr cx, 1 ; set bit 15 if carry was set rep movsw adc cx, cx rep movsb else .386 mov ax, cx rcr cx, 1 shr cx, 1 rep movsd mov cx, ax and cx, 3 rep movsb .286 endif endif; WOW_x86 ; we have now read 'cbseg' bytes from preload buffer, di == cbseg jmp sa_zero_fill_rest saerr1: xor ax,ax jmp sax sa_read_file: ; read segment contents from disk file, bx == file handle ; ax = disk file sector if 0 ;KDEBUG push ax push ds SetKernelDS cmp fPreloadSeg, 0 jne SHORT SkipDebugTrace mov ax, segno krDebugOut , "%ES0: reading segment #ax" SkipDebugTrace: pop ds UnSetKernelDS pop ax endif ; Get offset to data portion of segment in DX:AX mov ax, es:[si].ns_sector xor dx,dx mov cx,es:[ne_align] sa4a: shl ax,1 adc dx, dx loop sa4a ; DX:AX = file offset to segment mov cx,dx ; Seek to beginning of segment data mov dx,ax mov ax,4200h ; lseek(bx, sector << align, SEEK_SET) DOSCALL jc saerr mov cx,di ; Get #bytes to read test es:[si].ns_flags,NSRELOC jz no_read_extra_word add cx, 2 ; Relocation word no_read_extra_word: mov ds,pseg ; Read segment from file xor dx,dx mov ah,3Fh test es:[si].ns_flags,NSITER jz @F call iterated_data_seg jmps sa_iter_done @@: or cx, cx ; if cx == 0 at this point, it is 64K jnz not_huge_read cmp es:[si].ns_minalloc,0 ; If minalloc isn't zero too, then the jnz not_huge_read ; segment is too small. Case should't ; happen but does for dbwindow, mimic Win 3.0. mov cx, 8000h DOSCALL ; read first 32K from disk jc saerr add dx, cx ; update destination address mov ah, 3fh ; restore AX (doscall trashes it) DOSCALL ; read second 32K jc saerr cmp ax, cx jnz saerr jmp short sa_zero_fill_rest not_huge_read: DOSCALL sa_iter_done: jc saerr ; Continue if no errors cmp ax,cx ; Read ok, did we get what we asked for? jne saerr ; No, fail test es:[si].ns_flags,NSRELOC ; Relocation records? jz sa_zero_fill_rest ; No, continue mov ax, ds:[di] ; Extra word was read here mov OFF_prleinfo, ax jmps sa_zero_fill_rest saerr: pop ds pop si pop es mov ax, -1 ; File error jmp sax if ROM sa_exp_seg: xor si,si mov es,pseg ;; NOT Compiled for WOW call get_rover_2 cCall LZDecode, mov di,ax or ax,ax jnz sa_zero_fill_rest if KDEBUG Debug_Out "LZDecode of segment failed!" endif pop ds pop si pop es jmp sax endif sa_zero_fill_rest: ; di == bytes written so far GETSEGLEN pseg ; seg len to ax, 0 == 64K sub ax,di ; Any uninitialized portion? jz sa_after_read ; No, continue ifdef WOW_x86; .386 ;; WOW we don't want to call NT to set the selector push ax cCall get_physical_address, shl edx,16 mov dx,ax mov ax,FLAT_SEL mov es,ax and edi,0000ffffh add edi,edx ; es:edi -> pseg:0 pop cx push edx xor eax,eax cld mov dx,cx shr cx, 2 movzx ecx,cx rep stos dword ptr [edi] mov cx, dx and cx, 3 rep stos byte ptr [edi] pop edx sub edi,edx else mov es,psegdest ; Yes, set it to zero call get_rover_2 mov cx,ax xor ax,ax cld shr cx, 1 rep stosw adc cx, cx rep stosb endif sa_after_read: les si, pseginfo if LDCHKSUM mov ds,psegdest xor si,si mov cx,di shr cx,1 xor dx,dx cld sa5b: lodsw xor dx,ax loop sa5b endif cmp pleaseNoLock, 0 jnz dont_patch push dx cCall , pop dx dont_patch: pop ds ; Restore DS pop si ; segment info pointer pop es mov ax,es:[si].ns_flags ; Are we loading a code segment? and ax,NSDATA .errnz NSCODE jnz sa9 ; Here when loading a code segment if LDCHKSUM mov cx,segno dec cx shl cx,1 shl cx,1 mov di,es:[ne_psegcsum] add di,cx mov cx,dx xchg es:[di],cx jcxz sa6a0 cmp cx,dx je sa6a0 dec retry jl sa6a1 public badsegread badsegread: mov ah,0Dh ; Disk Reset DOSCALL jmp sareread sa6a1: krDebugOut DEB_ERROR, "Segment contents invalid %es2" xor ax,ax jmps sax sa6a0: mov word ptr es:[di+2],0 endif sa9: mov dx,SEG_prleinfo mov cx,OFF_prleinfo mov bx,hseg mov ax,pseg sax: or ax,ax cEnd .286 ;-----------------------------------------------------------------------; ; iterated_data_seg ; ; This expands out iterated data segments (specifically for the ; OS/2 m.exe). Due to the late date this is being sleazed in ; instead of being done right. To be done right, the read would ; go into the last part of the present block, and expanded in place, ; the stack used for the next record count because the last record ; never fits. ; ; Entry: ; CX = number of bytes to read ; DS:DX = place to put them ; DS:DI = place where #relocs will magically appear ; ES:SI = module exe header:seg info ; ; Returns: ; CF = 1 ; DS:DI = updated magic place where #relocs will magically appear ; ; Error Return: ; CX = 0 ; ; Registers Destroyed: ; ; History: ; Sun 28-Jan-1990 12:25:02 -by- David N. Weise [davidw] ; Wrote it! ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc iterated_data_seg,, localW temp_buf localW freloc cBegin ; deal with that extra relocation word! xor ax,ax test es:[si].ns_flags,NSRELOC ; Relocation records? jz @F inc ax @@: mov freloc,ax ; first get a temp buffer push bx push cx cCall IGlobalAlloc,<0,0,cx> mov temp_buf,ax pop cx pop bx or ax,ax stc ; assume failure jz ids_exit push dx push ds ; read into the temp buffer mov ds,ax xor dx,dx mov ah,3Fh DOSCALL pop ds pop dx jc ids_exit1 cmp ax,cx jnz ids_exit1 ; expand the buffer, yes we should special case strings of length 1 cmp freloc,0 ; was an extra word read? jz @F sub cx,2 @@: mov dx,cx smov es,ds xor di,di mov ds,temp_buf xor si,si cld ids_next_group: lodsw ; get the # interations mov cx,ax lodsw ; get the # bytes @@: push cx push si mov cx,ax rep movsb pop si pop cx loop @B add si,ax ; get past group cmp si,dx jb ids_next_group ; data segment now processed, deal with reloc word cmp freloc,0 ; was an extra word read? jz @F movsw sub di,2 add dx,2 @@: mov ax,dx mov cx,dx clc ids_exit1: pushf ; preserve the carry flag push ax push cx smov ds,0 cCall IGlobalFree, pop cx pop ax popf ids_exit: cEnd ;-----------------------------------------------------------------------; ; PatchCodeHandle ; ; ; ; Patches the prologs of the procedures in the given code segment. ; ; ; ; Arguments: ; ; parmW hseg ; ; ; ; Returns: ; ; AX = hseg ; ; DX = pseg ; ; ; ; Error Returns: ; ; ; ; Registers Preserved: ; ; DI,SI,DS ; ; ; ; Registers Destroyed: ; ; BX,CX,ES ; ; ; ; Calls: ; ; MyLock ; ; ; ; History: ; ; ; ; Sun 17-Sep-1989 10:45:24 -by- David N. Weise [davidw] ; ; Added support for symdeb to understand segments in himem. ; ; ; ; Tue Oct 27, 1987 06:19:12p -by- David N. Weise [davidw] ; ; Added this nifty comment block. ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc PatchCodeHandle,, parmW hseg localW pseg localW hexe localW segno localW segoffset ifdef WOW_x86 .386 localD rover_2 endif cBegin SetKernelDS cCall MyLock, mov pseg,ax ; Save physical addresss or ax,ax ; All done if discarded jz pcsDone1 xor si,si mov segoffset, si push ax cCall GetOwner, mov es, ax pop ax cmp es:[si].ne_magic,NEMAGIC if KDEBUG jz good_boy bad_boy: krDebugOut DEB_ERROR "PatchCodeHandle, owner not NewExe %es2" jmps pcsDone1 good_boy: endif jne pcsDone1 mov hexe,es mov cx,es:[si].ne_cseg ; We need si to point to entry mov si,es:[si].ne_segtab ; anyway so do it the slow way pcsLoop: cmp es:[si].ns_handle,dx ; Scan table for handle je pcsFound add si,SIZE NEW_SEG1 loop pcsLoop pcsDone1: jmp pcsDone pcsExit1: jmp pcsExit pcsFound: sub cx,es:[ne_cseg] ; Compute segment# from remainder neg cx ; of loop count inc cx ; 1-based segment# mov segno,cx test es:[si].ns_flags,NSDATA jnz pcsExit1 .errnz NSCODE push si mov di,es:[ne_pautodata] or di,di jz sa6a cCall MyLock, mov di,ax sa6a: ; DI:0 points to data segment (or 0) ifdef WOW_x86 ;; For WOW we use the NT Magic data selector, since all 16 bit code is DATA cCall get_physical_address, assumes es,nothing shl edx,16 mov dx,ax ; ES:EDX -> pseg:0 mov rover_2,edx mov ax,FLAT_SEL mov es,ax else mov es,pseg ; ES:0 points to code segment call get_rover_2 endif mov ds,hexe ; DS:SI points to entry table assumes ds,nothing mov si,ds:[ne_enttab] cld or di, di ; Anything to do? jz sa6x sa6b: lods word ptr ds:[si] mov dx, ax lods word ptr ds:[si] sub ax, dx ; Get # entries in this block or ax,ax jz sa6x ; Done if zero push word ptr ds:[si] ; Next block add si, 2 ; Skip Next mov cx,ax sa6c: mov al,ds:[si].pentsegno ; Get segment# from int instruction cmp byte ptr segno,al ; Does this moveable segment match ES? jne sa6e ; No, advance to next entry ifdef WOW_x86 movzx ebx, word ptr ds:[si].pentoffset ; Get entry point offset add ebx,rover_2 mov al, ds:[si].pentflags ; Get entry point flags cmp byte ptr es:[ebx+2],90h ; Yes, followed by nop? jne sa6e ; No, can;t patch prolog then cmp word ptr es:[ebx],0581Eh ; Is it a push ds, pop ax? jne @F ; Yes, take care of prolog mov word ptr es:[ebx],0D88Ch jmps sa6d1 @@: cmp word ptr es:[ebx],0D88Ch ; Is it a mov ax,ds? jne sa6e ; No, can't patch prolog then sa6d1: test al,ENT_DATA ; Valid prolog. shared data? jnz sa6d2 ; Yes, patch mov ax,DGROUP into prolog test byte ptr ds:[ne_flags],NEINST ; No, multiple instances? jz sa6e ; No, do nothing test al,ENT_PUBLIC ; Public entry point? jz sa6e ; No, do nothing mov word ptr es:[ebx],09090h ; Yes, set nop, nop in prolog jmps sa6e sa6d2: mov byte ptr es:[ebx],0B8h ; Set mov ax, mov es:[ebx+1],di ; DGROUP else ; NOT WOW_x86 mov bx, ds:[si].pentoffset ; Get entry point offset mov al, ds:[si].pentflags ; Get entry point flags cmp byte ptr es:[bx+2],90h ; Yes, followed by nop? jne sa6e ; No, can;t patch prolog then cmp word ptr es:[bx],0581Eh ; Is it a push ds, pop ax? jne @F ; Yes, take care of prolog mov word ptr es:[bx],0D88Ch jmps sa6d1 @@: cmp word ptr es:[bx],0D88Ch ; Is it a mov ax,ds? jne sa6e ; No, can't patch prolog then sa6d1: test al,ENT_DATA ; Valid prolog. shared data? jnz sa6d2 ; Yes, patch mov ax,DGROUP into prolog test byte ptr ds:[ne_flags],NEINST ; No, multiple instances? jz sa6e ; No, do nothing test al,ENT_PUBLIC ; Public entry point? jz sa6e ; No, do nothing mov word ptr es:[bx],09090h ; Yes, set nop, nop in prolog jmps sa6e sa6d2: mov byte ptr es:[bx],0B8h ; Set mov ax, mov es:[bx+1],di ; DGROUP endif; WOW_x86 sa6e: add si,SIZE PENT ; Advance to next entry in loop sa6c ; this block pop si or si, si jnz sa6b sa6x: mov es,hexe pop si pcsExit: or byte ptr es:[si].ns_flags,NSLOADED ; Mark segment as loaded ;;;if SDEBUG ; Tell debugger about new segment ;;; mov bx,es:[ne_restab] ;;; inc bx ;;; mov dx,es:[si].ns_flags ;;; mov ax,segoffset ; tell symdeb how to fixup symbols ;;; test dx,NSDATA ; test to pass NSKCACHED too ;;; jz sa8 ;;; test byte ptr es:[ne_flags],NEINST ;;; jz sa8 ;;; mov ax,es:[ne_usage] ;;; dec ax ;;;sa8: ;;; mov cx,segno ;;; dec cx ;;; cCall DebugDefineSegment, ;;;endif pcsDone: mov ax,hseg mov dx,pseg cEnd sEnd CODE externFP FarAllocSeg externFP FarMyAlloc externFP FarMyAllocLinear externFP FarMyFree externFP FarSetOwner sBegin NRESCODE assumes CS,NRESCODE assumes DS,NOTHING assumes ES,NOTHING externNP MapDStoDATA externA __AHINCR ;-----------------------------------------------------------------------; ; AllocAllSegs ; ; ; ; "Allocates" for all segments of the module being loaded and stores ; ; the addresses in the segment table. By allocate we mean: ; ; ; ; AUTOMATIC DATA gets space, but not yet loaded, ; ; PRELOAD FIXED get global mem allocated , but not yet loaded, ; ; MOVEABLE get a handle for later use, ; ; FIXED get nothing. ; ; ; ; If this is not the first instance, then just allocate space for ; ; the new instance of the automatic data segment. ; ; ; ; Arguments: ; ; parmW hexe ; ; ; ; Returns: ; ; ; ; Error Returns: ; ; AX =-1 not enough memory ; ; ; ; Registers Preserved: ; ; ; ; Registers Destroyed: ; ; ; ; Calls: ; ; FarAllocSeg ; ; FarMyAlloc ; ; FarMyFree ; ; ; ; History: ; ; ; ; Tue Feb 24, 1987 01:04:12p -by- David N. Weise [davidw] ; ; Added this nifty comment block. ; ;-----------------------------------------------------------------------; cProc AllocAllSegs,, parmW hexe localW cSegs localD hugeLen ; cum length of huge segment localW hugeIndex ; index of first segment of huge localW hugeOffs ; offset of first segment desc of huge localW hugeCnt ; segments making up huge seg localW hugeFlags ; flags of huge segment (needed?) cBegin call MapDStoDATA ReSetKernelDS mov es,hexe mov si,es:[ne_segtab] xor di,di mov cSegs,di inc di cmp es:[ne_usage],di je paloop mov si,es:[ne_pautodata] and byte ptr es:[si].ns_flags,not NSALLOCED+NSLOADED mov di,es:[si].ns_handle cCall FarAllocSeg, or ax,ax jz aa_nomem inc cSegs outahere: jmp pagood aa_nomem: mov es,hexe or byte ptr es:[si].ns_flags,NSALLOCED+NSLOADED mov es:[si].ns_handle,di jmp pafail3 paloop: cmp di,es:[ne_cseg] jbe more_to_go jmp pagood more_to_go: mov bx,es:[si].ns_flags test bl,NSPRELOAD ; Are we preloading? jz not_preload test bl,NSDATA ; Preload data although moveable jnz paalloc if ROM test bh,(NSINROM SHR 8) ; Segment in ROM? jz @f test bl,NSLOADED ; Yes, is it already 'loaded'? jnz set_rom_owner ; Yes, just need to set owner @@: endif test bl,NSMOVE ; Fixed segment? jz paalloc ; Yes, allocate segment not_preload: if ROM test bh,(NSINROM SHR 8) ; Segment in ROM? jz @f if KDEBUG test bl,NSDATA ; (non-preload data segments in ROM jz not_rom_data ; haven't been tested) int 3 not_rom_data: endif test bl,NSLOADED ; Yes, already 'loaded'? jnz set_rom_owner ; Yes, just need to set owner @@: endif test bl,NSALLOCED ; Already allocated? jnz panext ; Yes, then nothing to do test bl,NSMOVE ; Fixed segment? jz panext ; Yes, then nothing to do xor cx,cx ; No, allocate zero length push es ; object so that we guarantee cCall FarMyAlloc, ; we will have a handle. pop es or dx,dx ; Fail if we cant get a handle jz pafail if ROM ; If this segment gets loaded from ROM, change the segment handle ; to be the one that was used to fix-up the ROM code segments. This ; is the value of ns_sector in the segment table. test byte ptr es:[si].ns_flags+1,(NSINROM SHR 8) jz not_a_rom_seg mov bx,es:[si].ns_sector test dl,GA_FIXED jnz sa_fixed StoH bx sa_fixed: cCall ChangeROMHandle, mov dx,bx not_a_rom_seg: endif mov es:[si].ns_handle,dx ; Handle into seg table and byte ptr es:[si].ns_flags,not NSLOADED or byte ptr es:[si].ns_flags,NSALLOCED mov bx,dx ; put handle into base register call set_discarded_sel_owner jmps panext if ROM set_rom_owner: cCall FarSetROMOwner, jmps panext endif paalloc: cmp es:[si].ns_minalloc, 0 jnz paalloc_fer_shure jmps PAHugeAlloc paalloc_fer_shure: cCall FarAllocSeg, or ax,ax jz pafail inc cSegs panext: add si,size NEW_SEG1 inc di jmp paloop ; only gets here if not enough memory, free up all previous segments pafail: mov si,es:[ne_segtab] mov cx,es:[ne_cseg] pafail1: push cx mov cx,es:[si].ns_handle jcxz pafail2 push es ;Need to handle freeing huge segments!!! cCall FarMyFree, pop es mov es:[si].ns_handle, 0 ; Necessary for EntProcAddress pafail2: and byte ptr es:[si].ns_flags,not (NSALLOCED+NSLOADED) add si,size NEW_SEG1 pop cx loop pafail1 pafail3: mov cSegs,-1 jmp pagood PAHugeAlloc: ; at this point, es:si -> current seg record ; di is segment index (range from 1 to es:[ne_cseg]) mov off_hugeLen, 0 mov seg_hugeLen, 0 ; init length to 0K mov hugeOffs, si mov hugeCnt, 1 mov ax, es:[si].ns_flags or ax, NSHUGESEG mov hugeFlags, ax PAHugeLoop: mov ax, es:[si].ns_minalloc ; add current segment to group cmp ax, 1 sbb dx, dx neg dx add off_hugeLen, ax adc seg_hugeLen, dx or es:[si].ns_flags, NSHUGESEG cmp es:[si].ns_minalloc, 0 ; jnz PAHugeEndLoop cmp di, es:[ne_cseg] jae PAHugeEndLoop mov ax, si add ax, size NEW_SEG1 cmp ax, es:[ne_pautodata] jz PAHugeEndLoop mov ax, hugeFlags ; do flags have to be identical? cmp ax, es:[si].ns_flags jnz PAHugeEndLoop inc hugeCnt inc di add si, size NEW_SEG1 jmp PAHugeLoop PAHugeEndLoop: inc di push es or hugeFlags, NSMOVE cCall FarMyAllocLinear, pop es or ax, ax ; check for error jnz Not_pafail jmp pafail Not_pafail: mov si, hugeOffs ; fix up segment(s) and es:[si].ns_flags, NOT NSHUGESEG PAHugeSegLoop: mov es:[si].ns_handle, dx and byte ptr es:[si].ns_flags, not NSLOADED or byte ptr es:[si].ns_flags, NSALLOCED cCall FarSetOwner, add si, size NEW_SEG1 add dx, __AHINCR dec hugeCnt jnz PAHugeSegLoop ; continue with rest of allocations jmp paloop pagood: mov ax,cSegs cEnd sEnd NRESCODE end