Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2461 lines
60 KiB

;/* himem.asm
; *
; * Microsoft Confidential
; * Copyright (C) Microsoft Corporation 1988-1991
; * All Rights Reserved.
; *
; * Modification History
; *
; * Sudeepb 14-May-1991 Ported for NT XMS support
; *
; * williamh 25-Sept-1992 Added RequestUMB and ReleaseUMB
; */
page 95,160
title 'HIMEM.SYS - Microsoft XMS Device Driver'
;*****************************************************************************
;* *
;* HIMEM.ASM - *
;* *
;* Extended Memory Specification Driver - *
;* *
;*****************************************************************************
;
; himem.inc - global equates, macros, structures, opening segment
; himem.asm - main driver entry, interrupt hooks, a20/HMA functions
; himem1.asm - a20 switching code
; himem2.asm - driver initialization
; himem3.asm - messages for driver initialization
; himem4.asm - extended memory allocation functions
; himem5.asm - memory move function
;
; for revision history prior to 1990, see version 2.37 or earlier
;
; 2.35 - Removed a few push/pops from IsA20On, misc 01/14/90
; source code reformatting
; 2.36 - Include Int 6Dh vector in shadow RAM disable 01/18/90
; check, also allow disable if video Ints already
; point at C000h segment. Also added some CLD's near
; string instructions.
; 2.37 - Removed 2.33 'fix' for All Chargecard. They 01/23/89
; now do Global and Local enables to turn on A20, and
; the previous 'fix' caused us to never didle A20 again
; after running Windows real mode twice (Windows does
; Global enables/disables too). Also, GetParms needed to
; check for LF in addition to CR for end of line.
;;
;;; Following changes synced from \402\dev\himem tree
;;
; 2.50 - Revised version # for Windows 3.0 release. 02/05/90
; "" - Ignore 'super'-extended memory on EISA memory 02/08/90
; memory boards (mem > 16 meg). Software that
; uses 24 bit (80286) descriptors doesn't do
; well with memory @ 16 meg.
; "" - Himem will now try to control A20 by default, 02/12/90
; even if A20 is already enabled when himem is
; loaded. Added /A20CONTROL: ON | OFF switch to
; override this if necessary (ON is default and
; means we take control, OFF means we take control
; unless A20 was already on, in which case we
; don't mess with it).
;
; 2.60 - Added special A20 routine for Toshiba 1600 02/22/90
; laptop, and revised driver version number to
; be later than Compaq's (2.50) so Windows
; setup will install ours.
; "" - Clear bit 15 in device attributes word of 02/28/90
; device header if driver is being flushed. The
; MS-DOS Encylopedia says to do this, and a
; system with DOS 3.21 was hanging when loading
; the driver after himem if himem flushed itself.
; "" - Added special A20 handler for Wyse 12.5 MHz 03/27/90
; 286 machine. Almost the same as AT, but
; a little different.
; "" - Now displays a msg indicating which A20 04/05/90
; handler is installed, and allows numbers for the
; /MACHINE: parameter.
;;
;;; End of \402\dev\himem changes
;;
;
; "" - Added /INT15=xxxx option to reserve xxxxK of 04/13/90
; extended memory for INT 15. Himem will reserve xxxx K
; (64 K of HMA inclusive) for apps which use Ext Mem thru
; int 15 interface. The HMA portion of the INT 15 ext memory
; should be protected by a VDISK header. Apps which
; do not recognize VDISK headers may destroy the HMA.
;
; "" - When there is a /INT15=xxxx option on the 04/20/90
; command line, the HMA is made unavailable to the
; apps. But DOS 5.0 goes ahead and checks for INT 15
; memory if the alloc HMA call fails. And if INT 15 memory
; is present it uses the first 64 K for loading itself
; high (simulated HMA)
;
; "" - ORGed the movable segment to high value for flexibility
; in loading into HMA. Added code to be flexible enough to
; run from HMA as well as low memory.
public Interrupt
public dd_int_loc
public fHMAExists
public PrevInt15
public fA20Check
public OldStackSeg
public pPPFIRET
public EnableCount
public pReqHdr
public MinHMASize
public Int2fHandler
public fHMAMayExist
public MemCorr
public PrevInt2f
public MoveIt
public fCanChangeA20
ifndef NEC_98
public IsVDISKIn
public fVDISK
endif ;NEC_98
public LocalEnableA20
public LocalDisableA20
public FLclEnblA20
public FLclDsblA20
public xLocalEnableA20
public xLocalDisableA20
public IsA20On
public winbug_fix
ifndef NEC_98
public ATA20Delay
else ;NEC_98
public fAltA20Routine
endif ;NEC_98
public AddMem
public TopOfTextSeg
public A20State
public Int15Handler
; Define a direct call to the Phoenix Cascade BIOS for A20 handling
; Note: if these segments are not defined here, the Int13Handler
; definition in segment Zero in the 386 memory move will generate
; bad code.
PTL_Seg segment at 0f000h
PTL_Seg ends
BiosSeg SEGMENT AT 40h ; Used to locate 6300 PLUS reset address
BiosSeg ends
include himem.inc ; define structures, macros, open seg.
include xmssvc.inc
include vint.inc
extrn EndText:byte
_text ends
funky segment para public 'funky'
assume cs:funky
; externals from himem4
extrn Version:near
extrn MoveBlock:near
extrn QueryExtMemory:near
extrn AllocExtMemory:near
extrn FreeExtMemory:near
extrn LockExtMemory:near
extrn UnlockExtMemory:near
extrn GetExtMemoryInfo:near
extrn ReallocExtMemory:near
extrn RequestUMB:near
extrn ReleaseUMB:near
extrn cHandles:word
extrn KiddValley:word
; externals from himem5
funky ends
;
;------ the following segment should be the last in the sys file
; This segment is read by the stripdd utility to remove
; the zeroes introduced by the hi ORG in the movable segment
ZZZ segment para 'ZZZ'
dw 16 ; len of this segment
dw offset _text:EndText ; len of text seg in double word
dw 0
dw HISEG_ORG ; number of zeroes to be stripped
dw -1
dw -1 ; terminator
db (4) dup (55h) ; filler
ZZZ ends
_text segment word public 'code'
assume cs:_text
; externals from himem1
extrn A20Handler:near
; externals from himem2
extrn InitInterrupt:near
public DevAttr
public Int15MemSize
public fInHMA
; The Driver Header definition.
Header dd -1 ; Link to next driver, -1 = end of list
DevAttr dw 1010000000000000b ; Char device & Output until busy(?)
dw Strategy ; "Stategy" entry point
dd_int_loc dw InitInterrupt ; "Interrupt" entry point
db 'XMSXXXX0' ; Device name
;************************************************************************
;* *
;* Global Variables *
;* *
;************************************************************************
if keep_cs
callers_cs dw 0
endif
TopOfTextSeg dw 0 ; size of retained driver
pPPFIRet dw PPFIRet ; The offset of an IRET for the POPFF macro
pReqHdr dd ? ; Pointer to MSDOS Request Header structure
ifndef NEC_98
pInt15Vector dw 15h*4,0 ; Pointer to the INT 15 Vector
else ;NEC_98
pInt15Vector dw 1fh*4,0 ; Pointer to the INT 15 Vector
endif ;NEC_98
PrevInt15 dd 0 ; Original INT 15 Vector
PrevInt2f dd 0 ; Original INT 2f Vector
ifdef NEC_98
pInt220Vector dw 0dch*4,0; Pointer to the INT 220 Vector
PrevInt220 dd 0 ; Original INT 220 Vector
pInt20Vector dw 20h*4,0 ; Pointer to the INT 20 Vector
PrevInt20 dd 0 ; Original INT 20 Vector
pInt21Vector dw 21h*4,0 ; Pointer to the INT 21 Vector
PrevInt21 dd 0 ; Original INT 21 Vector
endif ;NEC_98
fHMAInUse db 0 ; High Memory Control Flag, != 0 -> In Use
fCanChangeA20 db 1 ; A20 Enabled at start? (assume changable)
fHMAMayExist db 0 ; True if the HMA could exist at init time
fHMAExists db 0 ; True if the HMA exists
fInstalled db 0 ; True if ext mem has been allocated
fInHMA db 0 ; true if hiseg is in HMA
fVDISK db 0 ; True if a VDISK device was found
fA20Check db 0 ; True if A20 handler supports On/Off check
ifndef NEC_98
ATA20Delay db 0 ; Type of AT A20 delay in use (0 - NUM_ALT_A20)
else ;NEC_98
fAltA20Routine db 0 ; True if alternative A20 routine in use
endif ;NEC_98
EnableCount dw 0 ; A20 Enable/Disable counter
fGlobalEnable dw 0 ; Global A20 Enable/Disable flag
MinHMASize dw 0 ; /HMAMIN= parameter value
Int15MemSize dw 0 ; Memory size reserved for INT 15
MemCorr dw 0 ; KB of memory at FA0000 on AT&T 6300 Plus.
; This is used to correct INT 15h,
; Function 88h return value.
OldStackSeg dw 0 ; Stack segment save area for 6300 Plus.
; Needed during processor reset.
ifndef NEC_98
if NUM_A20_RETRIES
A20Retries db 0 ; Count of retires remaining on A20 diddling
endif
else ;NEC_98
I2fCheckNH_Tbl dd 0 ; Old Pointer (ES:BX) for Windows ins NEC <91.09.27>
db 3,0 ; version
db 01h ; type for instance is INT Vector
db 0 ; R.F.U
dw offset _text:PrevInt15 ; offset
I2f_seg dw 0 ;
dw 4 ;
dw 1fh ;
dd -1 ;
endif ;NEC_98
A20State db 0 ; recored the current A20 state
ifndef NEC_98
public lpExtA20Handler
lpExtA20Handler dd 0 ; Far entry point to an external A20 handler
endif ;NEC_98
;*----------------------------------------------------------------------*
;* *
;* Strategy - *
;* *
;* Called by MS-DOS when ever the driver is accessed. *
;* *
;* ARGS: ES:BX = Address of Request Header *
;* RETS: Nothing *
;* REGS: Preserved *
;* *
;*----------------------------------------------------------------------*
Strategy proc far
assume ds:nothing
; Save the address of the request header.
mov word ptr [pReqHdr],bx
mov word ptr [pReqHdr][2],es
ret
Strategy endp
;*----------------------------------------------------------------------*
;* *
;* Interrupt - *
;* *
;* Called by MS-DOS immediately after Strategy routine *
;* *
;* ARGS: None *
;* RETS: Return code in Request Header's Status field *
;* REGS: Preserved *
;* *
;* This is our permanent entry point. By this time, the only *
;* useful function done by the device driver (initializing us) *
;* has been done by a previous call. There are no more valid *
;* uses for this entry point. All we have to do is decide *
;* whether to ignore the call or generate an error. *
;* *
;*----------------------------------------------------------------------*
Interrupt proc far
assume ds:nothing
push bx ; save minimal register set
push ds
lds bx,[pReqHdr] ; ds:bx = Request Header
cmp ds:[bx].Command,16 ; legal DOS function? (approx???)
mov ds:[bx].Status,100h ; "Done" for healthy calls
jbe FuncOk
or ds:[bx].Status,8003h ; Return "Unknown Command" error
FuncOk:
pop ds
pop bx
ret
Interrupt endp
;*----------------------------------------------------------------------*
;* *
;* Int2fHandler - *
;* *
;* Hooks Function 43h, Subfunction 10h to return the *
;* address of the High Memory Manager Control function. *
;* Also returns 80h if Function 43h, Subfunction 0h is requested. *
;* *
;* ARGS: AH = Function, AL = Subfunction *
;* RETS: ES:BX = Address of XMMControl function (if AX=4310h) *
;* AL = 80h (if AX=4300) *
;* REGS: Preserved except for ES:BX (if AX=4310h) *
;* Preserved except for AL (if AX=4300h) *
;* *
;*----------------------------------------------------------------------*
Int2fHandler proc far
assume ds:nothing
call DOSTI ; Flush any queued interrupts
cmp ah,43h ; Function 43h?
ifndef NEC_98
jne I2fNextInt
else ;NEC_98
jne I2fChk_NH ; check for Windows 3.0 function INS NEC <91.09.27>
endif ;NEC_98
or al,al ; Subfunction 0?
jne I2fNextSub ; No, continue
mov al,80h ; Return 80h in AL (XMS Installed)
PPFIRet:
jmp DOIRET ; Label sets up the POPFF macro
I2fNextSub:
cmp al,10h ; Subfunction 10?
jne I2fNextInt ; No, goto next handler
push cs ; return XMS entry in es:bx
pop es
mov bx,offset XMMControl
jmp DOIRET
; Continue down the Int 2f chain.
I2fNextInt:
call DOCLI ; Disable interrupts again
jmp [PrevInt2f]
ifdef NEC_98
; check N/H depend data for Windows 3.0 ;INS NEC <91.09.27>
I2fChk_NH: ; check N/H depended data
cmp ax,167fh
jne I2fNextInt ; No, goto next handler
cmp dx,0 ; check sub function
jne I2fNextInt ; No, goto next handler
mov word ptr [I2fCheckNH_Tbl], bx ; offset
mov bx,es ;
mov word ptr [I2fCheckNH_Tbl+2],bx ; segment
mov bx,cs ;
mov [I2f_Seg],bx ;
push cs ;
pop es ;
mov bx,offset I2fCheckNH_Tbl ;
jmp I2fNextInt ; goto next handler
endif ;NEC_98
Int2fHandler endp
;*----------------------------------------------------------------------*
;* *
;* ControlJumpTable - *
;* *
;* Contains the address for each of the XMS Functions. *
;* *
;* **************** WARNING ********************** *
;* *
;* Assumes that offsets of functions in lo mem seg are < 8000h *
;* & that offsets of segment in Hiseg are >= 8000h *
;* *
;*----------------------------------------------------------------------*
ControlJumpTable label word
dw Version ; Function 00h
dw RequestHMA ; Function 01h
dw ReleaseHMA ; Function 02h
dw GlobalEnableA20 ; Function 03h
dw GlobalDisableA20 ; Function 04h
xLocalEnableA20 dw LocalEnableA20 ; Function 05h
xLocalDisableA20 dw LocalDisableA20 ; Function 06h
dw IsA20On ; Function 07h
dw QueryExtMemory ; Function 08h
dw AllocExtMemory ; Function 09h
FreeMem dw FreeExtMemory ; Function 0Ah
MoveIt dw MoveBlock ; Function 0Bh
dw LockExtMemory ; Function 0Ch
dw UnlockExtMemory ; Function 0Dh
dw GetExtMemoryInfo ; Function 0Eh
dw ReallocExtMemory ; Function 0Fh
dw RequestUMB ; Function 10h
dw ReleaseUMB ; Function 11h
NumFns = ((offset $) - (offset ControlJumpTable))/2
;*----------------------------------------------------------------------*
;* *
;* XMMControl - *
;* *
;* Main Entry point for the Extended Memory Manager *
;* *
;* ARGS: AH = Function, AL = Optional parm *
;* RETS: AX = Function Success Code, BL = Optional Error Code *
;* REGS: AX, BX, DX and ES may not be preserved depending on func. *
;* *
;* INTERNALLY REENTRANT *
;* *
;*----------------------------------------------------------------------*
XMMControl proc far
jmp short XCControlEntry ; For "hookability"
nop ; NOTE: The jump must be a
nop ; short jump to indicate
nop ; the end of any hook chain.
; The nop's allow a far jump
; to be patched in.
XCControlEntry:
if keep_cs ;--------------------------------------------------------
push bp
mov bp,sp
mov bp,4[bp] ; get caller's cs
mov callers_cs,bp ; (debug only)
pop bp
endif ;--------------------------------------------------------
push cx ; preserve some registers
push si
push di
push ds
push es
pushf
cld
push ds ; save ds in es
pop es ; NOTE: ES cannot be used for parms!
push cs ; ds=cs
pop ds
assume ds:_text
push ax ; save the function number
if debug_vers
call debug_dump
endif
or ah,ah ; GetXMSVersion?
jz XCCallFunc ; Yes, don't hook INT 15h yet
cmp ah,NumFns ; valid function number??
jb XCCheckHook
pop ax ; No, Un-preserve AX and return an error
xor ax,ax
mov bl,ERR_NOTIMPLEMENTED
jmp short XCExit
XCCheckHook:
pushf ; Is INT 15h already hooked?
call DOCLI ; This is a critical section
cmp word ptr [PrevInt15][2],0 ; Is the segment non-zero?
jne XCCheckVD
push dx ; save callers DX
call HookInt15 ; claim all remaining ext mem
pop dx
ifdef NEC_98
call HookInt220 ; start emulating Int220
endif ;NEC_98
XCCheckVD:
popff ; End of critical section
ifndef NEC_98
cmp [fVDISK],0 ; was VDISK found?
je XCCallFunc
pop ax ; Yes, Un-preserve AX and return error
xor ax,ax
mov bl,ERR_VDISKFOUND
xor dx,dx
jmp short XCExit
endif ;NEC_98
; Call the appropriate API function.
XCCallFunc:
pop ax ; Restore AX
push ax ; save ax so functions get both ah & al
mov al,ah
xor ah,ah
shl ax,1
mov di,ax ; NOTE: DI cannot be used for parms!
pop ax ; restore callers ax for function
mov di,ControlJumpTable[di] ; get function address
ifndef NEC_98
or di,di
jns CallLowSegFn ; brif it's in the low segment
else ;NEC_98
cmp di,HISEG_ORG
jb CallLowSegFn ; brif it's in the low segment
endif ;NEC_98
cmp fInHMA, 0 ; is the hiseg in HMA ?
jz InLoMem
;
;------ Turn on the A20 line if it is off
;
push si
push di
push ax
push bx
push cx
call LocalEnableA20 ; Note: This is always necessary
cmp ax, 1
pop cx ; for the Memory Move function. In
pop bx ; the case where this driver loads
pop ax ; high, it is necessary for all calls
pop di ; to the high segment.
pop si
jne a20_error
InLoMem:
push cs ; set up far return
call call_hi_in_di ; and call the function
cmp fInHMA, 0 ; is the hiseg in HMA ?
jz XCExit
push ax ; save the registers which may be
push bx ; returning values
call LocalDisableA20 ; and restore a20
cmp ax, 1
pop bx
pop ax
je short XCExit
a20_error:
xor ax, ax
xor dx, dx
mov bl, ERR_A20
jmp short XCExit
CallLowSegFn:
call di ; call routine in this segment
XCExit:
; if debug_vers or tdump ;------------------------------------
; pusha
; call dump_tables
; popa
; endif ;------------------------------------------------------
popff ; NOTE: Flags must be restored
pop es ; immedately after call API functions.
pop ds
pop di
pop si
pop cx
; if debug_vers ;---------------------------------------------------
; pushf
; pusha
; mov al,'.'
; call cofa
; mov al,cs:byte ptr fun_number
; sub al,0bh ; don't get key on 0bh, 0ch or 0dh
; cmp al,2
; jbe no_keywait
; mov ah,1 ; wait for console key now!!!!!!
;; int 21h
;no_keywait:
; popa
; popf
; endif ;------------------------------------------------------
ret
XMMControl endp
if tdump or debug_vers ;------------------------------------
fun_number db 0 ; function number for debug info
dump_tables:
if not tdump
cmp fun_number,9 ; only display on allocate calls
jnz dd_done ; unless full tdump is enabled
endif
mov dx,offset heading
mov ah,9
int 21h
push es
mov es,hiseg
assume es:funky
mov si,[KiddValley]
mov cx,[cHandles]
mov bx,SIZE Handle
xlup:
mov al,[si].Flags ; get flags
cmp al,4 ; don't show UNUSED entries
jz x_entry_done
mov dx,offset msg_FREE
cmp al,1 ; free?
jz x_showflags
mov dx,offset msg_USED
cmp al,2 ; used?
jz x_showflags
mov dx,offset msg_BAD
x_showflags:
mov ah,9
int 21h
mov al,[si].cLock ; get lock count
call hex_byte
call space
mov ax,[si].Base ; get base
call hex_word
call space
mov ax,[si].Len ; get length
call hex_word
if keep_cs
call space
mov ax,[si].Acs ; get the allocator's cs:
call hex_word
endif
x_newline:
mov al,13
call cofa
mov al,10
call cofa
x_entry_done:
add si,bx
loop xlup
pop es
assume es:nothing
mov dx,offset donemsg
mov ah,9
int 21h
dd_done:
ret
heading db 'Flags Lock Base Len CS:',13,10,'$'
msg_FREE db 'FREE $'
msg_USED db 'USED $'
msg_BAD db 'BAD $'
donemsg db 'End of XMS table$'
endif
if debug_vers
debug_dump proc near
pusha
mov fun_number,ah ; save (non-reentrantly!) function number
; ; so that we can display different debug
; ; information on exit depending on which
; ; function we've been doing
mov al,ah ; just display function number
call hex_nib
popa
ret
if 0 ; enable this if you want to see the
; ; command block for memory moves
cmp ah,0bh ; memory move?
jnz debug_dump_done ; done if not
pusha
call crlf
mov ax,es:2[si] ; get count-hi
call hex_word
mov ax,es:[si] ; get count-low
call hex_word
add si,4 ; point to source address field
mov cx,2 ; now display two handle/addresses
dd1:
call space
lods es:word ptr [si] ; get a handle
call hex_word
mov al,'-'
call cofa
mov ax,es:2[si] ; get high address
call hex_word
mov al,':'
call cofa
lods es:word ptr [si] ; get low address
call hex_word
add si,2 ; skip to next entry for loop
loop dd1
popa
debug_dump_done:
endif
ret
debug_dump endp
endif
if debug_vers or tdump
ifdef NEC_98
RowCol dw 1700H ; ins NEC <90.07.11> Y.Ueno
endif ;NEC_98
hex_word:
push ax
mov al,ah
call hex_byte
pop ax
hex_byte:
push ax
shr ax,4 ; XMS present implies '286 or better
call hex_nib
pop ax
hex_nib:
and al,0fh
add al,90h
daa
adc al,3ah
daa
cofa:
; mov dl,al
; mov ah,2
; int 21h
ifndef NEC_98
mov ah,0eh
mov bx,7
int 10h
ret
else ;NEC_98
;======================CHG NEC <90.07.11> Y.Ueno =============================
push bx ; save callers regs
push cx
push dx
push si
push di
push es
push ds
push dx ; save this segment for later
mov ds, dx ; DS -> data segment
mov dx, ds:[RowCol] ; DX = current row/col
cmp al, CR ; is character a CR?
jne short kp1
mov dl, 0 ; yes, go to column 0
jmp short kp3 ; jump to common code
kp1:
cmp al, LF ; is character a LF?
jne short kp2
inc dh ; yes, go to next row
jmp short kp3 ; jump to common code
kp2:
cmp al, TAB ; is it a tab
jne short kp12
and dl, 0f8h ; mask off low 3 bits (8 ch)
add dl, 8 ; move to next tab position
jmp short kp3 ; jmp to common code
kp12:
cmp al, BS ; is it backspace
jne short kp13
dec dl ; back up one column
jmp short kp3 ; goto common code
kp13:
; Must be ordinary character. Write it to screen, update position
;@@@
XOR AH,AH ;
push ax ; save char/attr
mov al, dh ; AL = row
mov ah, 80 ; multiplier, 80 char per row
mul ah ; AX = cell at start of row
mov bh, 0
mov bl, dl ; BX = column
add bx, ax ; BX = cell
shl bx, 1 ; BX = byte offset of cell
mov ax, 0a000h ; screen para for real mode
mov es, ax ; ES -> screen
pop es:[bx] ; write character
inc dl ; update column
kp3:
; Common code, first check for line wrap:
cmp dl, 80 ; beyond rhs of screen?
jl short kp4
mov dl, 0 ; go to col 0
inc dh ; and move to next line
kp4:
; Now check for scroll needed:
cmp dh, 24 ; are we off end of screen?
jl short kp5
; Now scroll screen
mov ax, 0a000h ; screen para for real mode
mov ds, ax ; DS -> screen
mov es, ax ; ES -> screen
mov di, 0 ; ES:DI = copy destination
mov si, 160 ; DS:SI = copy source
mov cx, 2000-160 ; copy word count
cld
rep movsw ; scroll
; Blank bottom line
mov al, ' '
;@@@
mov ah, 0 ; AX = blank character
mov cx, 80 ; number of cells to blank
mov di, 4000-320 ; ES:DI = start point
rep stosw
; Update position
mov dh, 23 ; new row
kp5:
pop ds ; set DS to data again
mov ds:[RowCol], dx ; update row/col
;@@@
call SetCursor
pop ds ; restore regs
pop es
pop di
pop si
pop dx
pop cx
pop bx
ret
;*** SetCursor - updates cursor position
;
; This routine reprograms the 6845 cursor position, and
; stores the new cursor position in the ROM bios data area.
;
; ENTRY DUAL MODE
; DH, DL = row, col
;
; EXIT cursor updated
;
; USES ax, bx, cx, flags
;
CRT_COLS equ 04ah
CURSOR_POSN equ 050h
CRT_START equ 04eh
ADDR_6845 equ 063h
push ds
mov bx, 40h
mov ds, bx
; Save new position in BIOS data area
mov ds:[CURSOR_POSN], dx
; Calculate offset on screen
mov al, dh ; row
; mul byte ptr ds:[CRT_COLS] ; row * cols
MOV AH,80
mul AH ; row * cols
mov bl, dl ; bl = column
mov bh, 0 ; bx = column
add ax, bx ; ax = offset in screen
sal ax, 1 ; double for attribute bytes
; mov cx, ds:[CRT_START] ; cx = start point of screen
mov cx, 0h ; cx = start point of screen
ADD AX,CX
MOV DX,AX
; sar cx, 1 ; convert to char count only
; Now program 6845
mov al,49h
JMP SHORT $+2
JMP SHORT $+2
JMP SHORT $+2
JMP SHORT $+2
JMP SHORT $+2
JMP SHORT $+2
JMP SHORT $+2
JMP SHORT $+2
OUT 62H,AL
MOV AX,DX
SHR AX,1
JMP SHORT $+2
JMP SHORT $+2
JMP SHORT $+2
JMP SHORT $+2
JMP SHORT $+2
JMP SHORT $+2
JMP SHORT $+2
JMP SHORT $+2
OUT 60H,AL
MOV AL,AH
JMP SHORT $+2
JMP SHORT $+2
JMP SHORT $+2
JMP SHORT $+2
JMP SHORT $+2
JMP SHORT $+2
JMP SHORT $+2
JMP SHORT $+2
OUT 60H,AL
POP DS
RET
;=============================================================================
endif ;NEC_98
space:
mov al,' '
jmp cofa
crlf:
mov al,13
call cofa
mov al,10
jmp cofa
endif ;------------------------------------------------------
; little utility stub for calling routine in the other segment.
; called with the branch offset address in di
; a far return address is already on the stack. Now branch to
; hiseg:(di)
public hiseg ; allow initialization code to relocate hiseg
hiseg dw funky
public call_hi_in_di
call_hi_in_di proc near
push hiseg
push di
call_hi_in_di endp
call_hi_far proc far
ret
call_hi_far endp
;*----------------------------------------------------------------------*
;* *
;* HookInt15 - *
;* *
;* Insert the INT 15 hook *
;* *
;* ARGS: None *
;* RETS: None *
;* REGS: AX, BX, CX, DX, DI, SI, and Flags are clobbered *
;* *
;* EXTERNALLY NON-REENTRANT *
;* Interrupts must be disabled before calling this function. *
;* *
;*----------------------------------------------------------------------*
HookInt15 proc near
push es
ifndef NEC_98
call IsVDISKIn ; has a VDISK been installed?
cmp [fVDISK],0
je HINoVD ; No, continue
pop es ; Yes, return without hooking
ret
HINoVD: ; notify softpc of hooking I15
mov ax,offset Int15Handler ; args: cs:di new I15 vector
XMSSVC XMS_NOTIFYHOOKI15 ; returns CX=ExtMem in K
; Save the curr INT 15 vector, and put ours in the IVT
les si,dword ptr pInt15Vector
xchg ax,es:[si][0]
mov word ptr [PrevInt15][0],ax
mov ax,cs
xchg ax,es:[si][2]
mov word ptr [PrevInt15][2],ax
mov ax, cx
cmp ax,15*1024 ; Limit himem.sys to using 15 meg
jb @f ; of extended memory for apps
mov ax,15*1024 ; that don't deal with > 24 bit
@@: ; addresses
sub ax,[MemCorr] ; 6300 Plus may have memory at FA0000h
else ;NEC_98
;====================== chg NEC <90.07.11> Y.Ueno ======================
push es
mov ax,40h
mov es,ax
sub ah,ah
mov al,byte ptr es:[0001] ; get extend memory size
shl ax,7 ; convert to k byte size
pop es
endif ;NEC_98
cmp ax,64
jb HIInitMemory ; Less than 64K free? Then no HMA.
cmp Int15MemSize, 0 ; are we supporting int 15 memory
jnz HIInitMemory ; then we dont support HMA
mov [fHMAExists],1
HIInitMemory:
; Init the first handle to be one huge free block.
ifndef NEC_98
or ax, ax ; don't do it if no Int 15 memory avail
jz HISkipInit
endif ;NEC_98
mov cx,1024 ; base is just above 1 meg
xor bx, bx ; assume no HMA
cmp [fHMAExists],0 ; Reserve room for HMA if it exists
je @f
mov bx, 64
@@: cmp bx, Int15MemSize
jae @f
mov bx, Int15MemSize
@@: add cx,bx
sub ax,bx
ifdef NEC_98
push es
push ax
mov ax, 40h
mov es, ax
pop ax
push ax
add ax,127 ; set 128k boundly
shr ax,7
sub byte ptr es:[0001h],al
pop ax
pop es
endif ;NEC_98
call AddMem ; add that to memory table
ifndef NEC_98
HISkipInit:
else ;NEC_98
; Save the current INT 15 vector.
les si,dword ptr pInt15Vector
; Exchange the old vector with the new one.
mov ax,offset Int15Handler
xchg ax,es:[si][0]
mov word ptr [PrevInt15][0],ax
mov ax,cs
xchg ax,es:[si][2]
mov word ptr [PrevInt15][2],ax
endif ;NEC_98
pop es
ret
HookInt15 endp
ifndef NEC_98
;*----------------------------------------------------------------------*
;* *
;* IsVDISKIn - *
;* *
;* Looks for drivers which use the IBM VDISK method of allocating *
;* Extended Memory. XMS is incompatible with the VDISK method. It is *
;* necessary to check two different locations since some programs only *
;* one or the other, although they should do both. *
;* *
;* ARGS: None *
;* RETS: None. Sets "fVDISK" accordingly *
;* REGS: AX, BX, CX, SI, DI and Flags are clobbered *
;* *
;* INTERNALLY REENTRANT *
;* *
;*----------------------------------------------------------------------*
pVDISK label dword
dw 00013h
dw 0FFFFh
szVDISK db 'VDISK'
IsVDISKIn proc near
; Look for "VDISK" signature at offset 12h in Int 19h segment
push es
xor ax,ax
mov es,ax
mov es,es:[(19h * 4)+2]
mov di,12h
mov si,offset szVDISK
mov cx,5
cld
repz cmpsb
pop es
jz IVIFoundIt
; Look for "VDISK" starting at the 4th byte of extended memory.
call LocalEnableA20 ; Turn on A20
push es
les di,cs:pVDISK ; set up the comparison
mov si,offset szVDISK
mov cx,5
cld
repz cmpsb ; Do the comparison
pop es
pushf
call LocalDisableA20
popff
jz IVIFoundIt
mov [fVDISK],0 ; No VDISK device found
ret
IVIFoundIt:
mov [fVDISK],1 ; "VDISK" was found
ret
IsVDISKIn endp
endif ;NEC_98
;*----------------------------------------------------------------------*
;* *
;* Int15Handler - *
;* *
;* Hooks Function 88h to return zero as the amount of extended *
;* memory available in the system. *
;* *
;* Hooks Function 87h and preserves the state of A20 across the *
;* block move. *
;* *
;* ARGS: AH = Function, AL = Subfunction *
;* RETS: AX = 0 (if AH == 88h) *
;* REGS: AX is clobbered *
;* *
;*----------------------------------------------------------------------*
ifdef NEC_98
I15RegSave dw ?
endif ;NEC_98
Int15Handler proc far
ifndef NEC_98
cmp ah,88h ; request == report free ext mem?
je I15ExtMem
cmp ah,87h ; Block move?
je I15BlkMov
jmp cs:[PrevInt15] ; continue down the int 15h chain
I15ExtMem:
mov ax, cs:Int15MemSize ; return 'free' Int 15h extended memory
jmp DOIRET
I15BlkMov:
call DOCLI ; Make sure interrupts are off
sub sp,4 ; Make space for A20 flag & flags word
pusha ; Preserve the caller's registers
call IsA20On ; Get current A20 state
mov bp,sp ; Stk= [pusha] [fl] [a20] [ip] [cs] [fl]
mov [bp+18],ax ; Save A20 state
mov ax,[bp+24] ; Get caller's entry flags and save on
mov [bp+16],ax ; stack, forms part of iret frame
popa ; Restore the caller's registers
; Simulate an interrupt to lower level Int 15h handler. Note that
; the flags image is already on the stack from code above. The Int
; 15h handler may or may return with interrupts enabled.
call cs:[PrevInt15]
push ax ; Save returned AX
pushf ; Save flags returned from lower level
push bp ; Stack =
mov bp,sp ; [bp] [fl] [ax] [a20] [ip] [cs] [fl]
mov ax,[bp+2] ; Setup to pass lower level flags
mov [bp+12],ax ; back to caller on iret
cmp word ptr [bp+6],0 ; While we're here test old A20 state
pop bp
pop ax ; Discard flags
pop ax ; Restore AX
jz I15HExit ; A20 was off, don't mess with it
call DOCLI ; A20 handlers called with ints off
pusha ; Preserve previous handler's return
mov ax,1
call A20Handler ; turn A20 back on
popa ; Restore the previous handler's return
I15HExit:
add sp,2 ; 'pop' A20 state flag
jmp DOIRET ; Uses flags from lower level handler
else ;NEC_98
cmp ah,90h ; Is it a Block Move ?
jne I15HNext ; No , continue
call DOCLI ; Make sure interrupts are off
pusha ; Preserve the registers
mov al, 8 ; ins NEC <90.11.14> Y.Ueno
out 37h, al ; "
call IsA20On
mov cs:[I15RegSave],ax ; store A20's state
popa ; Restore the registers
; Call the previous Int 15h handler.
pushf ; Simualate an interrupt
call cs:[PrevInt15]
pushf ; bug ? ins NEC <90.07.12> Y.Ueno
pusha ; Preserve previous handler's return
cmp cs:[I15RegSave],0 ; Restore A20
je I15HExit ; It was off, continue
mov ax,1
call A20Handler ; turn A20 back on
I15HExit:
mov al, 09h ; ins NEC <90.11.14> Y.Ueno
out 37h, al ; "
popa ; Restore the previous handler's return
popf ; bug ? chg NEC <90.07.12> Y.Ueno
retf 2 ; "
;;; iret ; "
I15HNext:
jmp cs:[PrevInt15] ; continue down the int 15h chain
endif ;NEC_98
Int15Handler endp
ifdef NEC_98
;*----------------------------------------------------------------------*
;* *
;* HookInt220 - *
;* *
;* Insert the INT 220 hook *
;* *
;* ARGS: None *
;* *
;* RETS: None *
;* *
;* REGS: AX, SI, and Flags are clobbered *
;* *
;* EXTERNALLY NON-REENTRANT *
;* Interrupts must be disabled before calling this function. *
;* *
;*----------------------------------------------------------------------*
HookInt220 proc near
push cx
mov cl,81h
xor ax,ax
int 220 ; Get size of extended memory
pop cx
or ax,ax ; no extendec memory?
jz HI220Exit ; don't hook Int220
; Exchange the old vector with the new one.
push es
les si,dword ptr pInt220Vector ; ES:SI points Int220 vector
mov ax,offset Int220Handler
xchg ax,es:[si][0]
mov word ptr [PrevInt220][0],ax
mov ax,cs
xchg ax,es:[si][2]
mov word ptr [PrevInt220][2],ax
pop es
HI220Exit:
ret
HookInt220 endp
;*----------------------------------------------------------------------*
;* *
;* Int220Handler - *
;* *
;* Hooks Function 81h/82h and emulate it by twiddling EMB table *
;* *
;* ARGS: CL = Function, AX = Subfunction *
;* BX = Size of memory requested in 128k block, if function 81h*
;* *
;* RETS: Function 81h *
;* AX = 0 (if success) *
;* BX = Start addr *
;* DX = End addr *
;* *
;* AX = 01h (if fail) *
;* BX = size of available memory in blocks of 128k *
;* *
;* Function 82h *
;* AX = size of availabel memory in blocks of 128k *
;* BX = Start addr *
;* DX = End addr *
;* *
;* REGS: AX, BX, (DX) is clobbered *
;* *
;*----------------------------------------------------------------------*
USER_DX equ 6
USER_BX equ 10
USER_AX equ 12
I220EmlTbl dw offset Eml_81
dw offset Eml_82
Int220Handler proc far
cmp cl,81h ; Function 81h?
jne I220HCmp82 ;
cmp ax,0001h ; Sub function 01h?
jne I220HNext ;
jmp short I220HStart ; yes
I220HCmp82:
cmp cl,82h ; Function 82h?
jne I220HNext ;
cmp ax,0000h ; Subfunction 00Hh?
jne I220HNext ;
;
I220HStart: ; yes
sti
push es
push ds
push ax
push bx
push cx
push dx
push di
push si
push bp
mov bp,sp
mov dx,ss
mov es,dx
push cs
pop ds
mov si,offset I220EmlTbl
sub cl,81h
xor ch,ch
shl cx,1
add si,cx
call [si] ; call our Int 220 handler.
pop bp
pop si
pop di
pop dx
pop cx
pop bx
pop ax
pop ds
pop es
iret
I220HNext:
jmp cs:[PrevInt220] ; continue down the int 220 chain
Int220Handler endp
;*----------------------------------------------------------------------*
;* *
;* EML_81 - *
;* *
;* Emulate Int220h Function 81h *
;* *
;* ARGS: Int 220 regs but DS, ES, BP, CX *
;* *
;* RETS: Values are set into AX, BX, DX on the stacks *
;* *
;* REGS: AX, BX, CX, DX, SI, DI and Flags are clobbered *
;* *
;*----------------------------------------------------------------------*
EML_81 proc near
push bx ; save size of memory requested
mov ax,bx
call GetInt220mem ; return available memory size in CX
; handle in DX, SI
pop ax
cmp cx,ax ; is there enough memory?
jb E81Nomem ; no
or ax,ax ; requested size = 0 ?
jz E81ReqZero ; yes
mov bx,dx ; ax:size,bx:free handle,si:unused handle
call AllocInt220mem ; allocate memory for this Int 220
mov [bp].USER_BX,bx ; start addr
mov [bp].USER_DX,dx ; ending addr
mov word ptr [bp].USER_AX,0000h ; indicates sucsess
jmp short E81Exit
E81ReqZero:
mov word ptr [bp].USER_BX,0010h ; start addr
mov word ptr [bp].USER_DX,0010h ; ending addr
mov word ptr [bp].USER_AX,0000h ; indicates sucsess
jmp short E81Exit
E81Nomem:
mov [bp].USER_BX,cx ; size of abailable memories
mov word ptr [bp].USER_AX,0001h ; indicate not enough memories
E81Exit:
ret
EML_81 endp
;*----------------------------------------------------------------------*
;* *
;* EML_82 - *
;* *
;* Emulate Int220h Function 82h *
;* *
;* ARGS: Int 220 regs but DS, ES, BP, CX *
;* *
;* RETS: Values are set into AX, BX, DX on the stacks *
;* *
;* REGS: AX, BX, CX, DX, SI, DI and Flags are clobbered *
;* *
;*----------------------------------------------------------------------*
OwnersPSP dw 0 ;
OwnersHandle dw 0 ;
EML_82 proc near
mov ax,0ffffh ; fake request size
call GetInt220mem ; return maximum available memory in AX
; handle in BX, SI
or ax,ax ; available size = 0 ?
jz E82Nomem ; yes
; ax:size,bx:free handle,si:unused handle
call AllocInt220mem ; allocate memory for this Int 220
mov [bp].USER_BX,bx ; start addr
mov [bp].USER_DX,dx ; ending addr
mov [bp].USER_AX,ax ; size of memory allocated
mov [OwnersHandle],cx ; save handle of allocated block
mov ax,6200h
int 21h
mov [OwnersPSP],bx ; save current process's PSP
; we'll hook INt20h/21h from now on
; Exchange the old vector with the new one.
push es
cli
les si,dword ptr pInt20Vector ; replace Int20h vector
mov ax,offset Int20_Hooker ; with addr of Int20_Hooker
xchg ax,es:[si][0] ;
mov word ptr [PrevInt20][0],ax ;
mov ax,cs ;
xchg ax,es:[si][2] ;
mov word ptr [PrevInt20][2],ax ;
les si,dword ptr pInt21Vector ; replace Int21h vector
mov ax,offset Int21_Hooker ; with addr of Int21_Hooker
xchg ax,es:[si][0] ;
mov word ptr [PrevInt21][0],ax ;
mov ax,cs ;
xchg ax,es:[si][2] ;
mov word ptr [PrevInt21][2],ax ;
sti
pop es
jmp short E82Exit
E82Nomem:
mov word ptr [bp].USER_BX,0010h ; start addr
mov word ptr [bp].USER_DX,0010h ; ending addr
mov word ptr [bp].USER_AX,0000h ; no blocks was allocated
E82Exit:
ret
EML_82 endp
;*----------------------------------------------------------------------*
;* *
;* Int20_Hooker - *
;* Int21_Hooker - *
;* *
;* Hooks Int20h/21h *
;* *
;* ARGS: AH = Function *
;* *
;* REGS: All Regs are preserved *
;* *
;* EXIT: Fall through previous Int20h/21h handler *
;* *
;*----------------------------------------------------------------------*
Intnum db 0 ; number of Int we are handling
Int21_Hooker proc far
mov cs:[Intnum],21h
cmp ah,00h
je I2xHStart
cmp ah,4ch
jne I2xHNext
Int20_Hooker proc far
I2xHStart:
push ax
push bx
mov ax,6200h
pushf
call cs:[PrevInt21] ; Int21h GetPSP Function
cmp bx,cs:[OwnersPSP] ; this process own memory block?
pop bx
pop ax
jne I2xHNext
push ax
push bx
push cx
push dx
push di
push si
push ds
push cs
pop ds ; ds <- _text seg
push es
mov es,[hiseg] ; es <- funky seg
mov dx,[OwnersHandle] ; handle of block owned by this process
mov di,FreeMem ; get funtion in funky segment
push cs ; set up far return
call call_hi_in_di ; call into high segment
;------------------------------------------------------------------------------
; Restore the old vector.
; we won't hook Int20h/21h no longer.
cli
les di,dword ptr pInt20Vector ; restore Int20h vector
mov ax,word ptr [PrevInt20][0] ;
stosw ;
mov ax,word ptr [PrevInt20][2] ;
stosw ;
les di,dword ptr pInt21Vector ; restore Int21h vector
mov ax,word ptr [PrevInt21][0] ;
stosw ;
mov ax,word ptr [PrevInt21][2] ;
stosw ;
;------------------------------------------------------------------------------
pop es
pop ds
pop si
pop di
pop dx
pop cx
pop bx
pop ax
I2xHNext:
cmp cs:[Intnum],21h
je I21HNext
I20HNext:
jmp cs:[PrevInt20] ; continue down the int 20h chain
I21HNext:
mov cs:[Intnum],0
jmp cs:[PrevInt21] ; continue down the int 21h chain
Int20_Hooker endp
Int21_Hooker endp
assume ds:_text
;*----------------------------------------------------------------------*
;* *
;* GetInt220mem - *
;* *
;* Serach for available memory block for Int220 in EMB table *
;* *
;* ARGS: AX = size of memories requested in blocks of 128k *
;* *
;* RETS: AX = size of maximam EMB block in blocks of 128k *
;* BX = handle of maximam availabel EMB block *
;* CX = size of available EMB block whith the nearest *
;* size to request, in blocks of 128k *
;* DX = handle of available EMB block whith the nearest *
;* size to request *
;* SI = handle of unused EMB block *
;* *
;* REGS: AX, BX, CX, DX, SI, DI and Flags are clobbered *
;* *
;*----------------------------------------------------------------------*
hMax dw 0 ; Handle of block that has max size
MaxSize dw 0 ; Max. size found so far
hNearest dw 0 ; Handle of block that has nearest size
; with request size
NearestSize dw 0 ; Nearest size with request size
hUnused dw 0 ; Handle of unused block
GetInt220mem proc near
mov [hMax],0000h
mov [MaxSize],0000h
mov [hNearest],0000h
mov [NearestSize],0ffffh
mov [hUnused],0000h
; scan for largest FREE block
push es
mov es,[hiseg]
assume es:funky
mov bx,[KiddValley]
mov cx,[cHandles] ; Loop through the handle table
GI220Loop:
cmp [bx].Flags,FREEFLAG ; Is this block free?
jne GI220Anused ; no
mov di,[bx].base
mov si,di
add si,[bx].Len ; si has end addr of free block
and si,0ff80h ; round off to 128k boundary
add di,127 ; di had start addr of free block
and di,0ff80h ; 128k boundary
sub si,di ; available size in kbytes
jnc GI220Gotmem
xor si,si ; size = 0
GI220Gotmem:
shr si,7 ; convert to number of blocks
cmp si,[MaxSize] ; is this the largest so far?
jbe GI220Nearest
mov [MaxSize],si ; Yes, save it away
mov [hMax],bx ; save handle
GI220Nearest:
cmp si,ax ; is this larger than request?
jb GI220Bottom
cmp si,[NearestSize] ; is this the nearest so far?
jae GI220Bottom
mov [NearestSize],si ; Yes save it away
mov [hNearest],bx ; save handle
jmp short GI220Bottom
GI220Anused:
cmp [bx].Flags,UNUSEDFLAG ; Is this block unused?
jne GI220Bottom
cmp [hUnused],0 ; did we already find an unused handle?
jne GI220Bottom
mov [hUnused],bx ; save this guy away
GI220Bottom:
add bx,SIZE Handle
loop GI220Loop
cmp [hMax],0 ; Is there some free blocks
je GI220Nomem ; no
mov ax,[MaxSize]
mov bx,[hMax]
mov cx,[MaxSize]
mov dx,[hMax]
mov si,[hUnused]
cmp [hNearest],0
je GI220Exit
mov cx,[NearestSize]
mov dx,[hNearest]
jmp short GI220Exit
GI220Nomem:
xor ax,ax ; no memory available
xor cx,cx ;
GI220Exit:
pop es
assume es:nothing
ret
GetInt220mem endp
;*----------------------------------------------------------------------*
;* *
;* AllocInt220mem - *
;* *
;* Set memory block for Int220 onto EMB table *
;* *
;* ARGS: AX = size of memories requested in blocks of 128k *
;* BX = handle of free EMB block *
;* SI = handle of unused EMB block *
;* *
;* RETS: AX = size of EMB blocks allocated in blocks of 128k *
;* BX = start addr of allocated memories *
;* DX = ending addr of allocated memoies *
;* CX = handle of allocated EMB block *
;* *
;* REGS: AX, BX, CX, DX and Flags are clobbered *
;* *
;*----------------------------------------------------------------------*
AllocInt220mem proc near
push es
mov es,[hiseg]
assume es:funky
shl ax,7 ; request size in kbytes
or si,si ; is there a unused block?
jz AI220AllocAll ; no, allocate entire block
cmp ax,[bx].Len
je AI220AllocAll
mov dx,[bx].Base
mov cx,dx
add dx,[bx].Len ; end of free block
and dx,007fh ; size beyond 128k boundary
add dx,ax
mov [si].Len,dx
sub [bx].Len,dx
add cx,[bx].Len
mov [si].Base,cx
mov bx,si
AI220AllocAll:
mov [bx].Flags,USEDFLAG ; New.Flags = USED
shr ax,7 ; size of block allocated
mov cx,bx ; handle of block allocated
mov dx,[bx].Base
add dx,[bx].Len
and dx,0ff80h
shr dx,6 ; end addr
mov bx,dx
sub bx,ax
sub bx,ax ; start addr
pop es
assume es:nothing
ret
AllocInt220mem endp
endif ;NEC_98
;*----------------------------------------------------------------------*
;* *
;* RequestHMA - FUNCTION 01h *
;* *
;* Give caller control of the High Memory Area if it is available. *
;* *
;* ARGS: DX = HMA space requested in bytes *
;* RETS: AX = 1 if the HMA was reserved, 0 otherwise. BL = Error *
;* REGS: AX, BX and Flags clobbered *
;* *
;* INTERNALLY NON-REENTRANT *
;* *
;*----------------------------------------------------------------------*
winbug_fix dw 0 ; storage for windows bug workaround
RequestHMA proc near
call DOCLI ; This is a non-reentrant function.
; Flags are restored after the return.
mov bl,ERR_HMAINUSE
; ***************************
; ** There's a problem with WIN386 2.11. It calls XMS driver
; ** incorrectly and then goes ahead and uses the memory
; ** it didn't properly allocate. In order to convince it
; ** not to go ahead and use the extended memory, we must
; ** fail this function when it calls us. We know that
; ** al=40h and dx=free memory returned from QueryExtMemory
; ** when we're called from windows. Hopefully no legitimate
; ** caller will happen to have that exact same 24 bit code
; ** in al/dx when they call this function because they will fail.
; ***************************
cmp al,40h ; called from win386 2.11?
jnz not_winbug
cmp dx,winbug_fix ; dx=last result from QueryExtMem?
jz RHRetErr ; fail if so
not_winbug:
cmp [fHMAInUse],1 ; Is the HMA already allocated?
je RHRetErr
mov bl,ERR_HMANOTEXIST
cmp [fHMAExists],0 ; Is the HMA available?
je RHRetErr
mov bl,ERR_HMAMINSIZE
cmp dx,[MinHMASize] ; Is this guy allowed in?
jb RHRetErr
mov ax,1
mov [fHMAInUse],al ; Reserve the High Memory Area
xor bl,bl ; Clear the error code
ret
RHRetErr:
xor ax,ax ; Return failure with error code in BL
ret
RequestHMA endp
;*----------------------------------------------------------------------*
;* *
;* ReleaseHMA - FUNCTION 02h *
;* *
;* Caller is releasing control of the High Memory area *
;* *
;* ARGS: None *
;* RETS: AX = 1 if control is released, 0 otherwise. BL = Error *
;* REGS: AX, BX and Flags clobbered *
;* *
;* INTERNALLY NON-REENTRANT *
;* *
;*----------------------------------------------------------------------*
ReleaseHMA proc near
call DOCLI ; This is a non-reentrant function
mov al,[fHMAInUse] ; HMA currently in use?
or al,al
jz RLHRetErr ; No, return error
mov [fHMAInUse],0 ; Release the HMA and return success
mov ax,1
xor bl,bl
ret
RLHRetErr:
xor ax,ax
mov bl,ERR_HMANOTALLOCED
ret
ReleaseHMA endp
;*----------------------------------------------------------------------*
;* *
;* GlobalEnableA20 - FUNCTION 03h *
;* *
;* Globally enable the A20 line *
;* *
;* ARGS: None *
;* RETS: AX = 1 if the A20 line is enabled, 0 otherwise. BL = Error *
;* REGS: AX, BX CX, SI, DI and Flags clobbered *
;* *
;* INTERNALLY NON-REENTRANT *
;* *
;*----------------------------------------------------------------------*
GlobalEnableA20 proc near
call DOCLI ; This is a non-reentrant function
cmp [fGlobalEnable],1 ; Is A20 already globally enabled?
je GEARet
GEAEnable:
call LocalEnableA20 ; Attempt to enable A20
or ax,ax
jz GEAA20Err
mov [fGlobalEnable],1 ; Mark A20 global enabled
GEARet:
mov ax,1 ; return success
xor bl,bl
ret
GEAA20Err:
mov bl,ERR_A20 ; some A20 error occurred
xor ax,ax
ret
GlobalEnableA20 endp
;*----------------------------------------------------------------------*
;* *
;* GlobalDisableA20 - FUNCTION 04h *
;* *
;* Globally disable the A20 line *
;* *
;* ARGS: None *
;* RETS: AX=1 if the A20 line is disabled, 0 otherwise. BL = Error *
;* REGS: AX, BX, CX, SI, DI and Flags are clobbered *
;* *
;* INTERNALLY NON-REENTRANT *
;* *
;*----------------------------------------------------------------------*
GlobalDisableA20 proc near
call DOCLI ; This is a non-reentrant function
cmp [fGlobalEnable],0 ; Is A20 already global-disabled?
je GDARet
call LocalDisableA20 ; Attempt to disable it
or ax,ax ; (also zaps CX, SI, DI)
jz GDAA20Err
mov [fGlobalEnable],0 ; mark as global-disabled
GDARet:
mov ax,1 ; return success
xor bl,bl
ret
GDAA20Err:
mov bl,ERR_A20 ; some A20 error occurred
xor ax,ax
ret
GlobalDisableA20 endp
;*----------------------------------------------------------------------*
;* *
;* LocalEnableA20 - FUNCTION 05h *
;* *
;* Locally enable the A20 line *
;* *
;* ARGS: None *
;* RETS: AX = 1 if the A20 line is enabled, 0 otherwise. BL = Error *
;* REGS: AX, BX, CX, SI, DI and Flags clobbered *
;* *
;* INTERNALLY NON-REENTRANT *
;* *
;*----------------------------------------------------------------------*
LocalEnableA20 proc near
ifndef NEC_98
call DOCLI ; This is a non-reentrant function
cmp [fCanChangeA20],1 ; Can we change A20?
jne LEARet ; No, don't touch A20
if NUM_A20_RETRIES
mov A20Retries,NUM_A20_RETRIES
endif
cmp [EnableCount],0 ; If enable count == 0, go set it
jz LEASetIt ; without bothering to check 1st
if NUM_A20_RETRIES
LEATestIt:
endif
call IsA20On ; If A20 is already on, don't do
or ax,ax ; it again, but if it isn't on,
jnz LEAIncIt ; then make it so
LEASetIt:
mov ax,1 ; attempt to turn A20 on
call A20Handler ; Call machine-specific A20 handler
ife NUM_A20_RETRIES
or ax,ax ; If we're not doing retries, then
jz LEAA20Err ; use A20 handler's error return
else
dec A20Retries ; Any retries remaining? If so, go
jnz LEATestIt ; test current state, else return
jmp short LEAA20Err ; an error condition
endif
LEAIncIt:
inc [EnableCount]
LEARet:
mov ax,1 ; return success
xor bl,bl
ret
LEAA20Err:
mov bl,ERR_A20 ; some A20 error occurred
xor ax,ax
if debug_vers
disp_a20_err:
pusha
mov al,'#'
call cofa
popa
endif
ret
else ;NEC_98
call DOCLI ; This is a non-reentrant function
cmp [fCanChangeA20],1 ; Can we change A20?
jne LEARet ; No, don't touch A20
; From 2.14 - 2.25 the following 3 lines were commented out. This caused
; at least four (seemingly different) bugs on PS/2 systems. The problem
; seems to be that the PS2_A20Handler returns an error code if called to
; enable when A20 is already on (other handlers do this also!). JimMat
call IsA20On ; If A20 is already on, don't do
or ax,ax ; it again, but if it isn't on,
jnz LEAIncIt ; then make it so
mov ax,1 ; attempt to turn A20 on
call A20Handler ; Call machine-specific A20 handler
or ax,ax
jz LEAA20Err
LEAIncIt:
inc [EnableCount]
LEARet:
mov ax,1 ; return success
xor bl,bl
ret
LEAA20Err:
mov bl,ERR_A20 ; some A20 error occurred
xor ax,ax
if debug_vers
disp_a20_err:
pusha
mov al,'#'
call cofa
popa
endif
ret
endif ;NEC_98
LocalEnableA20 endp
;*----------------------------------------------------------------------*
;* *
;* LocalDisableA20 - FUNCTION 06h *
;* *
;* Locally disable the A20 line *
;* *
;* ARGS: None *
;* RETS: AX=1 if the A20 line is disabled, 0 otherwise. BL = Error *
;* REGS: AX, BX, CX, SI, DI and Flags are clobbered *
;* *
;* INTERNALLY NON-REENTRANT *
;* *
;*----------------------------------------------------------------------*
LocalDisableA20 proc near
call DOCLI ; This is a non-reentrant function
cmp [fCanChangeA20],0 ; Can we change A20?
je LDARet ; No, don't touch A20
cmp [EnableCount],0 ; make sure the count's not zero
je LDAA20Err
ifndef NEC_98
if NUM_A20_RETRIES
mov A20Retries,NUM_A20_RETRIES
LDATestIt:
endif
endif ;NEC_98
call IsA20On ; Currently on or off?
cmp [EnableCount],1 ; Only if the count = 1 should A20 be
jnz LDAStayOn ; turned off, otherwise it stays on
or ax,ax ; If A20 is already off, don't
jz LDADecIt ; bother to turn off again
xor ax,ax ; It's on, but should be turned off
jmp short LDASetIt
LDAStayOn:
or ax,ax ; A20 must stay on, if it is on, just
jnz LDADecIt ; dec count, else force A20 on
mov ax,1
LDASetIt:
call A20Handler ; Call machine-specific A20 handler
ifndef NEC_98
ife NUM_A20_RETRIES
or ax,ax ; If we're not doing retries, then
jz LDAA20Err ; use A20 handler's error return
else
dec A20Retries ; Any retries remaining? If so, go
jnz LDATestIt ; test current state, else return
jmp short LDAA20Err ; an error condition
endif
else ;NEC_98
or ax,ax ; If we're not doing retries, then
jz LDAA20Err ; use A20 handler's error return
endif ;NEC_98
LDADecIt:
dec [EnableCount]
LDARet:
mov ax,1 ; return success
xor bl,bl
ret
LDAA20Err:
mov bl,ERR_A20 ; some A20 error occurred
xor ax,ax
if debug_vers
jmp disp_a20_err
endif
ret
LocalDisableA20 endp
;
;---------------------------------------------------------------------------
; procedure : FLclEnblA20
; procedure : FLclDsblA20
;
; Called from the Block move functions. Serves 2 purposes
; 1. Interfaces a far call for a near routine
; 2. If funky is in HMA does a dummy success return
;---------------------------------------------------------------------------
;
FLclEnblA20 proc far
cmp cs:fInHMA, 0
jz @f
mov ax, 1
ret
@@:
call LocalEnableA20
ret
FLclEnblA20 endp
FLclDsblA20 proc far
cmp cs:fInHMA, 0
jz @f
mov ax, 1
ret
@@:
call LocalDisableA20
ret
FLclDsblA20 endp
;
;*----------------------------------------------------------------------*
;* *
;* IsA20On - FUNCTION 07h *
;* *
;* Returns the state of the A20 line *
;* *
;* ARGS: None *
;* RETS: AX = 1 if the A20 line is enabled, 0 otherwise *
;* BL = 0 *
;* REGS: AX, BL, CX, SI, DI and Flags clobbered *
;* *
;* INTERNALLY REENTRANT *
;* *
;*----------------------------------------------------------------------*
; NOTE: When this routine is called from the Int15 handler, ds is undefined.
; Hence the CS: overrides on data references.
IsA20On proc near
mov al, cs:A20State
cbw
xor bl, bl
ret
IsA20On endp
;*----------------------------------------------------------------------*
;* *
;* AddMem - add memory to free pool *
;* *
;* The trick here is that we're going to check for overlapping *
;* or adjacent blocks and crunch them together. The thinking *
;* here is that we may be informed of a memory resource from *
;* more than one source. In any case, we NEVER want the same *
;* memory to appear in our resource table more than once. *
;* *
;* Note: there's presently no way of reporting errors if the *
;* handle table is full. If it happens, we'll just lose the *
;* memory block. This should not be a problem as long as *
;* we're only being called during program initialization. *
;* *
;* It would be nice if we could throw this code away after *
;* initialization, unfortunately this is actually invoked *
;* at HookInt15 time, so it's too late to do away with *
;* obsolete code. *
;* *
;* ARGS: CX - base of block in 1K increments *
;* AX - length of block in 1K increments *
;* TRASHES: AX,BX,CX,DX,SI,DI *
;* *
;* messes with handle table - not reentrant - assumes ints disabled *
;* *
;*----------------------------------------------------------------------*
AddMem proc near
; We might as well be scanning for a free handle while we're
; at it since we're normally going to need one at the end
mov dx,ax ; save new block length in dx
mov si,cx ; save new block base in si
xor di,di ; haven't found free handle yet
push es
mov es,hiseg
assume es:funky
mov bx,[KiddValley] ; prepare to loop thru handle tab
mov cx,[cHandles]
AM01:
cmp [bx].Flags,UNUSEDFLAG ; is this handle available?
jnz AM02 ; skip if not
or di,di ; use the first free handle we
jnz AM05 ; find. skip if we've got one
mov di,bx ; save the unused handle in di
jmp short AM05
AM02:
; Note: Normally all handles will be either UNUSED or FREE at
; this point. However, in the case of checking for Zenith memory,
; it may have a temporarily allocated dummy block. Therefore
; we'll only be merging blocks marked as FREE.
cmp [bx].Flags,FREEFLAG
jnz AM05 ; ignore USED blocks
; First check for new block being entirely after block at [bx]
mov ax,[bx].Base
add ax,[bx].Len
cmp ax,si ; is [bx].end < new.Base?
jb AM05 ; done checking this entry if so
; Now check for new block being entirely before block at [bx]
mov ax,si ; new.base
add ax,dx ; + new.len = new.end
cmp ax,[bx].Base
jb AM05 ; brif no overlap at all
; Now put the block at [bx] up into our block in registers so
; that we can continue the scan. There may be other adjacent
; blocks, even in the case of no overlap, fr'instance when a
; block is added which entirely fills the gap between two others.
cmp si,[bx].Base ; Find base of combined block
jbe AM03 ; Brif new block on bottom
add dx,si ; Add new.base - [bx].base to
mov si,[bx].Base ; new.len, set new.base=[bx].Base
sub dx,si ; new.len
AM03:
mov ax,[bx].Base ; see which block ends later
add ax,[bx].Len ; get [bx].end
sub ax,dx ; less new.len
sub ax,si ; compare to new.Base
jbe AM04 ; brif new.end >= [bx].end
; now ax has the amount our block must grow by
add dx,ax
AM04:
mov [bx].Flags,UNUSEDFLAG ; mark the block unused
or di,di ; did we find an unused handle yet?
jnz AM05 ; brif so
mov di,bx ; save this one if not
AM05:
add bx,SIZE handle
loop AM01
or di,di ; did we find a free handle?
jz AM06 ; error! no handles free!
mov [di].cLock,0
mov [di].Flags,FREEFLAG ; create the free memory block
mov [di].Base,si
mov [di].Len,dx
AM06:
pop es
assume es:nothing
ret
AddMem endp
PUBLIC DOCLI
DOCLI:
FCLI
ret
PUBLIC DOSTI
DOSTI:
FSTI
ret
PUBLIC DOIRET
DOIRET:
FIRET
_text ends
end