dos_compilers/Zortech C++ v206/SOURCE/CLIB/HANDLE.ASM
2024-07-02 07:30:38 -07:00

849 lines
16 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;_ handle.asm Thu Jul 13 1989 Modified by: Walter Bright */
; Copyright (C) 1989 by Walter Bright
; All Rights Reserved
; Written by Walter Bright
include macros.asm
if LCODE
; extrn _sound_click:far
extrn __exit:far
extrn _page_malloc:far,_page_calloc:far,_page_realloc:far
extrn _page_free:far,_page_maxfree:far,_page_initialize:far
extrn _calloc:far,_malloc:far,_realloc:far,_free:far
else
; extrn _sound_click:near
extrn __exit:near
extrn _page_malloc:near,_page_calloc:near,_page_realloc:near
extrn _page_free:near,_page_maxfree:near,_page_initialize:near
extrn _calloc:near,_malloc:near,_realloc:near,_free:near
endif
HANDLE_BASE equ 0FE00h ;segment values >= are handles
HANDLE_MAXPAGES equ 0200h ;max number of pages (10000h-0FE00h)
HANDLE_PAGESIZE equ 04000h ;16k
begdata
public _handle_inited
extrn __osmode:byte ;= 1 if in protected mode
frametable dw 4 dup (?) ;index is frame number (0..3)
;value is logical page number (0..numpages)
lrulist db 4 dup (?) ;index is order of least frequently used
;value is frame number (0..3)
emm_handle dw -1 ;handle for our pages
emm_pageframe dw ? ;segment of page frame base
numpages dw ? ;number of pages alloc'd to us
numused dw ? ;number of pages actually in use
tableoffset dw ? ;offset in 0th page of page table
handle_maxsize dw ? ;max possible allocation size
emm_name db 'EMMXXXX0' ;EMS device driver name
_handle_inited db 0 ;!=0 if initialized
usestdlib db 1 ;0 if EMS is present and working
emm_version db 0 ;version number
emm_errmsg db 0Dh,0Ah,'EMM fatal error',0Dh,0Ah,'$'
enddata
begcode handle
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ctrl_break_int dd ? ;original ctrl-break handler
public ctrl_break_handler
ctrl_break_handler:
pushf
.push <AX,DX,DS>
mov AX,DGROUP
mov DS,AX
callm handle_term
.pop <DS,DX,AX>
popf
jmp CS:ctrl_break_int ;and continue with previous
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Initialize EMS handler.
c_public handle_init
func handle_init
.if _handle_inited ne 0, I6 ;quit if already initialized
.if __osmode ne 0, I6 ;quit if in protected mode
;Test for presence of EMS using 'get interrupt vector' technique
mov AX,3567h ;get interrupt vector for EMS interrupt
bdos ; into ES:BX
.save <SI,DI>
mov DI,10 ;offset to device name field
mov SI,offset DGROUP:emm_name
mov CX,8 ;number of bytes in name
repe cmpsb ;compare names
.restore <DI,SI>
mov AX,1 ;error code for not present or obsolete version
jne I6 ;if not present
;EMS is present. Get status of it.
mov AH,40h
int 67h
tst AH
jnz I6 ;error
;Get page frame address
mov AH,41h
int 67h
tst AH
jnz I6 ;error
mov emm_pageframe,BX
;Get version number, error out if version < 3.2
mov AH,46h
int 67h
tst AH
jnz I6
.if AL ae 32h, I5 ;if supported version
I6: ret
I5: mov emm_version,AL
;Determine number of unallocated pages
mov AH,42h
int 67h
tst AH
jnz I6 ;error
tst BX ;any available?
jz I6 ;no
.if emm_version b 40h, I3
mov BX,1 ;we'll expand it as necessary
I3: .if BX b HANDLE_MAXPAGES, I2
mov BX,HANDLE_MAXPAGES ;don't hog more than we can use
I2: mov numpages,BX
;And allocate all of them to us
mov AH,43h
int 67h
tst AH
jnz I6 ;error
mov emm_handle,DX
mov _handle_inited,1
mov usestdlib,0
;Intercept Ctrl-Break so handle_term is called
mov AL,23h ;Ctrl-Break interrupt number
bdos 35h ;get vector in ES:BX
mov CS:word ptr ctrl_break_int,BX
mov CS:word ptr ctrl_break_int[2],ES
mov DX,offset ctrl_break_handler
push DS
push CS
pop DS
bdos 25h ;set interrupt vector to DS:DX
pop DS
;Initialize lrulist
mov lrulist,0
mov lrulist+1,1
mov lrulist+2,2
mov lrulist+3,3
;Initialize frametable
mov AX,-1
mov frametable,AX
mov frametable+2,AX
mov frametable+4,AX
mov frametable+6,AX
.save <SI,DI>
;Bring page 0 in, initialize it, and create our map table in it
mov numused,1
clr BX
call mappage
mov SI,BX
mov DI,ES
mov AX,HANDLE_PAGESIZE
push AX
push ES
push BX
call _page_initialize
add SP,6
mov handle_maxsize,AX
mov AX,numpages
.if emm_version b 40h, I4
mov AX,HANDLE_MAXPAGES ;so we never need to realloc it
I4: shl AX,1
push AX
push DI
push SI
call _page_malloc
add SP,6
mov tableoffset,AX
push DI
push SI
call _page_maxfree
add SP,4
mov ES,DI
add SI,tableoffset
mov ES:[SI],AX
.restore <DI,SI>
ret
c_endp handle_init
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Terminate use of HANDLE handler.
c_public handle_term
func handle_term
.if _handle_inited e 0, T1 ;not initialized, so no terminate
mov DX,emm_handle
mov AH,45h
int 67h ;deallocate pages
;Ignore errors at this point
mov emm_handle,-1
mov _handle_inited,0
T1: ret
c_endp handle_term
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Non-recoverable EMM error has occurred.
; Print a message and abort the program with an exit status equivalent
; to the error code.
; Input:
; AH error code
; Returns:
; doesn't return
emm_error proc near
if LPTR
;DS might point to a buffer instead of the data segment,
;so reload it.
mov AX,seg DGROUP
mov DS,AX
endif
mov DX,offset DGROUP:emm_errmsg
bdos 9 ;print error message
mov AL,AH
clr AH
push AX
call __exit ;abort
emm_error endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Bring logical page BX into a frame.
; Returns:
; ES:BX pointer to frame
; AX,DX destroyed
public mappage
mappage proc near
;Look to see if it's already mapped. The idea is to minimize
;calls to the emm driver to swap pages, in case the driver
;must page to disk to emulate emm.
;The emm driver may also be inefficiently implemented.
clr AX
.if BX e <frametable>, L2
inc AL
.if BX e <frametable+2>, L2
inc AL
.if BX e <frametable+4>, L2
inc AL
.if BX e <frametable+6>, L2
mov AL,lrulist ;pick least recently used frame
;Map logical page BX into frame AL
xchg AX,BX
shl BX,1
mov frametable[BX],AX ;update frametable[]
shr BX,1
xchg AX,BX
mov DX,emm_handle
mov AH,044h ;map handle page
int 67h
tst AH
jnz emm_error
mov AL,lrulist
jmp L7 ;adjust lru list
L2: ;It's already mapped. Merely adjust lru list.
.if AL e <lrulist+3>,L10
.if AL e <lrulist+2>,L9
.if AL e <lrulist+1>,L8
;Then AL e <lrulist>
L7: mov BL,lrulist+1
mov lrulist,BL
L8: mov BL,lrulist+2
mov lrulist+1,BL
L9: mov BL,lrulist+3
mov lrulist+2,BL
mov lrulist+3,AL
L10: ;Convert frame number in AL to base pointer in ES:BX
xchg AH,AL ;note that AH is 0 at L10
shl AH,1
shl AH,1
add AX,emm_pageframe
mov ES,AX
clr BX ;offset portion is always 0
ret
mappage endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Access a handle.
; void far * pascal handle_access(void handle *);
_handle_access proc near
push BP
mov BP,SP
clr AX
mov DX,4+2[BP]
.if DX b HANDLE_BASE, A1
sub DX,HANDLE_BASE
mov BX,DX
call mappage
mov DX,ES
mov AX,BX
A1: add AX,4[BP]
pop BP
ret 4
_handle_access endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Add page to free handle pool.
; Returns:
; 0 unsuccessful
; !=0 page number of added page
public _handle_addpage
_handle_addpage proc near
mov BX,numused
.if emm_version b 40h, D2
inc BX ;we need another
push BX
mov DX,emm_handle
mov AH,51h ;reallocate pages
int 67h
pop CX
tst AH
jz D3 ;all's well
.if AH e 87h, D1 ;no more pages available
.if AH e 88h, D1 ;ditto (I don't understand the diff)
D4: jmp emm_error ;non-recoverable error
D3: .if CX ne BX, D4 ;if (actual count != requested count)
jmp D5 ;they're the same, so we're ok
D2: .if BX e numpages, D1 ;no more available
D5: call mappage ;swap in the new page
push ES
push BX ;for _page_maxfree
mov AX,HANDLE_PAGESIZE
push AX
push ES
push BX
call _page_initialize
add SP,6
call _page_maxfree
add SP,4
push AX ;save size of max free block
clr BX
call mappage
add BX,tableoffset
mov AX,numused ;get page number of new page
shl AX,1 ;convert to index into page table
add BX,AX
pop ES:[BX] ;store size of max free block
shr AX,1 ;back to page number
inc numused
ret
D1: clr AX
ret
_handle_addpage endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public _handle_malloc
func handle_malloc
.if usestdlib ne 0, M1
push BP
mov BP,SP
.save <SI,DI>
;Bring page 0 into a frame
clr BX
call mappage
add BX,tableoffset
;Search for page which has enough free space
mov SI,numused
dec SI ;numused should always be > 0
shl SI,1
mov DX,P[BP] ;nbytes
tst DX
jz M10 ;allocating 0 bytes
.if DX a handle_maxsize, M10 ;too big
M5: .if ES:[BX+SI] ae DX, M4 ;found one
sub SI,2
jnc M5
jmp M7 ;try regular malloc
M10: .restore <DI,SI>
pop BP
M1: ;Use stdlib's malloc()
push BP
mov BP,SP
push P[BP]
call _malloc
mov SP,BP
pop BP
if SPTR
M3: mov BX,AX
cwd
tst AX ;if malloc returned NULL
jz M8
mov DX,DS
M8: ret
else
mov BX,AX
ret
endif
M4: ;At this point:
; ES:BX == ptr to page 0
; SI == 2 * page number of that page
push ES
push BX
mov BX,SI
shr BX,1 ;BX = page number
call mappage
;Allocate from that page
push ES
push BX ;baseptr for _page_maxfree
push P[BP] ;nbytes
push ES
push BX ;baseptr
callm page_malloc
add SP,6
;Should always succeed
mov DI,AX
;Recalc free space for that page
call _page_maxfree ;baseptr is already on stack
add SP,4
;And stuff it into page 0
pop BX
pop ES
mov ES:[BX+SI],AX
mov BX,DI ;offset
mov DX,SI
shr DX,1 ;DX = page number
add DX,HANDLE_BASE ;to make it a real handle
M6: .restore <DI,SI>
pop BP
ret
M7: ;Attempt to get more pages
push ES
push BX ;save base ptr of page table
call _handle_addpage
pop BX
pop ES
tst AX ;succeeded?
jz M9 ;no
shl AX,1 ;convert page # to offset in table
mov SI,AX
jmp M4
M9: push P[BP] ;nbytes
call _malloc
pop BX ;clear stack
mov BX,AX
if SPTR
cwd
tst AX ;if malloc returned NULL
jz M6
mov DX,DS
endif
jmp M6
c_endp handle_malloc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public _handle_calloc
func handle_calloc
push BP
mov BP,SP
.if usestdlib ne 0, C1
;malloc the data
push P[BP]
call _handle_malloc
pop CX ;clean stack
tst DX
jz C2 ;result is NULL
.save <DI>
push DX
push BX
;DX:AX is the handle, we need to convert it to a pointer in ES:DI
push DX ;save handle
push BX
call _handle_access ;convert handle
mov ES,DX
mov DI,AX
;Clear the memory
mov CX,ES:-2[DI]
shr CX,1 ;# of words (including byte count)
dec CX ;skip # of bytes
clr AX
rep stosw ;clear the memory
pop BX ;restore handle
pop DX
.restore <DI>
C2: pop BP
ret
C1: mov AX,1
push AX
push P[BP] ;nbytes
call _calloc
add SP,4
pop BP
if SPTR
jmp M3 ;convert near pointer to far pointer
else
mov BX,AX
ret
endif
c_endp handle_calloc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public _handle_free
func handle_free
push BP
mov BP,SP
mov DX,P+2[BP]
.if DX b HANDLE_BASE, F1 ;if a regular far pointer
push DX
clr AX
push AX
call _handle_access
push DX
push AX ;baseptr for _page_maxfree
push P[BP] ;offset
push DX
push AX ;baseptr
call _page_free
add SP,6
call _page_maxfree ;recalc max free block size
mov SP,BP
push AX ;save max free size
clr BX
call mappage
add BX,tableoffset
mov DX,P+2[BP]
sub DX,HANDLE_BASE
shl DX,1
add BX,DX
pop ES:[BX] ;store max free size in page table
pop BP
ret
F1:
if LPTR
push DX
endif
push P[BP]
call _free
mov SP,BP
pop BP
ret
c_endp handle_free
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public _handle_realloc
func handle_realloc
push BP
mov BP,SP
mov AX,P+4[BP] ;nbytes
tst AX
jnz R1
;nbytes is 0, so same as handle_free()
push P+2[BP]
push P[BP]
call _handle_free
clr BX
mov DX,BX ;return NULL
mov SP,BP
pop BP
ret
R1: mov DX,P+2[BP] ;oldh
tst DX
jnz R2
;it's NULL, so same as handle_malloc()
push AX
call _handle_malloc
mov SP,BP
pop BP
ret
R2: .if DX b HANDLE_BASE, R7 ;if far pointer, use standard realloc()
.if usestdlib e 0, R3
R7: ;Use stdlib's realloc()
push AX ;nbytes
if LPTR
push DX
endif
push P[BP] ;old pointer
call _realloc
mov SP,BP
pop BP
if SPTR
jmp M3
else
mov BX,AX
ret
endif
R3: push DX
clr AX
push AX
call _handle_access ;get base pointer
push DX
push AX ;push baseptr for _page_maxfree
push P+4[BP] ;nbytes
push P[BP] ;old offset
push DX
push AX ;base pointer
call _page_realloc
add SP,8
tst AX ;succeeded?
jz R4 ;no
mov P[BP],AX ;save new offset
;Set new max size
call _page_maxfree
add SP,4
push AX ;save max free size
clr BX
call mappage ;map page 0
add BX,tableoffset
mov DX,P+2[BP]
sub DX,HANDLE_BASE
shl DX,1
add BX,DX
pop ES:[BX] ;store max free size in page table
mov BX,P[BP]
mov DX,P+2[BP] ;same handle as before, with new offset in AX
pop BP
ret
R4: add SP,4 ;extra baseptr parameter
;We'll have to handle_malloc() a new chunk, copy the data over,
;and free the original
push P+4[BP]
call _handle_malloc
add SP,2
tst DX ;failed?
jz R5 ;yes, return NULL
.save <SI,DI>
push DX
push BX
;Get pointer to new one in ES:DI
push DX
push BX
call _handle_access
mov SI,DX ;SI will be saved across the next handle_access
mov DI,AX
;Get pointer to original in DS:SI
push DS
push P+2[BP]
push P[BP]
call _handle_access
mov DS,DX
mov ES,SI
mov SI,AX
;Get into CX the smaller of nbytes or the old allocation size
mov CX,ES:-2[DI]
.if CX b -2[SI], R6
mov CX,-2[SI]
R6:
shr CX,1 ;convert to word count
dec CX ;skip extra word at beginning
rep movsw
pop DS
;Free the old handle
push P+2[BP]
push P[BP]
call _handle_free
add SP,4
;Get new handle into DX:BX
pop BX
pop DX
.restore <DI,SI>
R5: pop BP
ret
c_endp handle_realloc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; char handle *handle_strdup(const char handle *string);
public _handle_strdup
func handle_strdup
push BP
mov BP,SP
mov BX,P[BP]
mov DX,P+2[BP]
callm _HTOFPTR@ ;convert to far pointer
mov AX,ES
or AX,BX
jz S1 ;string is NULL, so return NULL
;Determine length of string pointed to by ES:BX
sub SP,6
mov -2[BP],ES
mov -4[BP],BX ;save dereferenced handle
push DI
mov DI,BX
clr AX ;scan for 0
mov CX,-1 ;longest possible string
repne scasb
not CX ;CX = strlen(string) + 1
mov -6[BP],CX
;Allocate storage for the duplicated string
push CX
callm handle_malloc
add SP,2
mov AX,BX
or BX,DX
jz S2 ;out of memory, return NULL
;Dereference the new handle
push DX
mov BX,AX
callm _HTOFPTR@
;Copy the string over
mov DI,BX ;destination
push DS
push SI
lds SI,-4[BP] ;DS:SI = source
mov CX,-6[BP] ;strlen(string) + 1
rep movsb
pop SI
pop DS
mov BX,AX
pop DX ;DX:BX = handle of result
S2: pop DI
mov SP,BP
S1: pop BP
ret
c_endp handle_strdup
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Input:
; DX:BX ;handle
; Output:
; ES:BX ;far pointer
public __HTOFPTR@
func _HTOFPTR@
.if DX ae HANDLE_BASE, H1
mov ES,DX
ret
H1: .if _handle_inited e 0, H2
push AX
; push AX
; push CX
; callm sound_click
; pop CX
; pop AX
push DX
sub DX,HANDLE_BASE
push BX
mov BX,DX
call mappage
pop AX
add BX,AX
pop DX
pop AX
ret
H2: jmp emm_error
c_endp _HTOFPTR@
endcode handle
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Setup function pointers for initialization and termination as
; static constructors/destructors.
static_ctor _handle_init
static_dtor _handle_term
end