highload.inc
来自「Dos6.0」· INC 代码 · 共 1,910 行 · 第 1/5 页
INC
1,910 行
;******************************************************************************
;
; (C) Copyright MICROSOFT Corp. 1989-1991
;
; Module: HIGHLOAD.INC - Code used to prepare for LoadHigh or DeviceHigh
;
; Date: May 14, 1992
;
;******************************************************************************
;
; Modification log:
;
; DATE WHO DESCRIPTION
; -------- ------- ----------------------------------------------
; 05/14/92 t-richj Original
; 06/21/92 t-richj Final revisions before check-in
;
;******************************************************************************
;
; This file contains routines needed to parse and implement user-given
; command-line options of the form "/S/L:3,0x500;2;7,127;0x0BE4". InitVar()
; and Parsevar() are used to parse this data and place it in encoded form into
; the variables in highvar.inc, for use by the rest of the routines.
;
; DeviceHigh accepts this command-line (handled in sysconf.asm, not here):
; DEVICEHIGH SIZE=hhhhhh module opts
; Or, DeviceHigh and LoadHigh accept any of the following:
; DH/LH module opts
; DH/LH [/S][/L:umb[,size][;umb[,size]]*] module opts
; DH/LH [/L:umb[,size][;umb[,size]]*][/S] module opts
; The initial UMB,SIZE pair designates the module's load address; the remainder
; of the UMB and SIZE pairs are used to indicate specific UMBs to be left
; available during the load.
;
; When an actual load is ready to be performed, a call to HideUMBs() will
; temporarily allocate (as owner 8+"HIDDEN ") all free elements in any
; upper-memory block which was not specified by the user... in addition, if
; UMBs were marked to shrink (/S option) to a certain size ("umb,size"), any
; elements in that umb SAVE the lower-half of the newly-shrunken one are also
; allocated. After the load, the function UnHideUMBs() (in highexit.inc) will
; free any UMBs so allocated.
;
; When a device driver loads, there is the additional problem of allocating its
; initial load site; this should be restricted to the first UMB specified on
; the command-line. The function FreezeUM temporarily allocates all remaining
; free upper-memory elements (as owner 8+"FROZEN "), except those in the load
; UMB. Then the initial allocation may be made, and a call to UnFreeze will
; return any so-allocated memory elements to FREE, for the true load. Note
; that UnFreeze leaves HIDDEN elements allocated; it only frees FROZEN ones.
;
;******************************************************************************
;
; Public:
;
;___PROCEDURES_________________________________________________________________
;
; AddrToUmb - converts a segment address in AX to its appropriate UMB #
; BigFree - makes ES:0 point to the largest free MCB in UMB given as AL
; FixMem - scans the UM chain and concatenates adjacent free MCBs
; FreezeUM - Marks FROZEN all UM elements now FREE, save those in load UMB
; GetLoadSize - Returns the load UMB minimum size (0 if not specified)
; GetLoadUMB - Returns the load UMB number in AL (-1 if not specified)
; GetSize - Returns the UMB in AL's minimum size (0 if not specified)
; GetXNum - reads a 32-bit ASCII number at ES:SI and returns it in DX:AX
; HideUMBs - links UMBs and hides upper-memory as appropriate
; InitVar - initializes all the variables used in ParseVar and HideUMBs
; NextMCB - moves an MCB pointer forward to the next MCB
; ParseVar - parses [/S][/L:umb[,size][;umb[,size]]*] and builds the table
; PrTable - produces a printout of the variables in highvar.inc
; StoLoadSize - Overrides the load UMB minimum size with what's in AX
; StoLoadUMB - Overrides the load UMB number with what's in AL
; UmbHead - returns in AX the address of the first UMB block (0x9FFF)
; UnFreeze - Marks FROZEN elements as FREE
;
;___VARIABLES__________________________________________________________________
;
; gnradix - After a call to GetXNum, is 16 or 10, depending on the # read
;
; Internal:
;___PROCEDURES_________________________________________________________________
;
; convUMB - checks after GetXNum to convert an address to a UMB number
; findUMB - makes ES:0 point to the first MCB in UMB given as AL
; fm_link - links UMBs not already linked in
; fm_unlink - unlinks UMBs if fm_umb is set to 0
; frezMCB - marks as 8+FROZEN the MCB at ES:0
; hideMCB - marks as HIDDEN the MCB at ES:0
; hideUMB - marks as HIDDEN all FREE elements in UMB passed as AL
; hideUMB? - hides as appropriate the UMB in CL
; hl_unlink - unlinks UMBs if fm_umb is set to 0; restores strategy too
; incArgc - increments fm_argc, for use with LH command-line parsing
; isEOL - returns with ZF set iff AL contains CR or LF, or 0
; isFreeMCB - returns with ZF set if current MCB (ES:0) is FREE
; isFrozMCB - returns with ZF set if current MCB (ES:0) is FROZEN
; isSpecified - sets ZF if UMB in AL wasn't specified in DH/LH line.
; isSysMCB - sets ZF iff ES points to an MCB owned by "SC" + (8 or 9)
; isTiny - returns with ZF set if user didn't specify /S
; isWhite - returns with ZF set iff AL contains whitespace (or "=")
; loadLow - returns AL==0 if UMB0 == 0, else AL==1
; mul32 - multiplies the number in DX:AX by gnradix
; parseL - parses ":nnnn[,nnnn][;nnnn[,nnnn]]*" for ParseVar
; setUMBs - links umbs and sets allocation strategy for a load
; shrinkMCB - breaks an MCB into two pieces, the lowest one's size==AX
; stowSiz - marks a given UMB as having a given minimum size
; stowUMB - marks a given UMB as used, if it hasn't been so marked before
; toDigit - converts a character-digit to its binary counterpart
; toPara - divides DX:AX by 16; result in AX only
; toUpper - accepts one argument (probly a register), and upper-cases it.
; unHideMCB - marks as FREE the MCB at ES:0
; unMarkUMB - marks a given UMB as unused, even if previously marked used
;
;******************************************************************************
SWTCH equ '/' ; Switch character
DOS_CHECK_STRATEGY equ 5800h ; Int 21h, Func 58h, Svc 0 = check alloc strat
DOS_SET_STRATEGY equ 5801h ; Int 21h, Func 58h, Svc 1 = set alloc strategy
DOS_CHECK_UMBLINK equ 5802h ; Int 21h, Func 58h, Svc 2 = check link state
DOS_SET_UMBLINK equ 5803h ; Int 21h, Func 58h, Svc 3 = set link state
DOS_GET_DOS_LISTS equ 52h ; Int 21h, Func 52h = return list of lists
DOS_UMB_HEAD equ 8Ch ; Offset from ES (after func52h) to get UMBHead
CR equ 0Dh ; Carriage Return
LF equ 0Ah ; Line Feed
TAB equ 09h ; Tab character (^I)
; -----------------------------------------------------------------------------
; This file needs arena.inc, but it should already have been included. Because
; of MASM's strange method of two-pass definitions, we can't just include it
; inside of an ifndef, or it won't make it to stage two. Odd odd odd.
; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------
;*** toUpper - accepts one argument (probly a register), and upper-cases it.
; BUGBUG: t-richj 6/3/92 - This method, though used elsewhere (for example,
; used in sysinit2.asm to upper-case config.sys), relies on ASCII
; conventions. Might be bad.
; -----------------------------------------------------------------------------
toUpper macro arg
and arg, 0DFh
endm
; -----------------------------------------------------------------------------
;*** NextMCB - moves an MCB pointer forward to the next MCB
; -----------------------------------------------------------------------------
; ENTRY: First arg - seg pointer (ES?); second, a scratch register (AX?)
; EXIT: Seg pointer moved forward, scratch register = distance moved
; ERROR EXIT: None
; USES: Flags, arguments
; -----------------------------------------------------------------------------
NextMCB macro seg, reg
mov reg, seg
add reg, seg:[arena_size]
inc reg ; Inc 1 paragraph for the header
mov seg, reg
endm
; -----------------------------------------------------------------------------
;*** InitVar - initializes all the variables used in ParseVar and HideUMBs
; -----------------------------------------------------------------------------
; ENTRY: None
; EXIT: Variables listed in highvar.inc are initialized
; ERROR EXIT: None
; USES: Flags, variables in highvar.inc
; -----------------------------------------------------------------------------
; Note that element 0 references UMB 0 (conventional), not UMB 1. Its contents
; are largely ignored, but it is initialized nonetheless.
; -----------------------------------------------------------------------------
public InitVar
InitVar proc near
pushreg <ax, cx, di, es>
dataseg es ;Point ES into appropriate data segment
xor ax, ax
mov fUmbTiny, al ;Shrink UMBs? (made 1 if /S given)
mov fInHigh, al ;Set to 1 when DH/LH has been called
mov SegLoad, ax ;Load Address (seg), used for DH only
mov UmbLoad, UNSPECIFIED ;Later is the # of the 1st spec'd UMB
mov fm_argc, al ;Start with zero args having been read
cld
mov cx, MAXUMB ;For each entry
mov di, offset ES:UmbUsed ;on the UmbUsed array,
rep stosb ; Store 0
mov cx, MAXUMB ;Okay... for each entry
mov di, offset ES:UmbSize ;on the UmbSize array,
rep stosw ; Store 0
normseg es ; Return ES
popreg <es, di, cx, ax>
ret
InitVar endp
; -----------------------------------------------------------------------------
;*** FixMem - scans the upper memory chain and concatenates adjacent free MCBs
; -----------------------------------------------------------------------------
; ENTRY : None
; EXIT : None
; ERROR : None
; USES : Flags, fm_umb, fm_strat
; -----------------------------------------------------------------------------
public FixMem
FixMem proc near
pushreg <ax, bx, cx, dx, es>
call fm_link ; Link in UMBs
call UmbHead ; Get first upper-memory MCB address (0x9FFF)
jc fmX ; (if couldn't get it, leave now).
mov es, ax ; It returns in AX, so move it to ES.
;
; - Walk MCB Chain ------------------------------------------------------------
;
xor dx, dx ; We're keeping the address of the last MCB
mov cx, dx ; in CX... and the last owner
inc dx ; in dx as we go through the loop:
; ------------------------------------------
; FM10--DX = last MCB's owner's PSP address
; CX = last MCB's address (segment)
; ------------------------------------------
fm10: mov al, es:[arena_signature] ; if 'Z', don't repeat loop
mov bx, es:[arena_owner] ; if not zero, do nothing
or bx, dx ; dx was owner of previous MCB
jnz fm30 ; If not both zero, don't cat.
; - Coalesce memory blocks at ES:00 and CX:00 -------------------------
fm20: mov bx, es:[arena_size] ; Grab this block's Size,
mov es, cx ; Go back to prev MCB's address
mov es:[arena_signature], al ; & move the SECOND sig here
add bx, es:[arena_size] ; Size += first MCB's size
add bx, 1h ; And add one for the header
mov es:[arena_size], bx ; Write the size
; ---------------------------------------------------------------------
fm30: mov cx, es ; Put this address on the stack
mov dx, es:[arena_owner] ; And remember its owner
NextMCB es, bx ; Move to the next MCB
cmp al, arena_signature_end
jnz fm10 ; If signature != 'Z', there are more.
fmX: call fm_unlink ; Unlink UMBs
popreg <es, dx, cx, bx, ax>
ret
FixMem endp
; -----------------------------------------------------------------------------
;*** fm_link - links UMBs not already linked in
; -----------------------------------------------------------------------------
; ENTRY: None
; EXIT: fm_umb == 0 if not linked in previously, 1 if already linked in
; ERROR: None
; USES: AX, BX, fm_umb
; -----------------------------------------------------------------------------
fm_link proc near
mov ax, DOS_CHECK_UMBLINK
int 21h ; Current link-state is now in al
putdata fm_umb, al ; So store it in fm_umb for later
mov ax, DOS_SET_UMBLINK
mov bx, 1
int 21h
ret
fm_link endp
; -----------------------------------------------------------------------------
;*** fm_unlink - unlinks UMBs if fm_umb is set to 0
; -----------------------------------------------------------------------------
; ENTRY: fm_umb == 1 : leave linked, else unlink
; EXIT: None
; ERROR: None
; USES: AX, BX
; -----------------------------------------------------------------------------
fm_unlink proc near
xor bx, bx
getdata bl, fm_umb ; fm_umb already has the old link-state
mov ax, DOS_SET_UMBLINK
int 21h ; so just use that, and call int 21h
ret
fm_unlink endp
; -----------------------------------------------------------------------------
;*** ParseVar - parses [/S][/L:umb[,size][;umb[,size]]*] and builds the table
; laid out in highvar.inc
; -----------------------------------------------------------------------------
; ENTRY: ES:SI points to command tail of LoadHigh/DeviceHigh (whitespace ok)
; EXIT: ES:SI points to first character in child program name
; ERROR: ES:SI points to character which caused error, carry set, AX == code
; USES: ES:SI, AX, flags, variables in highvar.inc
; -----------------------------------------------------------------------------
; Error codes (in AX if carry set on return):
;
PV_InvArg equ 1 ; Invalid argument passed
PV_BadUMB equ 2 ; Bad UMB number passed (duplicate?)
PV_InvSwt equ 3 ; Unrecognized switch passed
;
; This routine exects ES:SI to point to a string much like the following:
; "/S/L:1,200;2 module options"
; Optionally, the string can begin with whitespace; neither /S nor /L is
; required, though that's what this routine is supposed to parse.
;
optS equ 'S' ; /S
optL equ 'L' ; /L:...
;
; -----------------------------------------------------------------------------
; LoadHigh has a list of arguments, returned by cparse, which is used to create
; a command-line for spawning a child process. For a typical LH command, say,
; lh /l:1,1000;2 print/d:lpt2
; the arguments would look like (one per line):
; lh
; /l
; 1
; 1000
; 2
; print
; /d
; :lpt2
; In short, if "print" were, say, "43", there'd be no way to determine which
; arg was the filename. So, inside this routine, we keep a running counter
; of the number of arguments LH will need to skip in order to get to the
; program name. The "lh" is implicit--it'll always have to skip that. So if
; there's no "/l" or "/s", fm_argc will be 0 ... other than that, 1 is added
; for:
; Each /L
; Each /S (there should be only one)
; Each UMB number (they follow ":" or ";")
; Each UMB size (they follow ",")
; So, in the above example, fm_argc would be 4-- and LH would skip right to
; "print". Note that InitVar initializes fm_argc to zero.
; -----------------------------------------------------------------------------
public ParseVar
ParseVar proc near
pushreg <di, ds, es>
push es ; Make DS:SI point to it, as well as ES:SI
pop ds ; (regardless if we're in devhigh or loadhigh)
cld
; ------------------------------------------------
; PV10--ES:SI = any whitespace on the command-line
; ------------------------------------------------
pv10: lodsb ; here, ES:SI==" /L..."--must eat whitespace
call isWhite
jz pv10 ; ES:SI==" /L..."--keep eating.
cmp al, SWTCH
jz pv20 ; ES:SI=="/L..."--go process a switch
dec si ; Backup--it's now "odule options", and we need
clc ; that "m" we just read (or whatever it is).
jmp short pvX ; Then return with carry clear == we're done.
pv20: lodsb ; Just read 'S' or 'L', hopefully
toUpper al ; So we make it upper-case, and...
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?