page 58,132 ;****************************************************************************** title EMMSUP - EMM support routines ;****************************************************************************** ; ; (C) Copyright MICROSOFT Corp. 1986 ; ; Title: CEMM.EXE - COMPAQ Expanded Memory Manager 386 Driver ; EMMLIB.LIB - Expanded Memory Manager Functions Library ; ; Module: EMMSUP - EMM support routines ; ; Version: 0.04 ; ; Date: May 13, 1986 ; ;****************************************************************************** ; ; Change log: ; ; DATE REVISION DESCRIPTION ; -------- -------- ------------------------------------------------------- ; 5/13/86 Original Initial _TEXT ; 6/14/86 Added _sotofar routine and removed stack define. ; And added protected mode check to Map_Page (SBP). ; 6/14/86 map_page now sets _current_map(SBP). ; 6/14/86 moved save_current_map and restore_map from C code (SBP) ; 6/14/86 brought SegOffTo24 and SetDescInfo in from LAST code ; segment as local routines(SBP). ; 6/21/86 0.02 cld in copyout (SBP). ; 6/21/86 0.02 MapHandlePage added. ; 6/23/86 0.02 make_addr, sotofar removed. source_addr and dest_addr ; added. ; 6/27/86 0.02 Fix for restore_map. ; 6/28/86 0.02 Name change from CEMM386 to CEMM (SBP). ; 7/06/86 0.04 Changed _emm_page,_emm_free, & _pft386 to ptrs (SBP). ; 7/06/86 0.04 Changed assumes from _DATA to DGROUP (SBP). ; 7/06/86 0.04 Changed internal save area structure (SBP). ; 7/06/86 0.04 moved SavePageMap and RestorePageMap to .ASM (SBP). ; 7/07/86 0.04 moved MapHandlePage,SavePageMap, and RestorePageMap to ; emmp.asm (SBP). ; 5/09/88 1.01 moved routines names_match and flush_tlb from win386 ; 9/01/88 rename SegOffTo24/SetDescInfo to ; SegOffTo24Resident/SetDescInfoResdient and made public ;****************************************************************************** ; ; Functional Description: ; Support routines for emm/386 ; C callable ; ; ;****************************************************************************** .lfcond ; list false conditionals .386p ;****************************************************************************** ; P U B L I C S ;****************************************************************************** public _source_addr public _dest_addr public _copyout public _copyin public _wcopy public _wcopyb public _valid_handle public SetDescInfoResident public SegOffTo24Resident ; ;****************************************************************************** ; D E F I N E S ;****************************************************************************** include vdmseg.inc include vdmsel.inc include desc.inc include page.inc ; include instr386.inc include emmdef.inc FALSE equ 0 TRUE equ not FALSE CR equ 0dh LF equ 0ah page ;****************************************************************************** ; E X T E R N A L R E F E R E N C E S ;****************************************************************************** _DATA SEGMENT ; ; pointer to entry stack frame ; stored as offset, SS extrn _regp:word ; ; current state of mapping registers and # of mapping registers emulated ; ;extrn _current_map:byte ;extrn _map_size:byte ; ; total # of EMM pages in system ; extrn _total_pages:word ; ; table of offsets into in to the first page table ; for user logical emm page map ; extrn _page_frame_base:dword ; ; ptr to table of emm page # for each handle's logical pages. ; extrn _emm_page:word ; ; ptr to table of page table entries for the EMM pages ; extrn _pft386:word ; note: actually a dword array ; ; handle data structure ; extrn _handle_table:word extrn _handle_table_size:word ; ; save area for handles ; extrn _save_map:byte _DATA ENDS page ;****************************************************************************** ; L O C A L D A T A ;****************************************************************************** _DATA SEGMENT ; ; kludge to prevent unresolved from C compiler ; public __acrtused __acrtused label dword dd (0) _DATA ENDS page ;****************************************************************************** ; C O D E ;****************************************************************************** _TEXT SEGMENT assume cs:_TEXT, ds:DGROUP, ss:DGROUP ;*********************************************** ; ; _source_addr - return far pointer for source address (= int 67 entry DS:SI). ; ; SYNOPSIS: src = source_addr() ; char far *src; /* ptr to area at DS:SI */ ; ; DESCRIPTION: This function generates a far pointer equivalent to the client's ; DS:SI pointer. If this code was called in protected mode, the ; address is a (selector,offset) pair; otherwise, it is a segment ; offset pair. EMM1_GSEL is used if a selector is needed. ; ; 05/09/88 ISP No update needed for MEMM ;*********************************************** _source_addr proc near ; push bp ; mov bp,[_regp] ; get entry stack frame pointer test [bp.PFlag],PFLAG_VIRTUAL ;Q: real/virtual mode ? jnz sa_pm ; N: go get selector/offset mov ax,word ptr [bp.rSI] ; Y: get offset mov dx,word ptr [bp.rDS] ; get segment jmp sa_exit ; return DX:AX = seg:offset ; ; protected mode - set up selector to client's DS sa_pm: push bx push cx push es ; save ES ; ; load ES with GDT alias ; push GDTD_GSEL pop es ; ES -> GDT ; ; compute physical address ; mov ax,word ptr [bp.rDS] ; ax <-- base addr mov dx,word ptr [bp.rSI] ; dx <-- offset call SegOffTo24Resident ; converts to physical addr ; ; set up the appropriate table entry ; mov bx,EMM1_GSEL ; bx <-- selector mov cx,0FFFFh ; cx <-- gets limit (64k) mov ah,D_DATA0 ; ah <-- gets access rights ; ; at this point: ; ah -- access rights ; al -- bits 16-23 of linear address ; dx -- low 16 bits of linear address ; cx -- limit = 64k ; bx -- selector ; es -- selector to GDT Alias call SetDescInfoResident ; set up descriptor ; ; set up return pointer ; xor ax,ax ; ax <-- offset (0) mov dx,bx ; dx <-- selector ; pop es ; restore ES pop cx pop bx ; sa_exit: pop bp ret ; _source_addr endp ;*********************************************** ; ; _dest_addr - return far pointer for destination address (= int 67 entry ES:DI). ; ; SYNOPSIS: dest = dest_addr() ; char far *dest; /* ptr to area at ES:DI */ ; ; DESCRIPTION: This function generates a far pointer equivalent to the client's ; ES:DI pointer. If this code was called in protected mode, the ; address is a (selector,offset) pair; otherwise, it is a segment ; offset pair. EMM2_GSEL is used if a selector is needed. ; ; 05/09/88 ISP No update needed for MEMM ;*********************************************** _dest_addr proc near ; push bp ; mov bp,[_regp] ; get entry stack frame pointer test [bp.PFlag],PFLAG_VIRTUAL ;Q: real/virtual mode ? jnz da_pm ; N: go get selector/offset mov ax,word ptr [bp.rDI] ; Y: get offset mov dx,word ptr [bp.rES] ; get segment jmp da_exit ; return DX:AX = seg:offset ; ; protected mode - set up selector to client's DS da_pm: push bx push cx push es ; save ES ; ; load ES with GDT alias ; push GDTD_GSEL pop es ; ES -> GDT ; ; compute physical address ; mov ax,word ptr [bp.rES] ; ax <-- base addr mov dx,word ptr [bp.rDI] ; dx <-- offset call SegOffTo24Resident ; converts to physical addr ; ; set up the appropriate table entry ; mov bx,EMM2_GSEL ; bx <-- selector mov cx,0FFFFh ; cx <-- gets limit (64k) mov ah,D_DATA0 ; ah <-- gets access rights ; ; at this point: ; ah -- access rights ; al -- bits 16-23 of linear address ; dx -- low 16 bits of linear address ; cx -- limit = 64k ; bx -- selector ; es -- selector to GDT Alias call SetDescInfoResident ; set up descriptor ; ; set up return pointer ; xor ax,ax ; ax <-- offset (0) mov dx,bx ; dx <-- selector ; pop es ; restore ES pop cx pop bx ; da_exit: pop bp ret ; _dest_addr endp page ;*********************************************** ; ; _copyout ; ; This routine takes a far pointer, a near pointer ; and a byte count and copies from the near address ; to the far address. ; ; Parameters: ; destptr -- sel:off 286 pointer to target area ; srcptr --- offset of source data in current D Seg ; count ---- byte count for copy ; ; uses: ; cx, ax, es ; ; 05/09/88 ISP No update needed for MEMM ;*********************************************** destptr = 4 srcptr = 8 count = 10 _copyout proc near push bp ; entry prolog mov bp,sp push di ; reg var push si ; reg var les di,[bp+destptr] ; es:di <-- destination address mov si,[bp+srcptr] ; ds:si <-- source address mov cx,[bp+count] ; cx <-- byte count cld ; strings foward rep movsb ; do it pop si ; restore reg var pop di ; restore reg var pop bp ret _copyout endp page ;*********************************************** ; ; _copyin ; ; This routine takes a near pointer, a far pointer ; and a byte count and copies from the far address ; to the near address. ; ; Parameters: ; destptr -- offset of dest in current D Seg ; srcptr --- sel:off 286 pointer to source data area ; count ---- byte count for copy ; ; uses: ; cx, ax, es ; ; 05/09/88 ISP Written for MEMM. ;*********************************************** destptr = 4 srcptr = 6 count = 10 _copyin proc near push bp ; entry prolog mov bp,sp push di ; reg var push si ; reg var push ds push ds pop es ; es to dgroup mov di,[bp+destptr] ; es:di <-- destination address lds si,[bp+srcptr] ; ds:si <-- source address mov cx,[bp+count] ; cx <-- byte count cld ; strings foward rep movsb ; do it pop ds pop si ; restore reg var pop di ; restore reg var pop bp ret _copyin endp page ;*********************************************** ; ; _wcopy ; ; This routine takes a two near pointers ; and a word count and copies from the ; first address to the second address. ; ; Parameters: ; srcptr --- offset of source data in current D Seg ; destptr -- offset of destination address in DS ; count ---- word count for copy ; ; uses: ; si, di, cx, ax ; (si, di are restored) ; ; 05/09/88 ISP No update needed for MEMM ;*********************************************** srcptr = 4 destptr = 6 count = 8 _wcopy proc near push bp ; entry prolog mov bp,sp push di ; reg var push si ; reg var cld ; clear dir flag (forward move) mov ax,ds ; mov es,ax ; mov es,ds mov di,[bp+destptr] ; es:di <-- destination address mov si,[bp+srcptr] ; ds:si <-- source address mov cx,[bp+count] ; cx <-- word count rep movsw ; do it pop si ; restore reg var pop di ; restore reg var pop bp ret _wcopy endp page ;*********************************************** ; ; _wcopyb ; ; This routine takes a two near pointers ; and a word count and copies from the ; first address to the second address. ; The copy is done backwards to allow certain overlap of source and destination. ; ; Parameters: ; srcptr --- offset of source data in current D Seg ; destptr -- offset of destination address in DS ; count ---- word count for copy ; ; uses: ; si, di, cx, ax, es ; (si, di are restored) ; ; 05/20/88 ISP Shifted in from win386 and updated for 16 bit ptrs ;*********************************************** srcptr = 4 destptr = 6 count = 8 _wcopyb proc near push bp ; entry prolog mov bp,sp push di ; reg var push si ; reg var mov ax,ds ; mov es,ax ; mov es,ds mov di, word ptr [bp+destptr] ; destination address mov si, word ptr [bp+srcptr] ; source address mov cx, word ptr [bp+count] ; word count dec cx shl cx, 1 ; offset of 'last' word to move add si, cx add di, cx mov cx, word ptr [bp+count] ; recover word count std ; set dir flag (backward move) rep movsw ; do it cld ; 'C' tends to expect this. pop si ; restore reg var pop di ; restore reg var pop bp ret _wcopyb endp page ;*********************************************** ; ; _valid_handle - validate current handle ; ; SYNOPSIS: hp = _valid_handle() ; struct handle_ptr *hp; /* ptr to handle's structure */ ; /* OR NULL_HANDLE if invalid handle */ ; /* also sets AH = INVALID_HANDLE if it fails */ ; ; DESCRIPTION: This routine validates the current handle in regp->rDX and ; returns either an error or a ptr to the handle's index and ; page count structure. ; ; 05/09/88 ISP No update needed for MEMM ;*********************************************** _valid_handle proc near ; push bp mov bp,[_regp] ; get entry args pointer push bx ; mov bx,word ptr [bp.rDX] ; BX = entry handle cmp bx,[_handle_table_size] ;Q: handle in range ? jae vh_fail ; N: return invalid handle error shl bx,2 ; Y: BX = handle's table offset add bx,offset DGROUP:_handle_table ; BX = offset to handle's data cmp [bx.ht_index],NULL_PAGE ;Q: is this an active handle ? je vh_fail ; N: return invalid handle error mov ax,bx ; Y: return ptr to handle's data ; vh_exit: pop bx pop bp ret vh_fail: mov byte ptr [bp.rAX+1],INVALID_HANDLE ; set AH on stack mov ax,NULL_HANDLE ; return NULL_HANDLE to caller jmp short vh_exit ; _valid_handle endp ;*********************************************** ; ; flush_tlb: ; ; no params, no return value, uses eax ; ; flush the Translation Look-Aside Buffer ; ; 05/09/88 ISP Shifted in from WIN386 ;*********************************************** _flush_tlb proc near public _flush_tlb mov eax, cr3 mov cr3, eax ret _flush_tlb endp ;*********************************************** ; ; _Names_Match ; ; Returns a boolean value (0 = false, FFFF = True) if 2 handle names match ; ; uses: ; cx, ax ; ; 05/09/88 ISP Shifted in from WIN386 and modified for 16 bit ptrs ;*********************************************** name1 = 4 name2 = 6 public _Names_Match _Names_Match proc near push bp ; entry prolog mov bp,sp push di ; reg var push si ; reg var mov ax,ds ; initialise es segment to mov es,ax ; DGROUP xor ax, ax ; Assume it did NOT work mov di, word ptr [bp+name1] ; First name mov si, word ptr [bp+name2] ; Second name cld mov cx, 2 ; Compare 2 dwords rep cmpsd ; do it jne SHORT Names_Dont_Match not ax ; They match! Names_Dont_Match: pop si ; restore reg var pop di ; restore reg var pop bp ret _Names_Match endp page ;** SetDescInfoResident - set descriptor information ; ; The limit field of a specified descriptor is set. ; (limit = size - 1). ; The base address of the specified descriptor is set. ; The access field of the specified descriptor is set. ; ; ENTRY BX = selector ; ES:0 = descriptor table to use ; CX = limit ; AL, DX = 24 bit base address ; AH = access rights byte ; EXIT None ; USES Flags, other regs preserved ; ; WARNING This code only works on a 286. It can be called in ; either mode. SetDescInfoResident proc near push bx ; save selector and bl,SEL_LOW_MASK ; fill in the limit field mov es:[bx],cx ; fill in base address mov es:[bx + 2],dx mov es:[bx + 4],al ; fill in access rights byte mov es:[bx + 5],ah pop bx ret SetDescInfoResident endp page ;** SegOffTo24Resident - convert seg:off to 24 bit physical address ; ; The specified real mode segment:offset is converted to ; a 24 bit physical address. ; ; ENTRY AX = segment ; DX = offset ; EXIT AL, DX = 24 bit physical address ; USES AH, Flags, other regs preserved. ; ; WARNING This code only works on a 286. It can be called in ; either mode. SegOffTo24Resident proc near push cx ; Convert AX:DX into 24 bit addr in AL, DX mov ch,ah shl ax,4 shr ch,4 ; CH = high byte add dx,ax ; DX = low word mov al,ch ; AL = high byte adc al,0 ; propagate cy from low word pop cx ret SegOffTo24Resident endp _TEXT ENDS END