📄 himem2.asm
字号:
;/*
; * Microsoft Confidential
; * Copyright (C) Microsoft Corporation 1988-1992
; * All Rights Reserved.
; */
page 95,160
title 'HIMEM2 - Initialization code'
funky segment word public 'funky'
extrn InstallMoveBlock:near ; in high segment
extrn textseg:word ; in high segment
extrn KiddValley:word
extrn KiddValleyTop:word
extrn segKiddValley:word
extrn cHandles:word
extrn pack_and_truncate:near
extrn MmovSegReinit:far
extrn end_of_funky_seg:byte
extrn LEnblA20:word
extrn LDsblA20:word
funky ends
.xlist
include himem.inc ; get structures, equ's, etc.
; and open segment
.list
public f000
public InitInterrupt
public MachineNum
;************************************************************************
;* *
;* Global Variables *
;* *
;************************************************************************
extrn pPPFIRET:word
extrn dd_int_loc:word
extrn Interrupt:near
extrn hiseg:word
extrn call_hi_in_di:near
extrn fCanChangeA20:byte
extrn fHMAMayExist:byte
extrn fVDISK:byte
extrn IsVDISKIn:near
extrn A20Handler:near
extrn EnableCount:word
extrn MemCorr:word
extrn MinHMASize:word
ifdef debug_tsr
extrn MoveIt:dword
else
extrn MoveIt:word
endif
extrn pReqHdr:dword
extrn PrevInt2f:dword
extrn TopOfTextSeg:word
extrn InstallA20:near
extrn Int2fHandler:near
extrn Is6300Plus:near
extrn IsA20On:near
extrn pAddMem:word
extrn SignOnMsg:byte
extrn ROMDisabledMsg:byte
extrn UnsupportedROMMsg:byte
extrn ROMHookedMsg:byte
extrn BadDOSMsg:byte
extrn NowInMsg:byte
extrn On8086Msg:byte
extrn NoExtMemMsg:byte
extrn FlushMsg:byte
extrn StartMsg:byte
extrn HandlesMsg:byte
extrn HMAMINMsg:byte
extrn KMsg:byte
extrn NoHMAMsg:byte
extrn A20OnMsg:byte
extrn HMAOKMsg:byte
extrn VDISKInMsg:byte
extrn BadArgMsg:byte
extrn DevAttr:word
extrn Int15MemSize:word
extrn pInt15Vector:word
extrn PrevISAInt15:dword
extrn ISA15Handler:near
extrn EndText:byte
extrn XMMControl:far
extrn pfnEnabA20:word
extrn pfnDisabA20:word
extrn LocalEnableA20:near
extrn LocalDisableA20:near
;************************************************************************
;* *
;* Code/Data below here will be discarded after driver initialization *
;* *
;************************************************************************
; Discardable Initialization Data
pCOMPAQ label dword ; Pointer to COMPAQ specific for BIM
dw 0FFE8h ;
dw 0F000h ;
pBIMGDT dw offset BIMGDT ; Offset to BIMGDT for BIM alloc'n
GetBIMMemProc dw offset GetBIMMemory ; Offset of GetBIMMemory procedure
BIMBase dw 0 ; Base address and Lenght of remaining Compaq
BIMLength dw 0 ; Built-In Memory (set at Init time)
BIMBuffer dw ? ; Buffer for unlock/lock ROM for BIM
public fShadowOff, f1stWasWarning
fShadowOff db 0 ; NZ if shadow RAM should be disabled,
; 0/1 set by command line switch, 0FFh
; set if little extended and hope to disable
f1stWasWarning db 0 ; NZ if 1st attempt to diddle A20 generated
; a warning (and not an error)
public fA20Control
fA20Control db 0ffh ; NZ if himem should take control of A20, even
; it was already on when himem loaded.
public fCPUClock
fCPUClock db 0 ; NZ if himem should try to preserve CPU clock
; speed when gating A20
fEISA db 0 ; NZ if himem should take all EISA memory
; blocks
public fQuiet
fQuiet db 0ffh ; NZ if himem should be quiet during install
fSignOnMsg db 0 ; NZ if sign on msg has been displayed
fBigMem db 0ffh ; NZ if ISA memory above 16 meg allowed
fNumHandSet db 0 ; NZ if /NUMHANDLES= parameter used
fHMAminSet db 0 ; NZ if /HMAMIN= parameter used
; Parameter tables for GetParms
ParmEntry struc
cParmChar db 0 ; 1st char of option on cmd line
pParmRtn dw 0 ; offset of routine to process option
ParmEntry ends
; The 1st table is for parameters that have no arguments
ParmTbl1 label byte
ParmEntry <'E',GPGotEisa> ; /EISA
ParmEntry <'V',GPGotVerbose> ; /VERBOSE
ParmEntry <'N',GPGotBigMem> ; /NOABOVE16
ParmEntry <'Z',GPZSwitch> ; /Z
db 0 ; ** END OF TABLE **
; The 2nd table is for parameters with arguments
ParmTbl2 label byte
ParmEntry <'H',GPGotMin> ; /HMAMIN=
ParmEntry <'N',GPGotHands> ; /NUMHANDLES=
ParmEntry <'M',GPGotMachine> ; /MACHINE:
ParmEntry <'A',GPGotA20Control> ; /A20CONTROL:
ParmEntry <'S',GPGotShadow> ; /SHADOWRAM:
ParmEntry <'I',GPGotInt15> ; /INT15=
ParmEntry <'C',GPGotCPUClock> ; /CPUCLOCK:
db 0 ; ** END OF TABLE **
public StringParm, MachineNum, MachineName
StringParm db 13 DUP (' ')
MachineNum dw -1
; Note: the following table MUST be in the same order as the entries in the
; A20_Scan_Table! If you add entries here, also add one there!
MachineName label byte
db 'ptlcascade',0 ; Phoenix Cascade BIOS
db 'att6300plus',0 ; AT&T 6300 Plus
db 'ps2',0 ; IBM PS/2
db 'hpvectra',0 ; HP 'Classic' Vectra (A & A+)
db 'acer1100',0 ; Acer 1100
db 'toshiba',0 ; Toshiba 1600 & 1200XE
db 'wyse',0 ; Wyse 12.5 MHz 286 machine
db 'tulip',0 ; Tulip machines
db 'zenith',0 ; Zenith ZBIOS
db 'at1',0 ; IBM AT/delay 0
db 'at2',0 ; IBM AT/delay 1
db 'at3',0 ; IBM AT/delay 2
db 'philips',0 ; Philips machines
db 'css',0 ; CSS Lab machines
db 'fasthp',0 ; Single byte method for HP Vectras
db 'ibm7552',0 ; IBM 7552 Industrial Computer
db 'bullmicral',0 ; Bull Micral 60 M004
db 'dell',0 ; DELL XBIOS ; M010
db 'at',0 ; IBM AT
db 0FFh ; end of table
;NOTE: there is code in GetParms which depends on AltNameTbl coming
; after MachineName table.
public AltName1, AltName2, AltName3, AltName4, AltName5
public AltName6, AltName7, AltName8, AltName9, AltName10
public AltName11, AltName12, AltName13, AltName14, AltName15
public AltName16,AltName17 ;M004
AltNameTbl label byte
AltName3 db '3',0 ; Phoenix Cascade BIOS
AltName5 db '5',0 ; AT&T 6300 Plus
AltName2 db '2',0 ; IBM PS/2
AltName4 db '4',0 ; HP 'Classic' Vectra (A & A+)
AltName6 db '6',0 ; Acer 1100
AltName7 db '7',0 ; Toshiba 1600 & 1200XE
AltName8 db '8',0 ; Wyse 12.5 Mhz 286 machine
AltName9 db '9',0 ; Tulip machine
AltName10 db '10',0 ; Zenith ZBIOS
AltName11 db '11',0 ; IBM AT/delay 0
AltName12 db '12',0 ; IBM AT/delay 1
AltName13 db '13',0 ; IBM AT/delay 2
db '13',0 ; Philips machines (same as AT3)
db '12',0 ; CSS machines
AltName14 db '14',0 ; Single byte HP Vectra m/cs
AltName15 db '15',0 ; IBM 7552 Industrial Computer
AltName16 db '16',0 ; Bull Micral 60 M004
AltName17 db '17',0
AltName1 db '1',0 ; IBM AT
db 0FFh ; end of table
ifdef debug_tsr ;-----------------------------------------------
;*----------------------------------------------------------------------*
;* *
;* ExeStart - *
;* *
;* Entry point when himem is invoked as an .EXE. *
;* *
;*----------------------------------------------------------------------*
lpCmdLine dd 81h ; far ptr to command tail
public ExeStart
ExeStart:
mov word ptr cs:[lpCmdLine+2],es ; save PSP segment in pointer
mov ax,cs ; Setup segment regs to all be the same
mov ds,ax
mov es,ax
call InitDriver ; Initialize...
mov ax,TopOfTextSeg ; TopOfTextSeg == 0 is error installing
or ax,ax
jnz @f
mov ax,4C03h ; error, so just terminate
int 21h
@@:
mov di,offset pack_and_truncate
jmp call_hi_in_di ; terminate and stay resident
endif ;------------------------------------------------
;*----------------------------------------------------------------------*
;* *
;* InitInterrupt - *
;* *
;* Called by MS-DOS immediately after Strategy routine *
;* *
;* ARGS: None *
;* RETS: Return code in Request Header's Status field *
;* REGS: Preserved *
;* *
;* This entry point is used only during initialization. *
;* It replaces itself with a much shorter version which only *
;* serves to report the appropriate errors when this driver *
;* is called in error. *
;* *
;*----------------------------------------------------------------------*
InitInterrupt proc far
; Save the registers including flags.
push ax ; We cannot use pusha\popa because
push bx ; we could be on an 8086 at this point
push cx
push dx
push ds
push es
push di
push si
push bp
pushf
push cs ; Set DS=CS for access to global variables.
pop ds
les di,[pReqHdr] ; ES:DI = Request Header
mov bl,es:[di].Command ; Get Function code in BL
or bl,bl ; Only Function 00h (Init) is legal
jz IInit
cmp bl,16 ; Test for "legal" DOS functions
jle IOtherFunc
IBogusFunc:
mov ax,8003h ; Return "Unknown Command"
jmp short IExit
IOtherFunc:
xor ax,ax ; Return zero for unsupported functions
jmp short IExit
IInit:
call InitDriver ; Initialize the driver
les di,[pReqHdr] ; Restore es:di = Request Header
IExit:
or ax,0100h ; Turn on the "Done" bit
mov es:[di].Status,ax ; Store return code
popff ; restore the registers
pop bp
pop si
pop di
pop es
pop ds
pop dx
pop cx
pop bx
pop ax
mov dd_int_loc,offset Interrupt ; replace Interrupt with
ret ; tiny permanent stub
InitInterrupt endp
;*----------------------------------------------------------------------*
;* *
;* InitDriver - *
;* *
;* Called when driver is Initialized. *
;* *
;* ARGS: ES:DI = Address of the Request Header *
;* RETS: pHdr.Address = Bottom of resident driver code *
;* REGS: AX, CX and Flags are clobbered *
;* *
;*----------------------------------------------------------------------*
public InitDriver
InitDriver proc near
cld
ifndef debug_tsr
call LocateHiSeg ; locate the hiseg in low memory properly
mov di, offset MMovSegReinit
mov es, hiseg
push cs
call call_hi_in_di ; re-initialize the mem mover
mov ax,cs
push es
mov es,hiseg
assume es:funky
add textseg,ax ; relocate text segment pointer
add LEnblA20+2, ax ; update ptrs to enble & disable a20 rtns
add LDsblA20+2, ax
pop es
assume es:nothing
endif
mov ah,30h ; make sure we've got DOS 3.00 or higher
int 21h ; Get DOS versions number
cmp al,3
jae IDCheckXMS
mov dx,offset BadDOSMsg
jmp IDFlushMe
IDCheckXMS:
mov ax,(INT2F_ID SHL 8) OR INT2F_INS_CHK
int 2Fh ; make sure there's no other XMS installed
cmp al,80h ; Is INT 2F hooked?
jne IDNotInYet
mov dx,offset NowInMsg
jmp IDFlushMe
IDNotInYet:
xor ax,ax ; Move 0 into the Flags register
push ax
popf
pushf ; Try and get it back out
pop ax
and ax,0F000h ; If the top four bits are set...
cmp ax,0F000h
mov dx,offset On8086Msg ; we're on an 8086
jnz @f
jmp IDFlushMe ; so crap out
@@:
call GetInt15Memory ; If Int 15h/88h reports < 384k of
cmp ax,384 ; extended memory available, then
jae @f ; we will try to increase memory
mov fShadowOFF,0FFh ; by stealing shadow RAM
@@:
call GetParms ; process command line parameters
mov ah, 2 ; Force VERBOSE mode if user is
int 16h ; holding down the Alt key
test al, 08h ; Int 16h/2 == Get Keyboard Flags
jz @f ; 08h set if Alt key down
mov fQuiet, 0
@@:
ifndef debug_tsr
call DispSignOnMsg
endif
mov di,offset InstallMoveBlock ; install moveblock function
push cs ; setup for far return
call call_hi_in_di ; call into high segment
call IsA20On ; Is A20 already enabled?
or ax,ax ; (may zap cx, si, di)
jz IDInsA20 ; no, go install A20 handler
mov dx,offset A20OnMsg ; "A20 already on" message
cmp fA20Control,0 ; should we take control of A20 anyway?
jne IDInsA20 ; yes, go muck with it
mov [fCanChangeA20],0 ; no, don't allow changing of A20
call DispInfoMsg ; and tell user about it
jmp short IDAfterA20
IDInsA20:
call InstallA20 ; install proper A20 handler
jnc @f
jmp IDFlushMe ; CY means fatal error
@@:
; Note: A side affect of the previous InstallA20 is that MemCorr
; is set to reflect the adjustment factor if we're on an AT&T 6300+
IDAfterA20:
call InitHandles ; initialize handle table
call ScanEISA ; scan EISA memory into table
call CheckZBim ; Check for & allocate Zenith BIM
call CheckBIM ; Check for & allocate Compaq BIM
; Turn off shadow RAM if desired/possible
cmp fShadowOFF,0 ; should shadow RAM be turned off?
jz @f
call ShadowRAMOff ; try to turn it off--also adds to free list
or dx,dx ; display a msg if ShadowRAMOff is
jz @f ; pointing to one
call DispInfoMsg
@@:
call IsVDISKIn ; Is a VDISK style allocator already
cmp [fVDISK],0 ; installed? Don't bother to load
jz @f ; if so, cause we'll just fail all
mov dx,offset VDISKInMsg ; future calls anyway...
jmp short IDFlushMe
@@:
; Looks like himem will install, allocate Big ISA memory (above 16 meg)
; now if available
cmp [fBigMem], 0 ; Was parameter specified?
je @f ; NO: don't bother trying to get it
call GetBIGMemory ; Get extra ISA memory
@@:
call GetInt15Memory ; how much extended memory is installed?
cmp ax,64 ; Is there >= 64K of extended?
jae IDHMAOK
push es
mov es,hiseg
assume es:funky
mov bx,[KiddValley] ; get size of memory we already have in tables
mov cx,[cHandles]
IDAnyMem:
cmp [bx].Flags,FREEFLAG
jnz IDAnyMem_1 ; brif not a valid free block
mov ax, [bx].Len.hi
or ax, [bx].Len.lo
jnz IDAnyMem_2
IDAnyMem_1:
add bx,SIZE Handle
loop IDAnyMem
IDAnyMem_2:
pop es
assume es:nothing
mov dx,offset NoHMAMsg
or ax,ax ; no HMA, any other memory to control?
jnz disp_hma_msg ; jmp if some memory
; We can't find any memory to manage.
mov dx,offset NoExtMemMsg
; Display the message in DX followed by the "Flush" message.
IDFlushMe:
call DispErrMsg
mov dx,offset FlushMsg
call DispErrMsg
xor ax,ax ; discard the driver
mov [TopOfTextSeg],ax
ifndef debug_tsr ;-------------------------------
les di,[pReqHdr]
mov es:[di].Units,al
and cs:DevAttr,not 8000h ; clr bit 15 in attrib of driver header
endif
jmp short IDReturn ;-------------------------------
IDHMAOK:
mov [fHMAMayExist],1
mov dx,offset HMAOKMsg
disp_hma_msg:
call DispInfoMsg
call HookInt2F ; "turn on" the driver
; Initialization finished (or failed) -- return to caller
IDReturn:
ifndef debug_tsr ;-------------------------------
mov di,offset pack_and_truncate
jmp call_hi_in_di ; pack stuff down and terminate
else
mov ax, hiseg ; make sure far pointer to handle
mov es, ax ; table has correct segment
mov es:[segKiddValley], ax
endif ;-------------------------------
ret
InitDriver endp
;----------------------------------------------------------------------------
; DispXxxMsg Routines -- Display informational, error or sign on messages,
; if enabled by /VERBOSE parameter. Error msgs
; are displayed regardless of /VERBOSE.
; Entry:
; DX = offset of msg to display
; Exit:
;
; Used:
; AX
;----------------------------------------------------------------------------
public DispInfoMsg, DispInfoChar, DispErrMsg
DispInfoMsg proc near
cmp cs:[fQuiet], 0 ; display an informational msg if
jnz short DIM_ret ; not in QUIET mode
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -