|
|
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
DataBegin
externB Kernel_flags ;externB fBooting externB fPadCode ;externW pGlobalHeap ;externW MyCSDS externW Win_PDB
if KDEBUG externB fLoadTrace externB fPreloadSeg endif
externD FreeArenaCount extrn CountFreeSel:WORD
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,<PUBLIC,NEAR>,<si,es> 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,<bx,dxax> pop es pop bx or ax,ax jz asxj
as2: 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,<ax,es>
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,<PUBLIC,NEAR>,<si,di> 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 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 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
test bl,NSALLOCED jnz ls1 push bx cCall AllocSeg,<essi> ; 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, <hExe, fh, ax> 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,<hExe,ax,ax> ; 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,<essi,segno,ax,isfh> 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,<bx> mov bx, SavePDB mov Win_PDB, bx cCall FlushCachedFileHandle,<hExe> ; 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 .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 cCall IGlobalAlloc,<ax,xsize> mov hrleseg,ax ; Save handle or ax,ax ; Did we get the memory jz lm1a ; No, then read one at a time
cCall IGlobalLock,<ax> ; 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,<hexe,essi,creloc,pseginfo,fdataseg,myfh> lm2a: mov cx,hrleseg jcxz no_hrleseg push ax cCall IGlobalFree,<hrleseg> 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,<hseg> 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 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,<esbx,cx,si,ax,dx> keep_secrets: 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,<cx> lsdone: mov cx,myfh inc cx jz lsx dec cx cmp fh,cx je lsx push ax SetKernelDS ;;; cCall CloseCachedFileHandle,<cx> 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,<hExe> 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,<dx,ax,segno,hseg> 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 .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: 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,<NEAR,PUBLIC>,<si,di> 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,<ax> 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 cCall IGlobalReAlloc,<hseg,dx,bx,ax> 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,<hseg> 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,<pseg> 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
mov ds,bx ifdef WOW_x86 ; .386 ;; For WOW on NT we don't want to set the selector unesssarily cCall get_physical_address,<pseg> 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
; need to handle case where seg size is 64K (cx == 0) cmp cx, 1 ; set carry if 0 for big/huge segs .386 mov ax, cx rcr cx, 1 shr cx, 1 rep movsd mov cx, ax and cx, 3 rep movsb .286 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 <DEB_TRACE or DEB_krLoadSeg>, "%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
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,<psegdest> 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 <far ptr PatchCodeHandle>,<hseg> 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,<PUBLIC,NEAR>,<bx,dx,si,ds,es>
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,<temp_buf> 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,<PUBLIC,FAR>,<si,di> parmW hseg localW pseg localW hexe localW segno localW segoffset ifdef WOW_x86 .386 localD rover_2 endif cBegin SetKernelDS cCall MyLock,<hseg> 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,<pseg> 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,<es:[di].ns_handle> 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,<pseg> 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,<esbx,cx,pseg,ax,dx> ;;;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,<NEAR,PUBLIC>,<si,di,ds> 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,<essi> 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 test bl,NSMOVE ; Fixed segment? jz paalloc ; Yes, allocate segment not_preload:
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,<bx,cx,cx> ; we will have a handle. pop es or dx,dx ; Fail if we cant get a handle jz pafail 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
paalloc:
cmp es:[si].ns_minalloc, 0 jnz paalloc_fer_shure jmps PAHugeAlloc
paalloc_fer_shure: cCall FarAllocSeg,<essi> 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,<cx> 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, <hugeFlags, hugeLen> 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, <ax, es> 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
|