📄 ldthunk.asm
字号:
cProc PatchThunkDiscarded,<NEAR,PUBLIC>,<DS>
parmB segno
cBegin PatchThunkDiscarded
mov fLockoutSweep,1
;* * Scan the entry table
mov ds,psLom ;* assumed throughout
mov bx,ds:[neLom.ne_rgentmove]
mov cx,ds:[neLom.ne_cmovent]
mov al,segno
pds_lp:
cmp al,ds:[bx].segnoEntmove ;* segment in question ?
jne pds_nxt
cmp ds:[bx].opcEntmove1,opcCalln ;* already a calln
jz pds_already_entmove1
;* * convert ENTMOVE -> ENTMOVE1
AssertEq ds:[bx].opcEntmove1,opcJmpf ;* must have been far call
mov ds:[bx].opcEntmove1,opcCalln
mov dx,ds:[bx].offEntmove ;* resident offset
mov ds:[bx].offDestEntmove1,dx ;* non-resident offset
pds_already_entmove1:
mov dx,opcReloadLom-3 ;* reload - 3 for call
sub dx,bx
mov ds:[bx].relEntmove1,dx ;* relative jump
pds_nxt:
add bx,SIZE ENTMOVE
loop pds_lp
;* * set segment reference byte
dec al
xor ah,ah
add ax,ds:[neLom.ne_psegrefbytes]
mov bx,ax
mov byte ptr ds:[bx],segrefDiscarded
mov fLockoutSweep,0
cEnd PatchThunkDiscarded
;*****************************************************************************
;***** LRU SWEEP *****
assumes ds,DATA
assumes ss,nothing ;* called by interrupt
;********** SweepLru **********
;* entry : n/a (DS = DDS)
;* * if necessary, sweep the LRU
;* exit : n/a
;* * NOTE : sweeping the LRU is defined as follows:
;* 1) for all thunks that are direct jumps (ENTMOVE, i.e. JMPF),
;* change them to ENTMOVE1 calls to RelruSegment
;* 2) bump all segref bytes by 1, stick if new value negative
;* NOTE : fixed, discarded or max LRU will not change
cProc SweepLru,<NEAR,PUBLIC,ATOMIC>
cBegin SweepLru
assumes DS,DGROUP
cmp levelLru,1 ;* <=1 => ignore
ifdef FOR_QC
ja @F
jmp sw_end
@@:
else ; !FOR_QC
jbe sw_end
endif ; FOR_QC
;* * if we interrupted internal processing, then ignore interrupt
test fLockoutSweep,0ffh
ifdef FOR_QC
jz @F
jmp sw_end
@@:
else ; !FOR_QC
jnz sw_end
endif ; FOR_QC
;* * Perform Sweep
push ds
mov ds,psLom ;* all work in LOM
assumes ds,NOTHING
;* * STEP 1 - sweep thunks
mov bx,ds:[neLom.ne_rgentmove]
mov cx,ds:[neLom.ne_cmovent]
jcxz sw_end
AssertNe cx,0
IFDEF FOR_QC
mov dx,-1
ENDIF ; FOR_QC
swthk_loop:
Assert <opcEntmove EQ opcEntmove1>
cmp ds:[bx].opcEntmove,opcJmpf ;* JMPF => resident
jne swthk_next ;* else not resident
IFDEF FOR_QC
;* * See if the segment is bound
mov al,ds:[bx].segnoEntmove ;* Get the segment number
cmp al,dl ;* Is it the same as the last?
je swthk_qc1
push bx ;* Save value
mov bx,ds:[neLom.ne_psegrefbytes] ;* Point to array of segrefs
xor ah,ah ;* Clear byte
add bx,ax ;* Offset by segment number
dec bx ;* Make zero based
mov dh,ds:[bx] ;* Get current value
mov dl,al ;* Save segment number
pop bx ;* Restore value
swthk_qc1:
test dh,080h ;* Is it negative?
jnz swthk_next ;* Yes -- bound -- skip
ENDIF ; FOR_QC
;* * convert from resident to ReLru.
mov ds:[bx].opcEntmove1,opcCalln
mov ax,ds:[bx].offEntmove ;* resident offset
mov ds:[bx].offDestEntmove1,ax ;* non-resident offset
mov ax,opcRelruLom-3 ;* relru - 3 for call
sub ax,bx
mov ds:[bx].relEntmove1,ax ;* relative jump
swthk_next:
add bx,SIZE ENTMOVE
loop swthk_loop
;* * STEP 2 - sweep seg ref bytes
Assert <segrefLoaded EQ 0>
Assert <(segrefDiscarded+1) AND 80H> ;* must be negative to stick
Assert <(segrefFixed+1) AND 80H> ;* " " "
mov cx,ds:[neLom.ne_cseg]
dec cx ;* none for DGROUP
mov bx,ds:[neLom.ne_psegrefbytes]
AssertNe cx,0
swref_loop:
inc byte ptr ds:[bx]
jns swref_next
dec byte ptr ds:[bx] ;* overflow => keep at 255
swref_next:
inc bx
loop swref_loop
pop ds
assumes ds,DATA
IFNDEF NOPCODE
;* * sweep clear handle table
push di
mov di,dataOffset $q_mpsnq
xor cx,cx
xchg cx,ds:[di-2] ;* clear cwClear / get count
push ds
pop es ;* es:di => entries
xor ax,ax
cld ;* called from interrupt
;* D flag unknown !
rep stosw ;* clear table
pop di
ENDIF ;!NOPCODE
mov levelLru,0 ;* not active until Reload or
;* Relru is called
sw_end:
cEnd SweepLru
;********** BindSegment **********
;* entry : lpfn = pointer to a thunk
;* fBind => whether to bind or unbind
;* * Bind or unbind a segment
;* exit : n/a
cPublic BindSegment, <>
parmD lpfn
parmW fBind
cBegin BindSegment
assumes DS,DATA
assumes DS,DGROUP
les bx,lpfn ;* es == psLom
IFDEF DEBUG
;* * make sure that it is a thunk
mov ax,psLom
mov cx,es
cmp ax,cx
je ok_bind
cCall CowAssertFailed
DB "bad BindSegment call$"
ok_bind:
ENDIF ;DEBUG
;* * Get segment number to bind/unbind
xor dx,dx
mov dl,es:[bx+segnoEntmove1]
mov bx,dx
dec bx
BS10:
add bx,es:[neLom.ne_psegrefbytes]
mov al,es:[bx] ;* al = segref
mov cx,fBind
jcxz bind_unbind ;* cl == 0 => just LRU'd
;* * bind : we may have to reload the segment
cmp al,segrefBound
je end_bind ;* already bound
cmp al,segrefDiscarded
jne bind_loaded
Save <bx,dx>
cCall LoadSegment, <dx> ;* load it
bind_loaded:
mov cl,segrefBound
bind_update: ;* cl = segref
mov es:[bx],cl
ifdef FOR_QC
;* * Walk all thunks for this segment and make jmpfs
mov fLockoutSweep,1
push ds
;* Scan the entry table
mov ax,dx ;* Get segment number
dec ax ;* Zero base it
mov cx,SIZE NEW_SEG1 ;* Convert into offset in
imul cl ;* the segment info table
mov bx,ax ;*
add bx,es:[neLom.ne_segtab] ;*
mov bx,es:[bx].ns_handle ;* Get the segments handle
mov es,[pGlobalHeap] ;* Convert handle into segment no
AssertNe es:[bx].he_flags, HE_DISCARDED
mov es,es:[bx].he_address ;*
mov ds,[psLom] ;*
assumes ds,nothing ;*
mov bx,ds:[neLom.ne_rgentmove]
mov cx,ds:[neLom.ne_cmovent]
mov ax,dx
bs_pld_lp:
cmp al,ds:[bx].segnoEntmove ;* Segment in question ?
jne bs_pld_nxt
cmp ds:[bx].opcEntMove,opcJmpf
je bs_pld_nxt
AssertEq ds:[bx].opcEntmove,opcCalln ;* should have been a call
mov ds:[bx].opcEntmove,opcJmpf
mov dx,ds:[bx].offDestEntmove1
mov ds:[bx].offEntmove,dx
mov ds:[bx].segEntmove,es
bs_pld_nxt:
add bx,SIZE ENTMOVE
loop bs_pld_lp
pop ds
assumes ds,DGROUP
mov fLockoutSweep,0
endif ; FOR_QC
end_bind:
cEnd BindSegment
bind_unbind: ;* unbind segment
;* * Note: due to overbinding, the segment could be:
;* * normal resident (moveable/discardable), bound or discarded
cmp al,segrefDiscarded
je end_bind ;* keep discarded
AssertEQ cx,0
jmp short bind_update ;* just re-lru
IFDEF KERNEL_SWAP_STACK
;* the following is QC specific
;********** BindPS **********
;* entry : ps = physical segment to bind
;* fBind => whether to bind or unbind
;* * Bind or unbind a segment
;* exit : n/a
cPublic BindPS,<>
parmW ps
parmW dummy
parmW fBind
cBegin BindPS
assumes DS,DGROUP
push si
mov es,psLom
mov si,es:[neLom.ne_segtab]
mov cx,es:[neLom.ne_cseg]
xor dx,dx
BPS10:
mov bx,es:[si].ns_handle ;* handle or ps
mov ax,es:[si].ns_flags ;*
test ax,NSMOVE ;* can it move?
jz BPS50 ;* no-
push es
mov es,pGlobalHeap ;*
test es:[bx].he_flags,HE_DISCARDED ;* Can't bind a discarded
;* segment this way
mov bx,es:[bx].he_address ;* dereference
pop es
jnz BPS50 ;* --- TRUE if segment is discarded
cmp bx,ps ;* Is this the segment I want?
je BPS60 ;* Yes -- bind it down
BPS50:
add si,SIZE NEW_SEG1
inc dx
loop BPS10
ifdef DEBUG
cCall CowAssertFailed
DB "bad BindPS call$"
endif ; DEBUG
BPS60:
pop si
mov bx,dx
inc dx
jmp bs10
cEnd BindPS
ENDIF ;KERNEL_SWAP_STACK
;********** UnbindAll **********
;* entry : n/a (DS != DDS)
;* * unbind all bound segments (for low memory conditions)
;* exit : n/a
cProc UnbindAll, <NEAR, PUBLIC, ATOMIC>, <DS>
cBegin UnbindAll
assumes SS,DGROUP
assumes DS,NOTHING
mov ds,psLom
mov cx,ds:[neLom.ne_cseg]
dec cx ;* cx = # of code segments
mov bx,ds:[neLom.ne_psegrefbytes] ;* es:bx => segref array
unbind_loop:
cmp byte ptr ds:[bx],segrefBound
jne unbind_next
mov byte ptr ds:[bx],segrefLoaded ;* unbound
unbind_next:
inc bx
loop unbind_loop
cEnd UnbindAll
;********** GetCodeHandle **********
;* entry : ps = psThunk, ib = ibThunk
;* * Return a valid code handle for given thunk
;* * Code segment will be resident on exit
;* exit : ax == code handle
;*
cProc GetCodeHandle,<FAR,PUBLIC,ATOMIC>,<SI>
parmW ps
parmW ib
cBegin GetCodeHandle
assumes DS,DGROUP
mov es,ps ; es:bx => thunk
mov bx,ib
IFDEF DEBUG
mov ax,es
AssertEq ax,psLom ; thunks are in psLom
ENDIF ;DEBUG
cmp es:[bx].opcEntmove,opcJmpf
jnz not_ENTMOVE
;* * ENTMOVE Segment is resident, return ga_handle from arena
mov ax,es:[bx].segEntmove
dec ax
mov es,ax ; es:0 => arena
mov ax,es:[ga_handle]
jmp short gch_end
not_ENTMOVE:
;* * ENTMOVE1 or ENTMOVE2
; Segment may or may not be resident, load segment
; if necessary, return ns_handle from NEWSEG1
;* * get ns_handle
xor ax,ax
mov al,es:[bx].segnoEntmove1
AssertSet ax,0ffh ; must be non-zero
mov cx,ax ; segno in cx for LoadSegment
dec ax
mov bl,size NEW_SEG1 ; bigger speedier method in LoadSegment
mul bl
mov si,ax
IFDEF DEBUG
mov ax,es
AssertEq ax,psLom ; es should not have changed
ENDIF ;DEBUG
add si,es:[neLom.ne_segtab] ; es:si => NEW_EXE1
mov si,es:[si].ns_handle ; si == ns_handle
mov es,pGlobalHeap ; es:si => handle entry
;* * if segment is discarded, load it
test es:[si].he_flags,HE_DISCARDED
jz no_load
cCall LoadSegment,<cx>
no_load:
mov ax,si
gch_end:
cEnd GetCodeHandle
;*****************************************************************************
;IFDEF DEBUG ;* Debug entry for thunk info
;*********** GetCodeInfo **********
;* entry : lpProc = far pointer to a thunk or code segment
;* lpSegInfo => buffer of size SIZE(NEW_SEG1) + 2 bytes
;* exit : ax = 0 if not a valid thunk / entry
;* else ax != 0, *lpSegInfo filled with seg info (SEGI: see winreq.doc)
cProc GetCodeInfo,<PUBLIC,FAR>,<ds,si,di>
parmD lpProc
parmD lpSegInfo
cBegin
assumes DS,NOTHING
assumes SS,DGROUP
lds si,lpProc
mov ax,ds
cmp ax,psLom
jnz not_a_thunk
;* * ds:si => thunk
mov al,ds:[si].segnoEntmove
save_segi: ;* al = segno (1 based)
mov ds,psLom
dec ax ;* (dec al) -- make 0 based
mov bl,SIZE NEW_SEG1
mul bl
add ax,ds:[neLom.ne_segtab]
mov si,ax ;* source
les di,lpSegInfo ;* destination
mov cx,SIZE NEW_SEG1 / 2
;; cld
rep movsw
mov bx,lomOffset neLom ;* DS:BX => New Exe header
mov ax,ds:[bx].ne_align ; Return segment aligment
stosw
sub si,SIZE NEW_SEG1
sub di,SIZE NEW_SEG1+2
cmp si,ds:[bx].ne_autodata
jne gciExit
mov ax,ds:[bx].ne_stack
add ax,ds:[bx].ne_heap
add es:[di].ns_minalloc,ax
gciExit:
mov cx,ax
cEnd
not_a_thunk: ;* ds:si => a procedure in a fixed segment
mov dx,ds ;* psFixed
mov ds,psLom
mov cx,ds:[neLom.ne_cseg]
mov bx,ds:[neLom.ne_segtab]
mov ax,1 ;* 1 based segment #
find_fixed_loop:
cmp dx,ds:[bx].ns_handle
je save_segi
add bx,SIZE NEW_SEG1
inc al
loop find_fixed_loop
xor ax,ax ;* failure
jmp short gciExit
;ENDIF ;DEBUG
;*****************************************************************************
sEnd KERNEL
;*****************************************************************************
sBegin INIT
assumes CS,INIT
assumes DS,DATA
assumes SS,DGROUP
;********** InitThunk **********
;* entry : n/a
;* * Initialize the thunk manager
;* exit : n/a
;* * NONCONFORMING (trashes SI/DI)
cProc InitThunk,<PUBLIC,FAR,ATOMIC>
cBegin InitThunk
assumes ds,dgroup
push ds
mov ds,psLom ;* assumed throughout
assumes ds,nothing
xor di,di
;* * Patch near calls to far calls
;* * opcodes
mov al,opcJmpf
mov ds:[di].opcReloadLom,al
mov ds:[di].opcRelruLom,al
mov ds:[di].opcRetThunkLom,al
;* * segments
mov ax,SEG kernelBase ;* KERNEL FIXED segment
mov ds:[di].psReloadLom,ax
mov ds:[di].psRelruLom,ax
mov ds:[di].psRetThunkLom,ax
;* * offsets
mov ds:[di].offReloadLom,kernelOffset ReloadSegment
mov ds:[di].offRelruLom,kernelOffset RelruSegment
mov ds:[di].offRetThunkLom,kernelOffset ReturnThunk
;* * First re-format the entry table to contain reload pointers
;* * The loader has put CALLN opcodes in the entries that are not resident
mov si,ds:[neLom.ne_rgentmove]
mov cx,ds:[neLom.ne_cmovent]
jcxz thi_done
thi_lp:
mov al,ds:[si].opcEntmove ;* opcJmpf or opcCallf
cmp al,opcJmpf
je thi_nxt
AssertEq al,opcCalln
;* * insert CALLN to ReloadSegment
mov ax,opcReloadLom-3 ;* where to jump to - 3 for jump
sub ax,si ;* relative offset
mov ds:[si].relEntmove1,ax
thi_nxt:
add si,SIZE ENTMOVE
loop thi_lp
;* * Next, fill in the return thunk table
;* * The loader has done nothing but allocate this.
mov cx,ds:[neLom.ne_cseg]
dec cx ;* ignore DGROUP
mov si,ds:[neLom.ne_pretthunks]
mov dl,1 ;* 1 based seg #
thi2_lp:
mov ds:[si].opcEntret,opcCalln
mov ax,opcRetThunkLom-3 ;* where to jump to - 3 for jump
sub ax,si ;* relative offset
mov ds:[si].relEntret,ax
mov ds:[si].segnoEntret,dl
inc dl
add si,SIZE ENTRET
loop thi2_lp
assumes ds,data
thi_done:
pop ds
cEnd InitThunk
sEnd INIT
;*****************************************************************************
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -